A self driving car project. Pt 2.

Stefano C
5 min readJan 10, 2024

--

Serial communication between Jetson and Arduino.

Teleoperation with a joystick

Summary

In this story we are going to show how Jetson talks to Arduino. In order to check if everything works, i will use the rosserial blink application as example. We will see how to setup both Arduino and Jetson and we will acquire some basic terminology about ROS. Obviously if you haven’t read part one yet, go and read it - you fill find an introduction to the project and a high level view of the robot architecture.

Before starting on Arduino

  • You will need the Rosserial Library on both Arduino and Jetson.
  • I’m using Arduino IDE 2.2.1 on mac to build and upload arduino sketches on the board. The only thing you have to install is the Rosserial Arduino Library and you can do it through Arduino Ide (Go in the library manager section and search for Rosserial).
Arduino IDE on mac

Before starting on Jetson

  • On the Jetson side, things are a little more complicated:
  • First, be sure to have ROS installed. I installed ROS Noetic because it works with python 3 while ROS Melodic works with python 2. If you are going to create python3 scripts i strongly suggest to install ROS Noetic. Check this good tutorial on how to install ROS Noetic, and the reference page. On Jetson, which probably runs Ubuntu 18.04 (because of the Jetpack 4.6), like mine, ROS Noetic must be built from source — installer is only available for Ubuntu Focal (20.04).
  • Once ROS Noetic has been installed, you have to build from source the ROS Serial Package. (reference)

Let’s start on Jetson

If ROS is installed correctly, open the terminal and type:

rosrun

You will have something similar to this:

started roslaunch server http://192.168.1.73:41567/
ros_comm version 1.16.0


SUMMARY
========

PARAMETERS
* /rosdistro: noetic
* /rosversion: 1.16.0

NODES

auto-starting new master
process[master]: started with pid [10407]
ROS_MASTER_URI=http://192.168.1.73:11311/

setting /run_id to c5168e94-ac73-11ee-a716-3413e860bef9
process[rosout-1]: started with pid [10423]
started core service [/rosout]

Check the serial port

The next step is to know the port where arduino will be connected to. Using the command:

dmesg - follow

the terminal will display any kernel related message and it will wait any kind of hardware change. If you unplug-plug the arduino usb cable you should see something similar to :

[10532.033043] usb 1-2.1: Product: Arduino Nano 33 BLE
[10532.033045] usb 1-2.1: Manufacturer: Arduino
[10532.033048] usb 1-2.1: SerialNumber: 000000000000000099D9A71C67773EE1
[10532.038598] cdc_acm 1-2.1:1.0: ttyACM0: USB ACM device
[10532.299539] usb 1-2.1: USB disconnect, device number 6
[10532.524867] usb 1-2.1: new full-speed USB device number 7 using tegra-xusb
[10532.548013] usb 1-2.1: New USB device found, idVendor=2341, idProduct=805a
[10532.548020] usb 1-2.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[10532.548023] usb 1-2.1: Product: Nano 33 BLE
[10532.548026] usb 1-2.1: Manufacturer: Arduino
[10532.548029] usb 1-2.1: SerialNumber: 99D9A71C67773EE1
[10532.551698] cdc_acm 1-2.1:1.0: ttyACM0: USB ACM device

The name ttyACM0 is the Arduino serial port we are looking for!

Start the serial node

If rosserial library is correctly installed open another tab in the terminal and type:

rosrun rosserial_python serial_node.py /dev/ttyACM0

you should see this:

/home/polpybot/miniforge3/bin/python 3.9.7 | packaged by conda-forge | (default, Oct 10 2021, 15:08:54) 
[GCC 9.4.0]
[INFO] [1704487575.727975]: ROS Serial Python Node
[INFO] [1704487575.789013]: Connecting to /dev/ttyACM0 at 57600 baud
[INFO] [1704487577.904801]: Requesting topics...
[INFO] [1704487577.929810]: Note: subscribe buffer size is 512 bytes
[INFO] [1704487577.937283]: Setup subscriber on toggle_led [std_msgs/Empty]

rosrun is a command line tool that allows to run nodes. A node is a process that performs some kind of computation (think about nodes in a graph that can process data, messages and can exchange them). In this case we are telling to ROS to execute the node serial_node.py (yes, it’s a python script but it could be a C++ executable as well) which belongs to the rosserial_python package. Also, we are passing as arguments the serial port name /dev/ttyACM0.

Check permissions

If you have troubles in opening the serial port, try to change permissions on the port with:

sudo chmod 666 /dev/ttyACM0

Now, if the arduino program is running, type in another terminal tab the following command:

rostopic pub toggle_led std_msgs/Empty --once

rostopic is a command line tool that allows you to publish once a message std_msgs/Empty on the topic toggle_led. A topic is a communication channel through which two or more nodes can exchange messages. In this case, a node can be the serial_node (on the Jetson) which dispatches messages to the serial port. On the Arduino, the node can be the arduino script itself running on the board that listens every message of type std_msgs/Empty that belongs to toggle_led topic which it is subscribed to. Once the command has been sent, you should see the led changing state.

Arduino

Back to Arduino, if rosserial arduino library is correctly installed you should find the blink.pde in the menu. Open it and upload it on the board.

Arduino IDE
/* 
* rosserial Subscriber Example
* Blinks an LED on callback
*/

#include <ros.h>
#include <std_msgs/Empty.h>

ros::NodeHandle nh;

void messageCb( const std_msgs::Empty& toggle_msg){
digitalWrite(LED_BUILTIN, HIGH-digitalRead(LED_BUILTIN));
}

ros::Subscriber<std_msgs::Empty> sub("toggle_led", &messageCb );

void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
nh.initNode();
nh.subscribe(sub);
}

void loop()
{
nh.spinOnce();
delay(1);
}

In this code, Arduino (subscriber) waits a message from Jetson (publisher). Jetson will publish a message (in this case an object of type std_msgs::Empty) and it will toggle the led (on the Arduino board) on and off everytime a command is sent. This is done by instantiating a subscriber sub which listens to messages of type std_msgs::Empty (note that the message type is passed as template parameter in the ros::Subscriber<T> class). The ros::Subscriber class constructor takes two parameters:

  • a string “toggle_led” which is the name of the topic.
  • a reference to the callback function: void messageCb( const std_msgs::Empty& toggle_msg);

Check the reference for more info about this arduino code.

Conclusions

Ok, this was the very first “Hello World” of ros serial communication between Jetson and Arduino :). We can go further and we will see, in the next stories, how to drive the car using a joystick using ROS!

If you like this content, please consider to follow me on Medium :)

Happy reading, Stefano.

--

--

Stefano C

Master Degree in Physics, work in audio industry. Passion for C++, python, audio, robotics, electronics and programming. Modena, italy.