Arduino RC Tamiya – Part 3 – Adding Wifi Control

Last time we replaced the standard receiver with a custom coded Arduino. This allowed us to program the car ourselves and run simple automated scripts to turn around in a circle. In this post we’ll enhance our remote control car so it can be driven over WiFi.

The Arduino board we have been using is WiFi ready, due to its secure ECC608 crypto chip accelerator. This is perfect as we can use the readily available Arduino WiFi library in our code.

Tamiya Arduino WiFi Setup

The first step is to write some basic code to check the Arduino can connect to the Internet. In the following example, we’ll be connecting through a home router but you could hotspot your phone and connect directly. (If you’re using source control remember not to add your WiFi credentials!)

#include <SPI.h>
#include <WiFi.h>

char ssid[] = "yourNetworkName";  // your network SSID (name)
char pass[] = "secretPassword";   // your network password

int status = WL_IDLE_STATUS;

void setup() {
  Serial.begin(9600);

  // check for the presence of the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue:
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv != "1.1.0") {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);

    // Connect to WPA/WPA2 network
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }

  printWifiStatus();
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

The above code will connect to a WiFi SSID of your choice with a given password. Next it checks your Arduino has an available WiFi module and a supported firmware version. After that it tries to establish a connection. The debugging information about the connection will be recorded via the serial port output, so you can monitor the progress.

Tamiya Arduino WiFi Control

Now we have a successful WiFi connection it’s time to allow the Arduino controlled car to receive some commands and start moving.

To allow the car to receive commands we will program the Arduino to operate as a web server. It will host a web page available via the WiFi shield’s IP address that will have just enough HTML to control the digital Arduino pin inputs.

The following demo gives us the ability to steer left or right, it’s important to start simple and when confident add more control. This helps avoid breaking the car, precious household objects and people in close vicinity!

#include <Servo.h>
#include <SPI.h>
#include <WiFiNINA.h>

Servo steering;
WiFiServer server(80);

char ssid[] = "yourNetworkName";  // your network SSID (name)
char pass[] = "secretPassword";   // your network password

// Include a web page template with the UI car control buttons
const char *webpage = 
#include "uipage.h"
;

int leftTurn = 0;
int rightTurn = 180;
int status = WL_IDLE_STATUS;

void setup() {
  Serial.begin(9600);

  // check for the WiFi module:
  // removed for cleaner demo, view above snippet
  // check the firmware version
  // removed for cleaner demo, view above snippet

  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to Network named: ");
    Serial.println(ssid);

    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection:
    delay(10000);
  }
  // start the web server on port 80
  server.begin();
}

void loop() {
  // listen for incoming clients
  WiFiClient client = server.available();   
  if (client) {                             // if you get a client,
    String currentLine = "";                // make a String to hold incoming data from the client

    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out via the serial monitor
        if (c == '\n') {                   
          // if the current line is blank, you get two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            // the content of the HTTP response follows the header:
            // this is where we load our HTML UI template
            client.print(webpage);
            
            // HTTP response ends with another blank line:
            client.println();
            break;
          } else {    // if you got a newline, then clear currentLine:
            currentLine = "";
          }
        } else if (c != '\r') {  // if anything but a carriage return character,
          currentLine += c;
        }

        // check if client request was "GET /left"
        if (currentLine.endsWith("GET /left")) {
          steering.write(leftTurn);
        }

        // check if client request was "GET /right"
        if (currentLine.endsWith("GET /right")) {
          steering.write(rightTurn);
        }
      }
    }
    client.stop();
    Serial.println("Client disconnected");
  }
}

The following code is the HTML UI template. This is what we load in the above code to allow user input for sending commands to the car. For now we only have a left and right button. Bootstrap and jQuery are included to allow for pretty buttons and Ajax request handling.

R"(
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  </head>
  <body>
    <div class="container-fluid">
      <div class="row">
        <div class="col-xs-6">
          <button id="left" type="button" class="btn btn-default"
            onmousedown='makeAjaxCall("left")'
            ontouchstart='makeAjaxCall("left")' 
          >Left</button>
        </div>
        <div class="col-xs-6">
          <button id="right" type="button" class="btn btn-default" 
            onmousedown='makeAjaxCall("right")'                                                 
            ontouchstart='makeAjaxCall("right")' 
          >Right</button>
        </div>
      </div>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script>
        function makeAjaxCall(url) {
            $.ajax({"url": url});
        }
    </script>
  </body>
</html>
)"

With the above loaded onto your Arduino and running you should be able to navigate to the Arduino cars IP address in your browser and see the UI.

WiFi Remote Control Tamiya UI Web Server

In the above, clicking on either the left or right button will send a HTTP request to the running web server. The Arduino reads this request and converts the url path into an action that changes the Arduino pin value and the servos move. If all has gone well you should be able to steer your RC Tamiya via the Arduino through the web served UI!

Summary

Tune in for the next post where we’ll add more remote control functionality. At that point it gets a bit more complex as you try to mimic the remote control logic of an actual RC car. For instance steering straight on release of the left or right button and being able to stop and reverse.

Before I go, here’s a quick demo of forward and reverse working that will be coming very soon! Although I need to find a better way of sharing my phone screen and recording at the same time…

Arduino RC Tamiya

Arduino RC Tamiya – Part 2

In the previous post the Tamiya RC car was built and we covered the electronic components. This gave us the knowledge required to look at replacing the factory components and control the RC car via code! Now let’s look at adding an Arduino for custom functionality.

Setting up the hardware

For this step I will be using an Arduino board to replace the receiver. This means the car will no longer have any radio transmission. Instead the servos and electronic speed controller will be controlled via code written to the Arduino board.

I’ve chosen to use the Arduino Uno WiFi Rev2 board because it has the required power and functionality. It also has the added bonus of WiFi which will be useful to enable Internet remote control of the car. Take a look at the above link for more information on the technical specification of the board.

I also bought an Arduino Proto Shield Rev3. With some soldering this will sit on top of the Arduino Uno board and allow custom ports and wiring. The servos can then be quickly plugged in or unplugged.

Arduino Uno WiFi Rev2
PROTO SHIELD REV3

The first step is to act on the above and do the custom modification to the proto shield. This involves adding two 3 pin connectors to the board over the 5V, gnd and 8, 9 digital inputs. You can see the outcome of doing that in the following photos:

Both the three pin connectors shown allow for a servo and electronic speed controller to be directly connected, powered and controlled by the Arduino.

Writing Arduino code

We are ready to write and apply some custom code to the logic. I highly recommend that you try your code with the servos not connected to RC car parts to begin with. It is far too easy to accidentally upload some code that runs a servo at full speed and your fully built RC car flies off your desk and cables rip apart, drinks go flying and screens smash etc… I warned you!!

At this point we can open up the Arduino IDE to start writing some c++ code. There’s many tutorials out there on how to use this IDE to upload code to the board and it’s straightforward. A quick Google will get you on the right track.

The first step to setup the code is to declare which digital pins the two servos are connected to. I mentioned earlier that I’ve chosen to use pins 9 and 10. If you have good eyesight you might be able to see that on the board in the photos.

Fortunately there’s an Arduino Servo class ready for us to implement: https://www.arduino.cc/en/reference/servo

#include <Servo.h>

Servo steering;
Servo throttle;

void setup()  {
    throttle.attach(9);
    steering.attach(10);
}

Our first movement

Simple, now we have two Servo variables that we can write to and control the physical Servos. The next tricky bit is figuring out the ranges of your Servo, most Servos range from 0 to 180. In the acceleration configuration there’s a neutral range around 90-100 with forward and reverse above and below those ranges respectively. The higher or lower the value from the neutral the faster your speed. In the steering servo configuration 90 is straight, 0 -> 89 is left and 91 -> 180 right. The higher this value the tighter the turn.

The below is a very simple script to demo forward movement and stopping. The car will first steer straight and then move forwards at a slow speed for two seconds before stopping for five seconds. This gives us a few seconds to grab the car before we realise our speed controller works in a different range and accelerates into the nearest wall at full speed… (you’re testing without the Servos attached to the car though, right?!).

#include <Servo.h>

Servo steering;
Servo throttle;

void setup() {
    throttle.attach(9);
    steering.attach(10);
    // Before we move the car, reset the steering
    steering.write(90);
}

void loop() {
    // Accelerate forwards at a slow speed for two seconds
    throttle.write(105);
    delay(2000);

    // Enter the neutral range for 5 seconds
    throttle.write(90);
    delay(5000);
}

If the above was a success we can try getting our car to turn around in circles by itself. The following code will repeat an automated three point turn:

#include <Servo.h>

Servo steering;
Servo throttle;

int accelerationSpeed = 89; // Slowest accelerate speed 90
int reverseSpeed = 104;     // Slowest reverse speed 102
int neutral = 91;
int brake = 180;

int noTurn = 90;
int leftTurn = 0;
int rightTurn = 180;

bool debug = true;

void setup() {
    if (debug) {
        Serial.begin(9600);
    }
    throttle.attach(9);
    steering.attach(10);
}

void Logger(String message) {
    if (debug) {
        Serial.println(message);
    }
}

void MoveBackward() {
    Logger("Move: reverse");
    throttle.write(reverseSpeed);
}

void MoveForward() {
    Logger("Move: accelerate");
    throttle.write(accelerationSpeed);
}

void Brake() {
    Logger("Move: brake");
    throttle.write(brake);
}

void Stop() {
    Logger("Move: stop");
    throttle.write(neutral);
}

void SteerLeft() {
    Logger("Steer: left");
    steering.write(leftTurn);
}

void SteerStraight() {
    Logger("Steer: staight");
    steering.write(noTurn);
}

void SteerRight() {
    Logger("Steer: right");
    steering.write(rightTurn);
}

void loop() {
    SteerLeft();
    MoveForward();
    delay(2000);
      
    Brake();
    delay(250);
    
    Stop();
    delay(2000);

    SteerRight();
    MoveBackward();
    delay(2000);
    
    Stop();
    delay(2000);
}

Summary

You should now have an RC car that does something similar to the one I made in this video:

That’s all for part two. Have a play around with the code and see what you can make the car do. There’s a couple of projects out there that have incorporated sensors at this point. They would stop the cars movement before it drove into anything. That could be quite useful functionality if you’re looking for more small additions.

I’ve created a GitHub repository for the above code samples and I’ll be adding more along the way. Check it out: https://github.com/dant89/arduino-rc-car

Stay tuned for part 3 coming in the near future. The next step will be using the WiFi on the Arduino board to allow remote control over the Internet.

Arduino RC Tamiya Car