Servo Control

In my first lab we were getting a feel for the dsPIC30F4011 micro controller which we haven’t used before, we have used the MSP430 chip before and they work fairly similarly, just need to learn the names of the functions like P1DIR is like TRISD in the PIC. The way we’re doing this is by writing a code to control a servo, we’ll be controlling the servo using the bit banging method which is switching an output on and off creating certain length pulses. Using the pulse width modulation in the chip would be better but doing bit banging will help use get used to the __delay32.

We start with a code given to us by our lecturer which would switch from 0 degrees to 180 degrees but when I tested it, it didn’t look like it was going the full 180 degrees so I decided to change the pulse on top and bottom of the range to find the real values for 0 and 180 degrees. The datasheet suggests the values around 1ms to 2ms for the full range but from trial and error I found to get the full range of angles, the pulse range is 0.7ms to 2.2ms. The circuit and the final code for switching between 0 and 180 degrees is below, the code was edited from here.

servo.png

//
// dsPIC30F4011 bit-banging servo example
// Written by Ronan Byrne
// Last updated 26-9-2015
//

#include <xc.h>
#include <libpic30.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

int main()
{
    int counter;

    // Make all port D pins outputs
    TRISD = 0b0000;

    // Alternate between 0.7ms and 2.2ms pulses
    while(1)
    {

        // 100 1ms pulses @ 50Hz
        counter = 0;
        while(counter < 100)
        {
            _LATD1 = 1;
            __delay32(0.7*30000L); // 0.7ms delay
            _LATD1 = 0;
            __delay32(19.3*30000L); // 19.3ms delay

            counter = counter + 1;
        }

        // 100 2ms pulses @ 50Hz
        counter = 0;
        while(counter < 100)
        {
            _LATD1 = 1;
            __delay32(2.2*30000L); // 2.2ms delay
            _LATD1 = 0;
            __delay32(17.8*30000L); // 17.8ms delay

            counter = counter + 1;
        }
    }

    return 0;
}

From doing a bit of maths I found that its 8.33µs/degree and from this I can make a formula to find the pulse I need for a certain angle. P = P/° * θ + Po.
P = Pulse P/° = 8.33µs/degree,θ = Angle and Po = 0.7ms. And if you move around this formula you can find the angle for a certain pulse. From testing the formula its usually +- a few degrees which is accurate enough for any projects I’ll be doing. If I used other servos I’ll have to do this again but it didn’t take too long.
Next I decided to write a code that would have the servo rotate from side to side slowly instead of left to right in one step. This is the code I came up with.

//
// dsPIC30F4011 bit-banging servo rotating in steps
// Written by Ronan Byrne
// Last updated 24-9-2015
//

#include <xc.h>
#include <libpic30.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

int main()
{
    double pulse;
    int time;

    // Make all port D pins outputs
    TRISD = 0b0000;
    //Set the servo to 180 degrees
    pulse = 1.0;
    // Alternate between 1ms and 2ms pulses
    while(1)
    {
        // Creating a varying pulse to
        // rotate the servo to the right in steps @ 50Hz

        while(pulse< 2.2)
        {
            time = 0;
            // Give the servo time to get to new position
            while(time <5)
            {
                _LATD1 = 1;
                __delay32(pulse*30000L); // 1-2ms delay
                _LATD1 = 0;
                __delay32((20-pulse)*30000L); // 19-18ms delay
                time = time + 1;
            }

            pulse= pulse + 0.05;
        }

        // Creating a varying pulse to
        // rotate the servo to the left in steps @ 50Hz
        while(pulse > 0.7)
        {
            time = 0;
            while(time <5)
            {
                _LATD1 = 1;
                __delay32(pulse*30000L); // 2-1ms delay
                _LATD1 = 0;
                __delay32((20 - pulse)*30000L); // 18-19ms delay
                time = time + 1;
            }

            pulse = pulse- 0.05;
        }
    }

    return 0;
}

If you want the servo to rotate slower or faster, you’d just need to change the time value. I wrote this code because I may have to get a servo to do this in a future project so it would be good to know how to do it. This code could be used in something like a security camera to scan over an area.

Advertisements

One thought on “Servo Control

  1. Very good post.

    Just one little thing to watch out for. In both of your programs here, you say “TRISD = 0000;” to set all port D pins as output. Technically that’s correct because setting the TRISD register to zero will indeed make all port D pins outputs. However, writing it as “0000” makes it look like if some of those digits were set to “1” that would make the corresponding pins inputs, but that’s only the case if you write the TRISD value as a binary number, as in “TRISD = 0b1100” which makes RD0 and RD1 outputs and RD2 and RD3 inputs. The “0b” prefix tells the XC16 compiler that a number is a binary number rather than a decimal number (which will otherwise be assumed).

    As I said, in this case it makes no difference because

    0 (decimal) = 0000 (decimal) = 0b0000 (binary)
    

    However, let’s say you wrote…

    TRISD = 0010;
    

    That would assign the value 10 (ten) to the TRISD register. But…

    10 (decimal) = 0b1010 (binary)
    

    so the line above would actually set RD1 and RD3 as inputs.

    Ted

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s