Blair Kelly
About
Posted April 20, 2012, at 3:31 pm

Introduction

Since I was a kid I've been captivated by remote control vehicles. The R/C cars of Toys'R'Us can be fun, but what I've always been enthralled by are remotely operated vehicles (ROVs) such as the kind used to explore sunken ships. Or the type police forces use to disarm or explode a bomb. In my early teens I made my first attempt at an ROV by modifying a toy R/C car and mounting a small camera in its body. Technology has come a long way since then.

A few months ago a friend of mine reminded me of Arduino. I was in university when I first heard of it, but had been under the impression it was a special device musicians employed to make peculiar noises when sticks were bashed on dinner-plates. My friend told me Arduino was much more than that. He showed me Matt Richardson's "Enough Already," and that's when I got an inkling of Arduino's potential.

I picked up an Arduino UNO and began experimenting. At first I got a feel for the platform and attempted a modified version of Richardson's "Arduino High Speed Photography Trigger." Naturally, this tinkering evolved into a desire to build an ROV operated by a PS3 or XBOX 360 controller, or a Logitech G27 steering wheel, with communication done over WiFi, and with a First-Person-View (FPV), and Force Feedback.

The Arduino and FPV R/C communities are vast and full of extraordinarily talented people. So it was no surprise, once I had begun investigating the viability of my project, to discover that others had already done similar things. Someone already made a Logitech steering wheel control an R/C car, and a commenter on a blog relating to that project suggested adding force feedback. Another person got an XBOX 360 controller to direct an R/C vehicle; another did the same with a PS3 controller. There's even a project called 'Force Fly,' where the pilot receives force feedback from an aircraft. And my at-present favourite R/C video, "Tonka Summit Too," features a fantastic head-tracking FPV setup. But nothing I saw was exactly what I wanted: a ground based vehicle that could move at high speed, with very little response delay and could therefore be operated in real time over WiFi - and provide force feedback. And I wanted it to be expandable. And built by me. So I got to work.

Parts List

The following is a list of components used in the assembly and operation of the Arduino Wifly Mini:
  • Tamiya Mini M05, and using stock Motor and ESC
  • On-Road Tuned Spring Set, Blue on Rear Shocks, Green On Front. (To support the extra weight at the rear of the vehicle.)
  • One Dynamite 7.4v 4500 mAh NiMH Battery, for Tamiya's ESC.
  • Arduino UNO
  • Wifly Shield
  • One plastic housing component salvaged from another R/C vehicle for mounting the UNO and Wifly
  • One 750mAh 7.4v Battery for Arduino and Wifly shield.
  • Two Standard-Size metal-gear servos, one for steering and the other for camera panning.
  • One 6v 1500mAh battery for servo power. (Lots of batteries. The stock ESC's power output is too high for the servos, at 7 volts).
  • One 4.7k Ohm Potentiometer
  • One Triple Axis Accelerometer, ADXL335, for Force Feedback
  • Some 'arts and crafts' wood slats to aid in mounting the pot.
  • Several ball links and 4-40 rods for steering linkage and potentiometer apparatus, and other components.
  • Two pieces of plastic cut from the lid of a cheap container: these are used as debris shields to protect the camera's lens.
  • One GoPro HERO 2 Video camera, for FPV. These cameras are excellent.
  • One 300 mW 1.3gHz video transmitter with appropriate cables and connectors, and stock antenna.
  • One 3s 11.1v 1100mAh LiPo for Video TX power.
  • One 1.3GHz Low-pass antenna filter, to reduce interference from the video transmitter. (In my case this was not optional.)
  • Several ferrite rings, to mitigate interference from electronic equipment. Without the low-pass filter and the ferrite rings, the Wifly can't hear the base station when the video transmitter is powered-on. Don't underestimate the effectiveness of the ferrite ring! They're worth having.
  • One 1.3gHz video receiver
  • One 8dBi patch antenna for receiver.
  • A couple of 12volt deep cycle batteries, a Pure-Sine Wave inverter, and a regular monitor for FPV viewing when in the field. Bulky!
  • WRT54GL Router for base station. Excellent router when paired with DD-WRT Firmware, as I have.
  • 2.4 GHz Yagi (12dBi) and Patch antenna (14dBi) for base station, both from a local electronics store.
  • Tripod Stand for Mounting antennas.
  • Various connecting cables for base station (RP-SMA, TNC, N-Type, Cat-5, Etc).
  • Macbook, for base station.
  • Controllers (so far): Xbox360, PS3, G27 Steering Wheel, F510 rumblepad.

Choosing a Vehicle

My first choice of vehicle was a Jeep Rubicon 'replica' from Toys'R'Us. I bought it because it was inexpensive and seemed to be a good platform for the equipment I'd be mounting in it. Wouldn't it be neat to turn a cheap R/C toy into something far more?
Toy Jeep Rubicon, Wifly Project's First Vehicular Candidate

This idea turned out to be false economy. Modifications proved much more difficult than I anticipated. For example, I was not content on having a vehicle that could turn only left or right, with nothing in between. What good is a car without finite or gradual steering capability? (Other than guaranteed to flip at high speed...) Adding a servo-driven steering system to the existing body proved to be the breaking point for this vehicle's inclusion in the project. And there were other problems: The motor mount in this vehicle is totally custom and can accept only one size of generic, low-quality motor. I ended up purchasing an ESC (Electronic Speed Control) to govern the forward and reverse directions, since building an H-bridge to do the same thing was a bit too granular, too close to the building blocks, for the type of project I wanted this to be. And the wheels are not easily replaceable, and same goes for most other critical components. And I don't have much confidence the parts can be ordered separately, or for very long after the vehicle is discontinued, which probably it already is. If you decide on trying this project yourself, I recommend you get a remote control vehicle from a reputable manufacturer like Tamiya or Traxxas. You'll save yourself a lot of time and money in the long run. Of course, you could build a custom vehicle if you wished. If so, remember it is a highly skilled business if attempting to make something robust and reliable.

I ended up buying a Tamiya Mini with an MO5 chassis. It wasn't much more expensive than the Rubicon. It was a "build kit," which means all the pieces had to be put together one screw at a time. That wasn't a problem for me. The process was long but enjoyable and informative. If something goes wrong with the vehicle I have a much better chance of successfully diagnosing the problem, and obtaining the necessary parts to fix it.

Tamiya Mini with M05 Chassis (Front-Wheel Drive). Before Modifications.

From the get-go, this model was far more promising. It has graded steering thanks to the steering servo, and maintenance is possible if only sometimes a bit of a hassle. And it is much, much faster than the Rubicon.

Means of Communication

This section deals with the methods of communication employed in the Arduino Wifly Mini project.

General Communication

The electrical components of an R/C vehicle are typically controlled by a small onboard receiver. The receiver gets its instructions from the transmitter, usually held in the driver's hands. Most receivers don't send information back to the transmitter, and those that do don't have the required capabilities: Since an Arduino will be controlling the vehicle's components and measuring sensor inputs, I needed something that was not only compatible with the Arduino and could receive information wirelessly, but could also send specific information back. That's where the Wifly comes in.

The Wifly Module, Freshly Soldered. Not bad for my first soldering job in years. And for having learned from a YouTube video!

The Wifly module allows the Arduino to send and receive information over a WiFi network. It sits on top of an UNO board that runs the vehicle's software. The Arduino initiates a serial connection with the Wifly, and the two devices exchange information through this link. The Wifly module talks with the WiFi access point specified in its configuration.

In this project my controllers are connected to a computer running Processing, utilizing a library known as "ProControll" to read the controller inputs and initiate force feedback. The Arduino Wifly and Processing exchange information in UDP (User Datagram Protocol) packet form. It is not as reliable as TCP, but it is faster. It is not hard to see why a small response delay is desirable when manoeuvring at high-speed.

Video Transmission

The video feed from the Arduino Wifly Mini is sent via a 1.3GHz 300mW video transmitter. (The battery for this device can be seen on top of the vehicle.) A low-pass filter and ferrite rings were required to reduce interference with the Wifly module. The on-board camera is a GoPro Hero 2. It is an excellent camera and it has many more uses than just FPVing.

When driving at high speed, you need a low-latency video transmission method. The video transmitter I'm using provides this. Typically, the video feed from a webcam is not fast enough to make safe driving possible. However, the benefits of a WiFi-connected camera that is fast enough are plain to see; wherever you had a WiFi connection, you could see through the 'eye' of your vehicle. I have my sights set on a product that at the time of writing is yet to be released by GoPro: the WiFi BacPac. It was supposed to come out in March of this year but the release date has been repeatedly pushed back. They now say it will be released in 'Summer 2012'. Well, when it does come out, I plan to acquire one, and if I do I will give it a test and let you know if it works well enough to use safely with this project. Even if it doesn't send images in real-time (or close to it), I'm sure the WiFi BacPac could be used to provide a video feed for projects that didn't involve vehicles moving at such high speed.

Force Feedback Sensors

If sending 'force feedback' from the vehicle, one must decide exactly what force will be sent. I decided to try a couple of possibilities. For reasons described below, and for memory issues, the current version of the software running on the Arduino Wifly Mini does not observe potentiometer values. Also, the G27 steering wheel and F510 rumblepad are currently the only controllers that rumble when instructed by Processing.

The Potentiometer

I mounted a potentiometer to the body of the vehicle and attached it to the steering linkage. At runtime, the value of the potentiometer at each stage of the steering servo's movement, from hard left to hard right, is recorded. Knowing these values gives us a reference to compare values read later, when driving. A discrepancy in expected and actual values would indicate a force on the wheels in a certain direction. A small discrepancy would be a weak force; a large discrepancy would represent a strong force.

View of the steering potentiometer installed in the vehicle. Also in this picture: To the right, the Arduino and Wifly mounted between body posts. On either side of the steering linkage and potentiometer, above the motor and wheels, are 'debris shields' I devised to deflect flying matter away from the camera lens.

This approach, it turns out, is not reliable. In a controlled setting, with the vehicle sitting on my desk, I had good results when pushing on the wheels. But when driving, the feedback is inconsistent such that it serves to confuse rather than augment the driving experience. I suspect several issues are responsible for this. The Arduino compares stored pot values to present ones. How does it know which recorded value it needs to compare to the present one? It uses the current servo setting. The problem with this is the servo setting isn't necessarily where the servo is. This is because it takes time to move the servo horn from one position to another. And under the varying conditions of driving, the time it takes isn't always the same. My code estimates the movement delay, but as you can imagine, it is very difficult to produce an acceptably small margin of error. Also, the Mini has a fairly good suspension system, which dampens forces on the steering linkage. Anyway, I'm not driving the vehicle over many large bumps and nothing in the terrain should cause too much of a force in one direction or another. If I were using a rock crawler with this potentiometer system, and the steering servo was equipped to report its current position, and I was able to control the direction of force feedback in the steering wheel controller, this approach would probably work well when a tire got jammed on terrain. Otherwise, the potentiometer-as-force-feedback-sensor isn't worthwhile. At least not in this configuration.

The Accelerometer

I mounted a triple-axis accelerometer at the front of the vehicle. I programmed the Arduino to observe this sensor and take the average reading of both the Y (forward & backward) and Z (up & down) axis, over a short period. Deviations in these averages represent a change in acceleration. Detected changes are sent back to Processing, where they're converted into a force feedback representation in the controller.

Triple Axis Accelerometer

This approach offers much more reliable and predictable - and generally more usable - information. Testing on my desk and while driving produces results you'd expect: driving over bumpy terrain makes the controller shake, and so will hard acceleration and braking. The amplitude of these forces is mirrored in the strength of the controller's rumble. As stated above, memory issues with the Arduino UNO keep me from implementing both the potentiometer and accelerometer sensors, and the latter is superior anyway, so I just run the accelerometer code.

The accelerometer is located in the front bumper of the vehicle. The sensor's wires, leading to the Arduino, are visible between the shocks.

More Features Worth Mentioning

The beauty of Arduino is its... everything. It is a diverse platform. You can do so much with it. I'm only starting, and I want to squeeze as much out of it as I possibly can.

The ESC Switch

Using an opto-isolator chip connected to the Arduino, I can control remotely the power-state of the ESC. I did this primarily for safety reasons. If my code detects an error, such as multiple instructions received without a proper terminating character between each (a feature of an older version of the code, no longer posted), or the absence of a heartbeat character for a set period of time, the car performs a "take-no-chances" three-second full reverse (only if in forward throttle) and then cuts power to the ESC. This is to prevent a runaway, which of course could lead to an 'obliterated vehicle' situation. Or in the worst-case, somebody could get hurt. Both scenarios are highly undesirable.

Opto-Isolator Chip with Current Limiting Resistor, for remote ESC power-state control. It does what its name suggests. The voltage of the ESC is separated from the voltage of the Arduino's PWM output by means of an optically sensitive switch and an LED, all inside this little unit.
The Camera-Panning Servo

The limitations of a static camera will become apparent very soon after you start driving an FPV vehicle. Enthusiasts have created an array of solutions for this, and I've noticed they're often custom. This is because everybody's situation usually differs somewhat in terms of hardware or goals or both. The Mini is so small that a tilting camera was not really an option, at least not with the equipment I have, and it wasn't within the limited scope of this phase of the project. But a panning camera seemed like a must. I made some modifications to the body to accomodate a servo. It had to go on the roof. I suppose I could have finagled some kind of mount that attached to the chassis, but there is a lot more equipment to be added when implementing FPV than just a servo and a camera (transmitter, battery, connecting cables, ferrite rings, low-pass filter), and I wanted some degree of modularity. The only thing I lamented was the look of the car, but I got over that pretty quickly. I will focus on looks for the project's next phases.

Panning servo mounted in the roof of the Wifly Mini. You can also see I've cut out the front windshield for better visibility.

A Note on Wifly Configuration

If you're like me, you'll sometimes be frustrated when confronted with obstacles that are to you totally opaque but, to experienced individuals, so transparent it isn't worth mentioning. I ran into this when attempting to configure the Wifly module.

The Wifly is a wonderful device that is highly configurable. I recommend you download the manual and familiarize yourself with the various commands. Don't skip this step, as time consuming as it might seem. You'll save yourself some hassle and probably discover information you'll find useful later on. Once you've done this and you have the Wifly module attached to the Arduino (which should be connected to your computer), make sure you have the Wifly library loaded and accessible to the Arduino development tool. If done properly, you should see an example sketch titled SpiUartTerminal. Load that onto the Arduino. In the serial monitor, if you reboot the Arduino board you'll see a line that reads something like, 'press $$$ to enter commands.' In my initial experimentation, I could enter command mode but I could not issue commands. This is because, it turns out, the version of Arduino I'm using doesn't send a carriage return even when you press the return key! The Wifly recognizes, in its default state at least, the carriage return as the end of a command and a request from the user to execute it. So in order to issue commands I needed to connect to the Arduino through the 'Terminal' program on my mac. To do this, your Arduino should be plugged in via USB to your Mac just like it would be when loading a program, except you'll be using Terminal (or some equivalent in Windows) to open a serial connection instead of the Arduino IDE. You'll have to enter the following into the Terminal prompt (your location, i.e. 'usbmodem621' as seen below, will probably differ slightly. It could be usbmodem2201 or usbmodem323, or something like that):

screen /dev/tty.usbmodem621 9600

When you hit enter, the Terminal should connect to the Arduino (make sure you have that SpiUartTerminal sketch loaded!) and you'll be able to enter '$$$' to start issuing commands. This project requires the Wifly be set to UDP or combo mode.

The Code

The code for this project is a wild beast. This is practically my first (but literally my second) Arduino project and before this I had never programmed in C. Gradually, I will add highlights from the code below. There are still many improvements to be made to this code.

I want to learn how to make C classes, and soon! ;)

Soon after I finished the first phase of the Arduino Wifly Mini project, I started learning about PPM signals. I have now realized that my method of sending data back and forth from the Arduino is flawed: instead of sending packets with each instruction, I should be putting a series of instructions (steering, throttle, camera, etc) into one packet, so the method more greatly resembles a PPM stream. I will be making this modification to the code and will update it here when finished. This update has now been made to the code.

Permissions

I've been asked if the code can be used, modified, and republished. The answer is yes! Feel free to use the code however you like. My only request is this: if you use the code verbatim or you found it helped you substantially, please just make a note of it somewhere in your published project. Thanks! And have fun. :)

Libraries

Between Processing and Arduino, there are a few (that's not to say many) libraries in use. Check the import statements in the full code to see them all. Of note are the following. On the Processing side is Hypermedia NET (for UDP communication) and ProControll, a great little library that'll read the inputs of a wide range of devices. Though I wish it would handle controller rumbling better: that way we could have the XBOX360 controller shaking. On the Arduino side, we need the standard WiFly library in order to use the SpiSerial object.

Arduino Code

I have placed the whole Arduino code within it's own post to keep this page a reasonable length and make updates easier. Click here to see the Arduino sketch.

Sending Packets from the Arduino Wifly

One of the larger initial puzzles I faced was how to send packets from the Arduino/Wifly to the computer running Processing. I was able to do it the other way around fairly easily. I could find nothing that explained how to send packets from the Wifly. I found a thread on SparkFun that explained how to put the Wifly into UDP mode, and a few people commented they were able to send UDP packets from the Wifly, but didn't say exactly how. I decided to scour the Wifly's manual. And whatd'ya know? The answers were there.

Like the SparkFun forum thread indicated, the Wifly has to be put into UDP packet mode using the SPI-UART Terminal Sketch, or similar method. (This only has to happen once.) I figured out that you then have to write information to the SPI register/buffer on the Wifly. When you're ready to send the packet, the buffer needs to be 'flushed.' Here is a simplified version of the code I use to do this:

void ptb(char c)
{
  //prints to SpiSerial (fills up the buffer).
  SpiSerial.print(c, BYTE);
}
void fb()
{
  //FLUSH BUFFER (sends buffer contents to host).
  //a carriage return character (hex 0xd) flushes the WIFLYs buffer and sends the msg
  //where FBC is defined as: char FBC = 0xd;  //carriage return.
  SpiSerial.print(FBC, BYTE);
}

The Wifly then forms a proper UDP packet with the payload set as whatever you printed to the SPISerial before issuing the Flush command. Voila! Remember, you have to begin the serial connection in order to use the SpiSerial object, just like you'd have to begin a regular Serial connection between the Arduino and your computer. It looks like this, and is placed in your setup function:

SpiSerial.begin();

If you want, you can set the Wifly to 'flush' the buffer once it fills with a certain amount of data. Or you can disable that feature and flush the buffer when the Wifly sees a specified character. (The flush command should work even if you have a buffer limit set). I believe the default character is a carriage return.

Processing Code

Click here to see the whole Processing sketch.

UDP Packet Listening

To listen for packets in Processing on a specific port, you need the following code in your setup function:

udp = new UDP( this, listenPort );  //port 6000
udp.listen( true );

Then, somewhere in your code you'll need a read function. This is what mine looks like:

void receive( byte[] data ) {
  //void receive( byte[] data, String ip, int port ) {   // <-- extended handler
  char[] mrTdata = new char[data.length]; //FOR CONVERTING BYTE TO CHAR. here is stored information coming from the arduino.
  String incomingDataString = ""; //makes a whole string out of data presently being received...
  String firstChar = "";
  String currentChar = "";
 
 
  for (int i=0; i < data.length; i++) {
    mrTdata[i] = char(data[i]);   //BYTE TO CHAR.
    incomingDataString = incomingDataString + mrTdata[i];  //added to whole string used for reference.
    firstChar = "" + mrTdata[0];   //store the first char for reference... "" appears to be necessary to force conversion from CHAR to STRING
    currentChar = "" + mrTdata[i];
 
    if(!currentChar.equals("1") && !currentChar.equals("2") && !currentChar.equals("3") && !currentChar.equals("4") && !currentChar.equals("5") && !currentChar.equals("6") && !currentChar.equals("7") && !currentChar.equals("8") && !currentChar.equals("9") && !currentChar.equals("0") && !currentChar.equals(".")) { 
      //the character is not a number, not a value to go along with a command,
      //so it is probably a command.
      if(instructionDataString != "") {
        aCommandVal = Integer.parseInt(instructionDataString);
      }
      if(aCommand != "") {
        delegate();
      }
      aCommand = currentChar;
      instructionDataString = "";
    } else {
      //in this case, we're probably receiving a command value.
      //store it
      instructionDataString = instructionDataString + currentChar;
    }
 
  }
}

When data is received, the above function looks at it one character at a time. The function determines if the character is a command or data. Anything that's a number or a decimal is stored in string format as a 'command value.' Anything else is stored as a command. When another character that isn't a number or decimal is received the function throws the stored command and (if applicable) accompanying value at the delegate function.

Controller-Map Example

Here is an example of a controller map, for the PS3 controller in this instance. My processing code utilizes the information set within this function in conjunction with the ProControll library. The code then makes use of the various inputs from the controller through a large series of functions. To understand the basics of using a controller with ProControll I recommend reading through the examples offered by the library's authors. If you'd like to see how my code makes use of the various controllers, I recommend viewing the entire Processing sketch and following the trail from the main draw() function. You'll see the readControlDevice() function calls a set of more functions (sliderHandling(), buttonHandling(), etc) that watch - you guessed it - each slider and button on the controller, and those functions call more functions (shClutch(), shCamera(), shThrottle, etc) depending on what the controller readings are.

void mapPS3mac()
{
  controlDevice = controll.getDevice("PLAYSTATION(R)3 Controller");
  printDeviceItems();   //prints a list of available controls.
  controlDevice.setTolerance(0.05f);  //was 0.5f.
  wheelMovementMin = 0.001;  //wheel has to be moved this much in order to calculate new value.
  wheelStickDeadZone = 0.01;    //stick neutral deadzone. If stick reading is within + or - this value, it's as good as in the centre.
  wheelHardValue = 0.93;  //if the stick is moved to the right or left this amplitude then we consider it moved left or right 100%
  wheelPOW = 1.0;  //I haven't developed this fully, tinker with caution. It is intended to add progressive steering.
  throttleStickDeadzone = 0.05; //throttle neutral deadzone.
  pedalDeadZone = 0.004;  //if the pedal reading is under this value then we consider it not-activated.
  pedalMovementMin = 0.004;  //minimim distance pedal must be moved to calculate a new value
  pedalHardValue = 0.95;    //if pedal is depressed more than this amount then we consider it fully activated...
  cameraMoveInterval = 6; //milliseconds between camera steps.
  cameraMovementMin = 0.01; //if camera movement is controlled by a stick, the stick has to be moved this much to calculate a new value.
  cameraStickDeadZone = 0.07;
  cameraHardValue = 0.90;
  cameraMaxStep = 7;
  cameraMinStep = 4; 
  hasCoolieHat = true;    //the controller has a cooliehat.
  coolieIsCoolie = false;  //the cooliehat is broken into buttons.
  clutchForGears = true;  //does the clutch need to be depressed to change gears?
  hasSlidingClutch = false;
  hasForRevGear = false;  //false. used to determine if we should pay attention to "direction".
  oneSliderForThrottle = true; //one stick, on the left, signifies both directions...
  hasReversePedal = false; //this controller does not have a dedicated reverse pedal.
  wheelIsStick = true;    //steering is controlled by a stick. (as opposed to a wheel, like the G27)
  throttleIsStick = true; //make sure you use stick deadzones.
  hasCameraStick = false;   //is camera control a stick on this controller?
  hasCameraButtons = true;
  hasCameraCentreButton = true;
  hasRumblers = 2;  //controller has rumblers, though I can't get them to work yet for the PS3 or Xbox360 controller.
  maxRumbleIntensity = 1.0;  //max rumble intensity...
  throttleBase = 2;  //0 = -1 to 1, rests at 0. 1 = -1 to 1, rests at -1. 2= SPLIT across two padels, rests at 0, range: 1 to -1.
  reverseBase = 0;
  clutchBase = 0;
  //sliders
  sliderWheel = controlDevice.getSlider(2);
  sliderThrottle = controlDevice.getSlider(1);
  //sliderCameraX = controlDevice.getSlider(1);
  //buttons
  buttonStart = controlDevice.getButton(3);      //START BUTTON
  buttonESC = controlDevice.getButton(0);     //SELECT BUTTON
  buttonSendSettings = controlDevice.getButton(3);      //START BUTTON, clutch must be in.
  buttonResetOnFlatline = controlDevice.getButton(0);      //SELECT BUTTON (clutch must be in for this one to work).
 
  buttonGEARDOWN = controlDevice.getButton(10);       //LTB
  buttonGEARUP = controlDevice.getButton(11);        //RTB
  buttonCLUTCH = controlDevice.getButton(2);    //RJD
  
  buttonCentreCamera = controlDevice.getButton(1);    //LJD (depress to adjust camera trim).
  buttonAutoCamera = controlDevice.getButton(14);    //X. autoCamera ON/OFF
  buttonCameraMoveLeft = controlDevice.getButton(8);       //LEFT PADDLE
  buttonCameraMoveRight = controlDevice.getButton(9);        //RIGHT PADDLE
  
  buttonCalibrateSensors = controlDevice.getButton(12);        //TRIANGLE  (clutch must be in. calibrates sensors. Vehicle should be stopped!!)
  buttonSendFFaccels = controlDevice.getButton(12);        //TRIANGLE (when clutch is NOT in).
  
  //cooliehat
  //broken into buttons for this controller.
  //(left arrow pad)
  coolieUP = controlDevice.getButton(4);    //cooliehat UP
  coolieDOWN = controlDevice.getButton(6);    //cooliehat DOWN
  coolieLEFT = controlDevice.getButton(7);    //cooliehat LEFT
  coolieRIGHT = controlDevice.getButton(5);    //cooliehat RIGHT 
}

Notes and Ideas

Overall Performance

The performance of the Wifly Mini has exceeded my expectations. Steering, throttle, camera servo and force feedback are all fast and responsive under ideal conditions. (In my house.)

Bulk

The system is extremely bulky. (I'm talking about all the components needed to run the vehicle). I put this down mostly to the project being in its very early stages. At present I'm spending nearly an hour to set up in the field, which in the long run will be a total buzz-kill. It would be nice to be able to eliminate the computer and have an Arduino with, say, a USB host shield handle the the controller of choice. I believe this will be possible but isn't planned for the near future. I have found an incredible project that would help me cut out the laptop. It's called USB2PPM. If I can find more information about it, I will implement it into a new version of the Arduino Mini. This would be a major change to the project, since it would cut out the Wifly, but might be necessary if I want long-range communication (which I do). I will probably end up building my own version of USB2PPM and sharing the details on my site.

Range
I range test the Mini. Can you spot me?

I've been able to take the car out a few times to a track and a large parking lot for range testing. When the model is close (under 75 metres away), it performs very well. But anything beyond that and things start to get very glitchy. This is despite having a signal amplifier on my router and directional antennas. One of the major components of the next phase of this project is to improve range: I intend to build an antenna tracker and fiddle with the DD-WRT firmware on my WRT54GL router. I'll try turning off ACK timing and playing with other relevant settings.

A Closer Look: There I am!

When the car was on the ground, I could only achieve about 100 metres distance from the base station. But when picked up, the range improved dramatically. I suspect this has something to do with the ground somehow attenuating the signal. I'm not sure at the time of writing. I am going to try to get the Arduino Wifly Mini's antenna further off the ground.

Signal Strength at Several-Hundred Meters Distance
Changing Frequencies

With all the research I've done on 2.4GHz (the frequency in which most WiFi operates), I've learned that it is highly vulnerable to signal attenuation, particularly as a result of uneven and obstructive terrain. So after a bit of research I suspect 433MHz might be the way to go for long range control. Specifically I have my eyes on EzUHF and OpenLRS: both seem promising. The longer wavelength will mean less bandwidth, but telemetry and force feedback (at least in the form I've concocted) aren't very bandwidth-heavy. So this would constitute an Arduino Ham Mini. Babe could be the mascot!

Jessica stands over the Wifly Mini during range testing. 2.4 GHz directional antennas are aimed at the car. In this shot, the connection had been already lost. The Wifly has a hard time hearing signals from the base station when its antennas are close to the ground.
Platform Size

In the next phases of the project I will be moving to something larger. The Mini M05 is simply too small for what I want to do. (The cement lip of a driveway is an impassable obstacle.) It is fun to drive around the house on a single level, but the scenery quickly becomes repetetive. And outside, the Mini is confined to clean parking lots or tracks, both of which often have many people and cars to accidentally drive a prototype into... or under. Besides, I want to add a lot more sensors to the vehicle, such as a GPS module. I'd also like to add in a true brake to make the pedal on the G27 wheel behave more as one would expect. And with more than one transmission frequency in the mix, the proximity of radio devices onboard makes it hard to keep interference down. Suddenly I've had an idea...

Monster Mini! Raaaaaa!!
Communication Through Cellular Broadband

I was able to associate the Wifly with my iPhone hotspot, and with some adjustments to my home firewall I was able to exchange some packets, but none of this worked in the way we might wish. I was not able to send packets to my cell phone and then to the Wifly module. Rather, when my computer - the one running processing - was associated with the cell phone's hotspot, I was able to send packets to my home network and control the Wifly there. This state of affairs is the wrong way around, as you doubtless see if you consider I'm after long range control from a base station. Another thing: there was far too much latency to make safe driving a reality even if the cell phone could receive and route packets from external sources. However, my cell phone has only 3G connectivity, and it is a member of the walled-garden iPhone variety after all. So I have high hopes for LTE and Android phones, where one might be able to devise a custom and open source program to exchange UDP packets at high speed. Imagine an R/C car operated remotely through an LTE network in real time with a video uplink. Theoretically you could drive across Canada, given adequate cell coverage and a lot of helpful hobbyists...

Mentions

Thank you to everyone who so kindly took the time to write about this project or link to it, and thanks for all the kind things you've said about it. Here is a list of those I've known to have written about my project, or mentioned it. If you're missing from this list, please let me know. The fastest way would be to post a comment below or through Twitter. Also, thanks to all of you on YouTube for your generous comments. It means a lot to me.

Matt Richardson of MAKEzine
Mike Szczys of Hack-a-Day
Luke Plunkett of Kotaku
Mike of Mini Cooper Orange County
Lambert Varias of Technabob
Andrew Angus on Scoop.it
David Deloney of Walyou
Sven Wernicke of neuerdings.com. (In German.)
Julian Horsey of Geeky Gadgets
Alan Parekh of Hacked Gadgets

'Organic' is a word that might apply to the internet. Things change frequently. I've taken screencaps over the months of coverage of the Arduino Wifly Mini. They are provided in gallery form below.

Update History

August 15, 2012: Added "Mentions" section.
April 30, 2012: Added Controller-Map Example to Processing Code section.
April 29, 2012: Added 'Video Transmission' section to writeup under Means of Communication. Just to be clear on how the VTX is presently being done.
April 28, 2012: Updated Processing and Arduino code. Removed complicated braking functions. Simplified packet communications (both directions); payloads now more resemble PPM-style configuration, instead of the one-command-per-packet method I was using. Also simplified accelerometer/force-feedback functions.
April 22, 2012: Added 'Permissions' to code section.
April 21, 2012: Added parts list.
Leave a Comment