Updated: Mar 14
Our goal is to make a group of five cars drive synchronically and make some shapes while going.
The cars are controlled by a NodeMCU component, which can communicate with the computer through Wifi.
The cars are made from a plastic board and use a 5V battery.
We track the cars in real-time with the Optitrack cameras system.
The code for the NodeMCU component is in Arduino. We used the Arduino environment to write it. Here is a link for the Arduino code The main code, meaning the commands' interface for the cars and the show code, is in C++. We used Visual Studio 2015 as a programming environment for it. Here is a link for the C++ code
The computer communicates with the cars through Wifi.
The cars move synchronically and with no “delay.”
The cars make beautiful shapes.
To create the show, we had to work in two different planes: building the cars and writing a low-level code in Arduino to control them; writing a high-level code in C++ to synchronize the car's movements to create the show.
Building the cars and working with the Arduino
We used cars that Yair Marom developed, and we changed them according to our needs. Each vehicle is built from a plastic board and two DC motors connected to two big wheels. Another small wheel is placed at the front of the car, and this wheel is free to rotate 360 degrees, helping the turntable right and left. A DRV-8833 controller controls the wheels:
And here is a scheme of the component and the connections to it
We chose to control the cars with a NodeMCU component instead of an Arduino board because the communication in real-time with the NodeMCU is more comfortable. It is possible through Wifi. A nodeMCU:
And here is a scheme of the component:
The NodeMCU is connected to a battery (5V), and it provides the voltage to the DRV8833.
This is the car
The car is moving according to the commands we send to the NodeMCU through Wifi. We wrote an Arduino code which enables the user to write the order (move forward or backward, turn left or right, stop and more) in an HTTP browser, then parses the commands and make the car do what the user wanted (there is a link to the code upper).
Write the C++ interface and main code.
We then wrote a wrapper code to the Arduino code in C++. The wrapper code was aimed to supply a comfortable interface for sending the commands to the cars and make them move synchronically. At this point, we started using the Optitrack system. This is a set of unique cameras that can follow objects’ motion in real-time. Markers are stuck to the objects, and the cameras track them. The software we used to see the camera's output and manage their activity is called MotiveTracker (version 1.8.0). Each car held three markers on it and was treated as a “rigid body” in the MotiveTracker.
To get the car's coordinates in real-time from the MotiveTracker, we used a code from the Natnet (version 2.10) library of Optitrack. This library includes some samples, meaning codes that return the user the position of the object. We used the PacketClient sample. We designed a multithreaded interface using the PacketClient code. Our code is based on two main data structures: the cars array and the command queues array. The car array holds the car objects, and the command queues array contains a queue for each car. The commands that are sent to the car are inserted into its queue. The system works with five threads: client thread, meaning the thread which updates data, updates each car position (coordinates and angle) while driving (in real-time); and 4 execute threads, one for each car, which goes over the car command queue, pops commands and run them.
To be able to send commands to the cars easily, we wrote a code that enables the user to send commands from this type to the cars: Move(CAR_ID (here from 1 to 5), DIRECTION (forward or backward), NUMBER OF BLOCKS (here, one block size-0.2 meter)) and Rotate (CAR_ID (here from 1 to 5), COMPASS (one of 8 directions of the compass rose), ANGLE (in degrees)). The commands are based on sending a simple command to the NodeMCU (with the Arduino code burned on it), what makes the car start the motion, and then sending it a command to stop according to the command parameters coordinates the Optitrack returns. For example, if we want car 1 to move 3 blocks forwards, the command we need is Move(1, FORWARDS, 3). It will send the car a command to move forward and start calculating the distance from the current car place to its destination (3*0.2=0.6 meters from the starting point), which is changing every moment. When the car reaches the destination (the difference between the destination and the current place is 0), the code sends the car a command to stop. The commands of rotations are similar.
The main code, meaning the code that made the cars do the show (create the shapes), is based on our developed interface. It uses the commands Move and Rotates, and that makes the cars move synchronically. Here is a movie that displays two different Car Shows we created (it possible to develop various shows with the commands interface we coded)