├── .gitignore ├── .vscode ├── data │ └── Machine │ │ └── settings.json ├── c_cpp_properties.json ├── settings.json └── tasks.json ├── .devcontainer ├── compile_flags.txt ├── templates │ ├── model.urdf.xacro │ ├── launchfile.launch │ └── rosnode.cpp ├── build.sh ├── jupyter.conf ├── code-server.conf ├── devcontainer.json ├── supervisord.conf ├── entrypoint.sh └── sim.py ├── select-simulator.bat ├── select-simulator.sh ├── hooks ├── build └── post_push ├── start-mutagen.sh ├── .env.sample ├── LICENSE ├── docker-compose.yml ├── .github └── workflows │ └── docker-image.yml ├── README.md └── Dockerfile /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .vscode/ipch 3 | *~ 4 | -------------------------------------------------------------------------------- /.vscode/data/Machine/settings.json: -------------------------------------------------------------------------------- 1 | ../../settings.json -------------------------------------------------------------------------------- /.devcontainer/compile_flags.txt: -------------------------------------------------------------------------------- 1 | -c 2 | -I/opt/ros/$ROS_DISTRO/include 3 | -std=c++11 4 | -fno-exceptions -------------------------------------------------------------------------------- /select-simulator.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | docker run -ti --rm -v %cd%:/work devrt/simulator-index 3 | pause -------------------------------------------------------------------------------- /select-simulator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | docker pull devrt/simulator-index 3 | docker run -ti --rm -v $(pwd):/work devrt/simulator-index 4 | -------------------------------------------------------------------------------- /.devcontainer/templates/model.urdf.xacro: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /hooks/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | BASE_TAG=${DOCKER_TAG%"-desktop"} 3 | docker build --build-arg BASE_IMAGE=ros:${BASE_TAG} -f Dockerfile -t $IMAGE_NAME . 4 | -------------------------------------------------------------------------------- /start-mutagen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mutagen create \ 4 | --symlink-mode ignore \ 5 | src docker://$(docker-compose ps -q workspace)/workspace/src 6 | -------------------------------------------------------------------------------- /hooks/post_push: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$DOCKER_TAG" == "melodic-desktop" ]; then 4 | docker tag $IMAGE_NAME $DOCKER_REPO:latest 5 | docker push $DOCKER_REPO:latest 6 | fi 7 | -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | HTTP_PROXY="http://example.com:8080/" 2 | HTTPS_PROXY="http://example.com:8080/" 3 | _JAVA_OPTIONS="-Dhttp.proxyHost=example.com -Dhttp.proxyPort=8080 -Dhttps.proxyHost=example.com -Dhttps.proxyPort=8080" -------------------------------------------------------------------------------- /.devcontainer/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | for dist in melodic noetic 4 | do 5 | docker pull ros:$dist 6 | docker build --build-arg BASE_IMAGE=ros:$dist -f Dockerfile -t devrt/ros-devcontainer-vscode:$dist-desktop . 7 | done -------------------------------------------------------------------------------- /.devcontainer/templates/launchfile.launch: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /.devcontainer/jupyter.conf: -------------------------------------------------------------------------------- 1 | [program:jupyter] 2 | command=/entrypoint.sh jupyter notebook --ip=0.0.0.0 --no-browser --NotebookApp.notebook_dir='/workspace' --NotebookApp.token='' --NotebookApp.password='' 3 | user=developer 4 | directory=/workspace 5 | environment=ROS_DISTRO=%(ENV_ROS_DISTRO)s 6 | autostart=true 7 | autorestart=true 8 | stdout_logfile=/dev/stdout 9 | stdout_logfile_maxbytes=0 10 | stderr_logfile=/dev/stderr 11 | stderr_logfile_maxbytes=0 12 | -------------------------------------------------------------------------------- /.devcontainer/code-server.conf: -------------------------------------------------------------------------------- 1 | [program:code-server] 2 | command=code serve-web --host 0.0.0.0 --port 3000 --without-connection-token --accept-server-license-terms 3 | autostart=true 4 | autorestart=true 5 | autostart=true 6 | autorestart=true 7 | stdout_logfile=/dev/stdout 8 | stdout_logfile_maxbytes=0 9 | stderr_logfile=/dev/stderr 10 | stderr_logfile_maxbytes=0 11 | user=developer 12 | directory=/home/developer 13 | environment=HOME=/home/developer,ROS_DISTRO=%(ENV_ROS_DISTRO)s,DONT_PROMPT_WSL_INSTALL=1 -------------------------------------------------------------------------------- /.devcontainer/templates/rosnode.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char **argv) 5 | { 6 | ros::init(argc, argv, "node_name"); 7 | ros::NodeHandle n; 8 | std_msgs::String msg; 9 | ros::Publisher pub = n.advertise("topic_name", 1000); 10 | ros::Rate rate(10); 11 | 12 | while (ros::ok()) 13 | { 14 | msg.data = ""; 15 | pub.publish(msg); 16 | 17 | ros::spinOnce(); 18 | rate.sleep(); 19 | } 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ROS devcontainer for vscode", 3 | "dockerComposeFile": [ 4 | "../docker-compose.yml" 5 | ], 6 | "service": "workspace", 7 | "workspaceFolder": "/workspace", 8 | "shutdownAction": "stopCompose", 9 | "customizations": { 10 | "vscode": { 11 | "extensions": [ 12 | "ms-vscode.cpptools", 13 | "ms-python.python", 14 | "ajshort.msg", 15 | "twxs.cmake", 16 | "redhat.vscode-xml", 17 | "actboy168.tasks", 18 | "brpaz.file-templates" 19 | ] 20 | } 21 | }, 22 | //"appPort": [80], 23 | } -------------------------------------------------------------------------------- /.devcontainer/supervisord.conf: -------------------------------------------------------------------------------- 1 | [unix_http_server] 2 | file=/var/run/supervisor.sock 3 | chmod=0700 4 | 5 | [inet_http_server] 6 | port = :9001 7 | 8 | [supervisord] 9 | nodaemon=true 10 | 11 | [rpcinterface:supervisor] 12 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 13 | 14 | [rpcinterface:twiddler] 15 | supervisor.rpcinterface_factory = supervisor_twiddler.rpcinterface:make_twiddler_rpcinterface 16 | 17 | [supervisorctl] 18 | serverurl=unix:///var/run/supervisor.sock 19 | 20 | [include] 21 | files = /etc/supervisor/conf.d/*.conf 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Software License Agreement (Apache License) 2 | 3 | Copyright 2020 MID Academic Promotions, Inc. 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [{ 3 | "name": "Linux", 4 | "includePath": [ 5 | "${workspaceFolder}/**", 6 | "/opt/ros/${env:ROS_DISTRO}/include/**", 7 | "/usr/include/**" 8 | ], 9 | "browse": { 10 | "path": [ 11 | "${workspaceFolder}", 12 | "/opt/ros/${env:ROS_DISTRO}/include", 13 | "/usr/include" 14 | ] 15 | }, 16 | "defines": [], 17 | "compilerPath": "/usr/bin/g++", 18 | "cStandard": "c11", 19 | "cppStandard": "c++17", 20 | "intelliSenseMode": "gcc-x64" 21 | }], 22 | "version": 4 23 | } -------------------------------------------------------------------------------- /.devcontainer/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | USER_ID=$(id -u) 4 | GROUP_ID=$(id -g) 5 | 6 | sudo usermod -u $USER_ID -o -m -d /home/developer developer > /dev/null 2>&1 7 | sudo groupmod -g $GROUP_ID developer > /dev/null 2>&1 8 | sudo chown -R developer:developer /workspace 9 | 10 | ln -sfn /home/developer/.vscode /workspace/.vscode 11 | 12 | rm -f /workspace/compile_flags.txt || true 13 | sed -e 's@\$ROS_DISTRO@'"$ROS_DISTRO"'@' /home/developer/compile_flags.txt > /workspace/compile_flags.txt 14 | 15 | ln -sfn /workspace /home/developer/workspace 16 | 17 | source /opt/ros/$ROS_DISTRO/setup.bash 18 | 19 | mkdir -p /workspace/src && cd /workspace/src && catkin_init_workspace || true 20 | 21 | cd /home/developer 22 | 23 | exec $@ 24 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.3' 2 | services: 3 | xserver: 4 | image: devrt/xserver 5 | ipc: host 6 | security_opt: 7 | - seccomp:unconfined 8 | ports: 9 | - "3000:80" 10 | healthcheck: 11 | test: ["CMD-SHELL", "test -e /tmp/.X11-unix/X0"] 12 | interval: "1s" 13 | retries: 20 14 | simulator: 15 | image: devrt/simulator-empty 16 | ipc: host 17 | security_opt: 18 | - seccomp:unconfined 19 | environment: 20 | - DISPLAY=:0 21 | volumes_from: 22 | - xserver 23 | depends_on: 24 | - xserver 25 | workspace: 26 | # env_file: 27 | # - .env 28 | image: devrt/ros-devcontainer-vscode:noetic-desktop 29 | ipc: host 30 | security_opt: 31 | - seccomp:unconfined 32 | ports: 33 | - "3001:3000" 34 | - "3002:8888" 35 | volumes: 36 | - workspace:/workspace 37 | environment: 38 | - DISPLAY=:0 39 | - ROS_MASTER_URI=http://simulator:11311/ 40 | volumes_from: 41 | - xserver 42 | - simulator 43 | depends_on: 44 | - xserver 45 | volumes: 46 | workspace: 47 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | name: build and publish 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | version: [noetic] 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | - name: Set up QEMU 20 | uses: docker/setup-qemu-action@v3 21 | - name: Set up Docker Buildx 22 | uses: docker/setup-buildx-action@v3 23 | - name: Login to Docker Hub 24 | uses: docker/login-action@v3 25 | with: 26 | username: ${{ secrets.DOCKERHUB_USERNAME }} 27 | password: ${{ secrets.DOCKERHUB_TOKEN }} 28 | - name: Build and push 29 | uses: docker/build-push-action@v5 30 | with: 31 | platforms: linux/arm64/v8,linux/amd64 32 | build-args: | 33 | BASE_IMAGE=ros:${{ matrix.version }} 34 | push: true 35 | tags: devrt/ros-devcontainer-vscode:${{ matrix.version }}-desktop 36 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorTheme": "Monokai", 3 | "fileTemplates.templates_dir": "/home/developer/templates", 4 | "files.associations": { 5 | "*.launch": "xml", 6 | "*.launch.xml": "xml", 7 | "*.test": "xml", 8 | "*.urdf.xacro": "xml", 9 | "*.urdf": "xml", 10 | "model.config": "xml", 11 | "*.sdf": "xml", 12 | "*.world": "xml" 13 | }, 14 | "xml.fileAssociations": [ 15 | { 16 | "systemId": "/opt/xsd/package.xml/package_format2.xsd", 17 | "pattern": "package.xml" 18 | }, 19 | { 20 | "systemId": "/opt/xsd/roslaunch/roslaunch.xsd", 21 | "pattern": "**/*.launch" 22 | }, 23 | { 24 | "systemId": "/opt/xsd/roslaunch/roslaunch.xsd", 25 | "pattern": "**/*.test" 26 | }, 27 | { 28 | "systemId": "/opt/xsd/ros2launch/launch.0.1.1.xsd", 29 | "pattern": "**/*.launch.xml" 30 | }, 31 | { 32 | "systemId": "/opt/xsd/urdf/urdf.xsd", 33 | "pattern": "**/*.urdf.xacro" 34 | }, 35 | { 36 | "systemId": "/opt/xsd/urdf/urdf.xsd", 37 | "pattern": "**/*.urdf" 38 | }, 39 | { 40 | "systemId": "/opt/xsd/sdf/root.xsd", 41 | "pattern": "**/*.sdf" 42 | }, 43 | { 44 | "systemId": "/opt/xsd/sdf/root.xsd", 45 | "pattern": "**/*.world" 46 | } 47 | ], 48 | "C_Cpp.intelliSenseCacheSize": 0, 49 | "C_Cpp.intelliSenseEngine": "Tag Parser", 50 | "python.analysis.extraPaths": [ 51 | "/opt/ros/noetic/lib/python3/dist-packages" 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /.devcontainer/sim.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Utility script to control process on the simulator container 4 | # written by Yosuke Matsusaka 5 | # distributed under apache2 license 6 | 7 | import argparse 8 | import argcomplete 9 | import xmlrpclib 10 | import pprint 11 | 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument('command', choices=['launch', 'reset', 'status'], help='run roslaunch or reset the simulator container') 14 | parser.add_argument('args', nargs='*', help='command arguments') 15 | parser.add_argument('-n', '--name', default='simulator', help='specify name of the process (default: simulator)') 16 | parser.add_argument('-e', '--env', default='', help='specify environment variables') 17 | 18 | argcomplete.autocomplete(parser) 19 | 20 | args = parser.parse_args() 21 | 22 | s = xmlrpclib.ServerProxy('http://simulator:9001') 23 | 24 | if args.command == 'launch': 25 | try: 26 | s.supervisor.stopProcess('simulator:{0}'.format(args.name)) 27 | except xmlrpclib.Fault: 28 | pass 29 | try: 30 | s.twiddler.removeProcessFromGroup('simulator', args.name) 31 | except xmlrpclib.Fault: 32 | pass 33 | command = ['/ros_entrypoint.sh roslaunch'] 34 | command.extend(args.args) 35 | s.twiddler.addProgramToGroup('simulator', args.name, 36 | { 37 | 'command': ' '.join(command), 38 | 'environment': args.env, 39 | 'autostart': 'true', 40 | 'autorestart': 'true', 41 | 'stopwaitsecs': '30', 42 | 'stdout_logfile': '/dev/stdout', 43 | 'stdout_logfile_maxbytes': '0', 44 | 'stderr_logfile': '/dev/stderr', 45 | 'stderr_logfile_maxbytes': '0' 46 | }) 47 | elif args.command == 'reset': 48 | s.supervisor.stopProcess('simulator:{0}'.format(args.name)) 49 | s.supervisor.startProcess('simulator:{0}'.format(args.name)) 50 | elif args.command == 'status': 51 | pprint.pprint(s.supervisor.getAllProcessInfo()) 52 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "catkin_make", 8 | "type": "shell", 9 | "command": "bash -i -c catkin_make", 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | }, 14 | "problemMatcher": { 15 | "fileLocation": "absolute", 16 | "pattern": { 17 | "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 18 | "file": 1, 19 | "line": 2, 20 | "column": 3, 21 | "severity": 4, 22 | "message": 5 23 | } 24 | } 25 | }, 26 | { 27 | "label": "catkin_create_pkg", 28 | "type": "shell", 29 | "command": "bash -i -c 'cd src && catkin_create_pkg ${input:packageName} ${input:dependingPackages}'" 30 | }, 31 | { 32 | "label": "xserver", 33 | "type": "shell", 34 | "command": "echo", 35 | "args": [ 36 | "Please open http://localhost:3000/ using your favorite browser.\n(If you are using Docker Toolbox, open http://192.168.99.100:3000/ instead)" 37 | ] 38 | }, 39 | { 40 | "label": "roscore", 41 | "type": "shell", 42 | "command": "bash -i -c roscore", 43 | "presentation": { 44 | "reveal": "always", 45 | "panel": "new" 46 | } 47 | }, 48 | { 49 | "label": "rviz", 50 | "type": "shell", 51 | "command": "bash -i -c 'rosrun rviz rviz'", 52 | "presentation": { 53 | "reveal": "always", 54 | "panel": "new" 55 | } 56 | } 57 | ], 58 | "inputs": [ 59 | { 60 | "id": "packageName", 61 | "type": "promptString", 62 | "description": "Please enter the name of new package" 63 | }, 64 | { 65 | "id": "dependingPackages", 66 | "type": "promptString", 67 | "description": "Please enter name of depending packages", 68 | "default": "roscpp std_msgs" 69 | } 70 | ] 71 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ROS dev container for VSCode 2 | ---------------------------- 3 | Packed with: 4 | - Preconfigured docker image for ROS development. 5 | - Browser accessible X11 server to display gazebo, rviz, rqt (runs on Windows/Mac). 6 | - Tasks definition to run catkin_make, roscore, rviz commands. 7 | - Preconfigured code completion for C++, Python, XML (package.xml, launchfiles, URDF, SDF). 8 | - Preconfigured simulation environments (Flatland, TurtleBot3, ARIAC, Virtual RobotX, UUV). 9 | - Bonus: WebIDE (code-server) with preconfigured C++, Python, XML completion. 10 | 11 | VSCode and devcontainer running on Mac: 12 | ![screenshot](https://user-images.githubusercontent.com/18067/58605055-8dc84980-82d1-11e9-8ee5-dc969fcb2ae1.png) 13 | 14 | WebIDE opened from the local browser while devcontainer is running on the remote server: 15 | ![screenshot-theia](https://user-images.githubusercontent.com/18067/59972289-58a8d180-95c7-11e9-86fd-7d271684e8b3.PNG) 16 | 17 | How to select simulation environment 18 | ------------------------------------- 19 | You can run preconfigured simulation environment as a docker sidecar container. 20 | 21 | Enter following command to select the simulator: 22 | ```shell 23 | $ ./select-simulator.sh 24 | ``` 25 | 26 | Preconfigured simulation environment currently includes: Flatland, TurtleBot3, ARIAC, Virtual RobotX, UUV. 27 | 28 | See the following index for list of current simulators: 29 | 30 | https://github.com/devrt/simulator-index/blob/master/index.yaml 31 | 32 | If you want any other simulator, let us know by submitting the issue: 33 | 34 | https://github.com/devrt/simulator-index/issues 35 | 36 | How to use the WebIDE (recommended) 37 | ------------------------------------- 38 | As of writing, docker-compose support of VSCode is not so stable on all the platforms. 39 | We recommend using code-server WebIDE since it has complete VSCode function support. 40 | 41 | 1. Clone this repository: 42 | ```shell 43 | $ git clone https://github.com/devrt/ros-devcontainer-vscode.git 44 | ``` 45 | 46 | 2. Enter the following command under the folder of the cloned project: 47 | ```shell 48 | $ cd ros-devcontainer-vscode 49 | $ docker-compose up 50 | ``` 51 | 52 | 3. Open http://localhost:3001/ using your favorite browser. 53 | 54 | You can also use remote server to host the devcontainer (run `docker-compose up` on the remote server and open `http://[remote-server]:3001`). 55 | 56 | How to use this dev container with VSCode 57 | ----------------------------------------- 58 | First, you have to install VSCode and Docker for Windows/Mac: 59 | - https://code.visualstudio.com/ 60 | - https://docs.docker.com/docker-for-mac/ 61 | - https://docs.docker.com/docker-for-windows/ 62 | 63 | After you installed required softwares: 64 | 65 | 1. Install ["Remote Development" extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) on your VSCode. 66 | 2. Clone this repository by using git command. 67 | 3. Click on the quick actions status bar item (green icon) in the lower left corner of the VSCode. 68 | 4. Select "Remote-Containers: Open Folder in Container..." from the command list that appears, and open the root folder of the project you just cloned. 69 | 5. You need to wait a while for container to come up (only required once). 70 | 71 | For detailed instructions, see: 72 | https://code.visualstudio.com/docs/remote/containers 73 | 74 | If you are behind the proxy 75 | ----------------------------- 76 | 77 | Please apply following two settings, if you are using your PC behind the proxy. 78 | 79 | 1. Proxy setting for the Docker server. 80 | 81 | Click Docker Desktop task bar icon > Select `preference` menu item. You will see the following options: 82 | 83 | ![docker-proxy-settings](https://user-images.githubusercontent.com/18067/59744551-c4302d80-92ad-11e9-9b20-cc873a53a8bb.png) 84 | 85 | In most cases, `System proxy` option will work. But if you have problem downloading the docker images, please try `Manual proxy configuration` option. 86 | 87 | 2. Proxy setting for the devcontainer. 88 | 89 | This setting will enable you to use the `apt-get` or the other network commands inside the devcontainer. 90 | 91 | First, open `.env.sample` file under the root folder of the cloned project. 92 | Edit the settings according to your environment. 93 | Save the file as name `.env`. 94 | 95 | Next, open `docker-compose.yml` file under the root folder of the cloned project and uncomment the following lines: 96 | ```yaml 97 | workspace: 98 | env_file: 99 | - .env 100 | ``` 101 | 102 | How to reset or update the devcontainer 103 | --------------------------------------- 104 | 105 | If you want to reset the devcontainer. Please close vscode and enter the following command under the folder of the cloned project: 106 | ```shell 107 | $ docker-compose down 108 | ``` 109 | 110 | If you want to update the environment to the most recent version. Please enter the following commands under the folder of the cloned project: 111 | ```shell 112 | $ git pull origin master 113 | $ docker-compose pull 114 | ``` 115 | 116 | Please be noticed that the `docker-compose down` command will reset your environment including installed `.deb` packages. However, if you write `package.xml` files correctly, you can reinstall all the depending packages by entering the following two commands: 117 | ```shell 118 | $ rosdep update 119 | $ rosdep install --from-paths src --ignore-src -r -y 120 | ``` 121 | 122 | How to open X11 server screen 123 | ----------------------------- 124 | 125 | 1. Wait for the container to start. 126 | 2. Open http://localhost:3000/ using your favorite browser. 127 | 128 | If you are using Docker Toolbox, open the following URL instead: 129 | 130 | http://192.168.99.100:3000/ 131 | 132 | If you want browser screen to be integrated with VS Code, use [Browser Preview for VS Code extension](https://marketplace.visualstudio.com/items?itemName=auchenberg.vscode-browser-preview). 133 | 134 | Created by 135 | ---------- 136 | Yosuke Matsusaka (MID Academic Promotions, Inc.) 137 | 138 | License 139 | ------- 140 | Code in this repository (Dockerfile, utility scripts, etc) is distributed under Apache 2.0 license. 141 | 142 | Included components are distributed under each different licenses: 143 | - Jupyter notebook: BSD -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMAGE=ros:noetic 2 | 3 | FROM maven:3.8 AS xsdcache 4 | 5 | # install schema-fetcher 6 | RUN apt update && \ 7 | apt install -y git && \ 8 | git clone --depth=1 https://github.com/mfalaize/schema-fetcher.git && \ 9 | cd schema-fetcher && \ 10 | sed -i 's|>1.7<|>1.8<|g' pom.xml && \ 11 | mvn install 12 | 13 | # fetch XSD file for package.xml 14 | RUN mkdir -p /opt/xsd/package.xml && \ 15 | java -jar schema-fetcher/target/schema-fetcher-1.0.0-SNAPSHOT.jar /opt/xsd/package.xml http://download.ros.org/schema/package_format2.xsd 16 | 17 | # fetch XSD file for roslaunch 18 | RUN mkdir -p /opt/xsd/roslaunch && \ 19 | java -jar schema-fetcher/target/schema-fetcher-1.0.0-SNAPSHOT.jar /opt/xsd/roslaunch https://gist.githubusercontent.com/nalt/dfa2abc9d2e3ae4feb82ca5608090387/raw/roslaunch.xsd 20 | 21 | # fetch XSD file for ros2launch 22 | RUN mkdir -p /opt/xsd/ros2launch && \ 23 | java -jar schema-fetcher/target/schema-fetcher-1.0.0-SNAPSHOT.jar /opt/xsd/ros2launch https://raw.githubusercontent.com/ros2/design/gh-pages/articles/specs/launch.0.1.1.xsd 24 | 25 | # fetch XSD files for SDF 26 | RUN mkdir -p /opt/xsd/sdf && \ 27 | java -jar schema-fetcher/target/schema-fetcher-1.0.0-SNAPSHOT.jar /opt/xsd/sdf http://sdformat.org/schemas/root.xsd && \ 28 | sed -i 's|http://sdformat.org/schemas/||g' /opt/xsd/sdf/* 29 | 30 | # fetch XSD file for URDF 31 | RUN mkdir -p /opt/xsd/urdf && \ 32 | java -jar schema-fetcher/target/schema-fetcher-1.0.0-SNAPSHOT.jar /opt/xsd/urdf https://raw.githubusercontent.com/devrt/urdfdom/xsd-with-xacro/xsd/urdf.xsd 33 | 34 | FROM $BASE_IMAGE 35 | 36 | MAINTAINER Yosuke Matsusaka 37 | 38 | SHELL ["/bin/bash", "-c"] 39 | 40 | ENV DEBIAN_FRONTEND noninteractive 41 | 42 | # workaround to enable bash completion for apt-get 43 | # see: https://github.com/tianon/docker-brew-ubuntu-core/issues/75 44 | RUN rm /etc/apt/apt.conf.d/docker-clean 45 | 46 | # use closest mirror for apt updates 47 | RUN sed -i -e 's/http:\/\/archive/mirror:\/\/mirrors/' -e 's/http:\/\/security/mirror:\/\/mirrors/' -e 's/\/ubuntu\//\/mirrors.txt/' /etc/apt/sources.list 48 | 49 | RUN apt-get update || true && \ 50 | apt-get install -y curl apt-transport-https ca-certificates && \ 51 | apt-get clean 52 | 53 | # need to renew the key for some reason 54 | RUN curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | apt-key add - 55 | 56 | # OSRF distribution is better for gazebo 57 | RUN sh -c 'echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main" > /etc/apt/sources.list.d/gazebo-stable.list' && \ 58 | curl -L http://packages.osrfoundation.org/gazebo.key | apt-key add - 59 | 60 | # nice to have nodejs for web goodies 61 | RUN sh -c 'echo "deb https://deb.nodesource.com/node_14.x `lsb_release -cs` main" > /etc/apt/sources.list.d/nodesource.list' && \ 62 | curl -sSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - 63 | 64 | # vscode 65 | RUN curl -sSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg && \ 66 | install -D -o root -g root -m 644 packages.microsoft.gpg /etc/apt/keyrings/packages.microsoft.gpg && \ 67 | sh -c 'echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list' && \ 68 | rm -f packages.microsoft.gpg 69 | 70 | # install depending packages 71 | RUN apt-get update && apt-get upgrade -y && \ 72 | apt-get install -y bash-completion less wget language-pack-en code vim-tiny iputils-ping net-tools openssh-client git openjdk-8-jdk-headless nodejs sudo imagemagick byzanz python-dev libsecret-1-dev && \ 73 | npm install -g yarn && \ 74 | apt-get clean 75 | 76 | # basic python packages 77 | RUN if [ $(lsb_release -cs) = "focal" ]; then \ 78 | apt-get update; \ 79 | apt-get install -y python-is-python3 python3-catkin-tools python3-colcon-common-extensions; \ 80 | apt-get clean; \ 81 | curl -kL https://bootstrap.pypa.io/get-pip.py | python; \ 82 | else \ 83 | curl -kL https://bootstrap.pypa.io/pip/2.7/get-pip.py | python; \ 84 | fi && \ 85 | pip install --upgrade --ignore-installed --no-cache-dir pyassimp pylint==1.9.4 autopep8 python-language-server[all] notebook~=5.7 Pygments matplotlib ipywidgets jupyter_contrib_nbextensions nbimporter supervisor supervisor_twiddler argcomplete 86 | 87 | # jupyter extensions 88 | RUN jupyter nbextension enable --py widgetsnbextension && \ 89 | jupyter contrib nbextension install --system 90 | 91 | # add non-root user 92 | RUN useradd -m developer && \ 93 | echo developer ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/developer && \ 94 | chmod 0440 /etc/sudoers.d/developer 95 | 96 | # install depending packages (install moveit! algorithms on the workspace side, since moveit-commander loads it from the workspace) 97 | RUN apt-get update && apt-get upgrade -y && \ 98 | apt-get install -y ros-$ROS_DISTRO-desktop ros-$ROS_DISTRO-gazebo-msgs ros-$ROS_DISTRO-moveit ros-$ROS_DISTRO-moveit-commander ros-$ROS_DISTRO-moveit-ros-visualization ros-$ROS_DISTRO-trac-ik ros-$ROS_DISTRO-move-base-msgs ros-$ROS_DISTRO-ros-numpy && \ 99 | apt-get clean 100 | 101 | # temporal hack to fix ros_numpy problem 102 | RUN if [ $(lsb_release -cs) = "focal" ]; then \ 103 | curl -sSL https://raw.githubusercontent.com/eric-wieser/ros_numpy/master/src/ros_numpy/point_cloud2.py > /opt/ros/$ROS_DISTRO/lib/python3/dist-packages/ros_numpy/point_cloud2.py; \ 104 | fi 105 | 106 | # install bio_ik 107 | RUN source /opt/ros/$ROS_DISTRO/setup.bash && \ 108 | mkdir -p /bio_ik_ws/src && \ 109 | cd /bio_ik_ws/src && \ 110 | catkin_init_workspace && \ 111 | git clone --depth=1 https://github.com/TAMS-Group/bio_ik.git && \ 112 | cd .. && \ 113 | catkin_make install -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/opt/ros/$ROS_DISTRO -DCATKIN_ENABLE_TESTING=0 && \ 114 | cd / && rm -r /bio_ik_ws 115 | 116 | # configure services 117 | RUN mkdir -p /etc/supervisor/conf.d 118 | COPY .devcontainer/supervisord.conf /etc/supervisor/supervisord.conf 119 | COPY .devcontainer/code-server.conf /etc/supervisor/conf.d/code-server.conf 120 | COPY .devcontainer/jupyter.conf /etc/supervisor/conf.d/jupyter.conf 121 | 122 | COPY .devcontainer/entrypoint.sh /entrypoint.sh 123 | 124 | COPY .devcontainer/sim.py /usr/bin/sim 125 | 126 | COPY --from=xsdcache /opt/xsd /opt/xsd 127 | 128 | USER developer 129 | WORKDIR /home/developer 130 | 131 | ENV HOME /home/developer 132 | ENV SHELL /bin/bash 133 | 134 | # jre is required to use XML editor extension 135 | ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 136 | 137 | # enable bash completion 138 | RUN git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it && \ 139 | ~/.bash_it/install.sh --silent && \ 140 | rm ~/.bashrc.bak && \ 141 | echo "source /usr/share/bash-completion/bash_completion" >> ~/.bashrc && \ 142 | bash -i -c "bash-it enable completion git" 143 | 144 | RUN echo 'eval "$(register-python-argcomplete sim)"' >> ~/.bashrc 145 | 146 | RUN git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf && \ 147 | ~/.fzf/install --all 148 | 149 | #RUN git clone --depth 1 https://github.com/b4b4r07/enhancd.git ~/.enhancd && \ 150 | # echo "source ~/.enhancd/init.sh" >> ~/.bashrc 151 | 152 | # colorize less 153 | RUN lesspipe >> ~/.bashrc && \ 154 | echo "export LESS='-R'" >> ~/.bashrc && \ 155 | echo "export PYGMENTIZE_STYLE='monokai'" >> ~/.bashrc && \ 156 | curl -sSL https://raw.githubusercontent.com/CoeJoder/lessfilter-pygmentize/master/.lessfilter > ~/.lessfilter && \ 157 | chmod 755 ~/.lessfilter 158 | 159 | # init rosdep 160 | RUN rosdep update 161 | 162 | # global vscode config 163 | ADD .vscode /home/developer/.vscode 164 | RUN ln -s /home/developer/.vscode /home/developer/.vscode-server 165 | ADD .devcontainer/compile_flags.txt /home/developer/compile_flags.txt 166 | ADD .devcontainer/templates /home/developer/templates 167 | RUN sudo chown -R developer:developer /home/developer 168 | 169 | RUN code --install-extension ms-python.python && \ 170 | code --install-extension ms-vscode.cpptools-extension-pack && \ 171 | code --install-extension redhat.vscode-xml 172 | 173 | # enable jupyter extensions 174 | RUN jupyter nbextension enable hinterland/hinterland && \ 175 | jupyter nbextension enable toc2/main && \ 176 | jupyter nbextension enable code_prettify/autopep8 && \ 177 | jupyter nbextension enable nbTranslate/main && \ 178 | mkdir -p /home/developer/.ipython/profile_default && \ 179 | echo "c.Completer.use_jedi = False" >> /home/developer/.ipython/profile_default/ipython_kernel_config.py 180 | 181 | # ROS goodies 182 | RUN echo "alias rte='rostopic list | fzf --preview \"rostopic echo -c {}\"'" >> ~/.bashrc 183 | RUN echo "alias rti='rostopic list | fzf --preview \"rostopic info {}\"'" >> ~/.bashrc 184 | RUN echo "alias rni='rosnode list | fzf --preview \"rosnode info {}\"'" >> ~/.bashrc 185 | RUN echo "alias rsi='rosservice list | fzf --preview \"rosservice info {}\"'" >> ~/.bashrc 186 | RUN echo "alias rmi='rosmsg list | fzf --preview \"rosmsg info {}\"'" >> ~/.bashrc 187 | RUN echo "alias rcd='roscd \$(rospack list-names | fzf --preview=\"rospack find {} && pygmentize \\\$(rospack find {})/package.xml\")'" >> ~/.bashrc 188 | 189 | # enter ROS world 190 | RUN echo "source /opt/ros/$ROS_DISTRO/setup.bash" >> ~/.bashrc 191 | 192 | EXPOSE 3000 8888 193 | 194 | ENTRYPOINT [ "/entrypoint.sh" ] 195 | CMD [ "sudo", "-E", "/usr/local/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] 196 | --------------------------------------------------------------------------------