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.