Learn about mesh networking by building this swarm of Particle-powered robots

Hacking a toy is a fun form of electronics exploration. It’s a great way learn how real-world products are designed and built, and tinker without worrying about rendering expensive electronics useless in the pursuit of knowledge. Inexpensive consumer electronics are a fantastic platform for learning, exploration, and even building new, innovative solutions.

Remote-controlled (RC) vehicles are a common target for makers, and cars with the “Thunder Tumbler” name provide a cheap, accessible platform for RC car hacking. The Tumbler has been hacked a number of times before, but I don’t think it’s ever been used in a mesh network. That is, until now. Using a couple of Tumblers that you can find online or in stores like CVS, and a few of Particle’s new, mesh-ready hardware, I created a swarmbot network of Tumblers that move in synchronized fashion at my every command!

Note: This post originally appeared in Make: Magazine, volume 68 and online here. It is reprinted here with the author’s permission.

Materials needed

For this project, you’ll need the following items:

  • (2-3) “Thunder Tumbler” RC Cars, available at many chain drug stores or online — here in the states both Walgreens and CVS carry these cars. Note there are multiple versions of this product, but I’ll cover how you can handle these subtle variations.
  • (1) Particle Argon
  • (3) Particle Xenons
  • (3) breadboards — included with the Argon and Xenon kits
  • Assorted jumper wires for connecting each Xenon to the RC Car’s PCB
  • A multimeter for inspecting IC pin functions (as the pinout may vary from one cheap RC car to the next)
  • Soldering iron and solder

How does mesh networking work?

Most connected solutions tend to rely on Wi-Fi or cellular for connectivity. This typically means that each connected device maintains a direct connection to the Internet. While this is useful for connecting to the cloud for data storage or processing, some connected solutions need to be able to operate on a local network, with other devices, regardless of whether a connection to the Internet exists.

Mesh networking solutions enable these scenarios by allowing developers to create local networks of connected devices. The bulk of the network consists of endpoints that sense or actuate, and repeaters that help increase the size and reliability of the mesh by passing messages between devices. In addition, a small number of devices — often just one — serve as gateways to maintain a connection to the Internet. Critically, these local networks of devices can still communicate with one another when the connection to the network disappears. The Argon, Boron, and Xenon — all 3rd generation Particle devices — provide built-in mesh-networking capabilities.

For this build, I used mesh to create a network of RC cars, each controlled by a Particle Xenon. All of the Xenon RC cars are endpoints, and are connected to a mesh network with a single Particle Argon as the gateway. Once the network is established, I can use local network messaging to send low-latency commands to nodes on the network and make my RC cars dance.

First, however, I needed to hack the off-the-shelf Tumblers to Particle-power them!

Hacking the Thunder Tumbler

The first step of this process is hacking the RC car to add a Xenon. Regardless of the brand or style of RC car you’re using, the objective is to crack open the car to reveal the PCB inside, determine how the device sends commands to the motors to rotate the wheels, and connect pins from the Xenon to the corresponding motor driver pins on the car. Because these cars are inexpensive, you should expect to find some variation, even among those with the “Thunder Tumbler” name on the box.

Write-ups on Tumbler hacking can be found online going back over 9 years. That’s a lifetime in the electronics world, so be sure to test and verify the functionality of your own cars as you follow-along with the instructions below.

I suggest grabbing your favorite multi-meter and measuring voltages across various pins on the RC car PCB as you make the wheels spin with the remote control. Make sure to set your car somewhere where the wheels can rotate freely so that it doesn’t get away from you during testing.

Image of an R/C car and my multimeter.
R/C Tumbler with my trusty multimeter. Since these cars are inexpensive, a multimeter comes in handy to reverse engineer the IC pinouts.

Remove the two screws that hold the shell of the tumbler in place. Once these are out, you can lift the shell to expose the tumbler PCB. Inside, you should see 8-10 wires that run from the the car to the PCB, and a number of through-hole and surface-mount components.

Close up image of the H-bridge motor controller from the Tumbler. Using my multimeter, I was able to determine what pins control the motor.
The Tumbler uses a classic motor controller designed known as an H-bridge driver. By testing the pads with my multimeter, I was able to reverse engineer what combination drives the car forward and backward, plus left and right steering. Note that some Tumblers use a different pinout than mine, so you’ll want to have a meter nearby to test your car.

Understanding the various onboard ICs

The small surface-mount component on the top is a remote-controller receiver chip, the RX-2B. Its pair, the TX-2B transceiver chip sits in the remote control that ships with these cars. These ICs are commonly used for RC vehicles, and I was able to find their data sheets online to determine which pins map to forward, backward, left and right commands from the remote. I also used the data sheet to establish a known ground pin, which is needed to determine which pins power the car motors and can be controlled by a Xenon.

This ended up being critical because the main IC on these boards, through-hole mounted on the bottom of the car PCB, is one for which I couldn’t find a data sheet, in spite of many hours of searching. While I’m still not 100% certain of all the features on this chip, it functions primarily as an H-Bridge motor controller. Pulsing a signal into a certain pin on the IC results in a pulse out to one of the motor control pins, which makes a wheel spin forward or backwards.

Image of inserting the motor controller back into the Tumbler chassis.
Inserting the motor controller back into the Tumbler chassis.

By reverse-engineering, I was able to find that there are four pins I care about on this unknown IC: one that spins the left wheel forward, one that spins it back; one that spins the right wheel forward, and one that spins the right wheel back. I soldered one wire to the top of each of these pins, and one to a ground pin. Even though the Xenon and car are powered separately, they need to share a ground signal for everything to work, as needed.

Setting up a mesh network

Image of three screen shots from the mobile set up of a Particle Mesh network.
Setting up a Particle Mesh network is a quick process with the Particle mobile app.

Because this project requires a mesh network, you’ll want to set one up with one gateway (a Particle Argon or Boron) and one Xenon-based node for each RC car. If you want to program each Xenon over-the-air without having to connect each to a computer, you’ll want to set up your network in advance. You can do this from the Particle mobile app, or follow the instructions here.

Three images from the Particle mobile app. Each shows a different stage in the mesh network setup.
This image shows mobile flow you will go through when setting up a new Particle Mesh device.

Programming the tumblers

Once you have your first Xenon claimed and ready, the next step is to write firmware for controlling the actions of each car. Since the goal is to create a small mesh of swarmbots, you’re going to create a simple sequence that moves the car forward, back, left and right. The code for this sequence can be found below:

// Wheel pin mappings
int leftReverse = A0;
int leftForward = A1;
int rightForward = A2;
int rightReverse = A3;

// Speed and delay variables
int speed = 85;
int turnSpeed = 255;
int forwardDelay = 1000;
int backDelay = 1000;
int turnDelay = 2000;

void setup()
{
  // Set motor pins to outputs
  pinMode(leftReverse, OUTPUT);
  pinMode(leftForward, OUTPUT);
  pinMode(rightForward, OUTPUT);
  pinMode(rightReverse, OUTPUT);

  // Make sure each motor is off
  digitalWrite(leftReverse, LOW);
  digitalWrite(leftForward, LOW);
  digitalWrite(rightForward, LOW);
  digitalWrite(rightReverse, LOW);
}

void runDemo(const char *event, const char *data)
{
  allOff();

  goForward(speed);
  delay(forwardDelay);

  goBack(speed);
  delay(backDelay);

  // Max spin to raise up on the back tires
  turnLeft(turnSpeed);
  delay(turnDelay);

  allOff();
}

void allOff()
{
  analogWrite(leftReverse, 0);
  analogWrite(leftForward, 0);
  analogWrite(rightForward, 0);
  analogWrite(rightReverse, 0);

  delay(50);
}

void goForward(int speed)
{
  allOff();

  analogWrite(rightForward, speed);
  analogWrite(leftForward, speed);
}

void goBack(int speed)
{
  allOff();

  analogWrite(rightReverse, speed);
  analogWrite(leftReverse, speed);
}

void turnLeft(int speed)
{
  allOff();

  analogWrite(rightForward, speed);
}

void turnRight(int speed)
{
  allOff();

  analogWrite(leftForward, speed);
}

void loop()
{
  // Nothing needed here. 
}

You probably noticed that the meat of the demo is analogWrite commands to turn each wheel forward or backward by sending a voltage to a corresponding pin. Through testing, I determined that the cars I’m using are PWM-able, meaning that I can set a wheel pin to lower than digital HIGH (3.3 volts in the case of the Xenon) and have the wheel turn at lower speeds. Notice that I’m passing in different values for turning right or left vs forward and back. PWM enables pretty complex patterns and speeds for these inexpensive cars.

With the demo code done, the final piece you need on your RC cars is a subscription to a local network message that specifies the runDemo function as the handler. Particle enables local, in-mesh-network messaging between nodes on a network using a Mesh.publish and Mesh.subscribe API. Mesh.publish sends a broadcast message (with a name and payload) to all nodes on the network. Mesh.subscribe, on the other hand, listens for messages (by name) and specifies a handler to process and respond to those incoming messages.

Our Xenons will use Mesh.subscribe to listen for a network message, and then trigger the demo sequence.

// Add to setup function
Mesh.subscribe("run-demo", runDemo);

Flash the completed code to each RC car Xenon and you’re ready for the final piece: programming the gateway to coordinate the movements of the car swarm.

Programming the mesh gateway

The mesh gateway is less complex than the code that runs on each Xenon, but still needs two pieces for the purposes of our demo:

  1. a Mesh.publish call to trigger the RC car demo sequence and
  2. a way to tell the controller to fire the message to the mesh network.

We could skip the second step by just firing the message when the gateway comes online, or regularly on a delay, but what fun would that be? Instead, we can use another Particle API Particle.function, to allow us to trigger the cars from a mobile phone.

void setup() {
  Particle.function("runDemo", runDemo);
}

int runDemo (String command)
{
  Mesh.publish("run-demo", NULL);

  return 1;
}

void loop() {
  // Nothing needed here
}

Particle.function takes a string value name of the function (used when calling that function from a mobile or web app or through the cloud) and a handler function to execute when called. That function contains our Mesh.publish call, which sends a broadcast message with the name “run-demo” to all listeners (i.e. our RC cars) on the network. Once you’ve added the code above to your gateway, you’re ready to control some swarmbots!

Putting it all together

Screenshot of the Particle Console.
Once you’ve built your RC cars and have them configured in a mesh network, you’ll be able to control them from the Particle Console.

Particle functions can be called from any device that has a secure connection to the Particle Device Cloud, which could be the Particle Console, the CLI, or even your own applications. They can also be called from the Particle mobile app, which seems like a fitting place to finish this project. The Particle mobile app shows a listing of every Particle device you own. Click on your gateway, then the “Data” tab menu, and you should see a “runDemo” function. Put your Xenons in position with plenty of space, and click the function to trigger some RC swarming!

The demo code above illustrated a simple, coordinated sequence of actions. But with PWM and a bit of trial and error, there are a number of cool synchronized dances you can create with mesh-networked RC cars.

Command your swarm!

Three RC Tumblers on their back wheels. The image highlights the coordinated control you'll have thanks to the mesh network.
With the project complete, it’s time for an RC Tumbler dance party!

Now that your bots are meshed, let’s turn them into real swarmbots that can communicate with each other. A common swarm scenario is the leader-follower pattern. The leader determines movements for the swarm, and communicates these directly to all followers. One example would be to control the leader with the out-of-box remote control, read pin voltages off the leader car, and send these as instructions to all followers listening for a Mesh event.

To build this demo, I designated one of my three cars as a leader, and added firmware to control the fleet. Instead of writing to my motor pins, the leader simply reads the analog values sent by the remote control and sends these to listeners on the network with a Mesh.publish that includes the wheel, direction and analog value to apply to follower cars.

int32_t lastLeftRVal = 0;
int32_t lastLeftFVal = 0;
int32_t lastRightRVal = 0;
int32_t lastRightFVal = 0;

#define MIN_PIN_VAL 150
#define DRIVE_VAL 200

void setup()
{
  pinMode(leftReverse, INPUT);
  pinMode(leftForward, INPUT);
  pinMode(rightForward, INPUT);
  pinMode(rightReverse, INPUT);
}

void loop()
{
  checkPin(leftReverse, &lastLeftRVal, "leftR");
  checkPin(leftForward, &lastLeftFVal, "leftF");
  checkPin(rightReverse, &lastRightRVal, "rightR");
  checkPin(rightForward, &lastRightFVal, "rightF");
}

void checkPin(int pin, int32_t *lastVal, const char *event)
{
  int32_t pinVal = analogRead(pin) / 16;
  
  if (pinVal > MIN_PIN_VAL)
    pinVal = DRIVE_VAL;
  else
    pinVal = 0;

  if (pinVal != *lastVal && pinVal == DRIVE_VAL)
  
    *lastVal = pinVal;

    Mesh.publish(event, String(DRIVE_VAL));
  } else if (pinVal == 0 && *lastVal != 0) {
    *lastVal = 0;
    
    Mesh.publish(event, String(0));
  
}

Code for the follower robots

On the follower side, I added firmware that listens for a Mesh event for each pin, and performs an analogWrite with the passed-in value. On the cars themselves, I also removed the antenna on each board and cut the traces from the remote RX IC just to make sure that movement commands were only coming from the leader.

void setup()
{
  pinMode(leftReverse, OUTPUT);
  pinMode(leftForward, OUTPUT);
  pinMode(rightForward, OUTPUT);
  pinMode(rightReverse, OUTPUT);

  digitalWrite(leftReverse, LOW);
  digitalWrite(leftForward, LOW);
  digitalWrite(rightForward, LOW);
  digitalWrite(rightReverse, LOW);

  Mesh.subscribe("leftR", leftR);
  Mesh.subscribe("leftF", leftF);
  Mesh.subscribe("rightR", rightR);
  Mesh.subscribe("rightF", rightF);
}

void leftR(const char *event, const char *data)
{
  move(leftReverse, data);
}

void leftF(const char *event, const char *data)
{
  move(leftForward, data);
}

void rightR(const char *event, const char *data)
{
  move(rightReverse, data);
}

void rightF(const char *event, const char *data)
{
  move(rightForward, data);
}

void move(int pin, const char *speed)
{
  int32_t speedVal = atoi(speed);

  if (speedVal > 16) // Filter out noise from the leader
  {
    analogWrite(pin, speedVal);
  }
  else
  {
    analogWrite(pin, 0);
  }
}

void loop() {} 

With this simple R/C-controlled swarm as our foundation, we built a bunch more swarm sequences:

  • Follow the leader — basic forward and back demo with ending spin️
  • Splinter — cars separate in three different directions and come back together
  • Follow the leader and push — leader tells followers to stop, goes forward 2 seconds, turns around, goes back 2 seconds, then tells followers to move backward as it keeps moving forward
  • Sentry mode — square path with right-angle turns
  • Orbit — followers orbit a stationary leader.

You can grab the complete project source code, including these more complex demos, from the repository on Gihub. I’ve also done a number of Twitch streams focused on building the demos for this project; check them out on my Twitch channel.

Hack It and Share It

Ready to rule the world with my new RC Tumbler swarm robots.

We’d love to see makers extend and modify this project with sensors and new behaviors. You could add collision detection to the leader with a PIR or ultrasonic sensor, or even use the remote to log predefined sequences that could then be repeated automatically. And if you’ve built your own mesh-style swarmbot project, or anything else with Particle’s new hardware, we’d love to hear from you! Share with us on Twitter, Instagram, or in our community of 160,000 developers.

Swarm on, makers!

Author Bio

Brandon Satrom is Sr. Manager for Developer Relations at Particle. An unabashed lover of the web, mobile and an avid tinkerer, Brandon loves to talk about sensors and circuits, microcontrollers, open source, robots and whatever new shiny tool or technology has distracted him from that other thing he was working on. Brandon has spoken at national, international and online events, and is the author of four books. He lives in Austin, TX with his wife, Sarah, and three sons, Benjamin, Jack, and Matthew.