RC Receiver to BrainStem Example
Last Modified: 2006-11-15
find:

basket

Acroname Robotics PDF webpage version RC Receiver to BrainStem Example PDF

Related
Products

Product image for Brainstem GP 1.0 Module
Brainstem GP 1.0 Module
Product image for 2600mAh AA NiMH Battery
2600mAh AA NiMH Battery
Product image for Standard Servo
Standard Servo
Product image for 4X AAA Batt Pack w/Connector
4X AAA Batt Pack w/Connector

Contents

Hardware used for interfacing a RC controller to the BrainStem.

Introduction

A typical servo takes a series of pulses as its input and moves its arm to a position that is proportional to the input pulse width.  This pulse width ranges from 1ms to 2ms.  A pulse width of about 1.5ms will center a servo.  The pulse rate is approximately one pulse every 20ms.  This type of signal is called "pulse width modulation" or PWM.  A radio-controlled transmitter/receiver combo is specifically designed to convert joystick inputs at the transmitter into PWM servo outputs at the receiver. 

In this example, a BrainStem measures the PWM servo-control pulses from a standard radio-controlled receiver and sends positioning signals to two servos .  Such a system can be used to send signals to an otherwise autonomous robot.  It can also be used to translate standard servo positioning signals into commands for specialized radio-controlled vehicles like walkers and BattleBots. 

Circuit Schematic

In the following schematic, the BrainStem RC receiver, and servos are powered by a pack of four NiMH AA batteries .  Ni-Cad or Alkaline batteries would also work well.  Servos may draw up to 1 amp of current.  The servos get power from a special connector on the BrainStem board instead of the voltage regulator output.  Also, note the detail of the servo plugging.  Ground (the darkest servo wire) should be positioned nearest the board when the servo is plugged in. 

The RC combo is a Futaba 4-channel AM system.  The RC receiver takes its power from VCC and Ground pins located near the digital IO device connectors .  The outputs for channel 1 and channel 3 are connected to digital inputs 4 and 3, respectively.  Channel 1 is for the left-right motion of the right joystick.  Channel 3 is for the up-down motion of the left joystick.  This channel selection is analogous to the "steering" and "throttle" controls in a 2-channel RC system. 

Wiring diagram between the servos, BrainStem and RC Control.

Source Code - Monitoring the RC Reciever Pulse Times

This following program displays the pulse widths associated with input channels 1 and 3.  The BrainStem GP uses an internal 16-bit timer to measure input pulse widths.  The resolution of this timer is 1.6us.  Four of the digital input pins may be used as pulse width timers.  These timers are mapped to IO ports for use with the BrainStem TEA language. 

Use the Console program to compile, download, and run the program.  With the transmitter off, the displayed values should be 0.  With the transmitter on and the joysticks centered, the displayed values should be around 938.  (938*1.6us=1.5ms) You may need to determine the pulse width range of each channel independently. 

This code compiles with version 1.0 of the BrainStem GP TEA compiler and works with version 1.0 of the BrainStem GP 1.0 Module. 

/* filename: rcrcvr1a.tea */ /* use to observe RC receiver pulse times */ /* included for port access */ #include <aCore.tea> #include <aPrint.tea> /* uses Ch 1 and Ch 3 of 4-Channel RC Receiver */ #define dCH1 4 /* Ch 1 goes to pin timer 4 */ #define dCH3 3 /* Ch 3 goes to pin timer 3 */ int read_ch1() { int val=0; asm { /* configure digital IO pin as */ /* pulse width timer for high pulse input */ pushlb 25 popbm aPortDigital+ dCH1*aPortDigitalBlockSize+ aOffsetDigitalConfig /* take pulse measurement */ pushms aPortDigital+ dCH1*aPortDigitalBlockSize+ aOffsetDigitalPTime popss 2 } return val; } int read_ch3() { int val=0; asm { /* configure digital IO pin as */ /* pulse width timer for high pulse input */ pushlb 25 popbm aPortDigital+ dCH3*aPortDigitalBlockSize+ aOffsetDigitalConfig /* take pulse measurement */ pushms aPortDigital+ dCH3*aPortDigitalBlockSize+ aOffsetDigitalPTime popss 2 } return val; } void main() { int nc1; int nc3; while (1) { nc1=read_ch1(); nc3=read_ch3(); aPrint_IntDec(nc1); aPrint_Char(','); aPrint_IntDec(nc3); aPrint_Char('\n'); aCore_Sleep(2500); } }

Source Code - RC Control Input to Move Servo Motors

For the RC system in this example, the pulse widths for channel 1 ranged from 660 (left) to 1230 (right) and and the pulse widths for channel 3 ranged from 757 (down) to 1164 (up).  The following program uses these values for scaling the input. 

The BrainStem GP uses an 8-bit value to control the position of a servo, but uses a 16-bit value to measures input pulse widths.  So it is necessary to do some math to convert the pulse width into a valid servo position.  In this example the ranges for channel 1 and channel 3 are noticeably different.  Two different equations must be used to map the RC channel inputs to valid servo positions in the range 0-255. 

element type not assigned

The "rail" variables in the program listed above are the inputs limited to the desired minimums and maximums.  If these limits are not enforced, it is possible that some inputs could map to servo positions outside the range 0-255.  Implementing each equation requires a few more tricks.  The BrainStem GP can not do floating point operations, but it is possible to fake it with fractions.  In the program above, multiplication by 0.44 is performed with a multiplication by 44 followed with a division by 100.  Similarly, multiplication by 0.62 is performed with a multiplication by 62 followed with a division by 100.  A final type cast is required to force the int (2 bytes) into an unsigned char (1 byte) for the servo positioning function. 

/* filename: rcrcvr1b.tea */ /* use to control two servos via RC */ /* included for port and servo access */ #include <aCore.tea> #include <aServo.tea> /* uses Ch 1 and Ch 3 of 4-Channel RC Receiver */ #define dCH1 4 /* Ch 1 goes to pin timer 4 */ #define dCH3 3 /* Ch 3 goes to pin timer 3 */ int read_ch1() { int val=0; asm { /* configure digital IO pin as */ /* pulse width timer for high pulse input */ pushlb 25 popbm aPortDigital+ dCH1*aPortDigitalBlockSize+ aOffsetDigitalConfig /* take pulse measurement */ pushms aPortDigital+ dCH1*aPortDigitalBlockSize+ aOffsetDigitalPTime popss 2 } return val; } int read_ch3() { int val=0; asm { /* configure digital IO pin as */ /* pulse width timer for high pulse input */ pushlb 25 popbm aPortDigital+ dCH3*aPortDigitalBlockSize+ aOffsetDigitalConfig /* take pulse measurement */ pushms aPortDigital+ dCH3*aPortDigitalBlockSize+ aOffsetDigitalPTime popss 2 } return val; } void main() { int n; int nc1; int nc3; int nc1rail; int nc3rail; unsigned char cpos; while (1) { nc1=read_ch1(); nc3=read_ch3(); /* limit range of channel 1 input */ nc1rail=nc1; if (nc1>=1230) nc1rail=1230; if (nc1<=660) nc1rail=660; /* limit range of channel 3 input */ nc3rail=nc3; if (nc3>=1164) nc3rail=1164; if (nc3<=757) nc3rail=757; /* if transmitter is on then */ /* scale ch. 1 input for servo 0 */ if (nc1!=(int)0) { n=((nc1rail-660)*44)/100; cpos=(unsigned char)n; aServo_SetAbsolute(0,cpos); } /* if transmitter is on then */ /* scale ch. 3 input for servo 1 */ if (nc3!=(int)0) { n=((nc3rail-757)*62)/100; cpos=(unsigned char)n; aServo_SetAbsolute(1,cpos); } } }

Of course, this program mimics exactly what the receiver already does, so what is the point? This example merely shows how to process signals from an RC receiver.  These techniques may be used as a starting point for making a programmable radio-controlled system.  As an example of what you can do, use the Console program to run rcrcvr1b.tea listed above.  While the program is running, you can alter the servo behavior significantly with just a few simple commands:

element type not assigned

Source Code - Optimized PWM Scaling Equation

The first two programs cover the basics of the RC receiver and BrainStem GP interface.  The next program is more refined.  John J.  Kelly III suggested the following math trick to simplify the input scaling: Futaba RC systems are designed to produce pulses of 1.1ms to 1.9ms on all of their channels.  The BrainStem measures time in 1.6us increments which gives a minimum measurement of 688 and maximum measurement of 1188.  Decreasing the min by 6 and increasing the max by 5 produces an input range of 512 steps (682 to 1193).  This yields a very simple 0-255 scaling equation that is identical for all 4 channels: (input-682)/2.  The program below uses this trick along with a parameterized timer input routine.  It displays scaled input from a 4-channel AM system.  When no signal is present, it displays values of -1.  The circuitry is similar to the diagram above.  Just connect receiver outputs 1-4 to digital IO pins 1-4. 

/* filename: rcrcvr1c.tea */ /* use to read 4 RC channels */ /* included for port access and display routines */ #include <aCore.tea> #include <aPrint.tea> /* uses Ch 1 - 4 of 4-Channel RC Receiver */ #define dCH1 1 /* Ch 1 goes to pin timer 1 */ #define dCH2 2 /* Ch 2 goes to pin timer 2 */ #define dCH3 3 /* Ch 3 goes to pin timer 3 */ #define dCH4 4 /* Ch 4 goes to pin timer 4 */ #define PWMMAX 1193 #define PWMMIN 682 int read_channel(char n) { int val=0; asm { /* configure digital IO pin as high pulse timer */ pushlb 25 /* compute the address of the digital config port */ pushls aPortDigital + aOffsetDigitalConfig pushlb aPortDigitalBlockSize pushsb 9 multb adds /* write config byte to digital config port */ popbmx /* compute the address of the digital timer port */ pushls aPortDigital + aOffsetDigitalPTime pushlb aPortDigitalBlockSize pushsb 8 multb adds /* take pulse measurement */ pushmsx /* pop measurement into local variable */ popss 2 } /* apply rail and zero-check to the timer result */ /* scale the result to 0-255 if it is valid */ /* else return -1 */ if (val != 0) { if (val > PWMMAX) { val = PWMMAX; } if (val < PWMMIN) { val = PWMMIN; } val=(val-PWMMIN) / 2; } else { val = -1; } return val; } /* read_tmr */ void main(void) { int nc1; int nc2; int nc3; int nc4; while (1) { nc1=read_channel(dCH1); nc2=read_channel(dCH2); nc3=read_channel(dCH3); nc4=read_channel(dCH4); aPrint_IntDec(nc1); aPrint_Char(','); aPrint_IntDec(nc2); aPrint_Char(','); aPrint_IntDec(nc3); aPrint_Char(','); aPrint_IntDec(nc4); aPrint_Char('\n'); aCore_Sleep(2500); } } }

Revision History:

  • 2001-08-30: Example Created.
  • 2001-09-06: Added some servo command examples.
  • 2001-09-06: Updated the pulse measurement subroutines to re-initialize the digital IO pin configuration prior to taking a pulse measurement. A firmware limitation (prior to build 4) may cause some configuration bits to change after measuring pulse widths that exceed the 104ms measurement limit. Such pulses can occur when the RC transmitter power is turned off and on again.
  • 2001-10-04: Added rcrcvr1c.tea and its accompanying text.
  • 2002-01-11: * Updated programs for compatibility with Build 5 software and TEA libraries.
 

Related Links:

Brainstem Software: Console Overview

voice: 720-564-0373, email: sales@acroname.com, address: 4822 Sterling Dr., Boulder CO, 80301-2350, privacy
© Copyright 1994-2010 Acroname, Inc., Boulder, Colorado. All rights reserved.