RCKit
RCRx.h
1 // RCRx.h
2 //
3 // Remote Control Receiver module for RCOIP protocol
4 // Copyright (C) 2010-2012 Mike McCauley
5 // $Id: RCRx.h,v 1.6 2012/09/23 21:55:57 mikem Exp mikem $
6 
7 /// \mainpage RCKit library for Arduino
8 ///
9 /// This is the Arduino RCKit library.
10 ///
11 /// RCKit provides a kit of software objects that make it easy to build an
12 /// RCOIP (Remote Control Over IP) receiver on Arduino. RCOIP protocol is used to
13 /// carry remote control commands from a transmitter to a receiver over an IP
14 /// transport such as Ethernet or Wi-Fi.
15 ///
16 /// As such it can be used to build Remote Controlled (RC) vehicles and devices of various kinds, along with
17 /// matching transmitters. Large numbers of channels can be supported, along with a back-channel
18 /// which sends data from the Receiver to the Transmitter.
19 /// A compatible iPhone transmitter app is also available.
20 ///
21 /// The transmitter could be a handheld Wi-Fi enabled device such as an iPhone, iPad or Arduino based device.
22 /// Or it could be an interactive program running on a desktop computer. The RCTx iPhone transmitter app is
23 /// available on the Apple App Store. It provides a simple RCOIP transmitter equipped with 2 joysticks and
24 /// a number of switches.
25 ///
26 /// The receiver (using this RCKit software) could be a remote controlled car,
27 /// plane, helicopter or some other device.
28 ///
29 /// The RCOIP protocol is a 2-way protocol that defines UDP messages between
30 /// the RCOIP transmitter and receiver.
31 /// This effectively makes the transmitter a UDP client and the receiver a UDP server.
32 /// Messages sent from the transmitter to the receiver include setting analog outputs,
33 /// and messages from the receiver to the transmitter include receiver status messages.
34 ///
35 /// RCTx, RCKit and the RCOIP protocol offer the following advantages over conventional Remote Control:
36 /// \li Large numbers of channels (> 100) not just 5 or 6, including analog, digital, text, data etc.
37 /// \li Back channel for telemetry (voltages, signal strengths, GPS position etc)
38 /// \li Failsafe modes
39 /// \li Programmable, configurable and extensible
40 /// \li Works with a variety of types of vehicle and remote devices
41 /// \li Hackable
42 /// \li Opportunity to tightly integrate remote control and autonomous vehicle software control
43 /// \li Works with a variety of IP transports Wi-Fi (ad-hoc or infrastructure), Wired etc.
44 ///
45 /// Videos explaining how it works and what you can do with it can be found at:
46 /// \li http://www.youtube.com/watch?v=SKwY-CcotRY
47 /// \li http://www.youtube.com/watch?v=i0ZogFmytPI
48 ///
49 /// There is also a video showing how RCKit can be used with the IRrc library at
50 /// http://www.airspayce.com/mikem/arduino/IRrc to control a 3 channel infra-red model helicopter at:
51 /// \li http://www.youtube.com/watch?v=lzRpyqnD6_M
52 ///
53 /// The version of the package that this documentation refers to can be downloaded
54 /// from http://www.airspayce.com/mikem/arduino/RCKit/RCKit-2.5.zip
55 /// You can find the latest version at http://www.airspayce.com/mikem/arduino/RCKit
56 ///
57 /// You can also find online help and disussion at http://groups.google.com/group/rckit
58 /// Please use that group for all questions and discussions on this topic.
59 /// Do not contact the author directly, unless it is to discuss commercial licensing.
60 ///
61 /// Tested on Arduino Duemilanove, Diecimila, Mega and Asynclabs Yellowjacket
62 /// with arduino-1.0 and arduino 1.0.1 on OpenSuSE 12/
63 /// and avr-libc-1.6.2-5.11,
64 /// cross-avr-binutils-2.19-9.1 and cross-avr-gcc43-4.3.3_20081022-9.3
65 ///
66 /// \par RCRx
67 ///
68 /// RCRx class is an RCOIP receiver. It works with Arduino and a range of communications hardware like
69 /// WiShield and Ethernet to receiver commands from an
70 /// RCOIP compliant Transmitter (such as the RCTx iPhone app available on the Apple App Store).
71 ///
72 /// When the RCRx object is constructed, it must be given an array of Setter objects.
73 /// When a RCOIPv1CmdSetAnalogChannels message is received by RCRx, The Setter corresponding to each
74 /// Channel value in the RCOIPv1CmdSetAnalogChannels command will be passed to the
75 /// respective Setter in the analogOutputs array.
76 /// The Arduino software is expected to be configured so that each analogOutput is connected to a Setter that
77 /// will implement the received value, perhaps by setting an analog or digital output on an Arduino pin.
78 /// Setter objects are provided to achieve this. See below.
79 ///
80 /// RCRx will automatically respond to received commands with RCOIPv1ReplyReceiverStatus messages
81 /// as appropriate to the configured timeouts etc. See the RCOIP protocol document for more details.
82 ///
83 /// \par Setters
84 ///
85 /// Setter classes are objects that receive a value, maybe transform it and then do something with it. Typically
86 /// they set an output pin according to the received input value, but almost any other transformation,
87 /// output or communication can be imagined.
88 ///
89 /// The following output Setter objects are provided with RCKit. They can be used to translate
90 /// receiver channel values into physical outputs:
91 /// \li AnalogSetter
92 /// \li DigitalSetter
93 /// \li ServoSetter
94 /// \li AccelStepperPositionSetter
95 /// \li AccelStepperSpeedSetter
96 /// \li HBridgeSetter
97 /// \li DifferentialSetter
98 ///
99 /// The following transformation Setter objects are provided with RCKit. They can be used to
100 /// transform receiver channel values before being given to one of the output Setter classes above:
101 /// \li Inverter
102 /// \li Limiter
103 /// \li Linear
104 ///
105 /// \par Example Sketches
106 ///
107 /// Several example Arduino sketches are included, including a regression
108 /// test suite and a sample complete 5 channel receiver with Servo outputs for WiFi and Ethernet.
109 ///
110 /// \par Transceivers
111 ///
112 /// Version 2.0 of this library added the concept of a Transceiver, in order to be able to support
113 /// multiple type of communications transport.
114 /// A Transceiver is an object responsible for communicating with an RCOIP transmitter. Several types of
115 /// Transceiver are supported by the standard RCRx library:
116 /// - WiShield WiFi shield or Yellowjacket or WiFi Bee, using the WiShield library.
117 /// - Ethernet shield, or EtherTen, using the standard Arduino Ethernet library.
118 /// You can define your own subclass of the Transceiver class to implement your own transports
119 /// (if you do so, consider contributing it back to the RCRx project).
120 /// The main RCRx reciver object must be told where it Transceiver object is, using setTransceiver().
121 /// Thereafter it will use that
122 /// Transceiver to receive RCOIP requests and to send replies back to the transmitter.
123 ///
124 /// \par RCTx iPhone App
125 ///
126 /// RCTx is an RCOIP compliant transmitter for iPhone available on the Apple App Store
127 /// at https://itunes.apple.com/us/app/rctx/id567423127?mt=8
128 ///
129 /// You can use it with the WiShieldTransceiver object to use WiFi to communicate directly to a WiShield
130 /// equipped RCRx receiver. Or you can use it with the EthernetTransceiver object
131 /// and your LAN and Wirelesss Access Point to communicate to an Ethernet equipped RCRx receiver.
132 ///
133 /// RCTx presents a simulated RC transmitter with 2 joysticks and a number of switches.
134 /// The left josystick sets channels 0 and 1 and the right joystick channels 2 and 3.
135 /// The switches set channels 4 through 9 inclusive. The one connected to channel 4 is momentary contact.
136 ///
137 /// To install and configure RCTx to work with a WiShield equipped RCRx:
138 /// \li install the RCTx app on your iPhone.
139 /// \li Build and upload your RCRx+WiShieldTransceiver program you your Arduino+WiShield hardware
140 /// \li Power up the Arduino
141 /// \li Turn on your iphone, go to Settings, Wi-Fi. Enable Wi-Fi
142 /// \li After about 30 seconds, you should see the RCArduino network appear as an available
143 /// network on the iPhone. Tap on it.
144 /// Now tap on the RCArduino network details arrow to the right of the RCArduino line. Select 'Static'.
145 /// Enter an IP Address of 169.254.1.1. Enter a Subnet Mask of 255.255.0.0
146 /// \li After about 10 seconds, the iPhone should be successfully connected to the RCArduino network.
147 /// You now have an ad-hoc connection to the Arduino. The Arduino will have the address 169.254.1.100
148 /// and the iPhone will have address 169.254.1.1
149 /// \li Start the RCTx app on the iPhone.
150 /// \li After about 5 seconds, you should see the NO CONNECT in the bottom left corner change to
151 /// show RSSI and the correct battery voltage (if the Arduino is so equipped).
152 /// \li Move the josticks and buttons. This will send RCOIP commands to the Arduino.
153 /// RCRx in the arduino will convert them to analog output signals to drive your hardware. Have fun.
154 ///
155 /// To install and configure RCTx to work with an Ethernet equipped RCRx:
156 /// \li install the RCTx app on your iPhone.
157 /// \li Edit the sketch to set the desired IP address and MAC address for the Arduino
158 /// \li Build and upload your RCRx+EthernetTransceiver program you your Arduino+Ethernet hardware.
159 /// \li Power up the Arduino, connect it to your LAN.
160 /// \li Turn on your iphone, go to Settings, Wi-Fi. Enable Wi-Fi and connect to your LANs
161 /// wireless access point in the usual way.
162 /// \li Start the RCTx app on the iPhone.
163 /// \li Tap on the little 'i' icon on the bottom right, get the profiles page.
164 /// Edit the default profile or create a new profile and enter the IP address of the Arduino that you configured above.
165 /// \li After about 5 seconds, you should see the NO CONNECT in the bottom left corner change to
166 /// show RSSI of 0 and the correct battery voltage (if the Arduino is so equipped).
167 /// \li Move the josticks and buttons. This will send RCOIP commands to the Arduino.
168 /// RCRx in the arduino will convert them to analog output signals to drive your hardware. Have fun.
169 ///
170 ///
171 /// \par Prerequisites
172 ///
173 /// \li Arduino IDE 1.0 or later (earlier version do not support the EthernetUdp class required)
174 /// \li WiShield (http://asynclabs.com) edited and configured to suit (see below for help)
175 /// \li AccelStepper (http://www.airspayce.com/mikem/arduino/AccelStepper)
176 ///
177 /// These prerequisites must be installed in the libraries directory of your Arduino devlopment environment,
178 /// even if you are not going to use them with RCRx, otherwise the RCRx will not build.
179 ///
180 /// \par Installation
181 ///
182 /// Install in the usual way: unzip the distribution zip file to the libraries
183 /// sub-folder of your Arduino IDE sketchbook.
184 ///
185 /// \par WiShield Library Configuration
186 ///
187 /// Requires the Asynclabs WiShield library to be installed, even if you are not using
188 /// the WiShieldTransceiver. See http://asynclabs.com/wiki/index.php?title=WiShield_library
189 /// Install the WiShield library in the libraries directory of your arduino IDE installation,
190 /// then follow the configuration steps below:
191 ///
192 /// Support of RSSI (receiver signal strength indicator) requires mods to WiShield library g2100.c as per
193 /// http://asynclabs.com/forums/viewtopic.php?f=10&t=385&start=0. You dont have to add this but its a
194 /// good feature. It is included in the prebuilt WiShield library mentioned below.
195 ///
196 /// Correct operation of the WiShield requires you to set the jumper on the WiShield to INT0 or DIG8 to select
197 /// the arduino pin to use for WiShield interrupts, and also to make sure it agrees with the settings of
198 /// USE_DIG0_INTR or USE_DIG8_INTR in spi.h in the WiShield library (which defaults to
199 /// using Arduino digital pin 2, and which means setting the WiShield jumper to INT0 setting). Yes, the naming
200 /// conventions are inconsistent :-(. In summary:
201 /// \code
202 /// WiShield jumper spi.h Arduino
203 /// INT0 USE_DIG0_INTR Digital pin 2
204 /// D8 USE_DIG8_INTR Digital pin 8
205 /// \endcode
206 ///
207 /// For YellowJacket and WiFi Bee (which has no jumper), leave it as USE_DIG0_INTR.
208 ///
209 /// Caution: on WiFi Bee, Arduino Digital pin 4 is connected to the WiFi Chip HIBERNATE pin.
210 /// Do not use pin D4 as an RCKit output pin.
211 ///
212 /// In order for WiShield library to support UDP (as needed by this module),
213 /// you MUST set UIP_CONF_UDP to 1 in uip-conf.h. This is an unfortunate but necessary requirement,
214 /// otherwise UDP support will not be compiled into the WiShield library.
215 /// Further, you must edit apps-conf.h and make sure the only APP_* defined is APP_UDPAPP.
216 /// Failure to do this will cause compile errors.
217 ///
218 /// A modified version of the WiShield library already
219 /// modified and configured for use with RCKit (including RSSI support) is available at
220 /// http://www.airspayce.com/mikem/arduino/WiShield-v1.3.0-0-mikem-RCKit.zip
221 ///
222 /// WiShield will work with Arduino Mega, but with difficulty. The problem is that with the Mega, the SPI
223 /// pins that are required for interface with WiShield come out on different pins to the smaller form
224 /// factor arduinos like Diecimila and Duemilanove. So, to make the Mega work with the WiShield, you
225 /// have to reroute the SPI pin to different Arduino pins, as per
226 /// http://asynclabs.com/forums/viewtopic.php?f=13&t=19&hilit=mega&start=10
227 ///
228 /// By default, WiShieldTransceiver is configured as an Ad-Hoc Wi-Fi network with SSID of 'RCArduino'
229 /// By default, the network is Open (ie no encryption) and
230 /// It is configured with a static IP address of 169.254.1.100.
231 /// These setting can be changed by editing WiShieldTransceiver.cpp in the RCKit distribution.
232 ///
233 /// \author Mike McCauley (mikem@airspayce.com)
234 /// Do not contact the author directly unless it is to discuss commercial licensing.
235 /// See above for support and discussion groups.
236 ///
237 /// This software and the RCOIP protocol is Copyright (C) 2010-20112 Mike McCauley. Use is subject to license
238 /// conditions. The main licensing options available are GPL V2 or Commercial:
239 ///
240 /// This library has been tested with Duemilanove and (WiShield 1.0 or YellowJacket or WiFi Bee 1)
241 /// and iPhone 3.0
242 ///
243 /// \par Open Source Licensing GPL V2
244 ///
245 /// This is the appropriate option if you want to share the source code of your
246 /// application with everyone you distribute it to, and you also want to give them
247 /// the right to share who uses it. If you wish to use this software under Open
248 /// Source Licensing, you must contribute all your source code to the open source
249 /// community in accordance with the GPL Version 2 when your application is
250 /// distributed. See http://www.gnu.org/copyleft/gpl.html
251 ///
252 /// \par Commercial Licensing
253 ///
254 /// This is the appropriate option if you are creating proprietary applications
255 /// and you are not prepared to distribute and share the source code of your
256 /// application. Contact info@airspayce.com for details.
257 ///
258 /// \par Revision History
259 ///
260 /// \version 1.0 Initial release
261 /// \version 1.1 Added Linear
262 /// \version 1.2 Compiles under Arduino 1.0
263 /// \version 1.3 Fix error in test suite tat prevvented correct tests with latest versions of AccelStepper
264 /// Added documentation for examples.
265 /// Added new class MotorControllerSetter, which can be used to control motor controllers with
266 /// a direction and (PWM) speed pin.
267 /// \version 2.0 Caution: API Change: existing RCRx sketches will not work with this new version without (minor)
268 /// modifications.
269 /// Separate the WiShield WiFi driver code out into a separate Transceiver object.
270 /// Rationalise some includes and headers
271 /// Add support for WiShield and Ethernet transceivers, with examples to suit
272 /// \version 2.1 Some files were missing from the 2.0 release. Clarified the fact that only Arduino 1.0 and
273 /// later is now suported (due to incompatible changes in Ethernet UDP support)
274 /// \version 2.2 Compiler problems were reported unless SPI.h was include first in sketches (although
275 /// I could not reproduce this). Changed examples to suit.
276 /// \version 2.3 Found and documented a problem when you use Arduino digital pin D4 as an output with
277 /// WiFi-Bee, which uses that pin as HIBERNATE. Dont use D4 as output with WiFi-Bee
278 /// \version 2.4 Fixed incorrect link to RCTx on App Store.
279 /// \version 2.5 Updated author and distribution location details to airspayce.com
280 
281 #ifndef RCRx_h
282 #define RCRx_h
283 
284 #if (ARDUINO < 100)
285 #include "WProgram.h"
286 #else
287 #include "Arduino.h"
288 #endif
289 
290 class Setter;
291 class Transceiver;
292 
293 /////////////////////////////////////////////////////////////////////
294 /// \class RCRx RCRx.h <RCRx.h>
295 /// \brief Remote Control Receiver module for RCOIP protocol on Arduino.
296 ///
297 /// \par Overview
298 /// This class implements a receiver for RCOIP (Remote Control Over IP). It starts and manages a
299 /// WiFi receiver, which receives UDP messages containing RCOIP commands such as remote control channel
300 /// values. When channel setting commands are received they are translated into output values which are sent
301 /// to Setter objects to control the phycical output devices and pins on the Arduino.
302 /// Supports WiShield 1.0 etc.
303 ///
304 /// \par Outputs
305 /// RCRx maps RCOIP channels to physical output devices through the analogOutputs array. This is an array
306 /// of Setter objects, one for each physical output to be controlled by RCRx. Whenever a RCOIP message
307 /// is received with new channel settings, the input() function of each Setter with new data will be
308 /// called. This will cause each Setter to set its physical output in response to the remote control
309 /// data received by an RCOIP.
310 ///
311 /// \par Failsafe
312 /// RCRx supports failsafe behaviour if a connection to the transmitter is lost.
313 /// RCRx monitors the time of each received RCOIP request. If no request is received for more than
314 /// failInterval milliseconds, it will be considered as disconnected, and the failsafe() function of
315 /// every Setter will be called, allowing each Setter to adopt its failsafe configuration
316 /// (eg throttle to 0 etc). This allows remote control vehicles to fail safe if the transmitter
317 /// fails or goes out of range.
318 class RCRx
319 {
320 public:
321  /// Constructor.
322  /// After contruction and initialisation, call the init() and run() functions.
323  RCRx();
324 
325  /// Tells this object where to find the transceiver object.
326  /// RCRx requires an instance of a Transceiver object for the device that you are using to
327  /// Received RCOIP requests from the transmitter.
328  /// A number of Transceivers are provided with RCRx:
329  /// - WiShieldTransceiver for WiFi transport with WiSheild
330  /// - EthernetTransceiver for Ethernet transport with Ethernet shield
331  /// or you can define your own.
332  void setTransceiver(Transceiver* transceiver);
333 
334  /// Specifies the Setters that will be used by this receiver to set its output values
335  /// Whenever a RCOIP message is received with a new value for channel n, it will be passed
336  /// to the Setter at index n by calling the Setters input() function.
337  /// \param[in] analogOutputs Pointer to an array pointers to Setter objects.
338  /// \param[in] numAnalogOutputs Number of elements in analogOutputs
339  void setOutputs(Setter** analogOutputs, uint8_t numAnalogOutputs);
340 
341  /// Set the output for channel n. Calls the Setter at index n of the analogOutputs
342  /// array. Not usuallly called exernally, this is usually only called
343  /// from within RCRx. Subclasses can override this to get control
344  /// when new analog output values become available
345  /// \param[in] channel The analog channel number output to set
346  /// \param[in] value The new value to set
347  virtual void setAnalogOutput(uint8_t channel, int value);
348 
349  /// Initialises the wireless WiFi receiver
350  /// Call once at startup time after addresses etc have been configured.
351  void init();
352 
353  /// Call this to process pending Wireless events. Call this as often as possible in your
354  /// main loop. Runs the wireless driver stack or whatever in the Transceiver,
355  /// and does internal housekeeping.
356  void run();
357 
358  /// Call to handle an incoming UDP message containing an RCOIP command message.
359  /// This is usually only called from the Transceiver, but could be called externally
360  /// for testing purposes etc.
361  /// \param[in] msg Pointer to the RCOIP message
362  /// \param[in] len Length of the PCOIP mesage in bytes
363  /// \param[in] rssi Receiver Signal Strength as reported by the WiFi receiver (if any)
364  /// when the message was received.
365  void handleRequest(uint8_t *msg, uint16_t len, uint16_t rssi);
366 
367  /// Called by RCRx when no RCOIP message has been received for more than failInterval milliseconds.
368  /// Calls the failsafe function for all configured output Setters.
369  void failsafe();
370 
371  /// Called by RCRx periodically (typically twice per second) to do period processing such as
372  /// detecting loss of incoming messages
373  void periodicTask();
374 
375  /// Returns whether the RCRx considers itself to be connected to the transmitter.
376  /// Initialsed to false. Whenever an RCOIP request is receved, set to true. If no RCOIP request
377  /// is receved for more than failInterval miliseconds, set to false.
378  /// \return true if the RCRx is still receiving messages from the transmitter.
379  boolean connected();
380 
381  /// Sends an RCOIP reply message
382  /// Usually called internally at most once every _replyInterval milliseconds.
383  void sendReply();
384 
385 protected:
386 
387 private:
388  /// The transceiver
389  Transceiver* _transceiver;
390 
391  /// Array of output Setters
392  Setter** _analogOutputs;
393 
394  /// Number of Setters in _analogOutputs
395  uint8_t _numAnalogOutputs;
396 
397  /// Arduino analog input pin which yields the arduino battery voltage
398  uint8_t _batteryVoltageAnalogPin;
399 
400  /// Max time in milliseconds between RCOIP replies
401  unsigned int _replyInterval;
402 
403  /// Max time in milliseconds between received request before RCRx is considered to be disconnected
404  unsigned int _failInterval;
405 
406  /// The time we last got a RCOIP request from the transmitter
407  unsigned long _lastRequestTime;
408 
409  /// The last time we sent a RCOIP reply to the transmitter
410  unsigned long _lastReplyTime;
411 
412  /// Whether RCRx is considered to be connected to the transmitter
413  boolean _connected;
414 
415  /// The value of the RSSI (receiver signal strength indicator)
416  /// in the last request received
417  uint16_t _rssi;
418 };
419 
420 /// @example DifferentialRCRx.pde
421 /// This simple example handles 3 RCOIP receiver channels. Its configured like this:
422 /// 1 Differential motor driver (receiver channels 0 and 1) driving 4 analog outputs configured as 2 HBridges
423 /// 1 Digital output (horn) (receiver channel 4)
424 /// This is the program used for the tank shown in http://www.airspayce.com/mikem/arduino/RCKit/tank.mp4
425 
426 /// @example HBridge2RCRx.pde
427 /// This simple example handles 3 RCOIP receiver channels. Its configured like this:
428 /// This is the program used for the car shown in http://www.airspayce.com/mikem/arduino/RCKit/car1.mp4
429 
430 /// @example HBridgeRCRx.pde
431 /// This simple example handles 4 RCOIP receiver channels. Its configured like this:
432 /// 2 Servos (receiver channels 0, 1) (left joystick on RCTx)
433 /// 1 HBridge (receiver channel 3) driving 2 analog outputs (right joystick on RCTx)
434 /// 1 Digital output (horn) (receiver channel 4)
435 
436 /// @example RCRxWiShield.pde
437 /// Receives RCOIP commmands from a WiShield and uses them to set servo
438 /// and digital outputs.
439 /// This simple example handles 5 RCOIP receiver channels. Its configured like this:
440 /// 4 Servos (receiver channels 0, 1, 2, 3)
441 /// 1 Digital output (horn) (receiver channel 4)
442 
443 /// @example RCRxEthernet.pde
444 /// Receives RCOIP commmands on Ethernet and uses them to set servo
445 /// and digital outputs.
446 /// This simple example handles 5 RCOIP receiver channels. Its configured like this:
447 /// 4 Servos (receiver channels 0, 1, 2, 3)
448 /// 1 Digital output (horn) (receiver channel 4)
449 
450 /// @example TestSuite.pde
451 /// Self test suite for RCKit classes
452 
453 
454 #endif