Robot Control Library
Servo

Description

Control Servos and Brushless Motor Controllers.

<rc/servo.h>

The Robotics Cape has 8 3-pin headers for connecting hobby servos and ESCs. These are driven by the PRU for extremely precise signaling with minimal CPU use. Standard 3-pin servo connectors are not polarized so pay close attention to the symbols printed in white silkscreen on the cape before plugging anything in. The black/brown ground wire should always be closest to the cape PCB. The pinnout for these standard 3 pin connectors is as follows.

Both servos and Brushless ESCs expect pulse width signals corresponding to the desired output position or speed. These pulses normally range from 900us to 2100us which usually corresponds to +- 60 degrees of rotation from the neutral position. 1500us usually corresponds to the center position. Many servos work up to +- 90 degrees when given pulse widths in the extended range from 600us to 2400us. Test the limits of your servos very carefully to avoid stalling the servos motors.

Normalized Width Pulse Width Servo Angle
-1.5 600us 90 deg ccw
-1.0 900us 60 deg ccw
0.0 1500us centered
1.0 2100us 60 deg cw
1.5 2400us 90 deg cw

Unlike PWM which is concerned with the ratio of pulse width to pulse frequency, servos and ESCs are only concerned with the pulse width and can tolerate a wide range of update frequencies. Servos can typically tolerate update pulses from 5-50hz with more expensive digital models sometimes capable of higher update rates. Brushless ESCs are much more tolerant and typically accept update rates up to 200hz with some multirotor ESCs capable of 400hz when using sufficiently short pulse widths.

Since ESCs drive motor unidirectionally, it makes more sense to think of their normalized throttle as ranging from 0.0 (stopped) to 1.0 (full power). Thus, these functions translate a normalized value from 0.0 to 1.0 to a pulse width between 1000us and 2000us which is a common factory-calibration range for many ESCs. We suggest using the rc_calibrate_escs example program on all ESCs used with the robotics cape to ensure they are calibrated to this exact pulse range.

We HIGHLY recommend the use of ESCs which use the BLHeli firmware because this firmware allows the input pulse range to be programmed to exactly 1000-2000us and the old fashioned calibration mode to be disabled. This prevents accidental triggering of calibration mode during use and removes the need to run rc_calibrate_escs. BLHeli includes a plethora of configurable settings and features such as easily adjustable timing and sounds. More information on the BLHeli open source project here.

Unless calibration mode is disabled, most ESCs will go into a failsafe or calibration mode if the first signals they receive when powered up are not their calibrated minimum pulse width corresponding to the throttle-off condition. Therefore it is necessary for your program to start sending pulses with a normalized value of 0.0 for a second or more before sending any other value to ensure expected operation.

Some ESCs, including those running BLHeli firmware, will wake up but keep the motor idle when receiving pulses slightly below the minimum. This is largely undocumented but we call this "idle" mode. For this reason we allow inputs to rc_send_esc_pulse_normalized and rc_send_esc_pulse_normalized_all to range from -0.1 to 1.0 where 0.0 results in the lowest throttle the ESC allows and -0.1 can be used for idle where the motor is entirely powered off but the ESC is awake.

A recent trend among ESCs is support of "One-Shot" mode which shrinks the pulse range down to 125-250us for reduced latency. Like rc_send_esc_pulse_normalized, these oneshot equivalents also take a range from -0.1 to 1.0 to allow for idle signals.

Author
James Strawson
Date
3/7/2018

Macros

#define RC_SERVO_CH_MIN   1
 servo channels range from 1-8 More...
 
#define RC_SERVO_CH_MAX   8
 servo channels range from 1-8 More...
 
#define RC_SERVO_CH_ALL   0
 providing this as an argument writes the same pulse to all channels More...
 
#define RC_ESC_DEFAULT_MIN_US   1000
 
#define RC_ESC_DEFAULT_MAX_US   2000
 
#define RC_ESC_DJI_MIN_US   1120
 
#define RC_ESC_DJI_MAX_US   1920
 

Functions

int rc_servo_init (void)
 Configures the PRU to send servo pulses. More...
 
void rc_servo_cleanup (void)
 Cleans up servo functionality and turns off the power rail. More...
 
int rc_servo_power_rail_en (int en)
 enables or disables the 6V power rail to drive servos. More...
 
int rc_servo_set_esc_range (int min, int max)
 Sets the pulse width range used by the rc_servo_esc_send_pulse_normalized() function. More...
 
int rc_servo_send_pulse_us (int ch, int us)
 Sends a single pulse of desired width in microseconds to one or all channels. More...
 
int rc_servo_send_pulse_normalized (int ch, double input)
 Like rc_send_pulse_us but translates a desired servo position from -1.5 to 1.5 to a corresponding pulse width from 600 to 2400us. More...
 
int rc_servo_send_esc_pulse_normalized (int ch, double input)
 Like rc_send_pulse_normalized but translates a desired esc throttle position from 0 to 1.0 to a corresponding pulse width from 1000 to 2000us. More...
 
int rc_servo_send_oneshot_pulse_normalized (int ch, double input)
 Like rc_send_pulse_normalized but translates a desired esc throttle position from 0 to 1.0 to a corresponding pulse width from 125 to 250us. More...
 

Macro Definition Documentation

◆ RC_SERVO_CH_MIN

#define RC_SERVO_CH_MIN   1

servo channels range from 1-8

Examples:
rc_test_escs.c, and rc_test_servos.c.

◆ RC_SERVO_CH_MAX

#define RC_SERVO_CH_MAX   8

servo channels range from 1-8

Examples:
rc_test_escs.c, and rc_test_servos.c.

◆ RC_SERVO_CH_ALL

#define RC_SERVO_CH_ALL   0

providing this as an argument writes the same pulse to all channels

◆ RC_ESC_DEFAULT_MIN_US

#define RC_ESC_DEFAULT_MIN_US   1000
Examples:
rc_test_escs.c.

◆ RC_ESC_DEFAULT_MAX_US

#define RC_ESC_DEFAULT_MAX_US   2000
Examples:
rc_test_escs.c.

◆ RC_ESC_DJI_MIN_US

#define RC_ESC_DJI_MIN_US   1120

◆ RC_ESC_DJI_MAX_US

#define RC_ESC_DJI_MAX_US   1920

Function Documentation

◆ rc_servo_init()

int rc_servo_init ( void  )

Configures the PRU to send servo pulses.

Also leaves the servo power rail OFF, turn back on with rc_servo_power_rail_en(1) if you need to power servos off of the board.

Returns
0 on success, -1 on failure
Examples:
rc_calibrate_escs.c, rc_test_escs.c, and rc_test_servos.c.

◆ rc_servo_cleanup()

void rc_servo_cleanup ( void  )

Cleans up servo functionality and turns off the power rail.

Returns
0 on success, -1 on failure
Examples:
rc_calibrate_escs.c, rc_test_escs.c, and rc_test_servos.c.

◆ rc_servo_power_rail_en()

int rc_servo_power_rail_en ( int  en)

enables or disables the 6V power rail to drive servos.

The Robotics Cape has a 6V 4A high-efficiency switching regulator to power servos from the 2 cell LiPo battery. DO NOT enable this when using BEC-enabled brushless ESCs as it may damage them. Since brushless ESCs only need the ground and signal pins, it is safest to simply cut or disconnect the middle power wire. This will allow the use of servos and ESCs at the same time. Use the enable and disable functions above to control the power rail in software.

ALso use this to turn off power to the servos for example when the robot is in a paused state to save power or prevent noisy servos from buzzing.

Parameters
[in]en0 to disable, non-zero to enable
Returns
0 on success, -1 on failure
Examples:
rc_dsm_passthrough.c, rc_test_escs.c, and rc_test_servos.c.

◆ rc_servo_set_esc_range()

int rc_servo_set_esc_range ( int  min,
int  max 
)

Sets the pulse width range used by the rc_servo_esc_send_pulse_normalized() function.

This function is not necessary when using the default range which is RC_ESC_DEFAULT_MIN_US (1000) to RC_ESC_DEFAULT_MAX_US (2000). This is only neccessary when using custom ranges. The most common need for this is when dealing with DJI motor drivers which cannot be calibrated. In this case use the line:

rc_servo_set_esc_range(RC_ESC_DJI_MIN_US, RC_ESC_DJI_MAX_US);

This will set the range to 1120-1920 for DJI motor drivers. Note that the minimum value is what is sent when calling rc_servo_usc_send_pulse_normalized with a desired motor control input of 0. A slightly negative value is still possible which will send a pulse width shorter than the minimum value given here. These negative values shoul dbe avoided with DJI motor drivers as they don't register.

Parameters
[in]minThe minimum pulse width in microseconds
[in]maxThe maximum pulse width in microseconds
Returns
0 on success, -1 on failure.
Examples:
rc_test_escs.c.

◆ rc_servo_send_pulse_us()

int rc_servo_send_pulse_us ( int  ch,
int  us 
)

Sends a single pulse of desired width in microseconds to one or all channels.

This function returns right away and the PRU manages the accurate timing of the pulse in the background. Therefore calling this function succesively for each channel will start the pulse for each channel at approximately the same time.

As described above, servos and ESCs require regular pulses of at least 5hz to function. Since these pulses do not have to be accurate in frequency, the user can use these functions to start pulses from a userspace program at convenient locations in their program, such as immediately when new positions are calculated from sensor values.

Parameters
[in]chChannel to send signal to (1-8) or 0 to send to all channels.
[in]usPulse Width in microseconds
Returns
0 on success, -1 on failure
Examples:
rc_dsm_passthrough.c, rc_test_escs.c, and rc_test_servos.c.

◆ rc_servo_send_pulse_normalized()

int rc_servo_send_pulse_normalized ( int  ch,
double  input 
)

Like rc_send_pulse_us but translates a desired servo position from -1.5 to 1.5 to a corresponding pulse width from 600 to 2400us.

We cannot gurantee all servos will operate over the full range from -1.5 to 1.5 as that is normally considered the extended range. -1.0 to 1.0 is a more typical safe range but may not utilize the full range of all servos.

Parameters
[in]chChannel to send signal to (1-8) or 0 to send to all channels.
[in]inputnormalized position from -1.5 to 1.5
Returns
0 on success, -1 on failure
Examples:
rc_test_servos.c.

◆ rc_servo_send_esc_pulse_normalized()

int rc_servo_send_esc_pulse_normalized ( int  ch,
double  input 
)

Like rc_send_pulse_normalized but translates a desired esc throttle position from 0 to 1.0 to a corresponding pulse width from 1000 to 2000us.

This only works as expected if your ESCs are calibrated to accept pulse widths from 1000-2000us. This is best done with an ESC programming tool but can also be done with the rc_calibrate_escs example program that comes installed with this package.

While the normal operating range for the normalized input is 0.0 to 1.0, inputs as low as -0.1 are allowed. This is because many ESC firmwares such as BLHeli will still turn or chirp the motors at 0.0 throttle, but will be stationary and still armed and awake with throttle values slightly lower. We suggest using a throttle of -0.1 for at least a second at the beginnig of your program to wake the ESCs up from sleep but still keep the motors still.

Parameters
[in]chChannel to send signal to (1-8) or 0 to send to all channels.
[in]inputnormalized position from -0.1 to 1.0
Returns
0 on success, -1 on failure
Examples:
rc_calibrate_escs.c, and rc_test_escs.c.

◆ rc_servo_send_oneshot_pulse_normalized()

int rc_servo_send_oneshot_pulse_normalized ( int  ch,
double  input 
)

Like rc_send_pulse_normalized but translates a desired esc throttle position from 0 to 1.0 to a corresponding pulse width from 125 to 250us.

A recent trend among ESCs is support of "One-Shot" mode which shrinks the pulse range down to 125-250us for reduced latency. If you are sure your ESCs support this then you may try this function.

While the normal operating range for the normalized input is 0.0 to 1.0, inputs as low as -0.1 are allowed. This is because many ESC firmwares such as BLHeli will still turn or chirp the motors at 0.0 throttle, but will be stationary and still armed and awake with throttle values slightly lower. We suggest using a throttle of -0.1 for at least a second at the beginnig of your program to wake the ESCs up from sleep but still keep the motors still.

Parameters
[in]chChannel to send signal to (1-8) or 0 to send to all channels.
[in]inputnormalized position from -0.1 to 1.0
Returns
0 on success, -1 on failure
Examples:
rc_test_escs.c.