Introduction: UCL Embedded - B0B the Linefollower
This is B0B.*
B0B is a generic Radio Controlled car, tempoararily serving the basis of a line-following robot.
Like so many Line-following robots before him, he will do his very best to stay on a a line caused by a transition between the floor and a contrasting material, in our case duct tape.
Unlike so many other Line-following robots, B0B also collects data and sends it via WiFi.
Completely overkill for a hobby project, it does involve a number of subjects you might find interesting. This guide describes his birth, his functions and how you can make one just like him.
It also involves being angry at various electronics for not working like we wanted them to, and the steps we took to overcome those difficulties, (I'm looking at you ESP 8266-01).
There are 2 codes to make the project work. The first code is for the ESP8266 module which we use the Arduino as a programmer, and the second code is going to run on the Arduino.
Step 1: Components
For this project you will need:
• 1x radio controller car, (must have ESC and steering servo).
We were using a mostly stock Traxxas 1/16 E-Revo VXL, mostly because that's what we had, and were quite confident that we’d be able to control it with an Arduino. Also because it will end up carrying a not insignificant amount of extra hardware, we were confident this would not be an issue for the 1/16 E-Revo.
However, most radio controlled cars (that can easily be taken apart) could probably be used instead, and the process will be very similar.
• A ton of duct tape.
The color should contrast the floor as much as possible. In our testing environment we used white tape on a dark floor.
• 1x Arduino Mega 2560.
Smaller Arduino's are probably fine too, but you'll be pressed for pins.
• 1x large bread board.
One is enough, but we also had a smaller one to separate out the other voltage power lines to reduce risk of user error.
• 1x TCRT5000 IR analog sensor (used for collision avoidance).
The exact brand/model doesn't matter if it's Arduino compatible and measures distance. Search for keywords such as “Distance”, ” obstacle” sensor. Technically a digital sensor would work as well with minor code changes, but we’re using an analog one.
• 1x or 2x Gravity: Analog Grayscale Sensor v2
One is a necessity for the line follower. Exact model doesn’t matter, as long as it’s looking at intensity of reflected light and outputs an analog signal. The second for ‘room’ detection wasn’t working as well as expected and can be omitted, or an alternative, like an RGB color sensor can be found, presumably for better effect. We have yet to test this.
• 1 x ESP 8266-01.
There are a lot of versions of the ESP 8266 available. We only have experience with the 8266-01, and cannot guarantee the ESP code will work with a different version.
• 1 x ESP8266-01 Wi-Fi shield.
Technically optional, but if you don’t use this, everything involving the Wi-Fi module will get a lot more complicated. The guide, however, will assume you have this, (if not, find the guides online for correctly wiring the ESP-01 into the Arduino), as doing this incorrectly can and probably will damage the module.
• Batteries for the vehicle itself and batteries to power the add-on electronics.
We used a pair of 2.2 AH capacity, 7.4V Lipo batteries in parallel to power everything. You should be able to use whatever batteries you would normally use with your vehicle of choice. If you are above 5V but below 20V, capacity is more important than nominal voltage.
• A lot of jumper cables.
I’ve given up counting the exact number of these. If you think you have enough, you probably don’t.
• Finally, to attach everything, you will need to mount the Arduino, the sensors, the breadboard(s) and the Wi-Fi-module to the vehicle of your choice. Your result will vary depending on what you’re using as the base, and what materials are available.
• Zip ties.
• Some super glue.
• Small pieces of scrap paper/resin tube we had with a suitable diameter.
• An old Masonite backplate from a picture frame, cut to size.
• A little more duct tape.
• Any tools needed to work on your radio-controlled car of choice.
We mostly used a small screw driver set with multiple bits, but occasionally had to pull out the stock toolset that came with the car.
An important part of data collection.
• An MQTT server.
The middle-man between our vehicle and Node-red. Initially, for testing, we used test.mosquitto.org
Later we used:
This was a lot more reliable which more than made up for being slightly more complicated to set up.
The last part of data collection. Specifically, we will be using its SQL database for storing our collected data.
Step 2: Electrical Diagram
Step 3: Physical Construction
Our solution has a straight forward approach to physical assembly.
The original reciever and its waterproof enclosure was removed from the RC car, as it's not needed.
We found that there was one suitable location between the front wheels for our line follow sensor, so we held it in place by looping a ziptie above the front skid plate.
The sensor we use for anti-collision is sort of wedged in behind the front bumper. It's still being protected from impacts, and its friction fit. It ends up looking forward at an ever so slight upward angle. This is perfect.
The Masonite plate, (backplate from old picture frame), on top has small sections of paper/resin pipe cut to size and glued onto the bottom. These align with the mounts for the body posts and simply sits ontop, holding everything securely. Assuming the glue affixing the pipe to the plate holds, and that it doesn't tilt excessively, this will stay in place. It's also worth noting that the plate is within the protective sphere of the wheels and the bumpers. The Arduino Mega and the two breadboards have been affixed to the plate with either double side tape, or with a loop of duct tape looped around, glue out.
No special measures have been taken to secure the WiFi-module. It's not ours, so gluing it, or taping it down was deemed unnecessary as it's so light it won't move around much, and the wires are enough to hold it in place.
Finally, we have a sensor for detecting 'rooms' this was ziptied to the suspension components by one of the back wheels. During operation, this needs to be away from the line marking the vehicle uses to navigate.
Step 4: ESP8266 Module
The WiFi module, ESP8266, requires two different pin setup. One setup is to be used when flashing the module with a new program and using the Arduino Mega 2560 as a programmer. The other setup is for the module when it is in use and sending information to the MQTT Broker.
Using Arduino IDE to upload code to the ESP8266 module you will need to install a board manager and an additional boards manager
Under board manager install the esp8266 board manager. It will easily be found by searching "esp". It is crucial the you install the version 2.5.0, not older, not newer.
Under settings in additional boards manager URLs, copy in this line:
To be able to upload anything to the ESP8266 module you will need to use a specific pin setup so you can flash the module. This needs to be done every time you want to make a change to the current code running on the module. Don't forget to select the correct ESP8266 module from the board manager before flashing the module. In this project we picked the generic ESP8266 board. The pin setup for flashing the module is found on the first picture in this segment.
After having flashed the ESP8266 module you need to switch the pin setup. You may also choose to use an adapter to make the setup easier for you. In this project we chose to have an adapter whenever we had the module running. The pin setup with adapter is found on the second picture in this segment.
The code to be flashed onto the ESP8266 module setups the connection to a WiFi and a MQTT Broker, in this case with a username and password, but can be done without if you make the necessary changes described in the code's comments. For this project our Broker required a username and password to work. The module reads incoming messages from the serial port that it is connected to. It will read every new line created by the Arduino code, decipher the message and recreate the message. Thereafter it sends the message to the MQTT Broker that has been specified in the code. The code for the ESP8266 Module:
Step 5: Arduino
After having configured the WiFi module, we look at the program that will be used for controlling the motor and servo on the RC car. The car is going to react according to a gray scale information from the central sensor, also known as the "Line Detector" in this project. Plainly it aims at keeping the information from the Line Detector near a preset value which equals the information recorded at the change between light and dark or in this project, white and black. So if the value differs too much away, the corresponding output to the servo will steer the car near the preset value of the line.
The program has two buttons which functions as a start and stop button for the RC car. Technically the "stop" button is an "arming" button which in terms equals a PWM value sent to the motor that causes the RC car to halt. The start button sends a PWM value that equals the RC car barely moving forward since it will drive too fast if it gains too much momentum.
An collision avoidance detector is added to the front-end of the RC car to detect whether or not the way ahead is clear or blocked. If it is blocked the RC car will halt until the obstacle is gone/removed. The analog signal from the detector is used to determine whether or not something is blocking the way and is made a criteria for being able to move forward aswell as halting.
A secondary gray scale sensor, "Room Detector", is used to detect which room the RC car has entered. It works on a similar principle as the Line Detector, but it doesn't look for the change between light and dark, but rather for values within a specific range which corresponds to different rooms depending on the value seen from the Room Detector.
Lastly the program creates a line of information from the sensors for the WiFi module to read and afterwards send to the MQTT Broker. The line of information is created as a string and written to the corresponding serial of which the WiFi module is connected. It is important that the writing to the serial only happens as often as the WiFi module can read the incoming message, but remember to not use any delays in this code since it will interfere with the RC car's ability to follow the line. Instead use "millis" since it will allow the program to run without delay but after a defined amount of millis passed since the Arduino was turned on, will write a message to the serial without blocking the code the same way delay does.
The code for the Arduino Mega 2560:
Step 6: MySQL Database
WampServer is a web development environment for Windows that allow us to create applications with PHP and a MySQL database. PhpMyAdmin allows us to manage our databases in an easy way.
To get started go to: http://www.wampserver.com/en/
In this project we use version 3.17 x64 bits for Windows. After installation make sure all the services are running which in terms means the small icon turns green instead of red or orange. If the icon is green, then you can access PhpMyAdmin to manage your MySQL database.
Access MySQL using PhpMyAdmin and create a new database. Name it something appropriate that you can remember, in this project it was called “line_follow_log”. After creating the database, you should create a table in the database. Make sure the number of columns fits. In the project we use 4 columns. One column is for a timestamp and the last three is used to store data from the vehicle. Use a proper datatype for each column. We used “longtext” for the timestamp column and “mediumtext” for the rest.
That should be all you have to do in PhpMyAdmin and MySQL. Remember your database and the table for the section about Node-Red.
Step 7: Node-Red
To handle data collection, we'll be using a fairly simple flow in Node-red. It connects to our MQTT server, and writes to our MYSQL database.
To do this, we need a few palettes for various functions to work, and we need some actual code for it to run.
First things first. We'll need the following pallets.
This is the connection to our MQTT broker.
Our Dashboard, needed to visually represent the data collected.
Our connection to the SQL database.
This is not meant to be a fully fledged guide to Node-red, but I will be explaining what the Node-red flow does.
Early on, we had issues with our MQTT server of choice dying/disconnection, seemingly at random, which made doing any changes a frustrating endeavour as it was unclear if the changes had been beneficial, or not when we couldn't see the result. So the button 'Did the server die?' injects 'No' the following block injects it to our MQTT server. If it's not dead, 'No' will appear in the Debug window. This is done not only to test, but to force Node-red to attempt to reconnect to the MQTT server.
The 'Test string' sends a costum string to the MQTT broker. We formatted this string to be similar to what we would get from the Arduino. This was to have an easier time configuring the network that decodes the messages, without needing to have the project running, collecting data.
The last flow in the workspace can be divided into two segments. The bottom branch simply reads the incomming messages, posts them to the debug window and saves them to the SQL server.
The large network of connected switches following a function node if where the real 'magic' happens.
The proceeding function reads the incoming string, splitting it up with every semi-colon and passes the sections out on each of the outputs. The following switches look for one of two different incoming pieces of information. One specific piece of information is always passed through out of one output, the other option leaves by the second output. Following that, is a second group of switch blocks. They will only activate with one specific input, and output something else.
An example, 'obstacle', like all the others are a binary choice, it's either clear to drive, or it's not. So it will receive a 0, or a 1. A 0 will be send to the 'clear' branch, a 1 will be sent to the 'Obstructed' branch. The 'Clear', 'Obstructed' switches, if activated will output something specific, Clear, or obstructed, respectively. The green proceeding blocks will post in the debug window, the blue will write to our dashboard.
The 'status' and 'location' branches work exactly the same.
Step 8: MQTT Broker
A Broker is a server which routes messages from clients to the appropiate destination clients. An MQTT Broker is one where the clients use an MQTT Library to connect to the broker over a network.
For this project we created an MQTT Broker using the CloudMQTT service with the free subscription for a "Cute Cat" version. It has it's limitation but we don't exceed those in this project. The WiFi module can connect to the broker and the broker then routes the messages to an appropiate destination client. In this case the client is our Node-Red. CloudMQTT service sets up a username and password for their server, so we are guaranteed a higher security. Basically means that only those with the username and password can access this specific CloudMQTT service. The username and password is crucial when setting up the connection on the ESP8266 code aswell as Node-Red.
The on-going statistics for the messages the Broker recieves is a pleasant feature, which can be used to see how well your subscription plan is handling the information it routes.
A nice feature is the possibility to send messages from the Broker to the WiFi module but we didn't use those in this project.
Step 9: Hobby Electronics
Before beginning we knew from a past project that the stock steering servo could be controlled from an Arduino with a PWM signal, having similar wiring, and plugging into different channels on the same stock radio receiver, we assumed the Electronic Speed Control, (ESC from now on), that controls the motor, could similarly be controlled via PWM from the Arduino.
To test this theory, we device a small Arduino sketch. The sketch reads an analogue input from a potentiometer, remaps the value from 0,1024 to 0,255 and output the resulting value to a PWM pin, using analogWrite() while had the R/C car on a small box, and had the wheels removed.
After sweeping through the range on the pot meter, the ESC seemed to 'wake up' and we could throttle it up and down, we also had the Arduino print the values to the serial connection so we could monitor them.
The ESC seemed not to like values below a certain threshold, in this case 128. It saw the signal 191 as neutral throttle, and 255 was maximum throttle.
We didn't need to vary the speed of the vehicle and were perfectly having it chug along at the slowest speed that would make it move. 192 was the lowest value that would turn the motor, however we have yet to assemble everything and are unsure if this output would be enough to move the vehicle after final assembly, however entering a slightly larger value should be trivial.
Circumventing the potentiometer and putting in fixed value into the code, however, did not work. The stock ESC simply blinked and would not spin the motor, 'adjust throttle trim' according to the manual.
Furious trouble shooting, throwing various values at it, using different wires, and even experimenting with changing the PWM frequency the Arduino uses all resulted in more weirdness.
It seemed to be an intermittent issue, sometimes it would run, other times it refused to do anything. It simply continued blinking. A test with the original controller and receiver confirmed that the ESC was still working exactly as intended, which made the issues even stranger. Higher values, it ignored and kept blinking, lower values the ESC went back to shining a happy green, but still did not turn.
What was different from the setup with the potentiometer, or the stock transmitter and receiver, and the version that provided fixed values?
Sometimes working as intended and working as expected don't really overlap much on the Venn diagram. In this case, being a toy, there should be no chance of the model simply taking off or breaking fingers or getting hair caught in the wheels or drive train as the model turns on, even if something like holding the transmitter weirdly has the throttle in any other position than neutral.
'Adjust throttle trim', that's exactly what that means. The ESC is expecting a neutral signal when it powers on, before getting that it will do nothing. Normally the transmitter would always be in neutral when the ESC is turned on and from there will happily drive. In case it's not, it's probably back at neutral at least once by the time the model is firmly on the ground and the operator feels ready to race.
While using the potentiometer, we were 'sweeping' through ranges, and then it would start working. It simply armed as the potentiometer swept past the neutral position, and then it worked.
Lower ranges, however still seemed to displease the ESC. This turns out is a product of the PWM duty cycles.
Either by design or done for a technical reason, both the steering servo and the ESC ignores signals below 50% duty cycles. This could be in case the receiver/transmitter stops working or runs out of power, the model would return to neutral, and not take off into the distance on full reverse throttle. Equally, the servo only rotates 180 degrees, and does not need the full range.
With this new knowledge in hand, a new Arduino sketch was created. The initial version accepts strings entered into the Serial monitor, converts it to an integer and moves it to the PWM pin, using the servo library and write()*. If a new value is entered in the serial monitor, the write() value is updated.
During testing, the stock Traxxas ESC was replaced with a Mtroniks G2 Micro, however they should work the same, though exact values might be slightly different.
This library treats the ESC as a servo, this is fine apparently. The write() function from the Servo.h library goes from 0 to 180, the expected arming signal is expected to be around the middle.
The G2 Micro arms at a write() in a range of values near 90 however it was hard to pinpoint as it seems to 'remember' having been armed.
The Traxxas VXL-s3 is expected to arm at a write() value of 91.
After the arming signal, either ESC happily accepted PWM signals, no matter the Arduino functions called to generate them, and controls the motor accordingly.
Speaking of functions; the standard analogWrite(), as well as write() and writeMicroseconds() from the Servo.h library can all be used interchangeably, just keep in mind what does what, and ultimately nothing other than duty cycle matters. WriteMicroseconds() could be used if greater granularity is required, just keep in mind that the range here is from 1000 to 2000, with arming or 'neutral' expected to be at 1500. With the standard analogWrite() the usable range is expected to be from 128 to 255 with around 191 being neutral.