The Beam and Ball Project - Part 2 Servo Control

 

Software (continued)


Servo Control

To control the servo the microcontroller need to produce this 50 Hz waveform shown below. The resolution is defined by the microcontroller because the servo is an analog device.


There are mainly three ways of doing it.

Delays

Set output, then do delay. This is a bad way of doing it. The program is halted for every delay. However if you want to mash up some code to test your servo, this is the way to go.
  • Consumes the whole CPU
  • Good and quick technique to test servos.


Hardware PWM

The most positive about hardware PWM is that the overhead is 0. The CPU usage is practically zero, and only one or two instruction cycles are used to set a new pulsewidth.
Running the PWM at 50Hz demands that the PIC16F887 is ran in max 1 MHz due to max prescaler settings. So at the beginning of the project I went with 1 MHz.

The 10bit capable Hardware PWM uses a CCPx module, and TMR2. TMR2 is 8 bit, however the remaining two least significant bits are made possible by the fact that the oscillator is four times faster than the system clock. These bits has the be written into another register, but that is a small price to pay. The PWM period is set by register PR2, which basically resets the timer when TMR2=PR2. The pulsewidth (dutycycle) is set by the CCPRxL register.

Only a small portion of the pulsewidth is used. Only 1 of 20 ms is used to vary the servoposition. In theory, the resolution possible is then 1024 (10bit) * 1ms/20ms = 51 steps. In practice I used 80 steps.

For a while i used this technique. 1 MHz seemed to be more than enough. The beam vibrated for every step which seemed to cause the ball to move unexpectedly. Filtering the distance measurements helped a lot, but still the quantization noise (if I can call it that) of only having 51 steps resolution was quite poor.
  • 0% CPU usage
  • Demands max Fosc=1 MHz to produce ~50Hz PWM.
  • Only 51 of the 1024 steps of the PWM is usable for servo control. Practically, I used 80 steps though.

Interrupts

For 50 Hz PWM, using interrupts is recommended. You'll need four interrupts in 20ms, which at Fosc=8Mhz isn't so bad. In 20 ms, the cpu can do (Fosc/4) * 0.02 s = 40 000 .. Say there is about 5-6 instructions in each interrupts.. Round it up to 10 to include pushing the stack and moving program counter (PC). That's 40 instructions in one PWM periods. The overhead will then be 40 / 40 000 = 0.1 % . Unless you have some time sensitive communication going in your code the overhead is negligiable.

You can almost fit a full period of TMR0 into 1 ms. At Fosc = 8 Mhz, one instruction cycle is 1 / Fosc/4 = 0.5 us. If you set the TMR0 prescaler to 1:8, then the timer runs at 4 us/tick. The nice thing about these settings is that 250 of the 256 TMR0 ticks fits into 1 ms. You get 5 times the resolution of the hardware PWM above (or 3 times the practical. see above).

At 1:8 prescaler, 8 instructions are exectued for each tick. How short time can you set until next interrupt? It is possible to set the TMR0=254 and get 1 tick until next interrupt if the interrupt service routine is short enough. You can also compensate by making the initil 1ms a couple of ticks shorter and then offset the pwm pulsewidth by a couple of ticks because there are 6 ticks of the 256 ticks not used. I didn't care about that in my code.


The red dots in the figure above signifies cpu interrupts. Four interrupts are needed:
  • t = 1 ms, output=1
  • t = dutycycle
  • t = 1 ms - dutycycle (the complement of dutycycle)
  • t = 18 ms
The first interrupt sets output to high and sets the timer to 1 ms. Prescaler is set to 1:8, TMR0=6 because then there are 250 ticks left for 1 ms.
The second interrupt defines the variable part of the dutycycle. It can be 0-1 ms long. TMR0=PWM.
The third interrupt sets output to low and fills the rest of the 1 ms period to ensure a fixed 20 ms period independent of the PWM value. TMR0=-PWM (Which isn't technically correct, maybe adding 6 ticks to that will make it perfect but I didn't bother with that.
The last interrupt sets the timer to 18 ms. The prescaler is set to 256 and TMR0=141.
The interrupts are sequenced with if sentences and a variable that increments between 0..3.

Kommentarer

Populære innlegg fra denne bloggen

Reverse engineering PCBs with KiCAD 7

The Videopac G7000 composite mod

Designing the Videopac SDCart. 2: The SD Cart demo