From 3009a442f0eba0191d77fa69d5fd2b0e3fc0a68a Mon Sep 17 00:00:00 2001 From: whomihirpatel Date: Sun, 27 Feb 2022 22:22:16 -0600 Subject: [PATCH] added docker --- CMakeLists.txt | 4 +- README.md | 1 + docker-compose.yml | 92 +++++++++++++++++++++++++++++++++++ launch/offboard.launch.py | 2 +- meshes/Traffic_cone.stl | Bin 0 -> 36584 bytes scripts/landmark_detector.py | 5 +- scripts/visualizer.py | 14 +++--- 7 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 docker-compose.yml create mode 100755 meshes/Traffic_cone.stl diff --git a/CMakeLists.txt b/CMakeLists.txt index 10fa194..dcc1c2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,9 +42,9 @@ install(PROGRAMS DESTINATION lib/${PROJECT_NAME} ) -# Install launch, rviz and config directories +# Install launch, rviz, meshes and config directories install(DIRECTORY - launch config rviz + launch config rviz meshes DESTINATION share/${PROJECT_NAME} ) diff --git a/README.md b/README.md index e0ac355..0bbe2e6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ My implementation of the particle filter localization algorithm on turtlebot3 using ROS2 Galactic. +Please click on the gIF below to see the youtube video.

Youtube Link

\ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..638673b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,92 @@ +version: "3.9" # optional since v1.27.0 +services: + + webviz: + image: "cruise/webviz:latest" + container_name: netbots-webviz + ports: + - "8080:8080" + networks: + netbots: + ipv4_address: "172.18.0.2" + ros: + build: + context: . + dockerfile: ./netbots-ros/Dockerfile + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun:/dev/net/tun + container_name: netbots-ros + ports: + - "11411:11311" + - "9090:9090" + image: "net-bots:latest" + + volumes: + - ovpn-data:/vpn_ws/ + depends_on: + - openvpn-udp + links: + - "openvpn-udp" + networks: + netbots: + ipv4_address: "172.18.0.3" + command: roscore + + openvpn-udp: + cap_add: + - NET_ADMIN + image: kylemanna/openvpn + container_name: netbots-vpn + ports: + - "1194:1194/udp" + restart: always + volumes: + - ovpn-data:/etc/openvpn + + # openvpn-tcp: + # cap_add: + # - NET_ADMIN + # image: kylemanna/openvpn + # container_name: openvpn-tcp + # ports: + # - "1194:1194/tcp" + # restart: always + # volumes: + # - ./openvpn-data:/etc/openvpn + # command: 'ovpn_run --proto tcp' + + networks: + netbots: + ipv4_address: "172.18.0.4" + + nginx: + build: + context: . + dockerfile: ./netbots-nginx/Dockerfile + container_name: netbots-nginx + ports: + - "80:80" + - "443:443" + depends_on: + - webviz + links: + - "webviz" + networks: + netbots: + ipv4_address: "172.18.0.5" + +networks: + netbots: + name: netbots-network + ipam: + driver: default + config: + - subnet: 172.18.0.0/16 + +volumes: + ovpn-data: + external: true + name: ovpn-data + \ No newline at end of file diff --git a/launch/offboard.launch.py b/launch/offboard.launch.py index 5a15802..ed14615 100644 --- a/launch/offboard.launch.py +++ b/launch/offboard.launch.py @@ -56,7 +56,7 @@ def generate_launch_description(): ) return LaunchDescription([ - # rviz, + rviz, landmark_detector, visualizer, core_filter diff --git a/meshes/Traffic_cone.stl b/meshes/Traffic_cone.stl new file mode 100755 index 0000000000000000000000000000000000000000..15c57d5f13a07ee70082c5d938e92eac840d31e7 GIT binary patch literal 36584 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 w&1;jV+wg2$FiTZJzPKlOg=zVAo7&Lt+zEl_mhe