Back to [[docker:main|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 ([[https://bobcares.com/blog/move-docker-container-to-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.