Table of Contents

Back to main Docker page

Controlling Niryo Robotic Arm with ROS

Create a ROS Melodic container

Creates a Dockerfile called Dockerfile-ros-melodic :

#
# this dockerfile roughly follows the 'Ubuntu install of ROS Melodic' from:
#  http://wiki.ros.org/melodic/Installation/Ubuntu
# and Niryo ROS installation :
#  https://docs.niryo.com/dev/ros/v3.2.0/en/source/simulation.html 
#
# start from base image Ubuntu 18.04
ARG BASE_IMAGE=ubuntu:18.04
FROM ${BASE_IMAGE}
 
# label this new image 
LABEL maintainer="benblop@gmail.com"
LABEL version="0.1"
LABEL description="basic ROS melodic Docker image for teaching" 
 
ENV ROS_DISTRO=melodic
ENV ROS_ROOT=/opt/ros/${ROS_DISTRO}
 
# disable prompt during package installation
ENV DEBIAN_FRONTEND=noninteractive
 
# 
# add the ROS deb repo to the apt sources list
#
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
          git \
		cmake \
		build-essential \
		curl \
		wget \
		gnupg2 \
		lsb-release \
		ca-certificates \
    && rm -rf /var/lib/apt/lists/*
 
RUN sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
RUN curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | apt-key add -
 
 
# 
# install ROS packages
#
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
          ros-${ROS_DISTRO}-desktop-full \
          python-rosdep \
    && rm -rf /var/lib/apt/lists/*
 
#
# init/update rosdep
#
RUN apt-get update && \
    cd ${ROS_ROOT} && \
    rosdep init && \
    rosdep update && \
    rm -rf /var/lib/apt/lists/*
 
#
# always initialize ROS by default
RUN echo "# init ROS" >> /etc/bash.bashrc
RUN echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> /etc/bash.bashrc
 
# define a user
ENV newuser=rosuser
RUN useradd -ms /bin/bash ${newuser}
USER ${newuser}
WORKDIR /home/${newuser}

Create the image :

docker build -f Dockerfile-ros-melodic -t ros-melodic .

run the image interactively, try running roscore at prompt, then stop roscore with CTRL-C and leave the container with CTRL-D :

docker run -it ros-melodic:latest /bin/bash
roscore
CTRL-C
CTRL-D

In this container, a standard user (called rosuser) has been created. To run the conatiner as root user, add -u root in the command line :

docker run -u root -it ros-melodic:latest /bin/bash

To get the image name (ros-melodic:latest) , just type :

docker images

Save the container so it can be moved and restored on another host (from this link)

docker export container-name | gzip > container-name.gz
zcat container-name.gz | docker import - container-name

Test the ROS Melodic container

Open a terminal, start the container and execute roscore

docker run --rm --name ROS-Melodic-Test -it ros-melodic:latest /bin/bash
roscore

In a second terminal, verify that ROS is running, first we need to get the ID (and the name) of the container. Here the name is ROS-Melodic-Test and the ID is c012f4611c54. Then using the ID (or the name) of the container we can get its IP address by processing the docker inspect command output :

docker container  ls
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ROS-Melodic-Test

Here the IP address is 172.14.0.1. We can now setup the host so it can use ROS running in the ROS-Melodic-Test container :

export ROS_MASTER_URI=http://172.14.0.1:11311
rostopic list

Automatically starts roscore

This container aims at starting roscore without starting an interactive session and typing roscore. The dockerfile starts from the previous image and looks like this :

# start from base image ros-melodic:latest
ARG BASE_IMAGE=ros-melodic:latest
FROM ${BASE_IMAGE}
SHELL ["/bin/bash", "-c"]
COPY ./ros_init.bash .
ENTRYPOINT ["/bin/bash","/home/rosuser/ros_init.bash"]
CMD /opt/ros/melodic/bin/roscore

The command (CMD) is roscore and the entry point (ENTRYPOINT) is used to to initialize ROS with the following script (ros_init.bash) :

#!/bin/bash
set -e
 
#setup ros environment
source "/opt/ros/$ROS_DISTRO/setup.bash"
 
#setup workspace if it exists 
if [ -n "$WORKSPACE_NAME" ]; then
    if [ ! -e "/root/$WORKSPACE_NAME/devel/setup.sh" ]; then
        previousDirectory=$(pwd)
        cd /root/$WORKSPACE_NAME
        catkin_make
        cd $previousDirectory
    fi
    source "/root/$WORKSPACE_NAME/devel/setup.sh"
fi
 
exec "$@"

ROS container tests

In a first terminal, roscore is started

docker run --rm --name "ROS-Melodic-roscore"  ros-melodic-roscore:latest

In a second terminal we get the IP address of the container (here 170.14.0.1) and we try to get the default topics from roscore :

docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ROS-Melodic-roscore
export ROS_MASTER_URI=http://172.14.0.1:11311
rostopic list

We should see the default /rosout and /rosout_agg topics. Now we will wait for a /counter topic to be published :

rostopic echo /counter

The publication of this /counter topic we be done in a container. We start an interactive session on ROS-Melodic-Test container. In a third terminal, using docker inspect, we can get the IP address of this container (here 170.14.0.2) so we can connect both containers on the same **roscore*.

docker run --rm --name "ROS-Melodic-Test"  -it ros-melodic:latest /bin/bash
export ROS_MASTER_URI=http://172.14.0.1:11311
export ROS_IP=172.14.0.2
rostopic pub -r 1  /counter std_msgs/Int32 "data: 8"

In the last line we are sending an integer value (8) in the topic /counter every second. Going back in second terminal, the value 8 should be echoed every second. Other terminals can be connected to the ROS-Melodic-Test container. For example, a new session can be started in a fourth terminal as follows :

docker exec -it  ROS-Melodic-Test /bin/bash
export ROS_MASTER_URI=http://172.14.0.1:11311
export ROS_IP=172.14.0.2
rostopic pub -r 4  /counter std_msgs/Int32 "data: 1"

In the last line we are sending an integer value (1) in the topic /counter at 4 Hz (every 250 ms). Going back in second terminal, the values 1 and 8 should be echoed with corresponding rates , 1Hz and 4Hz.