Velocity control of a DC motor without any encoder

The new OpenServo V3 boards offer a new nifty feature for measuring the velocity of the driven motor without any additional sensors. The measurement principle is called Back-EMF (Back ElectroMotive Force). Here the electro-magnetic field which induces a voltage back to the turning coil is measurement. While supplying the motor with the needed current most of the time, the supply voltage is switched of periodically for a very short interval. For this interval the motor is used as a generator and the generated voltage is measured. This new feature provides the possibility to control the motor velocity without any additional sensor. Based on the current P(I)D algorithm for position control of the OpenServo I've implemented a PI+FF controller for velocity control like proposed by Barry Carter in this thread.

Technical Terms

Some readers may not be familiar with the technical terms in the following document so I will start with a short description of the important ones:

The PI+FF Controler

Explaining the PI+FF algorithm I wanted to start with a description of the letters PI+FF:

(!) Another function you need if you implement an I-component is an anti-windup. It's the maximum value the integrator can charge to compensate a steady error. If this limitation is omitted the integrator charges to very high values whenever the actuating variable exceeds it's natural limit. For example if we command a jump from zero to a high velocity the motor PWM will most likely exceeds it's maximum value until the motor has reached the setpoint velocity (the real signal to the motor is truncated of course to protect the hardware). Meanwhile the I-component will still increase because of the persisting difference between setpoint and measured velocity. When the motor reaches the setpoint velocity, the P-component vanishes and the FF-component should be exactly the PWM value needed to hold the setpoint velocity but the I-component causes an overshoot. To reduce this effect the I-component has to be limited.


The complete implementation can be found on the OpenServo CVS in /OpenServo/AVR_VelocityControl.

Toggle line numbers
   1 // The proportional component to the PD+FF is the velocity error.
   2   p_component  = seek_velocity - current_velocity;
   3 // Increment the integral component
   4   i_component += (int32_t) p_component * (int32_t) i_gain;
   5 // Saturate the integrator for anti wind-up
   6   if (i_component >  anti_windup) i_component =  anti_windup;
   7   if (i_component < -anti_windup) i_component = -anti_windup;
   8 // Start with zero PWM output.
   9   pwm_output = 0;
  10 // Apply the feed forward component of the PWM output.
  11   pwm_output += (int32_t) seek_velocity * (int32_t) feed_forward_gain;
  12 // Apply the proportional component of the PWM output.
  13   pwm_output += (int32_t) p_component * (int32_t) p_gain;
  14 // Apply the integral component of the PWM output.
  15   pwm_output += i_component;
  16 // Shift by 8 to account for the multiply by the 8:8 fixed point gain values.
  17   pwm_output >>= 8;

Test Bench

To see the quality of the measured back-emf signal and to evaluate the velocity control I've connected the OpenServo board to a test bench I've build for my balancing robot Hektor. The robot drive consists of a 3-6V DC motor and a gearbox. The shaft of the gearbox (where normally the wheel is mounted) is connected to a rotational sensor (in fact just an old ball mouse). Both signals are polled by an extra ATMEGA168 (back-emf over I2C from the OpenServo and angle over PS2 from the old mouse) and are send over RS232 to the PC.

TestBench.jpg pwm20to60.jpg

In the right plot you can see the motor velocity plotted over a short time inverval. The dashed curves is the velocity measured by the mouse and the dotted curves is the back-emf signal. The different colors are different PWM values started from 20 to 60. The fluctuation in both curves (back-emf and mouse signal) is because of the friction in the gearbox varies. You can even hear that the motor is not turning with constant speed.

Closed control loop

In the following plot you can see a comparison between the behavior of the controlled and the uncontrolled motor.

The green curve is the velocity of the controlled motor (velocity is commanded). At time step 100 the setpoint velocity is set to 150 and at time step 300 it's reset to zero again. The blue curve shows the velocity of the uncontrolled motor (PWM is commanded). At time step 100 the motor PWM is set to a value which correspond to a velocity of 150 (I've just tried different PWM values). At timestep 300 it's reset to zero again.


For a further discussion of the velocity control see the following thread:

OpenServo/VelocityControl (last edited 2008-05-09 15:08:22 by StefanEngelke)