This is an old revision of the document!
Necessary knowledge: [HW] Motor Module, [AVR] Digital Inputs/Outputs, [LIB] Motors, [LIB] Delay
Permanent magnet DC motors are very common in robotics and mechatronics. DC motors are relatively easy to control, both direction and speed. Motor rotation direction is determined by power supply polarity and H-bridge driver is often used when DC motor is controlled by microcontroller.
Even DC motor speed is easy to control there is no guarantee that required speed is also actually obtained. The reason is that the actual speed depends on several factors, primarily of the torque applied on the shaft, feeding current and other motor characteristics. The relationship between torque and speed of a ideal DC motor is linear, which means: the higher is the load on the shaft the lower is the speed of the shaft and the higher is the current through the coil. In reality it is not linear and can vary depending on the motor quite a lot.
Controlling the speed of DC motor can be realized either by analogous or digital signaling.
In general, motor speed is dependent of the applied voltage. When powering motor with its nominal voltage, motor runs at its nominal speed at no load condition. When reducing the voltage motor speed and torque also decreases. This kind of speed control can be called as analogous motor speed control. This can be realized for example with one transistor.
In robotics DC motors are in most cases controlled by microcontrollers and as microcontrollers are digital devices it is much easier to control motor speed also digitally. To do that, instead of keeping transistor open partly, transistors need to be closed and opened constantly using pulse width modulation (PWM), so the total energy supplied to the motor is somewhere between motor switched off and motor running on full power. Opened time in the whole PWM period is called duty cycle, which is marked as percents. 0% means the transistor is closed constantly – it is not conducting current. 100% means the transistor is constantly open and is conducting current all the time. The frequency of the PWM has to be high enough to avoid vibrations in the shaft of the motor. At low frequencies the motor produces noise and due to that, modulation frequencies over 20 kHz are used quite often. On the other hand the efficiency of the transistors might not be so good at higher frequencies. Vibrating of the shaft of the motor is reduced by inertia of the rotor and the inductivity of the coils. Instead of using single transistor, H-bridge can be feed with the same PWM signal by controlling so motor speed and direction.
Note: do not mix up RC PWM signal with ordinary PWM signals.
The Motor module of the HomeLab includes motor board and DC motor equipped with integrated gearbox and encoder. Motor board allows connecting up to four DC motors. The schemes and instructions for connection are found in the chapter “Motors module”. Every motor is connected to H-bridge which is controlled with two digital output pins of the microcontroller. Motor speed is controlled by timers which are generating software PWM signal for H-bridge. Motor speed can be controlled by relative value between 0 to 255, where 0 means that motor is stopped and 255 that motor runs at maximum speed.
// // The setup of the pins driving pins. // static pin dcmotor_pins[4][2] = { { PIN(B, 7), PIN(B, 4) }, { PIN(D, 1), PIN(D, 0) }, { PIN(D, 7), PIN(D, 6) }, { PIN(D, 5), PIN(D, 4) } }; // // Initialize PWM for specified DC motor. // void dcmotor_drive_pwm_init(unsigned char index, timer2_prescale prescaler) { unsigned char i, pwm; pin_setup_output(dcmotor_pins[index][0]); pin_setup_output(dcmotor_pins[index][1]); motor[index] = 1; pwm = PWMDEFAULT; for(i=0 ; i<CHMAX ; i++) // initialize all channels { compare[i] = pwm; // set default PWM values compbuff[i] = pwm; // set default PWM values } // Timer 2 normal regime, set prescaler timer2_init_normal(prescaler); // Timer 2 interrupts set enabled timer2_overflow_interrupt_enable(true); // Enable global interrupts sei(); } // // Change PWM for specified DC motor // void dcmotor_drive_pwm(unsigned char index, signed char direction, unsigned char speed) { switch (index) { case 0: if(direction == -1) { compbuff[0] = 0x00; compbuff[1] = speed; } if(direction == 1) { compbuff[0] = speed; compbuff[1] = 0x00; } break; case 1: if(direction == -1) { compbuff[2] = 0x00; compbuff[3] = speed; } if(direction == 1) { compbuff[2] = speed; compbuff[3] = 0x00; } break; case 2: if(direction == -1) { compbuff[4] = 0x00; compbuff[5] = speed; } if(direction == 1) { compbuff[4] = speed; compbuff[5] = 0x00; } break; case 3: if(direction == -1) { compbuff[6] = 0x00; compbuff[7] = speed; } if(direction == 1) { compbuff[6] = speed; compbuff[7] = 0x00; } break; } }
With the array dcmotor_pins in the library, the controlling pins of four motor-controllers are determined. Before controlling the motors and their speed, function dcmotor_drive_pwm_init with the number of the motor-controller (0 – 3) must be called out. It sets the pins as output. In addition prescaler - timer2_prescale prescaler have to be set as a second parameter. Prescaler sets PWM frequency and is important when using other timer based functions on the same time. If only motors are used TIMER2_NO_PRESCALE value is most suitable. If other timer based functions are used on the same time e.g. ultrasonic sensor TIMER2_PRESCALE_8 is recommended value. Bigger prescaler values are not suitable for DC motor speed control as vibration will be too high. However the same function can be used for example flashing the LED and in this case bigger prescaler values are important to consider.
For controlling motor speed the function dcmotor_drive_pwm is included into library. With this function three parameters are needed. First is motor index (0-3), second is direction -negative direction parameter is used to give to the motor one revolving direction and other direction with positive parameter, and 0 if the motor is stopped. Third parameter is speed where the value can be from 0 to 255. The speed value is not any specific rpm, but is relative value and the actual speed is depending on the motor and power supply. The precision of motor speed control is 8-bit, meaning that smallest controlling value is 1/255 of full speed.
The following is an example program which controls first DC motor (DC motor connector 0) so that motor speed is half of the full speed. The speed is modulated with PWM signal of controlling pin.
#include <homelab/module/motors.h> int main(void) { // DC motor 0 init with no prescaler dcmotor_drive_pwm_init(0, TIMER2_NO_PRESCALE); while(1) { // DC motor drive with half of the nominal speed dcmotor_drive_pwm(0, 1, 128); } }
Another example program which controls first DC motor (DC motor connector 0) with potentiometer from Sensor module.
#include <homelab/module/motors.h> #include <homelab/adc.h> int main(void) { int speed; // Adjusting ADC adc_init(ADC_REF_AVCC, ADC_PRESCALE_8); // DC motor 0 init with no prescaler dcmotor_drive_pwm_init(0, TIMER2_NO_PRESCALE); while(1) { // Potentiometer is connected to channel 3 // Average of 4 samples are acquired speed = adc_get_average_value(3, 4); // DC motor drive with speed from potentiometer // As potentiometer has 10-bit output but DC motor drive function // 8-bit input the adc output have to be converted to 8-bit // e.g dividing the output with 4, or shifting bit 2 position >>2 dcmotor_drive_pwm(0, 1, speed/4); } }