This article was translated from Arabic->English by: This article was translated from Arabic->English by: Nour Taweel

Because of its easy use and low cost, Arduino boards succeed to spread to a variety of applications, especially in robotics and electronic devices. But can this board alone be used to construct a robot that is able to navigate autonomously and plot a 2D map? The answer simply is NO!

The most recognized Arduino boards like UNO or MEGA have AVR internal Micro-controllers with processing potentials that aren’t suitable for such complicated applications or image processing.

So, can Arduino be used in high-level applications? Yes, it can be used in some aspects of these applications, for example, connecting robot’s sensors and motors to a more advanced computer – PC or Raspberry SBC – that will run the actual processing.

Since ROS is used with complex robot applications, we can dedicate it to the image processing task and use Arduino to get sensors’ readings. Now the question is how to communicate these sampled reading to our ROS?

What is rosserial?

This information is communicated with the help of the rosserial package. rosserial is a protocol to send data through a serial interface. In a client-server rosserial implementation, a rosserial-server is a computer running ROS and a rosserial-client is the microprocessor that receives sensors’ data and transports it to the server in the form of ROS messages. rosserial-server in this implementation is a publishing node while rosserial-client is a subscriber node, although this can sometimes be the other way round.

Rosserial-client package is available for several microprocessor types including Arduino, STM32, embeddedlinux and others. While rosserial-server package is available in Python or C++ versions.

Image courtesy ROS Integration for Miniature Mobile Robots

This article will go through the setup of Arduino and rosserial.

Installing rosserial package on Ubuntu

There are two methods to install any package on Ubuntu:

Using apt-get

To install rosserial on ROS kinetic, type



sudo apt-get install ros-kinectic-rosserial

Source code clone

First, create a new folder in your ROS workspace and name it rosseiral_ws for example. Create another folder inside named src



mkdir -p ~/rosserial_ws/src

cd ~/rosserial_ws/src

git clone https://github.com/ros-drivers/rosserial.git

cd ~/rosserial_ws

catkin_make

source ~/rosserial_ws/devel/setup.bash

Setup ros_lib into Arduino IDE

Move to yourfolderClone the source code in this directoryWhen the clone is complete, we need to build the package in the workspace. Go back to the main folderThen type this command. It will build the package creatingandfoldersTo introduce the installed package to ROS, use the following

For Arduino to be able to communicate with ROS, ros_lib must be installed. The next steps will guide you through this.

In your Arduino environment go to file-> preferences. For sketchbook location, look for libraries folder -create it yourself in case you can’t find it –

Now, in the command window, type

cd sketchbook/libraries roscore

In a new window, use rosrun command to generate ros_lib

rosrun rosserial_arduino make_library.py

You can see ros_lib included in your custom libraries list

Example 1: Blinking LED

This is the most basic example application. The following code sets up a node that subscribes to a topic that changes the state of a LED connected to pin 13. This code can be found in ros_lib -> Blink



#include <ros.h> #include <std_msgs/Empty.h> ros::NodeHandle nh; void messageCb( const std_msgs::Empty& toggle_msg){ digitalWrite(13, HIGH-digitalRead(13)); } ros::Subscriber<std_msgs::Empty> sub(“toggle _led”, &messageCb ); void setup() { pinMode(13, OUTPUT); nh.initNode(); nh.subscribe(sub); } void loop() { nh.spinOnce(); delay(1); }

Let’s explain the code:





#include <ros.h>

#include <std_msgs/Empty.h>

includes ROS library in the programincludes the messaging library that manages communication between publishers and subscribers. Since this application doesn’t need to exchange real data, an empty message is used and the code only creates a subscriber and no publisher gets created.

The operation is illustrated as





ros::NodeHandle nh

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

ros::Subscriber<std_msgs::Empty> sub(“toggle _led”, &messageCb )

pinMode(13, OUTPUT)

nh.initNode()

nh.spinOnce()

nh.subscribe(sub)

makes this program as a node in ROS . It’s a node object.Define the method that will be called when the topic message is received. When this method is called, the value on pin 13 is toggled.Creates a subscriber to the “toggle_led” topic with the callback function “messageCb” to be called on receiving a message.defines pin 13 as outputinit the nodechecks if there are any callbacks/services to control the update rate of ROS.subscribe/start listening

To run the code, open cmd window and type



roscore

rosrun rosserial_python serial_node.py /dev/ttyUSB0

Before uploading your code, check which port your Arduino is attached to by going to tools->port, or by using dmesg command

To run rosserial client that passes the messages from Arduino to ROS

To turn on the LED



rostopic pub toggle_led std_msgs/Empty –once

Now you can see the LED blinking

The following code is used as a template to write your custom publisher



#include <ros.h> ros::NodeHandle nh; std_msgs::String str_msg; ros::Publisher pub("any_topic", &str_msg); void setup(){ ... nh.advertise(pub); ... } void loop() { pub.publish( &str_msg ); nh.spinOnce(); }

Include ROS lib

Create a node to communicate with ROS

Create a publishing node: the first parameter is the topic’s name and the second is the callback function.

Start this publisher

In general, you need to do these steps:

Example 2: Motor Controller

This application is a little more complicated. Let’s assume a two-wheeled robot needs to be controlled using ROS. In terms of hardware, we need:

Arduino board

Motor driver

DC motors

L298 is used for driving the motors. It contains two H-bridge circuits, which has four input pins to enable the transistors and the motor is connected between the two output pins out1 and out2. This figure shows the internal structure of L298

H-bridge controls the voltage polarity. Therefore, if the goal is to control the rotation direction all you need to do is control which transistor to enable. For example, enable transistors 1&4 to rotate clockwise. While enabling 2&3 will produce anti-clockwise rotation.

We will connect 1 and 2 to Arduino pins and Out1 to one motor. Also, 3 and 4 to Arduino pins and Out2 to the other motor. The goal here is to control the speed of the motors, thus, the input voltage needs to be controlled using a Pulse Width Modulation (PWM). PWM values are between 0 and 225 while motors duty values are between 0% and 100%. As an example, to rotate in full duty, PWM=255. And to stop rotating PWM=0

In ROS there is a twist message in geometry_msgs package called cmd_vel which we can make use of to send speed values to the motors.

The next block diagram illustrates the idea





//Code Authors: //* Ahmed A. Radwan (author) //* Maisa Jazba #include <ArduinoHardware.h> #include <ros.h> #include <geometry_msgs/Twist.h> #define EN_L 9 #define IN1_L 10 #define IN2_L 11 #define EN_R 8 #define IN1_R 12 #define IN2_R 13 double w_r=0, w_l=0; //wheel_rad is the wheel radius ,wheel_sep is double wheel_rad = 0.0325, wheel_sep = 0.295; ros::NodeHandle nh; int lowSpeed = 200; int highSpeed = 50; double speed_ang=0, speed_lin=0; void messageCb( const geometry_msgs::Twist& msg){ speed_ang = msg.angular.z; speed_lin = msg.linear.x; w_r = (speed_lin/wheel_rad) + ((speed_ang*wheel_sep)/(2.0*wheel_rad)); w_l = (speed_lin/wheel_rad) - ((speed_ang*wheel_sep)/(2.0*wheel_rad)); } ros::Subscriber<geometry_msgs::Twist> sub("cmd_vel", &messageCb ); void Motors_init(); void MotorL(int Pulse_Width1); void MotorR(int Pulse_Width2); void setup(){ Motors_init(); nh.initNode(); nh.subscribe(sub); } void loop(){ MotorL(w_l*10); MotorR(w_r*10); nh.spinOnce(); } void Motors_init(){ pinMode(EN_L, OUTPUT); pinMode(EN_R, OUTPUT); pinMode(IN1_L, OUTPUT); pinMode(IN2_L, OUTPUT); pinMode(IN1_R, OUTPUT); pinMode(IN2_R, OUTPUT); digitalWrite(EN_L, LOW); digitalWrite(EN_R, LOW); digitalWrite(IN1_L, LOW); digitalWrite(IN2_L, LOW); digitalWrite(IN1_R, LOW); digitalWrite(IN2_R, LOW); } void MotorL(int Pulse_Width1){ if (Pulse_Width1 > 0){ analogWrite(EN_L, Pulse_Width1); digitalWrite(IN1_L, HIGH); digitalWrite(IN2_L, LOW); } if (Pulse_Width1 < 0){ Pulse_Width1=abs(Pulse_Width1); analogWrite(EN_L, Pulse_Width1); digitalWrite(IN1_L, LOW); digitalWrite(IN2_L, HIGH); } if (Pulse_Width1 == 0){ analogWrite(EN_L, Pulse_Width1); digitalWrite(IN1_L, LOW); digitalWrite(IN2_L, LOW); } } void MotorR(int Pulse_Width2){ if (Pulse_Width2 > 0){ analogWrite(EN_R, Pulse_Width2); digitalWrite(IN1_R, LOW); digitalWrite(IN2_R, HIGH); } if (Pulse_Width2 < 0){ Pulse_Width2=abs(Pulse_Width2); analogWrite(EN_R, Pulse_Width2); digitalWrite(IN1_R, HIGH); digitalWrite(IN2_R, LOW); } if (Pulse_Width2 == 0){ analogWrite(EN_R, Pulse_Width2); digitalWrite(IN1_R, LOW); digitalWrite(IN2_R, LOW); } }

Once the code is uploaded to Arduino, the robot can be controlled using the ROS viapackage that enables the ROS to control the linear velocity (forward and backwards) in addition to angular velocity on the z-axis. Themessages viatopic are used.

Type



rosrun teleop_twist_keyboard teleop_twist_keyboard.py

This output is produced

u: for left circle

i: forward

o: right circle

j: turn anti-clockwise

K: stop all motors

l: turn clockwise

m: left circle backwards

,: straight backwards

.: right circle backwards

This article presented why it is important to connect Arduino with a ROS system. We demonstrated how to setup Arduino and Ubuntu for this connection using the rosserial protocol and ros_lib library. We then showed a simple blinking LED example and a slightly advanced one of a moving two-wheeled robot. You can check also our other tutorial about IMU sensor connected with Arduino and ROS.