How to use rosserial with two Arduinos and Raspberry Pi

Arduino is a good development board for reading data from various sensors and for controlling the robot’s DC motors. Raspberry Pi is a very good Linux computer running ROS. To benefit from both systems, the easiest way is to connect and make them communicate through ROS nodes.

In this tutorial, I’ll show you how to use two Arduino boards as an extension of the Raspberry Pi computer. For this tutorial, you need Raspberry Pi to be able to identify each Arduino board. Such a system becomes necessary when the robot’s architecture is complex.

At one time, only one ROS node can run on an Arduino board. So in this tutorial, I will use one of the two Arduino boards to generate a random number, and a second Arduino board to control the LED connected to pin 13. On both boards, I will run one ROS node that will send or receive data according to the chart below.

How To use rosserial with Two Arduinos and Raspberry Pi

How To use rosserial with Two Arduinos and Raspberry Pi

The description of the structure

  • The user will start all ROS nodes by running a .launch file.
  • The first Arduino board will run a random number script and send data to Raspberry Pi.
  • A ROS node will receive a random number from the first Arduino board. The node will run on Raspberry Pi and will command the LED on the second Arduino board.
  • The second Arduino board will turn ON and OFF the LED (pin 13) depending on the commands received from the ROS node running on the Pi board.

The ROS node for random number generation

#include <ros.h>
#include <ros/time.h>
#include <std_msgs/Int32.h>

int min=1;
int max=5000;
int rand_no;


ros::NodeHandle nh;
std_msgs::Int32 rand_msg;
ros::Publisher pub_random("/random_number", &rand_msg);

char frameid[] = "/randomData";

#this function returns the random number
int random_number(){
rand_no= random(min, max);
return rand_no;
   }

 
void setup() {
   nh.initNode();
   nh.advertise(pub_random);
}


void loop() {
 rand_msg.data=random_number();
 pub_random.publish(&rand_msg);
 nh.spinOnce();
 delay(1000);
 }

Testing the node
Step 1: Open a Linux Terminal and type the command:

roscore

Step 2: Open a second Linux Terminal and type the following command:

rosrun rosserial_python serial_node.py /dev/ttyACM*

Step 3: To see the random numbers generated by the Arduino node, open a third Terminal and type the following command:

rostopic echo /random_number

The ROS node that displays and calculates the LED’s stage

This node will run on Raspberry Pi and will be a ROS node in Python. Before you start writing the Python code, you must create the workspace and the package that contains the node. The necessary steps can be found in this article.

#!/usr/bin/env python

import rospy

from std_msgs.msg import Int32
from std_msgs.msg import String

var=None

#define the display text
def callback(msg):
    global var
    var=msg.data

 
if __name__=='__main__':
   
 rospy.init_node('random_LED')
 rospy.Subscriber('random_number',Int32, callback)
 pub=rospy.Publisher('LED', String, queue_size=1)
 rate=rospy.Rate(10)

while not rospy.is_shutdown():
     if var<=2500:
        #send message to turn OFF the LED
          varP="OFF"
          rospy.loginfo("The output is OFF and the var is: %s", var)
     else:
        #send message to turn ON the LED
         varP="ON"
         rospy.loginfo("The output is ON and the var is: %s", var)

pub.publish(varP)    
rate.sleep()

The ROS node that controls the LED

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

ros::NodeHandle nh;

void messageCb(const std_msgs::String& msg)
{
  if(msg.data =="ON")
    digitalWrite(13, HIGH-digitalRead(13));   //blink the led
else
   digitalWrite(13, LOW-digitalRead(13));   //turn off the led
}

ros::Subscriber sub("LED", &messageCb);

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

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

Write the launch file

<launch>
<node pkg=”rosserial_python” type=”serial_node.py” name=”twoArduino_LED” output=”screen”>
<param name=”port” value=”/dev/ttyACM0″/>
<param name=”baud” value=”57600″/>
</node>
<node pkg=”rosserial_python” type=”serial_node.py” name=”twoArduinos_RandNo” output=”screen”>
<param name=”port” value=”/dev/ttyACM1″/>
<param name=”baud” value=”57600″/>
</node>
<node name=”random_number” pkg=”pi_and_arduino” type=”twoArduinos_Pi.py” output=”screen” />
</launch>

References:

 

9 comments » Write a comment

  1. When I try to compile the ROS node that controls the LED for arduino I get the error message :

    Invalid use of template-name ros::Subscriber without an agument list

  2. I believe the board receiving the control commands should rather be subscribed to the ‘LED’ topic. Could have been a simple omission.

  3. In the last script, there is a typo in
    ros::Subscriber sub(“OFF”, &messageCb);
    The arduino node should subscribe to “LED” topic not “OFF”
    ros::Subscriber sub(“LED”, &messageCb);

  4. Are the arduino’s communication over their USB cables to the rPi? You didn’t day anything about connection the serial pin of the arduino to the serial pin of the Rpi, so it must be using USB.

  5. There is still a typo in the last script; “The ROS node that controls the LED”
    The following would not compile…
    ros::Subscriber sub(“LED”, &messageCb);

    This worked on my setup…
    ros::Subscriber sub(“LED”, &messageCb);

    Thanks for the tutorial.

  6. My previous reply comment did not appear as I typed it.
    “ros::Subscriber sub(“LED”, &messageCb);”

    std_msgs::String needs to go between row::Subscriber and sub(“LED”, &messageCb); and it needs to be enclosed with “”

    ros::Subscriber sub(“LED”, &messageCb);

Leave a Reply

Required fields are marked *.