# Servo robot arm (PIC and MikroC)

#### stefan.54

Joined Dec 26, 2015
28
Hey guys!

I'm an EE student and I'm planning on building a 5 DOF robot arm with servo motors. I have searched the forums but couldn't find anything suitable for my needs.

The "big picture" looks like this: 6 180-degree servos and 5 10k-pots hooked to the MCU; the analog value of the pot reading should move the servos at a high resolution, describing an almost "fluid" motion. Also, one should be able to change 2 or more pots at a given time and the corresponding motors should move simultaneously, ignoring for the moment the stability of the whole arm.

Until now, I have implemented without success a hardware PWM code which moves the servos with low res and with jitter.

I know how servos work, but I cannot find a suitable approach for this problem. I have found Xor's high res servo controller program, but I do not understand Basic and cannot figure where to put the analog reading, nor can I think of a way to generate independent PWM signals (soft or hard-ware based).

I do have to add that I have access to a large variety of MCU (PIC 16F and 18F families).

I need all the guidance I can get with this projects, so please, help me out.

#### JohnInTX

Joined Jun 26, 2012
4,450
Welcome to AAC! You've described the basics - you need a PIC with at least 5 ADC channels and 6 pwms. I dont know if there is one.. time to do a parametric search at Microchip. (I'm on a slow connection ection or would do it). If you cant get 6 hardware pwms you can likely generate them with software. The firmware approach I would use is to write the analog in / pwm out in a zippy interrupt routine that posted adc results with any necessary signal conditioning to main and have main post the resulting pwm command for use by the interrupt. I'd use a minimum of a 18Fxxxx with a fast clock. So pick yer PIC, sketch up a schematic and post it. Once that is done, get an idea of pwm timings required, adc update rates etc. and see if makes sense. We just did a dual firmware pwm with an encoder input on a slow PIC in C so I would say its definitely do-able. Good luck in your search.

#### djsfantasi

Joined Apr 11, 2010
7,700
Robotshop.com sells a servo controller that uses TTL serial or USB to control up to 32 servos. You can then use a Pic to interface with your control pots. I did this with an animatronic figure with 11 servos (except I used an Arduino instead of a Pic.)

#### stefan.54

Joined Dec 26, 2015
28
Thank you guys for the swift answers! It is not my choice to use a PIC, but my lecturer demands it. I have a PIC16F1939 which has 5 CCP modules but only 3 type-2 timers (timer 2/4/6) and I believe some PWM signals will share the same timer. I cannot use the recommended servo controller as my project has to be made entirely by me (from schematic to etched boards). Good thing the university can provide any component I need.

I will keep you posted as soon as improvements are made.

#### spinnaker

Joined Oct 29, 2009
7,835
Just because you need to use the PIC16F1939 does not mean you can't use the kit I mentioned. Lots of the theory will still apply. But the lessons from Mikro are pretty good too and they are free. The downside is you need to wire everything up yourself which might introduce some error.

#### sailorjoe

Joined Jun 4, 2013
363
Is there a limit on the number of PICs you can use? Start with one PIC, and get it to run one servo. No timers, just one loop that reads the input and writes the output. Need to make it move smoother? Use a software based low pass filter, first or second order, but now you need to time the loop. Not difficult. If that works, just replicate it five more times.
Do the PICs have to communicate with each other to coordinate their actions? Use SPI to interconnect them together. There are other options.
The hardware is cheap in this case. Your time spent integrating all the bits is expensive. This approach tries to minimize your time by eliminating unnecessary problems.
Does that help?

#### JohnInTX

Joined Jun 26, 2012
4,450
Your distributed processing approach has merit. Little processors that have one task to do, and do well, can be integrated into a system controlled by a central processor - the 'brain' for lack of a better term... sorry. The tradeoffs are worth considering:

A single processor that controls all the functions by itself is certainly doable - the prime attraction is only one processor do deal with. The notable downside is that it takes some programming skills to pull it off. If statements like delay() are more comfortable than interrupt service, you'll have some things to learn. Its not that big a deal but yeah, not a gimmie. There is an extra layer of thought and some extra work that has to happen to make the processor get through its tasks (many pwms) and still have time left over for processing.. e.g. computing the pwm position. Not a trivial task. Not brain surgery either but will take some thinkin' to pull it off.

Your distributed-processor suggestion is a simplification to a point. If your processor only has to control one point that's pretty easy. But you are not completely off the hook. It still has to do its thing while receiving commands from a central controller. So.. no dumb delays here either. When you think about it, even a single point controller that has to listen to commands has a multi-tasking flavor.. Receive / process commands while doing the PWM. But in this configuration, you at least have enough hardware peripherals to help. One PWM. Nice. Leaves lots of time for the command receiver and processing. Nice nice. BUT (you knew this was coming..) the downside, besides the extra hardware, is that 1) you have to develop the communication protocol between the 'brain' processor and 2) you have to develop the 'brain' itself meaning 2 codesets to do and actually, 3 projects - the muscles, the nerves (comms) and the 'brain'. Hmm.. what to do.

Don't forget that we haven't touched on how we get the whole robotic action i.e. what the 'brain' is thinking... What to do , what to do...

The first (single PIC) approach is appealing because all of your problems are confined to one chip. Getting all of the PWMs going would require some slick programming. The 'brain' is integrated in such a way as not to affect PWM timing.. no delay() allowed. Doable - for me at least. You too if you are up to it. And we are here to help.
The second (distributed) approach has its appeal.. Develop on one, replicate on many. But then you have to control them. The 'brain' part is kind of the same as it would be in the the first scenario - and you'd have a bit more processing power to do it to boot. So that's a wash. But you would also have to connect all of the muscles to the brain (slaves to host - in the parlance) and that adds a layer of complexity ( a whole new program if you think about it).

I've done enough distributed systems to appreciate the simplicity of a single processor affair - if it has the horsepower in the first place.

Its late. Chew on it and check your comfort level. One intricate-timing project that does it all or multi-processor that is somewhat simpler on the PWM end but has the additional complexity of a comms link.
@GopherT touched on this using hardware pwm chips. It would have the same flavor but you would not have to program the slaves.

Sorry if this is rambling.. meant as food for thought.
What do you think?

#### dannyf

Joined Sep 13, 2015
2,197
I have implemented without success a hardware PWM code which moves the servos with low res and with jitter.
To do that, you will need to make sure that the mcu has sufficient number of pwm generators / timers. I suspect that your particular chip may not.

The easiest way to go is to use interrupts -> you can process far more "independent" pwm channels using one timer.

#### MMcLaren

Joined Feb 14, 2010
853
The PIC16F1939 has three ECCP modules. Two of those feature "PWM steering" onto four pins, while the remaining module features "PWM steering" onto two pins. With a relatively simple interrupt driven "helper", the ECCP module "PWM steering" feature can be used to drive up to ten Servos on the 16F1939. The secret is to stagger the four Servo output periods on each ECCP module by 5-millisecond intervals so that you can drive one Servo channel at a time from the single PWM output during each 5-millisecond interval while maintaining independent jitter free 20-millisecond Servo periods. In order to provide a high resolution pulse (1-microsecond steps) for each Servo, the PWM module uses a much smaller (250-microsecond) PWM period with twenty of these PWM periods linked together to make up the 5-millisecond "active" portion of each Servo period. Note that a 1000-microsecond PWM period would work just as well for this method.

If this method sounds confusing, I apologize. It may not be the easiest concept to grasp and I'd love to draw some graphs to help but I don't have much free time at the moment. If you're interested, I could attach a simple 4-channel Servo demo program in assembler with pseudo C code comments that I wrote a couple years ago to demonstrate the driver concept on a little 14-pin 16F1823. I suspect this subject might make a good article (does AAC pay for articles?). Anyway, here's a couple excerpts from that little 4-channel demo program;
Code:
;
;  unsigned int servo[] = { 1500, 1500, 1500, 1500 };
;
; // servo 0 on RC5 (pin 5), steer = 0b00001000
; // servo 1 on RC4 (pin 6), steer = 0b00000100
; // servo 2 on RC3 (pin 7), steer = 0b00000010
; // servo 3 on RC2 (pin 8), steer = 0b00000001
;
; /******************************************************************
;  *  4-Chan "PWM steering" Servo Driver        Mike McLaren, K8LH  *
;  ******************************************************************/
;
;  void interrupt()             // 250-uS (1000 cycle) interrupts
;  { static char index = 0;     //
;    static char frame = 1;     //
;    static char steer = 8;     //
;    static int width = 0;      //
;
;    TMR2IF = 0;                // clear TMR2 interrupt flag
;    if(width >= 250)           // if width >= 250-us
;      CCPR1L = 250;            // use full 100% duty cycle
;    else                       // otherwise
;      CCPR1L = width;          // use balance of width or 0%
;    width -= CCPR1L;           // adjust balance
;
;    PSTR1CON = steer | 1<<STR1SYNC;
;
;    if(--frame == 0)           // if end of 5-ms interval
;    { frame = 20;              // reset 5-ms counter and
;      steer >>= 1;             // prep for next channel
;      width = servo[index];    // new servo 'width'
;      index++; index &= 3;     // bump index, 0..3 inclusive
;      if(!(index)) steer = 8;  // prep steer for new cycle
;    }
;  }
;
Code:
;
; // setup PWM for a 250 us (1000 cycle) period (16 MHz clock)
;
;    CCP1CON = 0b00001100;      // active hi PWM mode
;    PSTR1CON = 1<<STR1SYNC;    // synchronous steering
;    CCPR1L = 0;                // 0% duty cycle initially
;    TMR2 = 0;                  // clear TMR2
;    T2CON = 0b00000101;        // -0000--- TOUTPS post 1:1
;                               // -----1-- TMR2ON -> "on"
;                               // ------01 T2CKPS prescale 4
;                               // for 1 usec 'ticks'
;    PR2 = 250-1;               // 250-us interrupts
;    TMR2IE = 1;                // enable TMR2 interrupts
;    PIR1 = 0;                  // clear peripheral int flags
;    GIE = 1;                   // enable interrupts
;    PEIE = 1;                  //  "
;

Cheerful regards, Mike

Last edited:

#### stefan.54

Joined Dec 26, 2015
28
Thank you guys for your replies. I will give them a careful insight.
JohnInTX, I'm willing to have a go with your methods after I've tested MMcLaren's ideas.

#### MMcLaren

Joined Feb 14, 2010
853
I would use dedicated Pwm chips controlled by the micro.

https://www.sparkfun.com/products/retired/10136
Hi GopherT.

Thank you very much for mentioning the use of the TLC5940 for driving Servos. While it may not fit stefan.54's requirements, I think this is a fascinating discovery.

At the risk of going slightly off-topic, may I ask if you're familiar with the TLC5940, please? Specifically, after just a cursory glance at the Datasheet, it seems that once you've loaded the TLC5940 with 192 bits of serial 'grayscale' data (12 bits per channel), you drive the GSCLK (Grey Scale Clock) pin with 4096 pulses at your desired PWM frequency between a set of BLANK pulses, and the TLC5940 will generate outputs that match the 'grayscale' setting automatically for you. Is this correct? If so, it would seem that you could drive GSCLK with 4096 clocks at 1-MHz for the desired 1-us Servo step size and simply wait another 15904-us before starting a new 20-ms Servo period cycle. Of course that otherwise unused 15904-us interval could be used to refresh the TLC5940 with 192 bits 'grayscale' (Servo pulse width) data for the next or upcoming Servo period.

I have a couple questions for the Guru's, please. Since the TLC5940 is a "sinking" driver, is there a way to generate an active high Servo pulse (without adding additional hardware)? Can you think of a simple and elegant "low overhead" method one might use to automatically generate 4096 clock pulses at a 1-MHz rate, scheduled or on-demand, on a PIC as a background (hardware) task? Or, could you leave a continuous 1-MHz clock signal on the GSCLK pin and inject the BLANK pin signal at the desired times?

My apologies to stefan.54 for going slightly off-topic...

Regards, Mike

Last edited:

#### GopherT

Joined Nov 23, 2012
8,012
Hi GopherT.

Thank you very much for mentioning the use of the TLC5940 for driving Servos. While it may not fit stefan.54's requirements, I think this is a fascinating discovery.

At the risk of going slightly off-topic, may I ask if you're familiar with the TLC5940, please? Specifically, after just a cursory glance at the Datasheet, it seems that once you've loaded the TLC5940 with 192 bits of serial 'grayscale' data (12 bits per channel), you drive the GSCLK (Grey Scale Clock) pin with 4096 pulses at your desired PWM frequency between a set of BLANK pulses, and the TLC5940 will generate outputs that match the 'grayscale' setting automatically for you. Is this correct? If so, it would seem that you could drive GSCLK with 4096 clocks at 1-MHz for the desired 1-us Servo step size and simply wait another 15904-us before starting a new 20-ms Servo period cycle. Of course that otherwise unused 15904-us interval could be used to refresh the TLC5940 with 192 bits 'grayscale' (Servo pulse width) data for the next or upcoming Servo period.

I have a couple questions for the Guru's, please. Since the TLC5940 is a "sinking" driver, is there a way to generate an active high Servo pulse (without adding additional hardware)? Can you think of a simple and elegant "low overhead" method one might use to automatically generate 4096 clock pulses at a 1-MHz rate, scheduled or on-demand, on a PIC as a background (hardware) task? Or, could you leave a continuous 1-MHz clock signal on the GSCLK pin and inject the BLANK pin signal at the desired times?

My apologies to stefan.54 for going slightly off-topic...

Regards, Mike

I have not used the chip myself. To answer your last question, I think there is a way to generate pulses with the PWM (very short clock cycle (2) (PR2) and 50% duty cycle. You can then let it run for one roll over of Timer0 or Timer2 (Timer1 is reset with each roll-over of PR2 and cannot be used).

#### John P

Joined Oct 14, 2008
1,897
I don't see what the problem is in generating your PWM signals in a PIC processor. All you have to do is set up a timer to produce first a "start" interrupt, at which time you set an output high, and then some time (1.0-2.0 msec) later, get a "stop" interrupt when you set it low again. Then reset the timer for 4msec minus whatever the interval was. Next time, operate a different output. After 5 cycles, you're back where you started and 20msec has elapsed, which is the repeat time for driving one of these servos. Possibly not the most trivial program anyone ever wrote, but not really brain-busting stuff.

#### dannyf

Joined Sep 13, 2015
2,197
is there a way to generate an active high Servo pulse (without adding additional hardware)?
Just feed the duty cycle (high duration) as the negative of what you desire.

#### dannyf

Joined Sep 13, 2015
2,197
The TI part is a poor choice here.

Look to NXP for a far better solution.

#### JohnInTX

Joined Jun 26, 2012
4,450
The TI part is a poor choice here.
Can you elaborate on that? Curious.
Look to NXP for a far better solution.
Which part number would you recommend/have you used?

Joined Jul 18, 2013
23,150
Two of those feature "PWM steering" onto four pins, while the remaining module features "PWM steering" onto two pins.
Mike
Mike, Taking the thread slightly off course, could you clarify a little on the use of the PSTR1CON register?
I am using a 18f23k22 ECCP1 module for a single full bridge control P1A,B,C,D .
Is the default value of PSTR1CON=0x01 used in this case or =0x0F?
Max.

Last edited:

#### MMcLaren

Joined Feb 14, 2010
853
Hi Max.

The Datasheet suggests PSTR1CON and "PWM steering" is only used in ECCP "single output" mode. Now does that imply that you don't need to do anything to the PSTR1CON register when using the other ECCP modes? I'm not sure... You might actually have to test this, Max...

Last edited: