You are here

RC Servo Control & RC Motor Speed Control

PIC RC servos and RC speed controllers used in the Radio Control hobby.

Servo Control Intro

RC or R/C (Radio Control) servos and RC motor speed controllers are used in the radio control hobby to control things like RC Cars, RC airplanes, boats, robots, etc.

Servos are used for there positioning capability and strength. Small, regular sized servos can be bought at a local hobby store for $10 or less. Of course there are more expansive ones depending on the quality and size. These servos normally plug into your radio control receiver, but today we will connect it to your PIC.

I will mostly be talking about RC servos, but you will also be able to connect a RC speed controller since they use the same technology. These speed controllers are made up of power MOS FETs to allow 12v at 50A+ to control the speed of a motor via PWM.

The only way to really know how something really works is to take it apart! I found some gears, a potentiometer some electronics and a motor. The servos gears are to give it the strength it needs to move whatever it is you want to move in your project. The servo knows it's position by reading a voltage off the potentiometer that gets turned by the gears which of course gets turned by the motor. After a signal is given, the servo will move to the correct location.

To control a servo, we need to send it a PWM (pulse width modulation) signal. Thankfully it will all be taken care of by the Jallib library I have created. A pulse will be sent every 20ms, and each pulse will be a width between 0.5ms and 2.5ms. The pulse width will vary depending on the position you have chosen. Servo pulse width required can very depending on the servo manufacturer, therefore the library has been created with some default values that you may change to get a full movement from left to right.

Here's a YouTube video of one servo moving and it's signal on my oscilloscope: http://www.youtube.com/watch?v=zA3anG0YZD4

Servos come with a verity of connector types but always have 3 wires. One is ground, one is power and the other is signal. Take a look at this guys connector pinouts:

http://www.horrorseek.com/home/halloween/wolfstone/Motors/svoint_RCServos.html

Here's an image of my RC servo connector (left), I will use some pins (right), to plug my servo into my breadboard.

There are two ways of implementing servos into your project. You may either have your servos connected to your main PIC, or to an external PIC. For smaller projects you will choose to control your servo from your main PIC, this is the method I will show you.

If your main PIC is needed to run some heavy code, or if you need more then 24 servos, you may wish to use external PIC(s) via I2C interface. There is a library and two samples for using an external PIC via I2c bus. I will not discuss this method here.

Servo control via your main PIC

This method will allow you to plug up to 24 servos into your main PIC. Any digital capable I/O pin on your PIC should be able to run your servo signal, always lookup your pin in the datasheet. Use a pull up resistor on open drain pins. You will need to choose a PIC with a hardware timer, 8 servos can run on each timer module.

The library supports timer0, timer1 and timer3. You can do a quick search for "timer0 module" in your datasheet to see if you have a timer, most PICs do have at least one timer. The library will give you an error if you if you do not have a timer when you try to compile your code.

I have chosen 18F4620 (3 timers), but I have also tested it on 16f877a (2 timers), and 18f452(3 timers) with the same schematic.

Build your circuit

The schematic is very very simple, just take your blink circuit and plug in your servo.

The Code

Since your main PIC will be controlling the servos, the PIC is acting as a master device and therefore we will be using the servo_rc_master library.

The library can be found under Jallib SVN at trunk\include\external\motor\servo\servo_rc_master.jal

The sample can be found in the Jallib SVN at trunk\sample\18f4620_servo_rc_master.jal

You can access the Jallib SVN at http://code.google.com/p/jallib/source/browse/

Let's start by including your PIC, and disable all analog pins

-- include chip
include 18f4620                    -- target PICmicro
pragma target clock 20_000_000     -- oscillator frequency
-- configuration memory settings (fuses)
pragma target OSC  HS              -- HS crystal or resonator
pragma target WDT  disabled        -- no watchdog
pragma target LVP  disabled        -- no Low Voltage Programming
pragma target MCLR external        -- reset externally

enable_digital_io()                -- disable analog I/O (if any)

This sample file will require 1 led, so define it now

-- led definition
alias led                is pin_a0
alias led_direction      is pin_a0_direction
--
led_direction = output

Now you may define the pins that will be used for each of your servos, I have defined 8 although I have not connected them all in my circuit.

-- setup servo pins
alias servo_1             is pin_b0
alias servo_1_direction   is pin_b0_direction
servo_1_direction = output
--
alias servo_2             is pin_b1
alias servo_2_direction   is pin_b1_direction
servo_2_direction = output
--
alias servo_3             is pin_b2
alias servo_3_direction   is pin_b2_direction
servo_3_direction = output
--
alias servo_4             is pin_b3
alias servo_4_direction   is pin_b3_direction
servo_4_direction = output
--
alias servo_5             is pin_b4
alias servo_5_direction   is pin_b4_direction
servo_5_direction = output
--
alias servo_6             is pin_b5
alias servo_6_direction   is pin_b5_direction
servo_6_direction = output
--
alias servo_7             is pin_b6
alias servo_7_direction   is pin_b6_direction
servo_7_direction = output
--
alias servo_8             is pin_b7
alias servo_8_direction   is pin_b7_direction
servo_8_direction = output
--
-- commenting out 9th servo
;alias servo_9             is pin_a0
;alias servo_9_direction   is pin_a0_direction
;servo_9_direction = output

Here we will define the min & mas movement. These values can be changed to limit the amount your servos can move. We will talk about this in detail later on, this is an important step. Changing these values will change the pulse width for all servos.

-- choose min & max servo movment / pulse size
const byte SERVO_MIN   = 50  -- default is 50  (0.5ms min pulse)
const byte SERVO_MAX   = 255 -- default is 255 (2.5ms max pulse)

Choose the timers your PIC will be using to control your servos. Each timer will take care of 8 servos. I have defined 8 servos, so I need only 1 timer. I have commented out the other 2 timers that I may use later on.

-- choose pic internal timers
const byte SERVO_USE_TIMER = 0            -- timer for servo's 1 to 8
;const byte SERVO_9_TO_16_USE_TIMER = 1    -- timer for servo's 9 to 16
;const byte SERVO_17_TO_24_USE_TIMER = 3   -- timer for servo's 17 to 24

I may now include the servo_rc_master library, and initialize the servos. Within the init() procedure, all servos will be centered.

include servo_rc_master -- include the servo library
servo_init()

If you wish to turn off a servo at any point in your program. This will turn off the servos motor by keeping the signal line low. You may set or unset the on/off bit for any servo as follows:

-- use this to turn off a servo
;servo_1_on = FALSE

Sometimes the servo you have may move in the opposite direction that you would like it to, so here you have an option of switching a servos direction. I have also noticed that some types of servos move in the reverse of others.

-- use this to reverse a servo
;servo_1_reverse = TRUE

The init procedure does center all servos, but you may want to start your servo at another location. Since I did not leave any delay yet, the servos did not actually have time to move to there center position.

I am going to center the servos again to show you an example of the correct way to move a servo. After I give the servos there move position, I will wait for 1sec so they have time to move to center.

You can use various delays or move in increments to slow the servo movement speed. 127 is center.

-- example center all servos
servo_move(127,1) -- center servo 1
servo_move(127,2) -- center servo 2
servo_move(127,3) -- center servo 3
servo_move(127,4) -- center servo 4
servo_move(127,5) -- center servo 5
servo_move(127,6) -- center servo 6
servo_move(127,7) -- center servo 7
servo_move(127,8) -- center servo 8
;servo_move(127,9)

_usec_delay (1_000_000) -- wait for servos to physically move

Now I will create my main loop and have 2 of the servos move to various positions.

-- example moving servos one and two and blink led
forever loop

   servo_move(255,1)
   servo_move(0,2)
   _usec_delay (1_000_000)
   led = !led

   servo_move(127,1) ;servo 1 centered
   servo_move(127,2) ;servo 2 centered
   _usec_delay (1_000_000)
   led = !led

   servo_move(0,1)
   servo_move(255,2)
   _usec_delay (1_000_000)
   led = !led

   servo_move(127,1) ;servo 1 centered
   servo_move(127,2) ;servo 2 centered
   _usec_delay (1_000_000)
   led = !led
end loop

So, that's it for the code. Simple right? I wish writing the library was that easy!

You can go ahead and turn on your circuit, you should see the led blink and the servos should be moving. Change and test your servo pinouts if needed. The two servos will move in opposite directions since my servo_move() procedure call values are different for each servo.

At this point, you should turn off the power when your servos are at the center position. We are turning the power off so you may remove the moving part on the top of your servo, and place it back on so it looks centered.

Here's a YouTube video of my two moving servos http://www.youtube.com/watch?v=QS8M07uuagY

Setting Your Servo Max & Min Movements

For my projects, I feel that it is important to set the servo min/max values. You may choose to either use the default values that I have set, or set your own. There are two reasons for setting these values correctly:

  1. You can get more movement out of your servo (far right to far left)
  2. You do not want your servo to try to move out of it's range. If your servo moves out of it's range for a long period of time, you may burn out the servos motor.

All manufacturers create there servos differently, there is no official specification for RC servos (that I know of).

So here are the steps:

  1. Set SERVO_MIN = 0 and SERVO_MAX to 255
  2. Set your servo_min values to restrict movement to one side. Directly after you call servo_init(), you should place this code:
    servo_move(0,1)
    forever loop
    end loop

    This will move your servo all the way to one side. You will hear your servo motor being ON all the time (not good for the motor).

  3. Now run your circuit and gradually increase servo_min value so the servo is at the correct location on one side. Try to get the servo to be 1mm from it's min location. You should not hear the motor running.
  4. Repeat step 2 by decreasing servo_max but use this:
    servo_move(255,1)
    forever loop
    end loop

Well, looks like your all set. I hope your having fun with Jalv2/Jallib!

sebastien.lelong
Storing min/max value in EEPROM

Hi Matt, 

Having min/max value, per servo, stored in EEPROM is really convenient. Init() procedure could check existing stored values, and restore them while PIC is powered up. I guess this isn't related to servo library itself, but rather to a servo controller firmware.

Cheers,

Seb

Anonymous (not verified)
Hey Seb. Sorry for the very

Hey Seb. Sorry for the very very late reply :) I didn't see the post.

My servo lib only has a main constant for min/max postion of ALL servo's. Mainly this is so servos do not go out of it's own limits.

At the time, I felt that adding the min/max for each servo seperatly could be memory consuming, so I leave it up to the user.It is quite easy to implement if a users application has it's own min/max limit. Simply just don't send it to a position :)

Anyways, shouldn't min/max values be constant? why store them in EEPROM?

I need to find more time to play with my own libraries. I built this without any project that needs servos :)

Matt.

sebastien.lelong
Hi Matt,Min/max values should

Hi Matt,

Min/max values should be per servo. Depending on your application, one servo may rotate 30° and another one 160°, due to physical constraints. Moving further would damage the robot for instance.

If it could be set programmatically (ie. using variables, not constants), user can set servo positions manually at their min/max values, and then declare these values as min/max ones. Since this should be done once, and since it's boring, saving these presets in EEPROM would be cool...

According to me, this feature should be part of the lib, maybe configurable. I don't have any servo projects (anymore) with me too. When I do, maybe we can work again on this ?

Anonymous (not verified)
I'll have another look when I

I'll have another look when I have time. I have so many projects right now. I am putting networking aside at the moment to work on my mp3 stuff a bit more. I hope to make portable mp3 player with touch graphical lcd. I also wish to complete my fat32 in the process, and get a tutorial up. I'll also do a vs1053b mp3 decoder tutorial, and eventually a glcd tutorial.

When I have time, I will also work on a software PWM library similar to this servo lib. useful for motor speed control. It may be a while however.

I understand you need some of this servo/pwm stuff for Jaluino. How urgent is it?

Matt.

sebastien.lelong
Absolutely no emergency. I've

Absolutely no emergency. I've been talking about creating a shielf for DC motor control with back-emf monitoring, with also some servo controls, but that's mostly a matter of hardware, as shield's firmware could be updated as needed.

Seb

Anonymous (not verified)
Signal from the radio

Hi my name is Mark and I'm bo Brazil, sorry for my English is not very good, I knew the JAL recently and I have two that I like to do all these codes included in the main application will not leave the application as swollen happens with PBP?
The second question I want to make is this, I want to control only 5 servos and I want to receive the signal from R / C power to interpret it and then I'll decide whether to send the servant or not, that's to do?

Thank you.


Marcos

mattschinkel
Hi Mark, I don't understand

Hi Mark, I don't understand your questions.

1. What is PBP?

2. I think you are telling me that you want to measure the length of the R/C reciever output signal. This is difficult. You will need to use a "interrupt on change" pin + timer.

You could also try to put resistor + capacitory on the R/C reciever output signal, then measure voltage with ADC.

Matt.

Anonymous (not verified)
Excuse me I said that my English is very bad ...

PBP (PIC BASIC PRO) ... I wonder if. HEX JAR are generated as large as the PBP.

You know where I can find examples of working with interrupt on pin change + timer? and how to do something simpler to control the servos?

Thank you.

mattschinkel
JAL is very optimized, JAL

JAL is very optimized, JAL HEX is good. I have never used PBP.

I think someone on JALLIST has a example to measure RC receiver pluse width. http://tech.groups.yahoo.com/group/jallist/

I don't have a interrupt on change pin example, look at your PIC datasheet. Here is a timer example: http://jallib.googlecode.com/svn/trunk/sample/18f452_timer3.jal

Matt.

 

Anonymous (not verified)
Thank you.

Thank you.

Anonymous (not verified)
Servo Slow down

Thanks so much for the library for controlling servo's, it made my life a heck of alot easier. Its easy to use even for a amateur like myself.

There is one question burning though, is there any way to slow down the servo in such a way that its is not so jerky? What I did was I placed a delay after a button is pressed and the servo moves for as long as the button remains pressed, but because of this the movement is somewhat jerky. I there any method I can use to modify tyhe code so that I can get a smooth motion? I need the servo to take approx 10sec to move 180 degrees.

 

Thanks again for the great tutorial, it helped me and I imagine others so much.

Electro_phunk

mattschinkel
Servo Slow down

Thanks for your interest :)

You'll need to move the servo in small increments untill it reaches the position, use smaller delay's as well. Servo's normally only move at one speed.

Maybe you can post your code.

Matt.

Anonymous (not verified)
Amazing Servo Control

Matt, 

I used your servo.jal and pulse.jal libs about 3 years ago when you essentially taught me JAL to control a RC helicopter retractable landing gear.

I am now making a servo controlled derailleur for my daughter's bike, and this library is even more robust and easy to use.  The servo control is crisp and clean!

 

Great Job! 

mattschinkel
Amazing Servo Control

Cool project.. Did you ever fix servo speed issue you had?

Log in to post comments