5

I want to write a program that controls a servo motor myself using a pi B+. Controlling the motor involves sending 1.5 millisecond pulses along a GPIO pin every 20 milliseconds. I have tested the following stripped-down code on a 32-bit x86 Ubuntu machine and the B+, and I get very different results. I compiled both with gcc.

#include <stdio.h>
#include <time.h>

int main()
{
    int num;
    long int signalTime = CLOCKS_PER_SEC * 3/2/1000; /* clocks in a 1.5 millisecond clock pulse */
    long int twentyMilliSec = CLOCKS_PER_SEC / 1000 * 20;
    clock_t start = clock();
    for (num = 0; num < 20; num++)
    {
        /* turn it on right here */
        printf("Turning on: %ld\n", clock() - start);
        while ((clock() - start) % twentyMilliSec  < signalTime)
            ;
        /*turn it off right here*/
        printf("Turning off: %ld\n", clock() - start);

        /* now we wait until 20 milliseconds is done */
        while ((clock() - start) % twentyMilliSec > signalTime)
            ;

    }
}

on the x86, I get the following output. Each number is 1 microsecond.

Turning on: 2
Turning off: 1501
Turning on: 20001
Turning off: 21501
Turning on: 40001
Turning off: 41501
Turning on: 60001
Turning off: 61501
Turning on: 80000
Turning off: 81500
Turning on: 100000
Turning off: 101500

Which is what I want, 1500 microsecond pulses with 20000 microsecond gaps between them. On the pi, I get the following.

Turning on: 0
Turning off: 10000
Turning on: 20000
Turning off: 30000
Turning on: 40000
Turning off: 50000
Turning on: 60000
Turning off: 70000
Turning on: 80000
Turning off: 90000
Turning on: 100000

It appears that the clock in is only accurate to 10000 microseconds. How can I get a clock in C that gives me enough precision to control a servo? I know it can be done, since there are C libraries that control servos for you.

3 Answers 3

4

Use gettimeofday(), it returns seconds and microseconds.

You are unlikely to get satisfactory results for servos using Linux sleeps. There will be glitches. Unless you have a particularly poor servo the glitches will result in servo twitches.

A B+ has two channels of hardware PWM suitable for driving servos.

The C libraries which generate hardware timed PWM on all the gpios use paced DMA to time the pulses.

1
  • Thank you. I will try using gettimeofday(), but if that does not work, it looks like pulse width modulation is what I'm looking for.
    – axl
    Jan 11, 2015 at 20:51
0

Sorry, but that will not work. Even if you tune the OS into the extremity, the servo will always wiggle about. I've done a lot of servo controlling myself, but using Atmel AVR microcontrollers (the ones used in Arduino's). You're way better off using a simple Arduino to control the servo('s).

I usually created an interrupt off a timer that would time 8 servo channels in a single go. The 1-2ms pulses would leave the pins one-by-one, but as long as the repeating frequency is 20ms you're fine (btw that is why I control 8 servo's - 8x2ms = 16ms which falls within the 20ms repeating frequency).

Maybe add a Pi to do any high-level stuff and telling the Arduino how to position the servos... If needed at all...?!?

1
  • A Pi can control servos, the point is that Linux sleeps are not the way to do so. Try one of the software modules which use hardware timing on the Pi (pigpio, servoblaster, piblaster, RPIO.GPIO, etc. etc.).
    – joan
    Jan 13, 2015 at 22:37
0

My PI v2 running raspbian jessie gives me:-

Turning on: 9
Turning off: 1502
Turning on: 20004
Turning off: 21503
Turning on: 40003
Turning off: 41504
Turning on: 60002
Turning off: 61503
Turning on: 80002
Turning off: 81502
Turning on: 100003
Turning off: 101502
Turning on: 120003
Turning off: 121502
Turning on: 140003
Turning off: 141502

etc etc etc So it seems to work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.