Machine Learning Robot Driving Autonomously with Arduino and LIDAR

The first video (the one above) was quite successful and the feedback was very positive so I made another one where I cloned the robot and made them race! It’s cool and there were plenty of interesting problems that I had to solve to get it working (spoiler: in the end, it worked). Here it is:

Currently, I am doing my master’s in data science. The learning process at the university is definitely not the most interesting one, but I do enjoy new information about topics I never heard about like machine learning, data processing, classification, and so on. To put this new knowledge to the test and understand it even more (theory and boring classes will take you only so far) I decided to build my own Arduino-based robot with a LIDAR and try to train it to autonomously navigate on a race track build out of cardboard 🙂

The video linked above goes through the whole process and explains it very well but here you can find some supplementary information, code, and my data collected for training.

Before we start I would like to say thank you for reading about my projects and watching my videos! I really appreciate it as working on these projects is not easy, and takes a lot of time and money. If you would like to support my work you can do that through my merch, Patreon or Store. Thanks a lot!

Robot

The robot was built according to ORP design rules, You can read more about the project here:
https://openroboticplatform.com/

ORP parts used to build the chassis:

NameLink
160mm circular platehttps://openroboticplatform.com/part:3
160mm circular plate with wheel cutoutshttps://openroboticplatform.com/part:4
RPLIDAR holderhttps://openroboticplatform.com/part:48
Cheap yellow (TT) motor holderhttps://openroboticplatform.com/part:6
170 point breadboard holderhttps://openroboticplatform.com/part:36
SD card module holderhttps://openroboticplatform.com/part:37
L9110S motor driver holderhttps://openroboticplatform.com/part:38

That made building the robot much easier and let me reuse parts from this robot in my future projects. Parts I used are rather popular and inexpensive but also can be replaced by something you have at hand. I am positively surprised by the cheap yellow motors I used in this project. I remember facing some problems with these in my previous projects but here the experience was really smooth. Below you can find a list of all the parts used to build the robot. I used a different lidar but it’s not available anymore.

NameLink
Arduino Uno R4https://amzn.to/44OeeIA
SD card modulehttps://amzn.to/3Pw6feS
Bluetooth modulehttps://amzn.to/3sOiSZV
Motor driverhttps://amzn.to/3sUmo4U
Breadboardhttps://amzn.to/3Rh1sPZ
LIDARhttps://amzn.to/45Laj0F

Data collection:

Collecting the data was an easy step as I prepared everything earlier. With an app on my Android phone, I was able to easily send the control orders to the robot. Arduino was reading that through the serial port and driving accordingly. To simplify there are only 3 states allowed: forward, forward left, and forward right. While controlling the robot you are also allowed to stop and go back but during these maneuvers, the data is not saved on the SD card. Data is saved 5 times a second on the SD card – 240 measurements from the LIDAR and at the end there is a letter F, G or I that is the control label. Then I spent about 30 minutes on driving the robot around to collect enough data, pretty fun thing to do 🙂

All the data that was collected during this project can be found on GitHub in case you want to play around and train your own classifiers.

Feature selection:

The first step is to select the most important features present in our dataset. There are 240 points but we don’t need all of them to properly drive around, most of that data is just noise (for example all the points that are behind the robot, we don’t need them). That’s why we are going to select only the features that are the most correlated with our labels. It sounds super hard but there are ready Python functions for that inside scikit learn library.

I also modified a visualization program I created a while ago to display the data from the SD card and highlight the selected features. That way it’s super easy to visualize what exactly was selected and it really makes sense as only the points in front of the robot on the left and right were selected.

Training the classifier

When the features are selected it’s time to choose and train the classifier. I will keep it short as I am not yet that comfortable with explaining how it all works and why random forest worked the best in my case but it did and that is what I used in the end. I tried a few different classifiers but random forest performed a little bit better than the others. Training the classifier is also super easy thanks to libraries and it is not time-consuming at all, it literally takes a few seconds to do that.

Here is the code for the selection, training, and testing of the classifier.

import numpy as np
import pandas as pd
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report
from micromlgen import port

def letters_to_colors(letters):
    color_mapping = {
        'F': 'blue',
        'G': 'cyan',
        'I': 'magenta'
    }
    
    return [color_mapping.get(letter, 'black') for letter in letters]

data = pd.read_csv('I:/arduino lidar/visualizer/test4567.txt', header=None)
data.rename(columns={data.columns[-1]: 'Label'}, inplace=True)
data = data[(data['Label'] != 'L') & (data['Label'] != 'R') & (data['Label'] != 'H')]
data.reset_index(drop=True, inplace=True)
X = data.iloc[:, :-1]
y = data.iloc[:, -1]

label_encoder = LabelEncoder()
y = label_encoder.fit_transform(y)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

k = 15
k_best = SelectKBest(score_func=f_classif, k=k)
k_best.fit(X_train, y_train)

selected_feature_indices = k_best.get_support(indices=True)
print("selected_feature_indices: ", selected_feature_indices)

plt.scatter(data.iloc[:, selected_feature_indices[0]], data.iloc[:, selected_feature_indices[9]], c = letters_to_colors(data.iloc[:, -1]), s=8)
plt.show()

clf = RandomForestClassifier(max_depth=3, random_state=42)
clf.fit(X_train.iloc[:, selected_feature_indices], y_train)

y_pred = clf.predict(X_test.iloc[:, selected_feature_indices])

accuracy = accuracy_score(y_test, y_pred)
print(f'Accuracy: {accuracy}')

class_names = label_encoder.classes_
report = classification_report(y_test, y_pred, target_names=class_names, zero_division=0)
print('Classification Report:\n', report)

arduino_code = open("arduino_random_forest3.c", mode="w+")
arduino_code.write(port(clf))

Running the machine learning classifier on the Arduino

Here is a very good and simple tutorial on how to convert the classifier from python to Arduino and most importantly it just works as you expect it to!

https://eloquentarduino.github.io/2019/11/how-to-train-a-classifier-in-scikit-learn/

After uploading the code to the Arduino for the very first time I wasn’t sure what to expect but it just started working exactly as I wanted it to! So running the machine learning on the Arduino (at least the new Arduino board like Uno R4 with a more powerful microcontroller or MKR series) is not a problem.

RACING!!!

So the second video was focused on making both robots race. I wanted to teach them to avoid each other. To simplify the problem one of them was meant to drive slowly and the other fast with the aim to catch up with the first one every few laps and attempt to overtake without crashing or destroying the race track. It might sound simple but it’s not and some basic data science principles can be observed with the development of this project. In case of any questions please let me know I will extend this article!

How to build a robot?

Robots are cool, I think we all agree on that. Right here I would like to give you a short introduction to all the topics that you will most likely face while building your first robot. In the beginning, I just wanted to say no worries, building simple robots is not hard at all, most of it doesn’t even require any soldering (sometimes you may need to solder cables to motors, but for simple robots that’s the only soldering required).

I also wanted to point out the difference between a robot and not a robot. Some tutorials refer to an RC car as a robot but in reality robot is a device that can work on it’s own. At the same time it’s not about fancy futuristic artificial intelligence or humanoid robots, it’s about simple tasks that are solved by the robot completely without human interaction. So a line follower or an obstacle avoiding robot are great examples of ROBOTS while a “robot” and a human with a remote next to it is not a robot.

Keep in mind that this is not a complete tutorial with code, schematic and DIY instruction. It’s meant as introduction to all the topics you should know about in order to even start and understand some of the robotics tutorials so that instead of mindlessly following those you understand what’s going on.

If you want to start easily with a kit, you can check out something like this with all the parts, chassis, motors, sensors, and Arduino. If you prefer to buy components individually check out the list below.

Here you can see a short one minute introduction video, and to learn more about all the topics continue reading:

Microcontroller

Microcontroller is a brain of the robot, all the logic, conditions and calculations are performed in here. To simplify it we can say that microcontroller is just a very very simplified computer, the internal structure is more or less similar. There is no screen or keyboard, just a chip with pins. By writing the program you can read pin states set conditions (if statements for example) do some math and set output pins conditions or communicate with other modules, sensors etc.

There are a lot of different types of microcontrollers but if you are just starting you should take a look at Arduino UNO (which is actually more than just a microcontroller, it uses Atmega328 as a microcontroller but Arduino is rather an ecosystem and collection of development boards). Any Arduino board is very easy to start with and Arduino UNO is additionally quite affordable (Original boards start at 23 USD or you can buy a Chinese Arduino clone for 5 USD). With UNO you can build blinking LEDs, learn electronics and programming, simple robots, home automation, measuring devices and even CNC machines! If you need more pins (trust me if you are just starting you don’t need more pins) you can buy Arduino Mega.

NameStore 1Store 2
Original Arduino UNOhttps://bit.ly/2MuCKMwhttps://bit.ly/3ormF7N
Clone Arduino UNOhttps://bit.ly/3t5gk59https://bit.ly/3osuWIi
Original Arduino Megahttps://bit.ly/2YnfYsQhttps://bit.ly/3pt5vro
Clone Arduino Megahttps://bit.ly/3aqqXHBhttps://bit.ly/2M3BsZf

Of course Arduino is not the only way to go. You can read about programming STM microcontrollers, AVR, or lately released Raspberry Pi Pico (programmed with C++ or Python). There are some more advanced boards like Maix Sipeed with an integrated screen and camera programmed with Python. You can also take a look at single-board computers like Raspberry Pi 4B or BeagleBone Black. But all of those examples are probably not the best for beginners.

Sensors

In order to build a robot (not an RC car) we need sensors. Sensors are devices that measure physical things and transform those readings into electrical signals so that we can read those with microcontroller. For example, to build object avoiding robot we need an ultrasonic sensor that will measure the distance between a robot and an obstacle. This distance or actually two-way time of travel of sound that is processed into the distance can further be processed to decide if the obstacle is close enough to stop the robot or turn. With 2 conditional statements (if(…){}) you can write a simple program for such a robot.

Another popular sensor for simple robots is a line sensor that can be used to build a line follower, that is a robot that follows the black line. By using three of those sensors at the front of the robot you can write a simple program that will drive forward when the line is detected by the sensor in the middle, if the line is detected by the right sensor it should turn right, and if the left sensor detects line you need to turn left. This is a simple example of a not really efficient program for a line follower but it works really well 🙂

There are other types of sensors, there is a sensor to measure everything you can think of air quality, pressure, soil pH sensor, LIDARs, movements sensors etc. Once you get more familiar with basic sensors you can start playing with those a bit more advanced. Ultrasonic sensor and line sensor are probably the easiest to start with and pretty straight forward to use.

NameStore 1Store 2
Line Sensorhttps://bit.ly/39q4qLxhttps://bit.ly/2MxQTbW
Ultrasonic Sensorhttps://bit.ly/3t1Quz7https://bit.ly/2YjCqTD
Sensor Kithttps://bit.ly/3aqzXfRhttps://bit.ly/39rnmJT

Motors

There is many options when it comes to motors for robotics but because this is an introduction I will focus only on simple and cheap motors. You should pay attention to the rated voltage and current of the motors. Usually, you should look for motors with voltage of about 5 to 12V. There should be a way to mount wheels or you will have to look for a DIY solution. In order to increase the torque and lower the RPM motor should have a built-in gearbox. To start I recommend those plastic yellow motors, those are not great and you wouldn’t build the most amazing robot ever with those but to start those are great!

NameStore 1Store 2
Yellow Motorshttps://bit.ly/3orwWknhttps://bit.ly/3pseObk
Small Motorshttps://bit.ly/3oqqgTmhttps://bit.ly/3adWmMX
Bigger Motorshttps://bit.ly/3qZZVxbhttps://bit.ly/3pthhSC

Motor driver (H Bridge)

There is no way to drive a motor directly with an Arduino, don’t even try because you will break it. In order to control the motors we need a motor driver also called H bridge. Again there is a lot of options and most of them are very similar. Main differences are max voltage and current that can be handled by a driver or some additional features. Some simple and popular drivers are listed below.

NameStore 1Store 2
L298https://bit.ly/36h9IH5https://bit.ly/3cgeLvq
L9110Shttps://bit.ly/3acjcVlhttps://bit.ly/3qYZyTI

Cables, Breadboards

Obviously, you will need some cables and a breadboard to connect everything together. They’re nothing complicated, buy some female-female, female-male, male-male cables. When it comes to breadboard use a bigger one for bigger projects and a smaller one for smaller projects, usually power rails on the sides are very useful.

NameStore 1Store 2
Cableshttps://bit.ly/2L20vLGhttps://bit.ly/2M2yGDx
Breadboardhttps://bit.ly/3cj6t67https://bit.ly/3t3MGgP

Chassis

In order to attach everything together, you will need a chassis. You can buy a set with chassis, motors and wheels or you can try to find your own DIY solution and make a chassis out of plastic or even cardboard (that’s how I built my first robot).

NameStore 1Store 2
Chassis 1https://bit.ly/3t3LJF7https://bit.ly/3cfuaw1
Chassis 2https://bit.ly/3a9Ebbmhttps://bit.ly/3cnsX5N

Batteries

The battery is always a really problematic part of building robots. The most common choice is a LiPo battery but it’s a little bit dangerous, you have to take care of it and be careful because discharging the cells under 3.2V may damage the battery. Those batteries are sold as 1S, 2S, 3S and so on which means one, two or three cells because each cell has a nominal voltage of 3.7V a two-cell battery has a nominal voltage of 7.4V (and a max voltage of 8.4V). Batteries vary with capacity, the bigger the capacity the longer you can power the robot. There is also max current that can be drawn from a battery this is labeled as for example 10C and it means that capacity multiplied by 10 will give the max amperage that you can draw from a battery.

Another (probably safer) way to go is to use protected 18650 batteries. It’s also more complicated because you need to create a battery pack on your own and combine a few of those batteries in parallel or in series. Professionally those batteries are spot welded together but you can just easily use a battery box to keep them together.

I don’t recommend going with AA or AAA batteries as you will need to recharge or replace those very often (it’s not good for the climate and your wallet) and the max current of those isn’t enough for some motors.

NameStore 1Store 2
2S LiPohttps://bit.ly/3iUpE7qhttps://bit.ly/2M2ILAn
3S LiPohttps://bit.ly/3qX8sRwhttps://bit.ly/2M2ILAn
4S LiPohttps://bit.ly/3iWMQSkhttps://bit.ly/2M2ILAn
18650 Batteryhttps://bit.ly/3a4ys6whttps://bit.ly/3orRskO
18650 Boxhttps://bit.ly/3a9hIv7https://bit.ly/36jr8Dh

Programming

A lot of people are scarred by programming, I am not really sure why. Programming is easy, you don’t need math to create simple robots! If you have any experience with C++ or similar programming languages you can start programming Arduino right now. If you don’t no worries, there is a lot of great tutorials and examples online. Once you start and try to write your own programs you will realize that it’s not that hard.

You can find some cool tutorials on official arduino website:

https://www.arduino.cc/en/Tutorial/HomePage

Or just type “Arduino tutorial” into YouTube and you will find thousands if videos on this topic!

I hope this article helped you a bit with your robotics journey! If so don’t forget to share with friends and share you progress on Instagram by tagging me: @nikodembartnik and @indystry

Have a nice day!