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.

Installing rosserial package on Ubuntu

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

Shell

1

mkdir-p~/rosserial_ws/src

Move to your src folder

Shell

1

cd~/rosserial_ws/src

Clone the source code in this directory

Shell

1

git clonehttps://github.com/ros-drivers/rosserial.git

When the clone is complete, we need to build the package in the workspace. Go back to the main folder

Shell

1

cd~/rosserial_ws

Then type this command. It will build the package creating build and devel folders

Shell

1

catkin_make

To introduce the installed package to ROS, use the following

Shell

1

source~/rosserial_ws/devel/setup.bash

Setup ros_lib into Arduino IDE

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

Shell

1

2

cdsketchbook/libraries

roscore

In a new window, use rosrun command to generate ros_lib

Shell

1

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

Arduino

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#include <ros.h>

#include <std_msgs/Empty.h>

ros::NodeHandlenh;

voidmessageCb(conststd_msgs::Empty&toggle_msg){

digitalWrite(13,HIGH-digitalRead(13));

}

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

voidsetup()

{

pinMode(13,OUTPUT);

nh.initNode();

nh.subscribe(sub);

}

voidloop()

{

nh.spinOnce();

delay(1);

}

Let’s explain the code:

C

1

#include <ros.h>

includes ROS library in the program

C

1

#include <std_msgs/Empty.h>

includes 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

C

1

ros::NodeHandle nh

makes this program as a node in ROS . It’s a node object.

C

1

2

3

voidmessageCb(conststd_msgs::Empty&toggle_msg){

digitalWrite(13,HIGH-digitalRead(13));

}

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.

C

1

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

Creates a subscriber to the “toggle_led” topic with the callback function “messageCb” to be called on receiving a message.

C

1

pinMode(13,OUTPUT)

defines pin 13 as output

C

1

nh.initNode()

init the node

C

1

nh.spinOnce()

checks if there are any callbacks/services to control the update rate of ROS.

C

1

nh.subscribe(sub)

subscribe/start listening

To run the code, open cmd window and type

Shell

1

roscore

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

Shell

1

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 turn on the LED

Shell

1

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

C

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include <ros.h>

ros::NodeHandle nh;

std_msgs::Stringstr_msg;

ros::Publisher pub("any_topic",&str_msg);

voidsetup(){

...

nh.advertise(pub);

...

}

voidloop()

{

pub.publish(&str_msg);

nh.spinOnce();

}

In general, you need to do these steps:

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

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

Arduino

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

//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

doublew_r=0,w_l=0;

//wheel_rad is the wheel radius ,wheel_sep is

doublewheel_rad=0.0325,wheel_sep=0.295;

ros::NodeHandlenh;

intlowSpeed=200;

inthighSpeed=50;

doublespeed_ang=0,speed_lin=0;

voidmessageCb(constgeometry_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);

voidMotors_init();

voidMotorL(intPulse_Width1);

voidMotorR(intPulse_Width2);

voidsetup(){

Motors_init();

nh.initNode();

nh.subscribe(sub);

}

voidloop(){

MotorL(w_l*10);

MotorR(w_r*10);

nh.spinOnce();

}

voidMotors_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);

}

voidMotorL(intPulse_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);

}

}

voidMotorR(intPulse_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 via teleop_twist_keyboard package that enables the ROS to control the linear velocity (forward and backwards) in addition to angular velocity on the z-axis. The Twist messages via cmd_vel topic are used.

Type

Shell

1

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.

A Mechatronic engineer from University of Aleppo, Syria. She works as a lecturer at the same university. Misa believes that people should be given the correct scientific information and informed in practical terms by touching the equipment and interacting with it and moving away from the idea of using simulation all the time.

Atadiat Community Newsletter

Enter your Email address

5 Comments

In the whole Universe there isn’t such a thing like “Arduino chips”; those things don’t exist. Somebody took a nice microcontroller from Atmel and then created the Arduino platform. And as a matter of fact, the “Arduino language” doesn’t exist either. The arduinos are programmed in C++.

Please don’t invent things that mislead the people that is new in this topic.

This is Yahya from Atadiat authors team. Yes you’re totally correct. Using the word “Arduino chips” is totally incorrect and was wrongly translated from the original text. About the “Arduino language”, you’re also right but it’s very common to say Arduino-C (AKA language) while I personally avoid using this misleading term.

I’m brand new to ROS, but not to building things
I’ve got 2 robots built, and I have ROS kinetic installed on one, and melodic installed on another, and I’ve been trying to find a way to install drivers for the motor controllers into ROS, but, after reading this article, I think I’ve got the whole idea wrong.
ROS doesn’t need drivers, the Arduino or Raspberry Pi does.

Tell me if I’ve got this right…

You have, in this case, an L298, connected to an Arduino, and you want to make the left motor turn at 1/2 speed forward. There is, for instance, a joystick connected to a computer running ROS Master, which publishes a msg, to which the Arduino is a subscriber.

You would then move the left joystick 1/2 forward, (which could be either digital or analogue) at which point, the ROS Master publishes a “left motor 1/2 forward”, which the Arduino receives, then sends out a 128 (1/2 of 255) signal to the L298 telling it to operate at the appropriate PWM, which makes the motor move at 1/2 speed. So the ROS has no idea what motor controller is connected to it. All ROS knows is to publish a msg saying “left motor 1/2 forward”

Advertisement

Follow Us

About

With passionate staff, Atadiat believe that Electronics is a practical domain and related content must be fine and practical. We aim to provide a new content experience with marketing related to electronics to our audience.