|  | @@ -10,14 +10,18 @@ The Robot Operating System (ROS) is a set of software libraries and tools that h
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  ## Create a `Dockerfile` in your ROS app project
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	FROM ros:indigo
 | 
	
		
			
				|  |  | -	# place here your application's setup specifics
 | 
	
		
			
				|  |  | -	CMD [ "roslaunch", "my-ros-app my-ros-app.launch" ]
 | 
	
		
			
				|  |  | +```dockerfile
 | 
	
		
			
				|  |  | +FROM ros:indigo
 | 
	
		
			
				|  |  | +# place here your application's setup specifics
 | 
	
		
			
				|  |  | +CMD [ "roslaunch", "my-ros-app my-ros-app.launch" ]
 | 
	
		
			
				|  |  | +```
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  You can then build and run the Docker image:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	docker build -t my-ros-app .
 | 
	
		
			
				|  |  | -	docker run -it --rm --name my-running-app my-ros-app
 | 
	
		
			
				|  |  | +```console
 | 
	
		
			
				|  |  | +$ docker build -t my-ros-app .
 | 
	
		
			
				|  |  | +$ docker run -it --rm --name my-running-app my-ros-app
 | 
	
		
			
				|  |  | +```
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  ## Deployment use cases
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -43,7 +47,9 @@ ROS uses the `~/.ros/` directory for storing logs, and debugging info. If you wi
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  For example, if one wishes to use their own `.ros` folder that already resides in their local home directory, with a username of `ubuntu`, we can simple launch the container with an additional volume argument:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	docker run -v "/home/ubuntu/.ros/:/root/.ros/" ros
 | 
	
		
			
				|  |  | +```console
 | 
	
		
			
				|  |  | +$ docker run -v "/home/ubuntu/.ros/:/root/.ros/" ros
 | 
	
		
			
				|  |  | +```
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  ### Devices
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -62,16 +68,20 @@ If we want our all ROS nodes to easily talk to each other, we'll can use a virtu
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  > Build a ROS image that includes ROS tutorials using this `Dockerfile:`
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	FROM ros:indigo-ros-base
 | 
	
		
			
				|  |  | -	# install ros tutorials packages
 | 
	
		
			
				|  |  | -	RUN apt-get update && apt-get install -y
 | 
	
		
			
				|  |  | -	    ros-indigo-ros-tutorials \
 | 
	
		
			
				|  |  | -	    ros-indigo-common-tutorials \
 | 
	
		
			
				|  |  | -	    && rm -rf /var/lib/apt/lists/
 | 
	
		
			
				|  |  | +```dockerfile
 | 
	
		
			
				|  |  | +FROM ros:indigo-ros-base
 | 
	
		
			
				|  |  | +# install ros tutorials packages
 | 
	
		
			
				|  |  | +RUN apt-get update && apt-get install -y
 | 
	
		
			
				|  |  | +    ros-indigo-ros-tutorials \
 | 
	
		
			
				|  |  | +    ros-indigo-common-tutorials \
 | 
	
		
			
				|  |  | +    && rm -rf /var/lib/apt/lists/
 | 
	
		
			
				|  |  | +```
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  > Then to build the image from within the same directory:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	docker build --tag ros:ros-tutorials .
 | 
	
		
			
				|  |  | +```console
 | 
	
		
			
				|  |  | +$ docker build --tag ros:ros-tutorials .
 | 
	
		
			
				|  |  | +```
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #### Create network
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -85,68 +95,84 @@ If we want our all ROS nodes to easily talk to each other, we'll can use a virtu
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  > To create a container for the ROS master and advertise it's service:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	docker run -it --rm\
 | 
	
		
			
				|  |  | -	    --publish-service=master.foo \
 | 
	
		
			
				|  |  | -	    --name master \
 | 
	
		
			
				|  |  | -	    ros:ros-tutorials \
 | 
	
		
			
				|  |  | -	    roscore
 | 
	
		
			
				|  |  | +```console
 | 
	
		
			
				|  |  | +$ docker run -it --rm\
 | 
	
		
			
				|  |  | +    --publish-service=master.foo \
 | 
	
		
			
				|  |  | +    --name master \
 | 
	
		
			
				|  |  | +    ros:ros-tutorials \
 | 
	
		
			
				|  |  | +    roscore
 | 
	
		
			
				|  |  | +```
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  > Now you can see that master is running and is ready manage our other ROS nodes. To add our `talker` node, we'll need to point the relevant environment variable to the master service:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	docker run -it --rm\
 | 
	
		
			
				|  |  | -	    --publish-service=talker.foo \
 | 
	
		
			
				|  |  | -	    --env ROS_HOSTNAME=talker \
 | 
	
		
			
				|  |  | -	    --env ROS_MASTER_URI=http://master:11311 \
 | 
	
		
			
				|  |  | -	    --name talker \
 | 
	
		
			
				|  |  | -	    ros:ros-tutorials \
 | 
	
		
			
				|  |  | -	    rosrun roscpp_tutorials talker
 | 
	
		
			
				|  |  | +```console
 | 
	
		
			
				|  |  | +$ docker run -it --rm\
 | 
	
		
			
				|  |  | +    --publish-service=talker.foo \
 | 
	
		
			
				|  |  | +    --env ROS_HOSTNAME=talker \
 | 
	
		
			
				|  |  | +    --env ROS_MASTER_URI=http://master:11311 \
 | 
	
		
			
				|  |  | +    --name talker \
 | 
	
		
			
				|  |  | +    ros:ros-tutorials \
 | 
	
		
			
				|  |  | +    rosrun roscpp_tutorials talker
 | 
	
		
			
				|  |  | +```
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  > Then in another terminal, run the `listener` node similarly:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	docker run -it --rm\
 | 
	
		
			
				|  |  | -	    --publish-service=listener.foo \
 | 
	
		
			
				|  |  | -	    --env ROS_HOSTNAME=listener \
 | 
	
		
			
				|  |  | -	    --env ROS_MASTER_URI=http://master:11311 \
 | 
	
		
			
				|  |  | -	    --name listener \
 | 
	
		
			
				|  |  | -	    ros:ros-tutorials \
 | 
	
		
			
				|  |  | -	    rosrun roscpp_tutorials listener
 | 
	
		
			
				|  |  | +```console
 | 
	
		
			
				|  |  | +$ docker run -it --rm\
 | 
	
		
			
				|  |  | +    --publish-service=listener.foo \
 | 
	
		
			
				|  |  | +    --env ROS_HOSTNAME=listener \
 | 
	
		
			
				|  |  | +    --env ROS_MASTER_URI=http://master:11311 \
 | 
	
		
			
				|  |  | +    --name listener \
 | 
	
		
			
				|  |  | +    ros:ros-tutorials \
 | 
	
		
			
				|  |  | +    rosrun roscpp_tutorials listener
 | 
	
		
			
				|  |  | +```
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  > Alright! You should see `listener` is now echoing each message the `talker` broadcasting. You can then list the containers and see something like this:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	$ docker service ls
 | 
	
		
			
				|  |  | -	SERVICE ID          NAME                NETWORK             CONTAINER
 | 
	
		
			
				|  |  | -	67ce73355e67        listener            foo                 a62019123321
 | 
	
		
			
				|  |  | -	917ee622d295        master              foo                 f6ab9155fdbe
 | 
	
		
			
				|  |  | -	7f5a4748fb8d        talker              foo                 e0da2ee7570a
 | 
	
		
			
				|  |  | +```console
 | 
	
		
			
				|  |  | +$ docker service ls
 | 
	
		
			
				|  |  | +SERVICE ID          NAME                NETWORK             CONTAINER
 | 
	
		
			
				|  |  | +67ce73355e67        listener            foo                 a62019123321
 | 
	
		
			
				|  |  | +917ee622d295        master              foo                 f6ab9155fdbe
 | 
	
		
			
				|  |  | +7f5a4748fb8d        talker              foo                 e0da2ee7570a
 | 
	
		
			
				|  |  | +```
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  > And for the services:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	$ docker ps
 | 
	
		
			
				|  |  | -	CONTAINER ID        IMAGE               COMMAND                CREATED              STATUS              PORTS               NAMES
 | 
	
		
			
				|  |  | -	a62019123321        ros:ros-tutorials   "/ros_entrypoint.sh    About a minute ago   Up About a minute   11311/tcp           listener
 | 
	
		
			
				|  |  | -	e0da2ee7570a        ros:ros-tutorials   "/ros_entrypoint.sh    About a minute ago   Up About a minute   11311/tcp           talker
 | 
	
		
			
				|  |  | -	f6ab9155fdbe        ros:ros-tutorials   "/ros_entrypoint.sh    About a minute ago   Up About a minute   11311/tcp           master
 | 
	
		
			
				|  |  | +```console
 | 
	
		
			
				|  |  | +$ docker ps
 | 
	
		
			
				|  |  | +CONTAINER ID        IMAGE               COMMAND                CREATED              STATUS              PORTS               NAMES
 | 
	
		
			
				|  |  | +a62019123321        ros:ros-tutorials   "/ros_entrypoint.sh    About a minute ago   Up About a minute   11311/tcp           listener
 | 
	
		
			
				|  |  | +e0da2ee7570a        ros:ros-tutorials   "/ros_entrypoint.sh    About a minute ago   Up About a minute   11311/tcp           talker
 | 
	
		
			
				|  |  | +f6ab9155fdbe        ros:ros-tutorials   "/ros_entrypoint.sh    About a minute ago   Up About a minute   11311/tcp           master
 | 
	
		
			
				|  |  | +```
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #### Introspection
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  > Ok, now that we see the two nodes are communicating, let get inside one of the containers and do some introspection what exactly the topics are:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	docker exec -it master bash
 | 
	
		
			
				|  |  | -	source /ros_entrypoint.sh
 | 
	
		
			
				|  |  | +```console
 | 
	
		
			
				|  |  | +$ docker exec -it master bash
 | 
	
		
			
				|  |  | +$ source /ros_entrypoint.sh
 | 
	
		
			
				|  |  | +```
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  > If we then use `rostopic` to list published message topics, we should see something like this:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	$ rostopic list
 | 
	
		
			
				|  |  | -	/chatter
 | 
	
		
			
				|  |  | -	/rosout
 | 
	
		
			
				|  |  | -	/rosout_agg
 | 
	
		
			
				|  |  | +```console
 | 
	
		
			
				|  |  | +$ rostopic list
 | 
	
		
			
				|  |  | +/chatter
 | 
	
		
			
				|  |  | +/rosout
 | 
	
		
			
				|  |  | +/rosout_agg
 | 
	
		
			
				|  |  | +```
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #### Tear down
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  > To tear down the structure we've made, we just need to stop the containers and the services. We can stop and remove the containers using `Ctrl^C` where we launched the containers or using the stop command with the names we gave them:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	docker stop master talker listener
 | 
	
		
			
				|  |  | -	docker rm master talker listener
 | 
	
		
			
				|  |  | +```console
 | 
	
		
			
				|  |  | +$ docker stop master talker listener
 | 
	
		
			
				|  |  | +$ docker rm master talker listener
 | 
	
		
			
				|  |  | +```
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  # More Resources
 | 
	
		
			
				|  |  |  
 |