2 Wheeled Drive Raspberry Pi Line Follower running ROS1 Noetic
A 2-wheel drive car, controlled by a Raspberry Pi 4 running Robot Operating System (ROS) 1 Noetic, is used as a line following robot; it follows a black line against a white background, with the aid of a 5 channel infrared sensor.
Hardware
Components
The components used in this project are as follows:
- 2 wheeled drive robot chassis
- Raspberry Pi 4
- Monitor, keyboard and mouse for initial setup
- Motor driver HAT (Waveshare)
- 2 x standoff spacers
- 5-channel infrared sensor (Waveshare)
- 9V battery
- 2 x alligator clip cables
- Powerbank rated at least 5V and 3A with USB type-A to USB-type C cable to power RPi
- Wires - to connect motors to motor driver HAT
- Track(s) for robot to follow
- Screwdriver set
- Double-sided tape
- Duck tape
The 5-channel infrared sensor from Waveshare is shown in the figures below:
The front, back and side views of the Motor driver HAT are as shown:
Assembly
The 2 wheeled robot chassis is assembled using the guide shown here. The motor driver HAT is firmly attached to the GPIO pins on the Raspberry Pi with standoff spacers for added stability. The 5 channel infrared sensor is mounted underneath the robot chassis and connected to the RPi GPIO pins via the motor driver HAT in this order:
Infrared sensor | Cable color | GPIO.BOARD | GPIO.BCM |
---|---|---|---|
IR1 | Blue | 19 | GPIO16 |
IR2 | Yellow | 21 | GPIO17 |
IR3 | Orange | 23 | GPIO18 |
IR4 | Green | 22 | GPIO13 |
IR5 | White | 24 | GPIO19 |
The red and black cables are connected to a 5V and ground (GND) GPIO pins respectively.
The RPi was placed on a 3D printed platform using double-sided tape, which was mounted to the chassis also with double-sided tape.
One end of the cables from the motors were soldered with the other end connected to the motor driver HAT. The motor driver HAT is powered using the 9V battery via the alligator cables.
Finally, the raspberry pi is powered by the power bank, via a USB type-A to USB type-C cable, which is mounted on the chassis with double-sided tape.
The fully assembled robot is shown in the following images:
Software
Software architecture
Raspberry Pi OS is the operating system used on the Raspberry Pi 4. The download and installation procedure can be found here. ROS 1 Noetic is the version of ROS used in this project and can be installed following this guide.
For ease of access, debugging and mobility, the Raspberry Pi (and further robot operations) is setup in a headless or remote mode using the VNC Viewer or ssh for more advanced users.
Package install and setup
Once Raspberry Pi OS and ROS Noetic have been successfully setup, the next step is to download and setup the ROS package in this repository.
Open up a terminal window and navigate to the source folder in your ROS workspace (ros_catkin_ws/src
in my case) and clone this repository by executing the following command in the terminal:
git clone https://github.com/TheNoobInventor/2wd-rpi-ros-line-follower.git
The motor driver HAT uses Inter-Integrated Circuit (I2C) serial interface to communicate with the Raspberry Pi. This interface needs to be enabled in Raspberry Pi OS, which is disabled by default. To do this, click on the RPi Home button, navigate to Preferences, then Raspberry Pi Configuration to I2C and finally click on the Enable radio button. Then reboot the RPi for this change to be effected.
Build package
To build the package, move up one level to the main ROS workspace (ros_catkin_ws
) and run the following command in the terminal:
catkin_make
Custom message
A custom message - IrSensor.msg
in the msg
folder - of type int32, was created to store data outputted from the different channels of the infrared sensor.
Run package nodes
There are two ROS nodes -- written in Python3 -- in this package in the src
directory:
ir_sensor_node.py
- this publishes data about the values
returned by the 5 channel infrared sensor, through the topic 'infra_readings'
rpi_car_main_node.py
- this node subscribes to the infrared sensor data in the 'infra_readings' topic and uses this data to control the robot to move around the track(s).
Before running these nodes, the following python packages will need to be installed - if they are not already installed:
rospkg
- this provides basic utilities for querying information about ROS packages and stacks.
smbus
- this package is required by the PCA9685 PWM controller in order to use the i2c serial interface.
Open up a new terminal window and run the following command:
pip3 install rospkg && pip3 install smbus
In addition to the node files previously introduced, these two files are needed in this package:
PCA9685.py
- this is a low-level driver script to use the PCA9865 PWM controller employed by the motor driver HAT to control the motors.
motor.py
- this is a motor class which uses the PCA9685 PWM controller to control the speeds of the motors connected to the motor driver HAT.
In order to run the nodes, the files first need to be made executable. This can be achieved by running this command in a terminal window:
chmod +x ir_sensor_node.py rpi_car_main_node.py
Both nodes can be started up at once by using the launch file rpi_car.launch
in the src/launch
directory. Execute the following commad:
roslaunch rpi_car_line_follower rpi_car.launch
For debugging purposes, the infrared sensor data can be viewed by echoing the data from the 'infra_readings' topic in a separate terminal window:
rostopic echo /infra_readings
Race tracks
The following race tracks are used to test out the ROS package:
With the robot placed on the black line of the track, the launch file is executed. The main node, rpi_car_main_node.py
, attempts to keep the robot on the black line whilst moving around the track. It uses data from the infrared sensors - which return 0 if they are over a black line or 1 if they are over the white part of the track. These numbers are used in varying the speeds of the motor to get the robot to follow the line. This process is shown in the following code block from the main node:
if (ir_1 == 1 and ir_2 == 1 and ir_3 == 0 and ir_4 == 1 and ir_5 == 1):
# Move robot forward
Motor.MotorRun(0, 'forward', 70)
Motor.MotorRun(1, 'forward', 70)
elif (ir_1 == 1 and ir_2 == 0 and ir_3 == 0 and ir_4 == 1 and ir_5 == 1):
# Move robot slightly left
Motor.MotorRun(0, 'forward', 65)
Motor.MotorRun(1, 'forward', 70)
...
The motor speeds were obtained iteratively through trial and error.
It was observed that the initial black lines of the race tracks were too thin and caused issues with the infrared sensors accurately returning values. Duck tape was used to widen the track to enable each infrared sensor to read the black line correctly.
The figure below visualizes the robot movememnts to be made based on the location of the infrared sensors in relation to the black line of the race track.
Rqt graph
The nodes and topics relations can be viewed by making use of the ROS tool: rqt. Run rqt by executing this command in the terminal:
rqt
In the Graphical User Interface (GUI) that opens up, click on check-button on the 'infra_readings' topic. Afterward, navigate to Plugins in the menu then to Introspection and click on Node graph. This will output a window with the following image showing the relationship between the nodes and the 'infra_readings' topic:
Video demonstration
The following video (clicking the image below) walks through the setup procedure for this project and shows the robot moving around both tracks whilst following the black line.
Future work
Some suggestions for upgrades include:
-
Moving project over to ROS2.
-
Employing a better power solution using a set of 18650 batteries instead of the 9V battery.
-
Adding more sensors to increase the complexity.