SERVO Controller

Category : ,

It has been a while since my last post. I have been working on image processing project that use webcam and laser pointer. However, i will keep it for later post.

Probably most of you know what is servo motor ( RC Servo ). It is a close-loop(system) motor and the rotation of the motor controlled by pulse. For example, at frequency 50Hz or 20ms period, given 1.5ms will keep the motor at the center while 1.0ms and 2.0ms will rotate the motor to the left and right respectively. By default, servo motor able to rotate from 0 to 90 degree(for each side). However, you can modify the servo to have full 360 degree of rotation.

Since we need pulse to control it, we must be able to provide PWM signal to the servo. Microcontroller basically could do that either using hardware-based PWM or software-based PWM. My aims today is to create a software-based PWM controller with UI Application. That means i can control the rotation of the servo by dragging the track bar around.


Basically, the apps will send a command to the controller board and the controller will interpret the command and generate required pulse. This is software-based PWM, means the generated pulse come from the algorithm that turn-off and turn-on at certain time. It is different from hardware-base PWM which has dedicated hardware to do the job.
I programmed my controller to generate interrupt every 5us, which means 4000 times of interrupt needed to complete 20ms of period time. Therefore, 1ms pulse equal to 200 and 2ms is equal to 400.

void interrupt() {
  if(PIR1.TMR1IF==1)    // trigger every 5us
  {
  servo0++;             // servo1 counter
  ctr_pwm++;
  if(servo0<=duty0) portb.f0=1;
  else portb.f0=0;
  if(ctr_pwm==4000)          // 20 ms elapse
  {
    servo0=0; ctr_pwm=0;  //clear counter
  }
  //TMR1H = 0xFF;             // Timer1 register value
  //TMR1L = 0xE6;
  PIR1.TMR1IF = 0;            // clear TMR1IF
  }
}
// In the main routine, just override duty0 register to required value, such as
// 1.0ms = 200
// 1.5ms = 300
// 2.0ms = 400

For the PC side, I used Visual Studio Express for application development. The App will communicate with controller through RS232 or serial port. Based on user input, ie the duty cycle, a packet of command will be sent to controller and then decode the message accordingly. The controller the execute the instruction and return acknowledge signal to PC. The routine continue as user gives another input.
// C# codes
    if (trackBar2.Value > 255)
    {
        data = (byte)((trackBar2.Value) >> 8);
        SP.WR_byte(token);
        SP.WR_byte(data);
        SP.WR_byte((byte)trackBar2.Value);
    }
    else
    {
        SP.WR_byte(token);
        SP.WR_byte(0);
        SP.WR_byte((byte)trackBar2.Value);
    }
}



I used trackbar instead of textbox. Just scroll the trackbar and duty cycle changed accordingly. The textbox on the right side of trackbar display the current value of the trackbar. The values shown actually is not in duty cycle format, ie, 0 to 100%, but it is in interrupt number format( 0 to 4000 ).

The codes works perfectly, i can control two servo motor simultaneously. The apps will help me to control and test RC servo motor, as well as reducing developing time of any project that requires servo motor.

However, there is a drawback of using software-based pwm because this method is not efficient. The rate of rising and falling edge of a signal might not accurate as our math’s calculation. Moreover, i believe that interrupt resolution also played an important role here. When i started the project, i choose 10us rather than 5us, but the later gives me more accurate and reliable PWM readings.