How to Connect Arduino to ROS

How do we connect ROS to an actual embedded system that operates in the real, physical world? I’ll show you how to do this now using Arduino

Arduino is a popular microcontroller for building electronics projects. A microcontroller is a bunch of circuits that do stuff, such as accepting data input, doing calculations, and producing output. With respect to robotics development, Arduino would be the “brain” of a robot.

Fortunately, ROS can integrate with Arduino. We will install some software that will enable your Arduino to be a bonafide ROS node that can do everything a normal node can do, such as publish and subscribe to ROS messages.

Here are the official steps for interfacing Arudino with ROS, but I’ll walk you through the process below.

Table of Contents


How to Install Arduino on Ubuntu Linux

First, let’s download the Arduino IDE (Linux 64 bit version) to our computer. I will follow these instructions for installing the Arduino IDE on Ubuntu. Go to this website, and download the software:


Save the file. It will be saved as tar.xz format to your Downloads folder.

Open a new terminal window.

Move to the Downloads folder (or wherever you saved the tar.xz file).

cd Downloads

Run this command to extract the files (substitute FILENAME with the name of the file you just downloaded):

tar xvf <FILENAME>

In my case, I will run:

tar xvf arduino-1.8.10-linux64.tar.xz

You will see a bunch of file names print out to your screen.

If you type the dir command, you will see the new folder. Let’s move that folder to the home directory. You can cut and paste it into the home directory using the file manager (the file cabinet on the left of the screen. Go there, then go to the Downloads folder, cut the file and paste it into the Home directory.


Now open up a new terminal window and type:

cd arduino-1.8.10

Type dir to see what files are inside.


To install the IDE, type:

sudo ./

Here is the output. You should see a “done” message. A desktop icon will also be present. You can activate it by clicking on it and allowing permissions at the prompt.

Now, get your Arduino and connect it to the USB port on your computer.

Start Arduino by going into a new terminal window and typing:


You might see an error message like this:


Failed to load module “canberra-gtk-module” … but already installed

To resolve that error, press CTRL+C and close the terminal window.

Open a new terminal window, and type:

sudo apt-get install libcanberra-gtk-module

Now open a new terminal window, and type:


Let’s see if everything works by trying to blink the light-emitting diode (LED) on your computer.

Go to File – > Examples -> 01.Basics, and choose Blink.

Try to upload that code to your Arduino by clicking the right arrow on the upper left of your screen.


You should see an error about the “Serial port not selected”.

Close out of your Ubuntu Virtual Machine completely. Do not save the state.

Set Up the Serial Port for VirtualBox With Ubuntu

Assuming you are using Windows, go to your Device Manager. Search for that in your computer in the bottom left of your desktop.

Under Device Manager, you should see Ports (COM & LPT). Note that Arduino is port 3 (Make sure your Arduino board is connected to the USB port of your computer).


Open your VirtualBox.

Click Settings and go down to Serial Ports.


Make sure your settings look exactly like this:


After you are done, click OK.

Restart the VirtualBox with Ubuntu.

Open a new terminal window and type:

ls -al /dev/ttyS0

Here is the output:


Now we need to give the IDE permissions to access the device.

In a new terminal window, find out your username. Type:


Now type the following commands, replacing YOUR_USER_NAME with what you found above:

sudo usermod -a -G dialout YOUR_USER_NAME
sudo chmod 660 /dev/ttyS0

Reboot your machine:

sudo reboot

Open up a terminal window and launch Arduino by typing:


Go to Tools -> Port, and you should see /dev/ttyS0. This is your Arduino board that is connected to the USB port of your computer. Make sure /dev/ttyS0 is checked.


Now open the Blink sketch again. Go to File – > Examples -> 01.Basics, and choose Blink.

Click the Upload button…the right arrow in the upper left of your screen.

The LED on your Arduino should be blinking! If it is not, go back to the beginning of this tutorial and follow the steps carefully.

To turn off the blinking light, open up a new sketch and upload it to your board. Go to File -> New.

Integrate Arduino With ROS

Now that we know Arduino is working, we need to integrate it with ROS. Here are the official instructions. I’ll walk you through the steps below.

Let’s install the necessary packages. 

Close Arduino. Then type the following commands in a new terminal window (these will take a while to download so be patient):

sudo apt-get install ros-melodic-rosserial-arduino
sudo apt-get install ros-melodic-rosserial

Open the IDE by typing arduino and go to File -> Preferences. Make a note of the Sketchbook location. Mine is:



Open a new terminal window and go to the sketchbook location you noted above. I’ll type:

cd arduino

Type the dir command to see the list of folders.

Go to the libraries directory.

cd libraries

Within that directory, run the following command to build the Arduino library that will be used by ROS (don’t leave out that period that comes at the end of the command):

rosrun rosserial_arduino .

Type the dir command to see the list of folders. You should now see the ros_lib library.


Make sure the Arduino IDE is closed. Now open it again.

You should see some sample code. Now, let’s take a look at the Blink example.

Go to File -> Examples -> ros_lib


Return to Table of Contents

How to Blink an LED (Light-Emitting Diode) Using ROS and Arduino

The Blink example is analogous to a “Hello World” program. Blinking an LED is the most basic thing we can do to make sure the hardware is working properly and that it accepts the software we are developing on our laptop. The goal of the Blink example is to toggle an LED on and off. 

In this example, Arduino is going to be considered a Subscriber node. It will subscribe to a topic called toggle_led. Publishing a message to that topic causes the LED to turn on. Publishing a message to the topic again causes the LED to turn off. 

Go to File -> Examples -> ros_lib and open the Blink sketch.

Now we need to upload the code to Arduino. Make sure your Arduino is plugged into the USB port on your computer.

Upload the code to your Arduino using the right arrow button in the upper left of your screen. When you upload the code, your Arduino should flicker a little bit.

Open a new terminal window and type:


In a new terminal window, launch the ROS serial server. This command is explained here on the ROS website. It is necessary to complete the integration between ROS and Arduino:

rosrun rosserial_python /dev/ttyS0

Now let’s turn on the LED by publishing a single empty message to the /toggle_led topic. Open a new terminal window and type:

rostopic pub toggle_led std_msgs/Empty --once

The LED on the Arduino should turn on. Note the yellow light is on (my Arduino is inside a protective case).


Now press the Up arrow in the terminal and press ENTER to run this code again. You should see the LED turn off. You might also see a tiny yellow light blinking as well. Just ignore that one…you’re interested in the big yellow light that you’re able to turn off and on by publishing single messages to the /toggle_led topic.


Return to Table of Contents

That’s it! You have now seen how you can integrate Arduino with ROS.

Benefits of Cross Compiling from a Host Computer to the Raspberry Pi

Having just developed a number of applications for the Raspberry Pi by building and executing the code directly on the Raspberry Pi, I can tell you that this will soon become impractical for larger projects.

The benefits of cross compiling from a host computer to the Raspberry Pi are numerous. Here are six benefits that come to mind:

VNC Viewer Lag


You don’t have to deal with the lag created on the VNC viewer session on your host machine. Sometimes I would type in some text on to my keyboard, and it would take five to ten seconds to appear on the Raspberry Pi. This could become annoying for large projects when I have hundreds of lines of code.

Compile Time


The processor in a host machine, such as my HP Omen laptop, is way more powerful than the Raspberry Pi’s processor. This leads to much faster compile times and increased responsiveness.

If you are creating a large program, you’ll need to compile that program numerous times over the course of development. Those precious seconds that you will need to spend waiting for the Raspberry Pi to finish compiling and responding add up over time, resulting in reduced productivity.

Graphical User Interface


A host machine typically has a more advanced and user-friendly graphical user interface.



A host machine, such as a Windows 10 machine, is built for heavy-duty multitasking. A Raspberry Pi is not built for such a level of multitasking. I am for example unable to search the web for code examples, check my email, and code all at the same time. Doing all of this on the Raspberry Pi presents significant challenges because of the lack of power compared to my host machine.

Debugging Capabilities


An IDE such as the Eclipse IDE, that could be downloaded on the host machine, has a number of advanced development capabilities, including remote debugging.

Screen Resolution


Even though I was able to increase the font size on the Raspberry Pi, using my own laptop resulted in a much crisper image. This is very important when I am staring at a screen and looking at code for long hours during the day.

UART vs I2C vs SPI – Communication Interfaces for Raspberry Pi

The Raspberry Pi provides us with three main communication protocols. These protocols enable devices such as sensors, display modules, other computers, and scientific instruments to communicate and exchange data with the Raspberry Pi.

Here are the communication protocols in order from slowest to fastest:

  • UART = Universal Asynchronous Receiver / Transmitter
  • I2C = Inter-Integrated Circuit
  • SPI = Serial Peripheral Interface

These methods are digital, serial communication protocols.

UART vs I2C vs. SPI Comparison


UART is slow. I2C is faster but not as fast as the SPI. SPI has a data transfer rate that is roughly twice as fast.

Number of Devices

I2C is the easiest of the three protocols for chaining multiple devices. I2C supports multiple masters and slaves. It enables up to 127 devices without extreme complexity. On the other hand, SPI gets hairy beyond two devices because a select signal line is required for each device. UART only can handle two devices.

Transmission Confirmation

I2C is the only communications protocol that ensures the data that was sent to the slave device was actually received.

Number of Wires

I2C only uses two wires. UART uses two wires, but it is slow. SPI needs four wires.


I2C is well known and widely used. I2C has a formal standard while SPI does not.


I2C is cheaper to implement than the SPI communication protocol.


I2C has less noise than SPI.


I2C can send data over greater distances than SPI. SPI is really limited to short distance communication.

When to Use Arduino Instead of Raspberry Pi for Your Projects

Arduino has limited RAM, a small amount of storage, and minimal processing power compared to Raspberry Pi. Arduino is a microcontroller motherboard and is designed for simple, low-level tasks. On the other hand, Raspberry Pi is a full-blown general-purpose computer capable of multitasking and executing high level interaction between software and hardware.

If Raspberry Pi is so powerful, more powerful than an Arduino, why would anyone ever think of using an Arduino instead of a Raspberry Pi for a project?

The rule of thumb is as follows:

  • If you can explain what your system is designed to do with fewer than two “and’s”, use an Arduino.
  • If your system requires more than two “and’s” to describe, use a Raspberry Pi.

For example:

  • I want my system to read temperature sensor data and generate a noise when the temperature exceeds 32°F. – Use an Arduino
  • I want my system to read temperature sensor data and send me an email with the temperature and generate a noise when the temperature exceeds 32°F. – Use a Raspberry Pi

In short, Arduino excels for projects that require capturing data from sensors quickly and doing something simple with that data. Raspberry Pi is great for projects where you need to have multiple things going on simultaneously.

Raspberry Pi definitely has the steeper learning curve compared to Arduino. You can get an Arduino up and running in only a matter of minutes. Raspberry Pi setup can be arduous. The first time I used Raspberry Pi, it took one to two hours to get everything up and running.

The benefit of both platforms is that both Raspberry Pi and Arduino have vibrant communities where you can go to ask questions if you get stuck with your project. In contrast, less popular platforms (Beaglebone for example) have small communities with just a handful of books that cover the details. If you have a project that requires your system to do something complex and you run into a brick wall, you are going to have to figure everything out by yourself.

One other thing. In order to shutdown Raspberry Pi, you have to shut it down properly typing this command:

sudo shutdown -h now

If you shut down a Raspberry Pi by cutting off its power, bad things can happen. However, with Arduino, you just unplug it or cut off its power to turn it off.

Common Tools and Instrumentation for Embedded System Debugging

Imagine you’re a software manager and are in charge of developing an embedded system. What tools will you use to debug? In this post, I will cover the common tools and instrumentation for embedded system debugging.

Host Machine with Test Scaffold

We do not want to begin our troubleshooting on the target system. Troubleshooting on the target system present a lot of complications. We need a host machine with test scaffold because the hardware might go through several iterations and is often replete with bugs and unstable early in the development process. It is also hard to create repeatable tests on the target system.

Think of a test scaffold as a test site on your host computer that mimics what would occur on the target hardware. Just like a construction scaffold, it is a temporary work area.

Finally, since embedded systems do not often contain a permanent storage medium, it can be difficult to keep track of the results of the debugging process. There is no “GitHub”-like system that can be implemented on an embedded target system.

Instruction Set Simulators

I need instruction set simulators in order to measure response time and throughput as well as to debug the startup code.

Assert Macro

The assert macro will help me to test my assumptions since it stops as soon as one of those assumptions is false.

Mechanism to Get the Software into the Target System

The locator output file needs to get into the target system somehow. We have a lot of options: PROM programmers, ROM emulators, In-circuit emulators, flash memory, and monitors. My personal choice would be PROM programmers since this is the “classic” way to get software into the target system. Using PROM programmers means that we are able to make changes to the software when we deem necessary.



A multimeter is a must-have tool for testing hardware. The kinds of multimeters that exist nowadays are a voltmeter, ohmmeter, and ammeter all-in-one tool.



Oscilloscopes are another useful tool for testing the hardware. Oscilloscopes enable us to receive and display analog signals.

Logic Analyzer


Logic analyzers enable us to receive and display digital signals instead of analog signals. This tool is useful for hardware debugging.

In-circuit Emulator

This tool is used as a replacement for the actual microprocessor on the target system. With the in-circuit emulator, you can to debug like you would with a normal debugger in a desktop environment.

Queues vs Mailboxes vs Pipes for RTOSs

In this post, I will discuss the differences between message queues, mailboxes, and pipes. Message queues, mailboxes, and pipes are services that are provided by RTOSs that enable tasks to communicate with each other. Tasks need to communicate with each other in order to coordinate activities and to share data.

What is a Mailbox?

Image Source: Vegpuff/Wikipedia

If you need strong control over prioritization, mailboxes might be a good choice. You can easily prioritize mailbox messages no matter when they entered the mailbox.

This characteristic provides a definite advantage over other inter-task communication options such as queues which are particularly sensitive to the order in which messages are added and removed from the data structure.

The other benefit of mailboxes is that there is typically no size limit on individual mailboxes. The size limit is typically fixed and is set by the programmer.

What is a Queue?

Image Source: Davidjcmorris

If you have an implementation that requires first-in-first-out prioritization, queues are a great choice. They are flexible and relatively easy to implement, making them a common choice in RTOS implementations.

The downside of queues is that, unlike mailboxes, you are often limited in the amount of data that you can write to the queue in any given call. Many RTOSs don’t have a lot of flexibility when it comes to this.

What is a Pipe?

If you need to be able to write messages of varying lengths, pipes are the best choice. Pipes are identical to queues except they are byte-oriented. The main difference between pipes and queues is that  pipes allow you to write messages of any length, while queues do not.

Mutex vs Semaphore Using a Gas Station Bathroom Analogy

Table of Contents

In this post, I will discuss the difference between a mutex and a semaphore using a gas station bathroom analogy.

What is a Mutex?

A mutex (mutual exclusion object) grants exclusive access to shared data or computer hardware. It is like a bathroom key at a gas station. If you have the key, nobody else can enter the bathroom while you are using it. Only one person (task) can use the bathroom (shared resource) at a time.

If a person (task) wants to use the bathroom, he or she must first get the bathroom key (mutex) since there is only one copy. The gas station owner (operating system) is responsible for managing the bathroom key (mutex).

Return to Table of Contents

What is a Semaphore?

Continuing from our example in the previous section, imagine that there are two bathrooms (shared resources) instead of one. Also there are two bathroom keys instead of one. Since bathroom entry is no longer exclusive, this is not a mutex scenario. Instead, the keys are called semaphores.

A semaphore enables two or more (two in this example) tasks (people) to use a shared resource (gas station bathroom) simultaneously.

  • If two keys (semaphores) are available, the value of the semaphore is 2.
  • If one key is available, the value of the semaphore is 1.
  • If no keys are available, that means that two tasks (people) are currently working (in the bathroom). The value of the semaphore is 0. The next task (person) must wait until a semaphore becomes available (i.e. a task finishes, and the semaphore is incremented by 1).

Return to Table of Contents

What Technique of Protecting Shared Data Requires Less Overhead?

Answer: Semaphore

Overhead includes things like memory, bandwidth, and task execution time. If tasks are able to work on different copies of shared data, each individual task will undoubtedly perform its function with less overhead. There is no waiting in line or waiting for a semaphore to be released.

However, the operating system (gas station owner) will have more overhead. It will spend a lot of resources having to manage the different copies of data. In addition, relative to a mutex implementation, copying data and enabling concurrent processing of that data will require more memory and processing power.

Return to Table of Contents

Round-Robin vs Function-Queue-Scheduling | Embedded Software Architecture

Table of Contents

In this post, I will discuss the tradeoffs of using the Round Robin, Round Robin with Interrupts, and Function Queue Scheduling approaches when building an embedded system. Let’s consider that we will use an Arduino to perform tasks such as capturing sensor data and downloading to a host machine (e.g. your personal laptop computer).

Round Robin



The Round Robin architecture is the easiest architecture for embedded systems. The main method consists of a loop that runs again and again, checking each of the I/O devices at each turn in order to see if they need service. No fancy interrupts, no fear of shared data…just a plain single execution thread that gets executed again and again.


  • Simplest of all the architectures
  • No interrupts
  • No shared data
  • No latency concerns
  • No tight response requirements


  • A sensor connected to the Arduino that urgently needs service must wait its turn.
  • Fragile. Only as strong as the weakest link. If a sensor breaks or something else breaks, everything breaks.
  • Response time has low stability in the event of changes to the code

Return to Table of Contents

Round Robin with Interrupts


This Round Robin with Interrupts architecture is similar to the Round Robin architecture, except it has interrupts. When an interrupt is triggered, the main program is put on hold and control shifts to the interrupt service routine. Code that is inside the interrupt service routines has a higher priority than the task code.


  • Greater control over the priority levels
  • Flexible
  • Fast response time to I/O signals
  • Great for managing sensors that need to be read at prespecified time intervals


  • Shared data
  • All interrupts could fire off concurrently

Return to Table of Contents

Function Queue Scheduling


In the Function Queue Scheduling architecture, interrupt routines add function pointers to a queue of function pointers. The main program calls the function pointers one at a time based on their priority in the queue.


  • Great control over priority
  • Reduces the worst-case response for the high-priority task code
  • Response time has good stability in the event of changes to the code


  • Shared data
  • Low priority tasks might never execute (a.k.a. starving)

Return to Table of Contents

What is the Shared Data Problem?

Table of Contents

Before we discuss the shared data problem when building embedded systems, it is important to understand what interrupts are.

What are Interrupts?

The most basic embedded software has a main program that runs uninterrupted…that is, it runs until either it stops on its own or something else causes it to stop.

For example, if you unplug your refrigerator, all programs that were running will immediately stop, and the refrigerator will shutdown. Otherwise, while the refrigerator is plugged in, programs will continue to run uninterrupted. This is called embedded software without interrupts.

You also have software where the main program executes normally but stops either periodically or due to some code (that is not part of the main method) that must get executed immediately. The main program stops, some other code is executed…(i.e. code that is not part of the main program). We call this an interrupt service routine. When this interrupt service routine is finished, control is shifted back to the main program, and the main program gets back to doing what is was doing prior to being interrupted.

Here is an image that shows what I just explained:


You likely trigger interrupt service routines all of the time without even knowing. For example, normally your desktop computer runs various background programs when you are not on your computer. Let’s call this the main() program. As soon as you click your mouse or type on your keyboard, you trigger an interrupt service routine. The computer handles this interrupt service routine by exiting the main() program temporarily, reading what you just did and doing what you commanded it to do (i.e. servicing the interrupt).

After that, the computer exits the interrupt service routine, goes back to doing what it was doing before you interrupted it (i.e. control shifts back to the main() program). That is a lot like how interrupts work in embedded systems, and you will find them in many if not most embedded programs in some form or fashion.

Return to Table of Contents

The Shared Data Problem

A big problem in embedded systems occurs in embedded software when an interrupt service routine and the main program share the same data. What happens if the main program is in the middle of doing some important calculations using some piece of data…an interrupt occurs that alters that piece of data…and then the main program finishes its calculation? Oops! The calculation performed by the main program might be corrupted because it is based off the wrong/different data value. This is known as the shared data problem.

Real-World Analogy: Running a Bakery

Imagine you own a bakery. You are trying to calculate how much money you made in 2018. You have just entered the revenue for each month listed in a Google spreadsheet. It looks like this:

Addison’s Bakery 2018 Revenue By Month

  • January: $10,000
  • February: $10,000
  • March: $10,000
  • April: $10,000
  • May: $10,000
  • June: $10,000
  • July: $10,000
  • August: $10,000
  • September: $10,000
  • October: $10,000
  • November: $10,000
  • December: $10,000

You get out your handy calculator.

“calculator” by stockcatalog is licensed under CC BY 2.0 

Starting with January through March, you add the first three months of revenue into your calculator “10000 + 10000 + 10000 +” and then all of a sudden, your assistant (whose job it is to keep revenue updated periodically), interrupts you and asks if he can update something in the spreadsheet. You say, “Sure.”

You get up from your chair and go to the break room.

In the meantime, your assistant (i.e. the “interrupt service routine”) then gets on your computer.

While you are in the break room, your assistant changes the revenue on your spreadsheet in January 2018, increasing it from $10,000 to $15,000. He then leaves the room.

You then return from the break room. You get back in your chair and continue entering in the numbers in your calculator for the other nine months, for April through December. You conclude that the revenue for 2018 was $10000 per month for 12 months (i.e. $120,000). You record that number so that you can use it for your tax filings. Oops! See the mistake?

The main program (i.e. you) was unaware that the interrupt service routine (i.e. your assistant) made a change to the January 2018 revenue data, so the value of $120,000 is not consistent with the updated data. It should be $125,000 not $120,000.

This in a nutshell is the shared data problem. We need to make sure that you, the main() program, are NEVER interrupted while you are in the middle of making important calculations on your calculator. You and your assistant both share responsibility for making sure revenue is accurate, but we need to make sure you both aren’t working on the revenue at the same time.

In the real world, this would take the form of you posting a “DO NOT DISTURB” sign on your door to keep your assistant out when you are making critical calculations. In software engineering, we call this “disabling interrupts.” While interrupts are disabled, nothing can interrupt the main program.

Disabling interrupts is like the main program putting up a big DO NOT DISTURB sign. Source: Wikimedia Commons

Real-World Example: Designing an Automatic Doggy Door


Let’s look at a real-world example to further show you the shared data problem.


Imagine you are a software engineer working at a company. Your team is responsible for designing an automatic dog entry door. This embedded device can be wirelessly updated with RFID tags for dogs or other pets to be allowed entry.

The door needs to automatically unlock for dogs that are in the vicinity of the door. A pet must be allowed to enter even when the table of RFID tags is being updated. The RFID tag IDs are shared data since the interrupt service routine that must update the tag IDs and the main() program that is responsible for automatically unlocking the door when dogs are in the vicinity both share and use this data. A problem will occur when the doggy door is in the middle of an RFID tag ID update when a dog needs to get through the door. We wouldn’t want to let the poor dog wait outside in the freezing cold while the device is in the middle of an RFID tag update!

How do we create a solution that solves the shared data problem? The RFID tags need to be updated regularly but that same data is needed regularly by the main() program to let dogs enter when they need to. Let’s solve this now.

System Requirements

Dogs wearing RFID tags/cards need to be able to enter the door (i.e. gate) when they get close to the doggy door.
  • This embedded device can be wirelessly updated with RFID tags.
  • Dogs or other pets must be allowed entry when they are in the vicinity of the door.
  • Dog must be allowed to enter even when the table of RFID tags is being updated.
  • RFID tag IDs are shared data which must be managed.

In the shared data problem for the doggy door controller, we need to make sure the dog can enter at all times while the RFID tags are being updated. Because this is a dog, it is unacceptable for the door to remain locked and keep a dog waiting.


To solve this problem, I would design the following loop for the main program in pseudocode:

While (True)

  // Begin Critical Section of Code - Can't Be Interrupted
    Scan to see if dogs are in the area (i.e. RFID scan)
      If a valid dog is in the area, unlock the door
      Else, do nothing
  // End Critical Section of Code That Can't Be Interrupted

  Update RFID table (interrupt service routine)
  // In the meantime, dog is walking through the door
  Check if the door is unlocked
    If the door is unlocked, delay 30 seconds to give 
    the dog sufficient time to enter

  Make sure the doggy door is locked
  Go back to the beginning of this loop

The above architecture satisfies the requirements and enables a dog to enter even when the table of RFID tags is in the middle of an update.

Return to Table of Contents