From c60d56a6cd50fa50f924831082bb8637004ce281 Mon Sep 17 00:00:00 2001 From: dominikn Date: Sun, 15 Sep 2024 18:18:58 +0000 Subject: [PATCH 1/3] work in progress --- .gitignore | 5 +- justfile | 24 +- snap/hooks/configure | 27 +- snap/hooks/connect-plug-ros-humble-ros-base | 8 - .../hooks/disconnect-plug-ros-humble-ros-base | 4 - snap/hooks/install | 17 +- snap/local/Caddyfile | 48 -- snap/local/bridge_launch.py | 24 - snap/local/bridge_launcher.sh | 13 - snap/local/caddy_launcher.sh | 41 -- snap/local/flash_launcher.sh | 2 +- snap/local/foxglove-default.json | 145 ------ snap/local/foxglove-sensors.json | 445 ------------------ snap/local/foxglove-set-namespace.sh | 33 -- snap/local/joy.launch.py | 65 +++ snap/local/joy_launcher.sh | 53 ++- snap/local/joy_params.yaml | 4 +- snap/local/joy_teleop.config.yaml | 5 +- snap/local/local-ros/check_daemon_running.sh | 12 - snap/local/local-ros/configure_hook_ros.sh | 176 ------- snap/local/local-ros/install_hook_ros.sh | 22 - snap/local/local-ros/ros_setup.sh | 5 - snap/local/local-ros/shm.xml | 18 - snap/local/local-ros/udp-lo-cyclone.xml | 16 - snap/local/local-ros/udp-lo.xml | 21 - snap/local/local-ros/udp.xml | 18 - snap/local/local-ros/utils.sh | 224 --------- snap/local/rosbot-manipulator.launch.py | 26 - snap/local/rosbot.launch.py | 22 - snap/local/start_launcher.sh | 2 + snap/local/start_web_ui_launcher.sh | 13 - snap/local/stop_launcher.sh | 3 + snap/local/stop_web_ui_launcher.sh | 7 - snap/local/teleop_twist_joy_launch.py | 42 -- snap/local/teleop_twist_joy_launcher.sh | 13 - snap/snapcraft.yaml | 155 ++---- snapcraft_template.yaml.jinja2 | 153 ++---- 37 files changed, 224 insertions(+), 1687 deletions(-) delete mode 100644 snap/hooks/connect-plug-ros-humble-ros-base delete mode 100644 snap/hooks/disconnect-plug-ros-humble-ros-base delete mode 100644 snap/local/Caddyfile delete mode 100755 snap/local/bridge_launch.py delete mode 100755 snap/local/bridge_launcher.sh delete mode 100755 snap/local/caddy_launcher.sh delete mode 100644 snap/local/foxglove-default.json delete mode 100644 snap/local/foxglove-sensors.json delete mode 100755 snap/local/foxglove-set-namespace.sh create mode 100755 snap/local/joy.launch.py delete mode 100755 snap/local/local-ros/check_daemon_running.sh delete mode 100755 snap/local/local-ros/configure_hook_ros.sh delete mode 100755 snap/local/local-ros/install_hook_ros.sh delete mode 100755 snap/local/local-ros/ros_setup.sh delete mode 100644 snap/local/local-ros/shm.xml delete mode 100644 snap/local/local-ros/udp-lo-cyclone.xml delete mode 100644 snap/local/local-ros/udp-lo.xml delete mode 100644 snap/local/local-ros/udp.xml delete mode 100755 snap/local/local-ros/utils.sh mode change 100644 => 100755 snap/local/rosbot-manipulator.launch.py mode change 100644 => 100755 snap/local/rosbot.launch.py delete mode 100755 snap/local/start_web_ui_launcher.sh delete mode 100755 snap/local/stop_web_ui_launcher.sh delete mode 100755 snap/local/teleop_twist_joy_launch.py delete mode 100755 snap/local/teleop_twist_joy_launcher.sh diff --git a/.gitignore b/.gitignore index 65dae27..98b74d6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.snap -squashfs-root -test* \ No newline at end of file +.snapcraft_store_credentials.txt +squashfs-root/ +**/snapcraft.yaml \ No newline at end of file diff --git a/justfile b/justfile index 953c7d8..d978061 100644 --- a/justfile +++ b/justfile @@ -142,8 +142,8 @@ teleop: # export FASTRTPS_DEFAULT_PROFILES_FILE=$(pwd)/shm-only.xml ros2 run teleop_twist_keyboard teleop_twist_keyboard # --ros-args -r __ns:=/robot -iterate: - #!/bin/bash -e +iterate target="jazzy": + #!/bin/bash start_time=$(date +%s) echo "Starting script..." @@ -152,13 +152,31 @@ iterate: sudo rm -rf squashfs-root/ sudo rm -rf rosbot-xl*.snap export SNAPCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS=1 - snapcraft clean + + if [ {{target}} == "humble" ]; then + export ROS_DISTRO=humble + elif [ {{target}} == "jazzy" ]; then + export ROS_DISTRO=jazzy + else + echo "Unknown target: {{target}}" + exit 1 + fi + + if [ -f snap/snapcraft.yaml ]; then + snapcraft clean + sudo rm -rf snap/snapcraft.yaml + fi + + ./render_template.py ./snapcraft_template.yaml.jinja2 snap/snapcraft.yaml + chmod 444 snap/snapcraft.yaml snapcraft unsquashfs rosbot-xl*.snap sudo snap try squashfs-root/ sudo snap connect rosbot-xl:raw-usb sudo snap connect rosbot-xl:shm-plug rosbot-xl:shm-slot sudo snap connect rosbot-xl:shutdown + sudo snap connect rosbot-xl:hardware-observe + sudo snap connect rosbot-xl:joystick end_time=$(date +%s) duration=$(( end_time - start_time )) diff --git a/snap/hooks/configure b/snap/hooks/configure index 856672f..d895219 100644 --- a/snap/hooks/configure +++ b/snap/hooks/configure @@ -9,11 +9,9 @@ source $SNAP/usr/bin/utils.sh # Define the top-level key and the list of valid keys VALID_DRIVER_KEYS=("mecanum" "include-camera-mount" "camera-model" "lidar-model" "db-serial-port" "manipulator-serial-port" ) -VALID_WEBUI_KEYS=("layout" "port") # Call the validation function validate_keys "driver" VALID_DRIVER_KEYS[@] -validate_keys "webui" VALID_WEBUI_KEYS[@] # Define the valid options for camera model and lidar model VALID_CAMERA_OPTIONS=("None" "intel_realsense_d435" "orbbec_astra" "stereolabs_zed" "stereolabs_zedm" "stereolabs_zed2" "stereolabs_zed2i" "stereolabs_zedx" "stereolabs_zedxm") @@ -27,25 +25,10 @@ validate_option "driver.mecanum" VALID_BOOLEAN_OPTIONS[@] validate_option "driver.include-camera-mount" VALID_BOOLEAN_OPTIONS[@] # Validate specific serial ports -validate_serial_port "driver.db-serial-port" -validate_serial_port "driver.manipulator-serial-port" - -# Get the transport setting using snapctl -OPT="webui.layout" -LAYOUT="$(snapctl get ${OPT})" - -# Only exit with status 1 if conditions are not met -if [ ! -f "${SNAP_COMMON}/foxglove-${LAYOUT}.json" ]; then - log_and_echo "'${SNAP_COMMON}/foxglove-${LAYOUT}.json' does not exist." - exit 1 -fi - -# Make sure WEBUI_PORT is valid -EXCLUDED_PORTS=(3000 8888) -SUPPORTED_RANGE=(0 65535) - -# Validate a specific port, for example, webui.port -validate_number "webui.port" SUPPORTED_RANGE[@] EXCLUDED_PORTS[@] +# validate driver.serial-port +ALTERNATIVE_SERIAL_PORT_OPTIONS=("auto") +validate_path "driver.db-serial-port" "/dev/ttyUSB[0-9]+" ALTERNATIVE_SERIAL_PORT_OPTIONS[@] +validate_path "driver.manipulator-serial-port" "/dev/ttyUSB[0-9]+" ALTERNATIVE_SERIAL_PORT_OPTIONS[@] VALID_CONFIGURATION_OPTIONS=("basic" "manipulation") @@ -65,7 +48,7 @@ fi $SNAP/usr/bin/configure_hook_ros.sh # restart services with new ROS 2 config -for service in daemon web-ui web-ws joy teleop-twist-joy; do +for service in daemon joy; do if snapctl services ${SNAP_NAME}.${service} | grep -qw enabled; then snapctl restart ${SNAP_NAME}.${service} log "Restarted ${SNAP_NAME}.${service}" diff --git a/snap/hooks/connect-plug-ros-humble-ros-base b/snap/hooks/connect-plug-ros-humble-ros-base deleted file mode 100644 index 39d5c18..0000000 --- a/snap/hooks/connect-plug-ros-humble-ros-base +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -e - -# now we can start the service -# if snapctl services ${SNAP_NAME}.${SNAP_NAME} | grep -q inactive; then -# snapctl start --enable ${SNAP_NAME}.${SNAP_NAME} 2>&1 || true -# fi - -logger -t ${SNAP_NAME} "Plug 'ros-humble-ros-base' connected" \ No newline at end of file diff --git a/snap/hooks/disconnect-plug-ros-humble-ros-base b/snap/hooks/disconnect-plug-ros-humble-ros-base deleted file mode 100644 index bc2c60d..0000000 --- a/snap/hooks/disconnect-plug-ros-humble-ros-base +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -e - -logger -t ${SNAP_NAME} "Plug 'ros-humble-ros-base' disconnected" -snapctl stop --disable ${SNAP_NAME}.daemon 2>&1 || true diff --git a/snap/hooks/install b/snap/hooks/install index 8b4bea7..bbdb65e 100644 --- a/snap/hooks/install +++ b/snap/hooks/install @@ -14,9 +14,6 @@ snapctl set driver.lidar-model=None snapctl set driver.db-serial-port=auto snapctl set driver.manipulator-serial-port=auto -snapctl set webui.layout=default -snapctl set webui.port=8080 - snapctl set configuration=basic if ! snapctl is-connected raw-usb; then @@ -24,11 +21,11 @@ if ! snapctl is-connected raw-usb; then log "sudo snap connect ${SNAP_NAME}:raw-usb" fi -# copy meshes to shared folder -log "copy meshes to '${SNAP_COMMON}/ros2_ws/'" -mkdir -p ${SNAP_COMMON}/ros2_ws -cp -r $SNAP/opt/ros/snap/share/rosbot_xl_description ${SNAP_COMMON}/ros2_ws/rosbot_xl_description -cp -r $SNAP/opt/ros/snap/share/ros_components_description ${SNAP_COMMON}/ros2_ws/ros_components_description +# # copy meshes to shared folder +# log "copy meshes to '${SNAP_COMMON}/ros2_ws/'" +# mkdir -p ${SNAP_COMMON}/ros2_ws +# cp -r $SNAP/opt/ros/snap/share/rosbot_xl_description ${SNAP_COMMON}/ros2_ws/rosbot_xl_description +# cp -r $SNAP/opt/ros/snap/share/ros_components_description ${SNAP_COMMON}/ros2_ws/ros_components_description # copy joy params cp -r $SNAP/usr/share/rosbot-xl/config/teleop_twist_joy_params.yaml ${SNAP_COMMON}/ @@ -38,5 +35,5 @@ cp -r $SNAP/usr/share/rosbot-xl/config/joy_servo.yaml ${SNAP_COMMON}/ cp -r $SNAP/usr/share/rosbot-xl/config/joy_teleop.config.yaml ${SNAP_COMMON}/ cp -r $SNAP/usr/share/rosbot-xl/config/joy_params.yaml ${SNAP_COMMON}/ -# copy webui layouts -cp -r $SNAP/usr/share/$SNAP_NAME/config/foxglove-*.json ${SNAP_COMMON}/ \ No newline at end of file +# # copy webui layouts +# cp -r $SNAP/usr/share/$SNAP_NAME/config/foxglove-*.json ${SNAP_COMMON}/ \ No newline at end of file diff --git a/snap/local/Caddyfile b/snap/local/Caddyfile deleted file mode 100644 index 70edc28..0000000 --- a/snap/local/Caddyfile +++ /dev/null @@ -1,48 +0,0 @@ -# :8080 { -# # Serve static files from /var/www/foxglove -# root * /var/www/foxglove - -# # Handle all requests -# file_server -# } - -:{$UI_PORT} { - # Enable HTTP/2 over clear text (h2c) - # protocols h2c - - # Reverse Proxy for WebSocket connections on /ws - handle_path /ws { - reverse_proxy http://127.0.0.1:8765 - } - - # Reverse Proxy for the main site - handle_path /* { - # reverse_proxy http://127.0.0.1:8080 - # Serve static files from /var/www/foxglove - root * {$SNAP_DATA}/www/foxglove/ - - @ipv6Client { - expression {http.request.host}.startsWith("fc94") - } - - handle @ipv6Client { - vars full_host [{http.request.host}] - redir /ui /?ds=foxglove-websocket&ds.url=ws%3A%2F%2F%5B{http.request.host}%5D%3A{http.request.port}%2Fws - } - - # Handle all other requests (from non-IPv6 clients) - handle { - vars full_host {http.request.host} - redir /ui /?ds=foxglove-websocket&ds.url=ws%3A%2F%2F{http.request.host}%3A{http.request.port}%2Fws - } - - # Handle envs in foxglove templates - templates { - mime "text/html" - # mime "application/json" "text/plain" "text/html" - } - - # Handle all requests - file_server - } -} diff --git a/snap/local/bridge_launch.py b/snap/local/bridge_launch.py deleted file mode 100755 index 965b95f..0000000 --- a/snap/local/bridge_launch.py +++ /dev/null @@ -1,24 +0,0 @@ -import os -from launch import LaunchDescription -from launch_ros.actions import Node - -def generate_launch_description(): - - # Node configuration for foxglove_bridge - foxglove_bridge = Node( - package='foxglove_bridge', - executable='foxglove_bridge', - name='foxglove_bridge', - parameters=[{ - 'port': 8765, - 'address': '127.0.0.1', - 'capabilities': ['clientPublish', 'parameters', 'parametersSubscribe', 'services', 'connectionGraph', 'assets'] - # 'capabilities': ['clientPublish', 'connectionGraph', 'assets'] - }], - output='screen' - ) - - # Return the launch description which includes both nodes and the launch argument - return LaunchDescription([ - foxglove_bridge, - ]) diff --git a/snap/local/bridge_launcher.sh b/snap/local/bridge_launcher.sh deleted file mode 100755 index f34213b..0000000 --- a/snap/local/bridge_launcher.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -e - -LAUNCH_OPTIONS="" - -# Retrieve the namespace using snapctl -NAMESPACE="$(snapctl get ros.namespace)" - -# Check if NAMESPACE is not set or is empty -if [ -n "$NAMESPACE" ]; then - LAUNCH_OPTIONS+="namespace:=${NAMESPACE} " -fi - -ros2 launch $SNAP/usr/bin/bridge_launch.py ${LAUNCH_OPTIONS} diff --git a/snap/local/caddy_launcher.sh b/snap/local/caddy_launcher.sh deleted file mode 100755 index 75b2bc8..0000000 --- a/snap/local/caddy_launcher.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -e - -# Define a function to log and echo messages -source $SNAP/usr/bin/utils.sh - -# Define the source and destination directories -site_path="$SNAP/usr/local/www/" -site_tmp_path="$SNAP_DATA/www/" -layout="$(snapctl get webui.layout)" -# layout="layout" -export UI_PORT="$(snapctl get webui.port)" -log_and_echo "Using ${SNAP_COMMON}/foxglove-$layout.json" - -# Ensure the destination directory exists -rm -rf $site_tmp_path -mkdir -p "$site_tmp_path" - -# Copy foxglove folder to temp path -cp -R $site_path/foxglove $site_tmp_path - -# apply the layout -index_html_path=$site_tmp_path/foxglove/index.html -index_html_content=$(cat $index_html_path) -replace_pattern='/*FOXGLOVE_STUDIO_DEFAULT_LAYOUT_PLACEHOLDER*/' -replace_value=$(cat ${SNAP_COMMON}/foxglove-$layout.json) -echo "${index_html_content/"$replace_pattern"/$replace_value}" > $index_html_path - -# disable cache -sed -i "s|
|\n&|" $index_html_path - -# Define a function to log and echo messages -# Retrieve the ros.namespace value -namespace=$(snapctl get ros.namespace) - -# Check if the namespace is set and not empty -if [ -n "$namespace" ]; then - # Set the environment variable - export NAMESPACE="/$namespace" -fi -caddy run --config $SNAP/usr/share/$SNAP_NAME/config/Caddyfile --adapter caddyfile - diff --git a/snap/local/flash_launcher.sh b/snap/local/flash_launcher.sh index ef6ef46..deed7bf 100755 --- a/snap/local/flash_launcher.sh +++ b/snap/local/flash_launcher.sh @@ -19,7 +19,7 @@ else fi # Check if SERIAL_PORT is set to auto or specified -SERIAL_PORT=$(find_ttyUSB driver.db-serial-port "0403" "6015") +SERIAL_PORT=$(find_usb_device "ttyUSB" driver.db-serial-port "0403" "6015") if [ $? -ne 0 ]; then log_and_echo "Failed to find the serial port." exit 1 diff --git a/snap/local/foxglove-default.json b/snap/local/foxglove-default.json deleted file mode 100644 index 43c72a1..0000000 --- a/snap/local/foxglove-default.json +++ /dev/null @@ -1,145 +0,0 @@ -{ - "configById": { - "Teleop!3yjcv6d": { - "topic": "{{env "NAMESPACE"}}/cmd_vel", - "publishRate": 10, - "upButton": { - "field": "linear-x", - "value": 1 - }, - "downButton": { - "field": "linear-x", - "value": -1 - }, - "leftButton": { - "field": "angular-z", - "value": 1 - }, - "rightButton": { - "field": "angular-z", - "value": -1 - } - }, - "3D!36yxwbl": { - "cameraState": { - "perspective": true, - "distance": 2.2036622046999295, - "phi": 59.99999999999968, - "thetaOffset": 45.000000000000036, - "targetOffset": [ - -0.1884647536706241, - 0.13784349522327283, - -3.166224866510698e-17 - ], - "target": [ - 0, - 0, - 0 - ], - "targetOrientation": [ - 0, - 0, - 0, - 1 - ], - "fovy": 45, - "near": 0.5, - "far": 5000 - }, - "followMode": "follow-pose", - "scene": {}, - "transforms": { - "frame:antenna_link": { - "visible": false - }, - "frame:antenna_connector_link": { - "visible": false - }, - "frame:body_link": { - "visible": false - }, - "frame:base_link": { - "visible": true - }, - "frame:cover_link": { - "visible": false - }, - "frame:imu_link": { - "visible": false - }, - "frame:camera_mount_mid_link": { - "visible": false - }, - "frame:camera_mount_bot_link": { - "visible": false - }, - "frame:camera_mount_top_link": { - "visible": false - }, - "frame:camera_mount_link": { - "visible": false - }, - "frame:slamtec_rplidar_s1_link": { - "visible": false - }, - "frame:laser": { - "visible": false - }, - "frame:fl_wheel_link": { - "visible": false - }, - "frame:fr_wheel_link": { - "visible": false - }, - "frame:rl_wheel_link": { - "visible": false - }, - "frame:rr_wheel_link": { - "visible": false - }, - "frame:odom": { - "visible": true - } - }, - "topics": {}, - "layers": { - "48c64d32-2812-4be5-9335-65c414e3722d": { - "visible": true, - "frameLocked": true, - "label": "URDF", - "instanceId": "48c64d32-2812-4be5-9335-65c414e3722d", - "layerId": "foxglove.Urdf", - "sourceType": "topic", - "url": "", - "filePath": "", - "parameter": "", - "topic": "{{env "NAMESPACE"}}/robot_description", - "framePrefix": "", - "displayMode": "auto", - "fallbackColor": "#ffffff", - "order": 1 - } - }, - "publish": { - "type": "point", - "poseTopic": "{{env "NAMESPACE"}}/move_base_simple/goal", - "pointTopic": "{{env "NAMESPACE"}}/clicked_point", - "poseEstimateTopic": "{{env "NAMESPACE"}}/initialpose", - "poseEstimateXDeviation": 0.5, - "poseEstimateYDeviation": 0.5, - "poseEstimateThetaDeviation": 0.26179939 - }, - "imageMode": {} - } - }, - "globalVariables": {}, - "userNodes": {}, - "playbackConfig": { - "speed": 1 - }, - "layout": { - "direction": "row", - "first": "3D!36yxwbl", - "second": "Teleop!3yjcv6d" - } -} \ No newline at end of file diff --git a/snap/local/foxglove-sensors.json b/snap/local/foxglove-sensors.json deleted file mode 100644 index 783cd67..0000000 --- a/snap/local/foxglove-sensors.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "configById": { - "Plot!1u5bb0v": { - "paths": [ - { - "value": "{{env "NAMESPACE"}}/imu_broadcaster/imu.orientation.w", - "enabled": true, - "timestampMethod": "receiveTime" - }, - { - "value": "{{env "NAMESPACE"}}/imu_broadcaster/imu.orientation.x", - "enabled": true, - "timestampMethod": "receiveTime" - }, - { - "value": "{{env "NAMESPACE"}}/imu_broadcaster/imu.orientation.y", - "enabled": true, - "timestampMethod": "receiveTime" - }, - { - "value": "{{env "NAMESPACE"}}/imu_broadcaster/imu.orientation.z", - "enabled": true, - "timestampMethod": "receiveTime" - } - ], - "minYValue": -1.1, - "maxYValue": 1.1, - "showXAxisLabels": true, - "showYAxisLabels": true, - "showLegend": false, - "legendDisplay": "floating", - "showPlotValuesInLegend": false, - "isSynced": true, - "xAxisVal": "timestamp", - "sidebarDimension": 240, - "foxglovePanelTitle": "Plot", - "followingViewWidth": 30 - }, - "RosOut!b0toow": { - "searchTerms": [], - "minLogLevel": 2 - }, - "Publish!3yfprcp": { - "topicName": "{{env "NAMESPACE"}}/cmd_vel", - "datatype": "geometry_msgs/msg/Twist", - "buttonText": "Motors Test", - "buttonTooltip": "", - "buttonColor": "#a85600", - "advancedView": false, - "value": "{\n \"linear\": {\n \"x\": 1.0,\n \"y\": 0,\n \"z\": 0\n },\n \"angular\": {\n \"x\": 0,\n \"y\": 0,\n \"z\": -0.5\n }\n}" - }, - "3D!4atcr8w": { - "cameraState": { - "perspective": true, - "distance": 4.078136514915201, - "phi": 0.27634279333612527, - "thetaOffset": 88.9293939734993, - "targetOffset": [ - 0.34677234754289576, - 0.03223816139348337, - -2.8618304713627643e-18 - ], - "target": [ - 0, - 0, - 0 - ], - "targetOrientation": [ - 0, - 0, - 0, - 1 - ], - "fovy": 45, - "near": 0.5, - "far": 5000 - }, - "followMode": "follow-pose", - "scene": {}, - "transforms": { - "frame:antenna_link": { - "visible": false - }, - "frame:antenna_connector_link": { - "visible": false - }, - "frame:body_link": { - "visible": false - }, - "frame:base_link": { - "visible": false - }, - "frame:cover_link": { - "visible": false - }, - "frame:imu_link": { - "visible": false - }, - "frame:camera_mount_mid_link": { - "visible": false - }, - "frame:camera_mount_bot_link": { - "visible": false - }, - "frame:camera_mount_top_link": { - "visible": false - }, - "frame:camera_mount_link": { - "visible": false - }, - "frame:slamtec_rplidar_s1_link": { - "visible": false - }, - "frame:laser": { - "visible": false - }, - "frame:odom": { - "visible": false - }, - "frame:fl_wheel_link": { - "visible": false - }, - "frame:fr_wheel_link": { - "visible": false - }, - "frame:rl_wheel_link": { - "visible": false - }, - "frame:rr_wheel_link": { - "visible": false - } - }, - "topics": { - "{{env "NAMESPACE"}}/robot_description": { - "visible": true - }, - "{{env "NAMESPACE"}}/scan": { - "visible": false, - "colorField": "intensity", - "colorMode": "colormap", - "colorMap": "turbo", - "pointSize": 6 - }, - "{{env "NAMESPACE"}}/scan_filtered": { - "visible": true, - "colorField": "intensity", - "colorMode": "colormap", - "colorMap": "turbo", - "pointSize": 6 - } - }, - "layers": { - "65f38642-dc67-4219-8e4d-bb0330368f80": { - "visible": true, - "frameLocked": true, - "label": "URDF", - "instanceId": "65f38642-dc67-4219-8e4d-bb0330368f80", - "layerId": "foxglove.Urdf", - "sourceType": "topic", - "url": "", - "filePath": "", - "parameter": "", - "topic": "{{env "NAMESPACE"}}/robot_description", - "framePrefix": "", - "displayMode": "auto", - "fallbackColor": "#ffffff", - "order": 1 - }, - "eebc5132-8e96-40f6-a746-e61c0daaedab": { - "visible": true, - "frameLocked": true, - "label": "Grid", - "instanceId": "eebc5132-8e96-40f6-a746-e61c0daaedab", - "layerId": "foxglove.Grid", - "size": 10, - "divisions": 10, - "lineWidth": 1, - "color": "#248eff", - "position": [ - 0, - 0, - 0 - ], - "rotation": [ - 0, - 0, - 0 - ], - "order": 1 - } - }, - "publish": { - "type": "point", - "poseTopic": "{{env "NAMESPACE"}}/move_base_simple/goal", - "pointTopic": "{{env "NAMESPACE"}}/clicked_point", - "poseEstimateTopic": "{{env "NAMESPACE"}}/initialpose", - "poseEstimateXDeviation": 0.5, - "poseEstimateYDeviation": 0.5, - "poseEstimateThetaDeviation": 0.26179939 - }, - "imageMode": {} - }, - "Tab!2qhku9u": { - "activeTabIdx": 0, - "tabs": [ - { - "title": "IMU Plots", - "layout": { - "first": "Plot!1u5bb0v", - "second": "RosOut!b0toow", - "direction": "column" - } - }, - { - "title": "Production", - "layout": "Publish!3yfprcp" - } - ] - }, - "Image!2zw8l2a": { - "cameraState": { - "distance": 20, - "perspective": true, - "phi": 60, - "target": [ - 0, - 0, - 0 - ], - "targetOffset": [ - 0, - 0, - 0 - ], - "targetOrientation": [ - 0, - 0, - 0, - 1 - ], - "thetaOffset": 45, - "fovy": 45, - "near": 0.5, - "far": 5000 - }, - "followMode": "follow-pose", - "scene": {}, - "transforms": {}, - "topics": {}, - "layers": {}, - "publish": { - "type": "point", - "poseTopic": "{{env "NAMESPACE"}}/move_base_simple/goal", - "pointTopic": "{{env "NAMESPACE"}}/clicked_point", - "poseEstimateTopic": "{{env "NAMESPACE"}}/initialpose", - "poseEstimateXDeviation": 0.5, - "poseEstimateYDeviation": 0.5, - "poseEstimateThetaDeviation": 0.26179939 - }, - "imageMode": { - "imageTopic": "{{env "NAMESPACE"}}/oak/rgb/image_raw/compressed", - "calibrationTopic": "{{env "NAMESPACE"}}/oak/rgb/camera_info" - } - }, - "Teleop!13emlz4": { - "topic": "{{env "NAMESPACE"}}/cmd_vel", - "publishRate": 10, - "upButton": { - "field": "linear-x", - "value": 0.19754204525471783 - }, - "downButton": { - "field": "linear-x", - "value": -0.20000000000000015 - }, - "leftButton": { - "field": "angular-z", - "value": 1 - }, - "rightButton": { - "field": "angular-z", - "value": -1 - }, - "foxglovePanelTitle": "Diff Drive" - }, - "Gauge!4jffafa": { - "path": "/battery_state.voltage", - "minValue": 9.8, - "maxValue": 12.6, - "colorMap": "red-yellow-green", - "colorMode": "colormap", - "gradient": [ - "#0000ff", - "#ff00ff" - ], - "reverse": false, - "foxglovePanelTitle": "Battery" - }, - "Indicator!11kizr9": { - "path": "/battery_state.voltage", - "style": "background", - "fallbackColor": "#000000", - "fallbackLabel": "Ok", - "rules": [ - { - "operator": "<", - "rawValue": "10.8", - "color": "#ff0000", - "label": "Plug charger!" - } - ], - "foxglovePanelTitle": "Plug Charger Info" - }, - "Plot!4dl4s92": { - "paths": [ - { - "value": "/battery_state.voltage", - "enabled": true, - "timestampMethod": "receiveTime" - } - ], - "minYValue": 9.482842712474614, - "maxYValue": 13, - "showXAxisLabels": true, - "showYAxisLabels": true, - "showLegend": true, - "legendDisplay": "floating", - "showPlotValuesInLegend": true, - "isSynced": true, - "xAxisVal": "timestamp", - "sidebarDimension": 240, - "foxglovePanelTitle": "Voltage", - "followingViewWidth": 60 - }, - "Gauge!43atfmu": { - "path": "/battery_state.current", - "minValue": -3, - "maxValue": 3, - "colorMap": "red-yellow-green", - "colorMode": "colormap", - "gradient": [ - "#0000ff", - "#ff00ff" - ], - "reverse": true, - "foxglovePanelTitle": "Battery Current" - }, - "Gauge!1t2ifzu": { - "path": "/battery_state.charge", - "minValue": 0, - "maxValue": 3, - "colorMap": "red-yellow-green", - "colorMode": "colormap", - "gradient": [ - "#0000ff", - "#ff00ff" - ], - "reverse": true, - "foxglovePanelTitle": "Battery Charger Current" - }, - "Plot!3gmoqow": { - "paths": [ - { - "value": "/battery_state.current", - "enabled": true, - "timestampMethod": "receiveTime" - }, - { - "value": "/battery_state.charge", - "enabled": true, - "timestampMethod": "receiveTime" - } - ], - "minYValue": -3, - "maxYValue": 3, - "showXAxisLabels": true, - "showYAxisLabels": true, - "showLegend": true, - "legendDisplay": "floating", - "showPlotValuesInLegend": true, - "isSynced": true, - "xAxisVal": "timestamp", - "sidebarDimension": 240, - "foxglovePanelTitle": "Current" - } - }, - "globalVariables": { - "globalVariable": 7 - }, - "userNodes": { - "f5206e1d-deee-4f90-a03e-f561fbb9a7dd": { - "sourceCode": "// The ./types module provides helper types for your Input events and messages.\nimport { Input, Message } from \"./types\";\n\n// Your script can output well-known message types, any of your custom message types, or\n// complete custom message types.\n//\n// Use `Message` to access your data source types or well-known types:\n// type Twist = Message<\"geometry_msgs/Twist\">;\n//\n// Conventionally, it's common to make a _type alias_ for your script's output type\n// and use that type name as the return type for your script function.\n// Here we've called the type `Output` but you can pick any type name.\ntype Output = {\n hello: string;\n};\n\n// These are the topics your script \"subscribes\" to. Studio will invoke your script function\n// when any message is received on one of these topics.\nexport const inputs = [\"/input/topic\"];\n\n// Any output your script produces is \"published\" to this topic. Published messages are only visible within Studio, not to your original data source.\nexport const output = \"/studio_script/output_topic\";\n\n// This function is called with messages from your input topics.\n// The first argument is an event with the topic, receive time, and message.\n// Use the `Input<...>` helper to get the correct event type for your input topic messages.\nexport default function script(event: Input<\"/input/topic\">): Output {\n return {\n hello: \"world!\",\n };\n};", - "name": "f5206e1d" - }, - "1a9e6183-d4b1-47dd-a024-efc14ab90b6b": { - "sourceCode": "// This example shows how to subscribe to multiple input topics.\n//\n// NOTE:\n// User Scripts can subscribe to multiple input topics, but can only publish on a single topic.\n\nimport { Input } from \"./types\";\n\ntype Output = { topic: string };\ntype GlobalVariables = { id: number };\n\n// List all the input topics in the `input` array\nexport const inputs = [\"/input/topic\", \"/input/another\"];\nexport const output = \"/studio_script/output_topic\";\n\n// Make an InputEvent type alias. Since our node will get a message from either input topic, we need to enumerate the topics.\ntype InputEvent = Input<\"/input/topic\"> | Input<\"/input/another\">;\n\nexport default function node(event: InputEvent, globalVars: GlobalVariables): Output {\n // Remember that your node will get messages on each topic, so you\n // need to check each event's topic to know which fields are available on the message.\n switch (event.topic) {\n case \"/input/topic\":\n // topic specific input logic\n // Our message fields are specific to our topic message\n break;\n case \"/input/another\":\n // another specific logic\n break;\n }\n\n // Nodes can only output one type of message regardless of the inputs\n // Here we echo back the input topic as an example.\n return {\n topic: event.topic,\n };\n};\n", - "name": "1a9e6183" - } - }, - "playbackConfig": { - "speed": 1 - }, - "layout": { - "first": { - "direction": "row", - "first": "Tab!2qhku9u", - "second": { - "first": "3D!4atcr8w", - "second": { - "first": "Teleop!13emlz4", - "second": "Image!2zw8l2a", - "direction": "column" - }, - "direction": "row" - }, - "splitPercentage": 30.5849582172702 - }, - "second": { - "first": { - "first": "Gauge!4jffafa", - "second": "Indicator!11kizr9", - "direction": "column" - }, - "second": { - "first": "Plot!4dl4s92", - "second": { - "first": { - "first": "Gauge!43atfmu", - "second": "Gauge!1t2ifzu", - "direction": "column" - }, - "second": "Plot!3gmoqow", - "direction": "row", - "splitPercentage": 40.95744286095124 - }, - "direction": "row", - "splitPercentage": 38.157892540045665 - }, - "direction": "row", - "splitPercentage": 18.12550403728454 - }, - "direction": "column", - "splitPercentage": 67.44897959183673 - } -} \ No newline at end of file diff --git a/snap/local/foxglove-set-namespace.sh b/snap/local/foxglove-set-namespace.sh deleted file mode 100755 index e1fe76c..0000000 --- a/snap/local/foxglove-set-namespace.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -e - -# deprecated (using caddy templates instead) - -LAYOUT="$(snapctl get webui.layout)" -NAMESPACE="$(snapctl get driver.namespace)" - -cp ${SNAP_COMMON}/foxglove-${LAYOUT}.json ${SNAP_COMMON}/foxglove-layout.json - -if [ -n "$NAMESPACE" ]; then - # Update path fields - yq -i -o=json '(.configById[] | select(has("path")) | .path) |= "/'$NAMESPACE'" + .' ${SNAP_COMMON}/foxglove-layout.json - - # Update paths[].value fields - yq -i -o=json '(.configById[] | select(has("paths")) | .paths[].value) |= "/'$NAMESPACE'" + .' ${SNAP_COMMON}/foxglove-layout.json - - # Update topicName fields - yq -i -o=json '(.configById[] | select(has("topicName")) | .topicName) |= "/'$NAMESPACE'" + .' ${SNAP_COMMON}/foxglove-layout.json - - # Update topic fields - yq -i -o=json '(.configById[] | select(has("topic")) | .topic) |= "/'$NAMESPACE'" + .' ${SNAP_COMMON}/foxglove-layout.json - - # Update keys within topics - yq -i -o=json '(.configById[] | select(has("topics")) | .topics) |= with_entries(.key |= "/'$NAMESPACE'" + .)' ${SNAP_COMMON}/foxglove-layout.json - - # Update values of keys matching .*Topic$ - yq -i -o=json '(.configById[] | select(has("publish")) | .publish | select(has("poseTopic")) | .poseTopic) |= "/'$NAMESPACE'" + .' ${SNAP_COMMON}/foxglove-layout.json - yq -i -o=json '(.configById[] | select(has("publish")) | .publish | select(has("pointTopic")) | .pointTopic) |= "/'$NAMESPACE'" + .' ${SNAP_COMMON}/foxglove-layout.json - yq -i -o=json '(.configById[] | select(has("publish")) | .publish | select(has("poseEstimateTopic")) | .poseEstimateTopic) |= "/'$NAMESPACE'" + .' ${SNAP_COMMON}/foxglove-layout.json - - # Update imageTopic - yq -i -o=json '(.configById[] | select(has("imageMode")) | .imageMode | select(has("imageTopic")) | .imageTopic) |= "/'$NAMESPACE'" + .' ${SNAP_COMMON}/foxglove-layout.json -fi diff --git a/snap/local/joy.launch.py b/snap/local/joy.launch.py new file mode 100755 index 0000000..efa6da0 --- /dev/null +++ b/snap/local/joy.launch.py @@ -0,0 +1,65 @@ +import os + +from ament_index_python.packages import get_package_share_directory + +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node + + +def generate_launch_description(): + joy_dev = LaunchConfiguration('joy_dev') + config_filepath = LaunchConfiguration('config_filepath') + publish_stamped_twist = LaunchConfiguration('publish_stamped_twist') + namespace = LaunchConfiguration('namespace') # Capture the namespace + + return LaunchDescription([ + DeclareLaunchArgument( + 'joy_vel', + default_value='cmd_vel', + description='The topic name to which velocity commands will be published.' + ), + DeclareLaunchArgument( + 'joy_dev', + default_value='/dev/input/js0', + description='The device file for the joystick (e.g., /dev/input/js0).' + ), + DeclareLaunchArgument( + 'config_filepath', + default_value=[ + os.path.join(os.environ.get("SNAP_COMMON"), 'joy_teleop.config.yaml') + ], + description='The file path to the configuration YAML file for the teleop_twist_joy node.' + ), + DeclareLaunchArgument( + 'publish_stamped_twist', + default_value='false', # Default set to false + description='Flag to control whether to publish geometry_msgs/TwistStamped messages instead of geometry_msgs/Twist.' + ), + DeclareLaunchArgument( + 'namespace', + default_value='', + description='Optional namespace to apply to the nodes and remapped topics. If left empty, no namespace is applied.' + ), + + Node( + package='joy', + executable='joy_node', + name='joy_node', + namespace=namespace, # Apply the namespace here + parameters=[{ + 'dev': joy_dev, + 'deadzone': 0.3, + 'autorepeat_rate': 20.0, + }] + ), + Node( + package='teleop_twist_joy', + executable='teleop_node', + name='teleop_twist_joy_node', + namespace=namespace, # Apply the namespace here + parameters=[config_filepath, {'publish_stamped_twist': publish_stamped_twist}], + remappings={('/cmd_vel', LaunchConfiguration('joy_vel'))}, # Remap the topic under the namespace + ), + ]) diff --git a/snap/local/joy_launcher.sh b/snap/local/joy_launcher.sh index b41f19a..731fb27 100755 --- a/snap/local/joy_launcher.sh +++ b/snap/local/joy_launcher.sh @@ -1,19 +1,38 @@ #!/bin/bash -e -ros2 run joy joy_node --ros-args --params-file $SNAP_COMMON/joy_params.yaml - -# # Retrieve the namespace using snapctl -# NAMESPACE="$(snapctl get ros.namespace)" - -# # Check if NAMESPACE is not set or is empty -# if [ -z "$NAMESPACE" ]; then -# # No namespace is set, run the launch command without the namespace argument -# ros2 launch teleop_twist_joy teleop-launch.py \ -# config_filepath:=$SNAP_COMMON/joy_teleop.config.yaml -# # ros2 launch teleop_twist_joy teleop-launch.py -# else -# # Namespace is set, include it in the launch command -# ros2 launch teleop_twist_joy teleop-launch.py \ -# config_filepath:=$SNAP_COMMON/joy_teleop.config.yaml --ros-args -r __ns:=/$NAMESPACE -# # ros2 launch teleop_twist_joy teleop-launch.py --ros-args -r __ns:=/$NAMESPACE -# fi +source $SNAP/usr/bin/utils.sh + +# Retrieve the namespace using snapctl +NAMESPACE="$(snapctl get ros.namespace)" + +# Initialize the launch arguments +LAUNCH_ARGS="config_filepath:=$SNAP_COMMON/joy_teleop.config.yaml" + +# If NAMESPACE is set, append the namespace argument +if [ -n "$NAMESPACE" ]; then + LAUNCH_ARGS="$LAUNCH_ARGS namespace:=/$NAMESPACE" +fi + +# If ROS_DISTRO is jazzy, append the publish_stamped_twist argument +if [ "$ROS_DISTRO" == "jazzy" ]; then + LAUNCH_ARGS="$LAUNCH_ARGS publish_stamped_twist:=true" +elif [ "$ROS_DISTRO" == "humble" ]; then + LAUNCH_ARGS="$LAUNCH_ARGS publish_stamped_twist:=false" +fi + +# export LD_LIBRARY_PATH="$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/pulseaudio:$LD_LIBRARY_PATH" + +# export LD_LIBRARY_PATH="$SNAP/usr/lib/aarch64-linux-gnu/pulseaudio/libpulsecommon-16.1.so:$LD_LIBRARY_PATH" + +# export LD_LIBRARY_PATH=/snap/${SNAP_NAME}/x1/opt/ros/snap/lib:/snap/${SNAP_NAME}/x1/opt/ros/humble/lib/aarch64-linux-gnu:/snap/${SNAP_NAME}/x1/opt/ros/humble/lib:/snap/${SNAP_NAME}/x1/opt/ros/underlay_ws/usr/lib:/snap/${SNAP_NAME}/x1/opt/ros/underlay_ws/usr/lib/aarch64-linux-gnu:/snap/${SNAP_NAME}/x1/opt/ros/underlay_ws/opt/ros/humble/lib/aarch64-linux-gnu:/snap/${SNAP_NAME}/x1/opt/ros/underlay_ws/opt/ros/humble/lib:/snap/${SNAP_NAME}/x1/usr/lib/aarch64-linux-gnu/pulseaudio:/var/lib/snapd/lib/gl:/var/lib/snapd/lib/gl32:/var/lib/snapd/void:/snap/${SNAP_NAME}/x1/usr/lib:/snap/${SNAP_NAME}/x1/usr/lib/aarch64-linux-gnu +# echo $LD_LIBRARY_PATH + +if [ "${LAUNCH_ARGS}" ]; then + # watch the log with: "journalctl -t husarion-depthai" + log_and_echo "Running with options: ${LAUNCH_ARGS}" +fi + +# Run the launch command with the constructed arguments +# ros2 launch teleop_twist_joy teleop-launch.py $LAUNCH_ARGS +ros2 launch $SNAP/usr/bin/joy.launch.py $LAUNCH_ARGS +# ros2 run teleop_twist_joy teleop_node --ros-args -p publish_stamped_twist:=true diff --git a/snap/local/joy_params.yaml b/snap/local/joy_params.yaml index 99dd41d..0ff0bb5 100644 --- a/snap/local/joy_params.yaml +++ b/snap/local/joy_params.yaml @@ -1,4 +1,6 @@ -joy_node: +# joy_node: +--- +/**: ros__parameters: dev: "/dev/input/js0" # Replace with your joystick device deadzone: 0.1 diff --git a/snap/local/joy_teleop.config.yaml b/snap/local/joy_teleop.config.yaml index a8783a6..be69fff 100644 --- a/snap/local/joy_teleop.config.yaml +++ b/snap/local/joy_teleop.config.yaml @@ -22,5 +22,6 @@ yaw: 0.4 require_enable_button: true - enable_button: 4 # TL shoulder button - enable_turbo_button: -1 # disabled \ No newline at end of file + enable_button: 4 # LB button + enable_turbo_button: 7 + publish_stamped_twist: true \ No newline at end of file diff --git a/snap/local/local-ros/check_daemon_running.sh b/snap/local/local-ros/check_daemon_running.sh deleted file mode 100755 index cbe1590..0000000 --- a/snap/local/local-ros/check_daemon_running.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -e - -# Define a function to log and echo messages -source $SNAP/usr/bin/utils.sh - -if snapctl services ${SNAP_NAME}.daemon | grep -qw active; then - log_and_echo "to run ${SNAP_NAME} snap interactively, you need to stop the daemon first, run:" - log_and_echo "sudo ${SNAP_NAME}.stop" - exit 1 -fi - -exec $@ \ No newline at end of file diff --git a/snap/local/local-ros/configure_hook_ros.sh b/snap/local/local-ros/configure_hook_ros.sh deleted file mode 100755 index 9104b2b..0000000 --- a/snap/local/local-ros/configure_hook_ros.sh +++ /dev/null @@ -1,176 +0,0 @@ -#!/bin/bash -e - -# The configure hook is called every time one the following actions happen: -# - initial snap installation -# - snap refresh -# - whenever the user runs snap set|unset to change a configuration option - -# Define a function to log and echo messages -source $SNAP/usr/bin/utils.sh - -# Function to check the type of the provided XML file -check_xml_profile_type() { - local xml_file="$1" - - if [[ ! -f "$xml_file" ]]; then - log_and_echo "File '$xml_file' does not exist." - return 1 - fi - - local root_element - local namespace - - # Extract the root element - root_element=$(yq '. | keys | .[1]' "$xml_file") - - # Extract the namespace based on the root element - if [[ "$root_element" == "CycloneDDS" ]]; then - namespace=$(yq .CycloneDDS."+@xmlns" "$xml_file") - elif [[ "$root_element" == "profiles" ]]; then - namespace=$(yq .profiles."+@xmlns" "$xml_file") - else - namespace="unknown" - fi - - # Remove quotes from the extracted values - root_element=${root_element//\"/} - namespace=${namespace//\"/} - - if [[ "$root_element" == "profiles" ]] && [[ "$namespace" == "http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles" ]]; then - echo "rmw_fastrtps_cpp" - elif [[ "$root_element" == "CycloneDDS" ]] && [[ "$namespace" == "https://cdds.io/config" ]]; then - echo "rmw_cyclonedds_cpp" - else - exit 1 - fi -} - -VALID_ROS_KEYS=("localhost-only" "domain-id" "transport" "namespace") - -# Call the validation function -validate_keys "ros" VALID_ROS_KEYS[@] - -ROS_LOCALHOST_ONLY="$(snapctl get ros.localhost-only)" -ROS_DOMAIN_ID="$(snapctl get ros.domain-id)" - -# Make sure ROS_LOCALHOST_ONLY is valid -VALID_ROS_LOCALHOST_ONLY_OPTIONS=(1 0) -validate_option "ros.localhost-only" VALID_ROS_LOCALHOST_ONLY_OPTIONS[@] - -# Make sure ROS_DOMAIN_ID is valid -# Make sure WEBUI_PORT is valid -SUPPORTED_RANGE=(0 232) -# Validate a specific port, for example, webui.port -validate_number "ros.domain-id" SUPPORTED_RANGE[@] - -# Get the ros.transport setting using snapctl -OPT="ros.transport" -TRANSPORT_SETTING="$(snapctl get ${OPT})" - -# Check if TRANSPORT_SETTING is "builtin" -if [ "$TRANSPORT_SETTING" == "builtin" ]; then - # Change the value to "rmw_fastrtps_cpp" - TRANSPORT_SETTING="rmw_fastrtps_cpp" -fi - -# Only exit with status 1 if conditions are not met -if [ "$TRANSPORT_SETTING" != "rmw_fastrtps_cpp" ] && [ "$TRANSPORT_SETTING" != "rmw_cyclonedds_cpp" ] && [ ! -f "${SNAP_COMMON}/${TRANSPORT_SETTING}.xml" ]; then - log_and_echo "'${SNAP_COMMON}/${TRANSPORT_SETTING}.xml' does not exist." - exit 1 -fi - -if [ "$TRANSPORT_SETTING" = "rmw_fastrtps_cpp" ] || [ "$TRANSPORT_SETTING" = "shm" ]; then - if ! snapctl is-connected shm-plug; then - log_and_echo "to use 'rmw_fastrtps_cpp' and 'shm' tranport shm-plug need to be connected, please run:" - log_and_echo "sudo snap connect ${SNAP_NAME}:shm-plug ${SNAP_NAME}:shm-slot" - exit 1 - fi -fi - -# # Make sure ros-humble-ros-base is connected -# ROS_PLUG="ros-humble-ros-base" - -# if ! snapctl is-connected ${ROS_PLUG}; then -# log_and_echo "Plug '${ROS_PLUG}' isn't connected. Please run:" -# log_and_echo "snap connect ${SNAP_NAME}:${ROS_PLUG} ${ROS_PLUG}:${ROS_PLUG}" -# exit 1 -# fi - -# Create the ${SNAP_COMMON}/ros.env file and export variables (for bash session running ROS2) -ROS_ENV_FILE="${SNAP_COMMON}/ros.env" - -# Create the ${SNAP_COMMON}/ros.env file and export variables (for bash session running ROS2) -ROS_SNAP_ARGS="${SNAP_COMMON}/ros_snap_args" - -echo "export ROS_DOMAIN_ID=${ROS_DOMAIN_ID}" > "${ROS_ENV_FILE}" -echo "export ROS_LOCALHOST_ONLY=${ROS_LOCALHOST_ONLY}" >> "${ROS_ENV_FILE}" - -NAMESPACE=$(snapctl get ros.namespace) - -# Check if the namespace is set and not empty -if [ -n "$NAMESPACE" ]; then - echo "ros.domain-id=${ROS_DOMAIN_ID} ros.localhost-only=${ROS_LOCALHOST_ONLY} ros.transport=${TRANSPORT_SETTING} ros.namespace=${NAMESPACE}" > "${ROS_SNAP_ARGS}" - echo "export ROS_NAMESPACE=${NAMESPACE}" >> "${ROS_ENV_FILE}" -else - echo "ros.domain-id=${ROS_DOMAIN_ID} ros.localhost-only=${ROS_LOCALHOST_ONLY} ros.transport=${TRANSPORT_SETTING} ros.namespace!" > "${ROS_SNAP_ARGS}" - echo "unset ROS_NAMESPACE" >> "${ROS_ENV_FILE}" -fi - -# Check the ros.transport setting and export the appropriate environment variable -if [ "$TRANSPORT_SETTING" != "rmw_fastrtps_cpp" ] && [ "$TRANSPORT_SETTING" != "rmw_cyclonedds_cpp" ]; then - profile_type=$(check_xml_profile_type "${SNAP_COMMON}/${TRANSPORT_SETTING}.xml") - if [[ "$profile_type" == "rmw_fastrtps_cpp" ]]; then - echo "unset CYCLONEDDS_URI" >> "${ROS_ENV_FILE}" - echo "export RMW_IMPLEMENTATION=${profile_type}" >> "${ROS_ENV_FILE}" - echo "export FASTRTPS_DEFAULT_PROFILES_FILE=${SNAP_COMMON}/${TRANSPORT_SETTING}.xml" >> "${ROS_ENV_FILE}" - elif [[ "$profile_type" == "rmw_cyclonedds_cpp" ]]; then - echo "unset FASTRTPS_DEFAULT_PROFILES_FILE" >> "${ROS_ENV_FILE}" - echo "export RMW_IMPLEMENTATION=${profile_type}" >> "${ROS_ENV_FILE}" - echo "export CYCLONEDDS_URI=file://${SNAP_COMMON}/${TRANSPORT_SETTING}.xml" >> "${ROS_ENV_FILE}" - else - log_and_echo "'${TRANSPORT_SETTING}' is not a supported value for '${OPT}'. Possible values are: rmw_fastrtps_cpp, rmw_cyclonedds_cpp, or a valid profile XML file." - exit 1 - fi -elif [ "$TRANSPORT_SETTING" == "rmw_fastrtps_cpp" ] || [ "$TRANSPORT_SETTING" == "rmw_cyclonedds_cpp" ]; then - echo "unset CYCLONEDDS_URI" >> "${ROS_ENV_FILE}" - echo "unset FASTRTPS_DEFAULT_PROFILES_FILE" >> "${ROS_ENV_FILE}" - echo "export RMW_IMPLEMENTATION=${TRANSPORT_SETTING}" >> "${ROS_ENV_FILE}" -fi - -# Define the path for the manage_ros_env.sh script -MANAGE_SCRIPT="${SNAP_COMMON}/manage_ros_env.sh" - -# Create the manage_ros_env.sh script in ${SNAP_COMMON} -cat << EOF > "${MANAGE_SCRIPT}" -#!/bin/bash - -ROS_ENV_FILE="${SNAP_COMMON}/ros.env" -SOURCE_LINE="source \${ROS_ENV_FILE}" - -add_source_to_bashrc() { - if ! grep -Fxq "\$SOURCE_LINE" ~/.bashrc; then - echo "\$SOURCE_LINE" >> ~/.bashrc - echo "Added '\$SOURCE_LINE' to ~/.bashrc" - else - echo "'\$SOURCE_LINE' is already in ~/.bashrc" - fi -} - -remove_source_from_bashrc() { - sed -i "\|\$SOURCE_LINE|d" ~/.bashrc - echo "Removed '\$SOURCE_LINE' from ~/.bashrc" -} - -case "\$1" in - remove) - remove_source_from_bashrc - ;; - add|*) - add_source_to_bashrc - ;; -esac -EOF - -# Make the manage_ros_env.sh script executable -chmod +x "${MANAGE_SCRIPT}" - diff --git a/snap/local/local-ros/install_hook_ros.sh b/snap/local/local-ros/install_hook_ros.sh deleted file mode 100755 index 86848fb..0000000 --- a/snap/local/local-ros/install_hook_ros.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -e - -# Define a function to log messages -source $SNAP/usr/bin/utils.sh - -snapctl set ros.transport="udp" -snapctl set ros.localhost-only=0 -snapctl set ros.domain-id=0 -snapctl set ros.namespace! # unset - -if ! snapctl is-connected ros-humble-ros-base; then - log "Plug 'ros-humble-ros-base' isn't connected, please run:" - log "sudo snap connect ${SNAP_NAME}:ros-humble-ros-base ros-humble-ros-base:ros-humble-ros-base" -fi - -if ! snapctl is-connected shm-plug; then - log "Plug 'shm-plug' isn't connected, please run:" - log "sudo snap connect ${SNAP_NAME}:shm-plug ${SNAP_NAME}:shm-slot" -fi - -# copy DDS config files to shared folder -cp -r $SNAP/usr/share/${SNAP_NAME}/config/*.xml ${SNAP_COMMON}/ \ No newline at end of file diff --git a/snap/local/local-ros/ros_setup.sh b/snap/local/local-ros/ros_setup.sh deleted file mode 100755 index 2fffe43..0000000 --- a/snap/local/local-ros/ros_setup.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -e - -source $SNAP_COMMON/ros.env - -exec $@ \ No newline at end of file diff --git a/snap/local/local-ros/shm.xml b/snap/local/local-ros/shm.xml deleted file mode 100644 index 4f2910f..0000000 --- a/snap/local/local-ros/shm.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - shm_transport - SHM - - - - - - - shm_transport - - false - - - diff --git a/snap/local/local-ros/udp-lo-cyclone.xml b/snap/local/local-ros/udp-lo-cyclone.xml deleted file mode 100644 index 6cdc91c..0000000 --- a/snap/local/local-ros/udp-lo-cyclone.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - lo - false - - - auto - 30 - - - - - - \ No newline at end of file diff --git a/snap/local/local-ros/udp-lo.xml b/snap/local/local-ros/udp-lo.xml deleted file mode 100644 index fd0d0b2..0000000 --- a/snap/local/local-ros/udp-lo.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - udp_transport_localhost - UDPv4 - -
127.0.0.1
-
-
-
- - - - - udp_transport_localhost - - false - - -
diff --git a/snap/local/local-ros/udp.xml b/snap/local/local-ros/udp.xml deleted file mode 100644 index 73e3e55..0000000 --- a/snap/local/local-ros/udp.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - udp_transport - UDPv4 - - - - - - - udp_transport - - false - - - diff --git a/snap/local/local-ros/utils.sh b/snap/local/local-ros/utils.sh deleted file mode 100755 index 7f05342..0000000 --- a/snap/local/local-ros/utils.sh +++ /dev/null @@ -1,224 +0,0 @@ -#!/bin/bash -e - -# Define a function to log and echo messages -log_and_echo() { - local message="$1" - local script_name=$(basename "$0") - # Log the message with logger - logger -t "${SNAP_NAME}" "${script_name}: $message" - # Echo the message to standard error - echo -e >&2 "$message" -} - -log() { - local message="$1" - local script_name=$(basename "$0") - # Log the message with logger - logger -t "${SNAP_NAME}" "${script_name}: $message" -} - -is_integer() { - expr "$1" : '-\?[0-9][0-9]*$' >/dev/null 2>&1 -} - -# Function to validate the option values -validate_option() { - local OPT=$1 - local VALID_OPTIONS=("${!2}") - - VALUE="$(snapctl get ${OPT})" - - # Create an associative array to check valid options - declare -A valid_options_map - for option in "${VALID_OPTIONS[@]}"; do - valid_options_map["$option"]=1 - done - - # Join the valid options with newlines - JOINED_OPTIONS=$(printf "%s\n" "${VALID_OPTIONS[@]}") - - if [ -n "${VALUE}" ]; then - if [[ -z "${valid_options_map[$VALUE]}" ]]; then - log_and_echo "'${VALUE}' is not a supported value for '${OPT}' parameter. Possible values are:\n${JOINED_OPTIONS}" - exit 1 - fi - fi -} - -# Function to validate configuration keys -validate_keys() { - local top_level_key=$1 - local valid_keys=("${!2}") - - # Get the current configuration keys - local config_keys=$(snapctl get "$top_level_key" | yq '. | keys' | sed 's/- //g' | tr -d '"') - - # Create an associative array to check valid keys - declare -A valid_keys_map - for key in "${valid_keys[@]}"; do - valid_keys_map["$key"]=1 - done - - # Join the valid options with newlines - JOINED_OPTIONS=$(printf "%s\n" "${valid_keys[@]}") - - # Iterate over the keys in the configuration - for key in $config_keys; do - # Check if the key is in the list of valid keys - if [[ -z "${valid_keys_map[$key]}" ]]; then - log_and_echo "'${key}' is not a supported value for '${top_level_key}' key. Possible values are:\n${JOINED_OPTIONS}" - exit 1 - fi - done -} - -validate_number() { - local value_key=$1 - local range=("${!2}") - local excluded_values=("${!3:-}") - - # Get the value using snapctl - local value=$(snapctl get "$value_key") - - # Extract the min and max range values - local min_value=${range[0]} - local max_value=${range[1]} - - # Join the excluded values with newlines if they exist - local joined_excluded_values - local exclude_message - if [ -n "$excluded_values" ]; then - joined_excluded_values=$(printf "%s\n" "${excluded_values[@]}") - exclude_message=" excluding:\n${joined_excluded_values[*]}" - else - exclude_message="" - fi - - # Check if the value is an integer - if ! [[ "$value" =~ ^[0-9]+$ ]]; then - log_and_echo "'${value}' is not a supported value for '${value_key}'. Possible values are integers between ${min_value} and ${max_value}.${exclude_message}" - exit 1 - fi - - # Check if the value is in the valid range - if [ "$value" -lt "$min_value" ] || [ "$value" -gt "$max_value" ]; then - log_and_echo "'${value}' is not a supported value for '${value_key}'. Possible values are integers between ${min_value} and ${max_value}.${exclude_message}" - exit 1 - fi - - # Check if the value is in the excluded list - if [ -n "$excluded_values" ]; then - for excluded_value in "${excluded_values[@]}"; do - if [ "$value" -eq "$excluded_value" ]; then - log_and_echo "'${value}' is not a supported value for '${value_key}'. Possible values are integers between ${min_value} and ${max_value}.${exclude_message}" - exit 1 - fi - done - fi -} - -validate_regex() { - local value_key=$1 - local regex=$2 - local error_message=$3 - - # Get the value using snapctl - local value=$(snapctl get "$value_key") - - # Check if the value matches the regex - if ! [[ "$value" =~ $regex ]]; then - log_and_echo "'${value}' is not a supported value for '${value_key}'. ${error_message}" - exit 1 - fi -} - -validate_path() { - local value_key=$1 - - # Get the value using snapctl - local config_path=$(snapctl get "$value_key") - - # Check if the path is a valid file - if [ ! -f "$config_path" ]; then - log_and_echo "The path specified in '$value_key' does not exist: '$config_path'." - exit 1 - fi -} - -validate_ipv4_addr() { - local value_key=$1 - - # Get the value using snapctl - local ip_address=$(snapctl get "$value_key") - local ip_address_regex='^(([0-9]{1,3}\.){3}[0-9]{1,3})$' - - if [[ "$ip_address" =~ $ip_address_regex ]]; then - # Split the IP address into its parts - IFS='.' read -r -a octets <<< "$ip_address" - - # Check each octet - for octet in "${octets[@]}"; do - if ((octet < 0 || octet > 255)); then - log_and_echo "Invalid format for '$value_key'. Each part of the IPv4 address must be between 0 and 255. Received: '$ip_address'." - exit 1 - fi - done - else - log_and_echo "Invalid format for '$value_key'. Expected format: a valid IPv4 address. Received: '$ip_address'." - exit 1 - fi -} - -# Universal function to validate serial ports -validate_serial_port() { - local port_key=$1 - - # Get the port value using snapctl - local port_value=$(snapctl get "$port_key") - - # Check if the value is "auto" or a valid serial port - if [ "$port_value" != "auto" ] && [ ! -e "$port_value" ]; then - log_and_echo "'${port_value}' is not a valid value for '${port_key}'. It must be 'auto' or a valid serial port in the /dev/ directory." - exit 1 - fi -} - -# Function to find the ttyUSB* device for the specified USB Vendor and Product ID -find_ttyUSB() { - # Extract port parameter, vendor, and product ID - PORT_PARAM="$1" - VENDOR_ID="$2" - PRODUCT_ID="$3" - - # Get the serial-port value using snapctl - SERIAL_PORT=$(snapctl get "$PORT_PARAM") - - if [ "$SERIAL_PORT" == "auto" ]; then - for device in /sys/bus/usb/devices/*; do - if [ -f "$device/idVendor" ]; then - current_vendor_id=$(cat "$device/idVendor") - if [ "$current_vendor_id" == "$VENDOR_ID" ]; then - if [ -z "$PRODUCT_ID" ] || ([ -f "$device/idProduct" ] && [ "$(cat "$device/idProduct")" == "$PRODUCT_ID" ]); then - # Look for ttyUSB device in the subdirectories - for subdir in "$device/"*; do - if [ -d "$subdir" ]; then - for tty in $(find "$subdir" -name "ttyUSB*" -print 2>/dev/null); do - if [ -e "$tty" ]; then - ttydev=$(basename "$tty") - echo "/dev/$ttydev" - return 0 - fi - done - fi - done - fi - fi - fi - done - echo "Error: Device with ID $VENDOR_ID:${PRODUCT_ID:-*} not found." - return 1 - else - echo "$SERIAL_PORT" - return 0 - fi -} \ No newline at end of file diff --git a/snap/local/rosbot-manipulator.launch.py b/snap/local/rosbot-manipulator.launch.py old mode 100644 new mode 100755 index 7e37ae6..80255c6 --- a/snap/local/rosbot-manipulator.launch.py +++ b/snap/local/rosbot-manipulator.launch.py @@ -236,12 +236,6 @@ def generate_launch_description(): namespace=namespace, ) - launch_joy_node = LaunchConfiguration("launch_joy_node") - declare_launch_joy_node_arg = DeclareLaunchArgument( - "launch_joy_node", - default_value="False", - ) - manipulator_usb_port = LaunchConfiguration("manipulator_usb_port") declare_manipulator_usb_port_arg = DeclareLaunchArgument( "manipulator_usb_port", @@ -329,7 +323,6 @@ def generate_launch_description(): ) ), launch_arguments={ - "launch_joy_node": launch_joy_node, "joy_servo_params_file": joy_servo_config, "joint1_limit_min": joint1_limit_min, "joint1_limit_max": joint1_limit_max, @@ -341,22 +334,6 @@ def generate_launch_description(): # Retrieve the SNAP_COMMON environment variable snap_common = os.environ.get('SNAP_COMMON', '/var/snap/rosbot-xl/common/') # Provide a default path in case it's not set - # Declare the parameters file launch argument - joy_params_file = LaunchConfiguration("params_file") - joy_params_file_arg = DeclareLaunchArgument( - "params_file", - default_value=os.path.join(snap_common, 'teleop_twist_joy_params.yaml') - ) - - # Node configuration for teleop_twist_joy - teleop_twist_joy = Node( - package='teleop_twist_joy', - executable='teleop_node', - name='teleop_twist_joy_node', - parameters=[joy_params_file], - output='screen', - namespace=namespace, - ) return LaunchDescription( [ @@ -370,7 +347,6 @@ def generate_launch_description(): declare_use_sim_arg, declare_simulation_engine_arg, declare_combined_launch_deprecated_arg, - declare_launch_joy_node_arg, declare_manipulator_usb_port_arg, declare_manipulator_baud_rate_arg, declare_joy_servo_config_arg, @@ -384,7 +360,5 @@ def generate_launch_description(): manipulator_controller_launch, moveit_launch, servo_launch, - joy_params_file_arg, - teleop_twist_joy ] ) diff --git a/snap/local/rosbot.launch.py b/snap/local/rosbot.launch.py old mode 100644 new mode 100755 index eac51d8..2029b5f --- a/snap/local/rosbot.launch.py +++ b/snap/local/rosbot.launch.py @@ -233,26 +233,6 @@ def generate_launch_description(): namespace=namespace, ) - # Retrieve the SNAP_COMMON environment variable - snap_common = os.environ.get('SNAP_COMMON', '/var/snap/rosbot-xl/common/') # Provide a default path in case it's not set - - # Declare the parameters file launch argument - joy_params_file = LaunchConfiguration("params_file") - joy_params_file_arg = DeclareLaunchArgument( - "params_file", - default_value=os.path.join(snap_common, 'teleop_twist_joy_params.yaml') - ) - - # Node configuration for teleop_twist_joy - teleop_twist_joy = Node( - package='teleop_twist_joy', - executable='teleop_node', - name='teleop_twist_joy_node', - parameters=[joy_params_file], - output='screen', - namespace=namespace, - ) - return LaunchDescription( [ declare_port_arg, @@ -270,7 +250,5 @@ def generate_launch_description(): robot_localization_node, laser_filter_node, OpaqueFunction(function=generate_microros_agent_node), - joy_params_file_arg, - teleop_twist_joy ] ) diff --git a/snap/local/start_launcher.sh b/snap/local/start_launcher.sh index a13d124..cccbc1e 100755 --- a/snap/local/start_launcher.sh +++ b/snap/local/start_launcher.sh @@ -5,3 +5,5 @@ source $SNAP/usr/bin/utils.sh log "Start ${SNAP_NAME}.daemon service" snapctl start --enable ${SNAP_NAME}.daemon 2>&1 || true +log "Start ${SNAP_NAME}.joy service" +snapctl start --enable ${SNAP_NAME}.joy 2>&1 || true \ No newline at end of file diff --git a/snap/local/start_web_ui_launcher.sh b/snap/local/start_web_ui_launcher.sh deleted file mode 100755 index 8c816dc..0000000 --- a/snap/local/start_web_ui_launcher.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -e - -# Define a function to log and echo messages -source $SNAP/usr/bin/utils.sh - -# Check if the script is being run as root -if [ "$(id -u)" -ne 0 ]; then - log_and_echo "Error: This script must be run as root." - exit 1 -fi - -snapctl start --enable ${SNAP_NAME}.web-ui 2>&1 || true -snapctl start --enable ${SNAP_NAME}.web-ws 2>&1 || true \ No newline at end of file diff --git a/snap/local/stop_launcher.sh b/snap/local/stop_launcher.sh index 9b40d4e..787f0b0 100755 --- a/snap/local/stop_launcher.sh +++ b/snap/local/stop_launcher.sh @@ -4,3 +4,6 @@ source $SNAP/usr/bin/utils.sh log "Stop ${SNAP_NAME}.daemon service" snapctl stop --disable ${SNAP_NAME}.daemon 2>&1 || true + +log "Stop ${SNAP_NAME}.joy service" +snapctl stop --disable ${SNAP_NAME}.joy 2>&1 || true \ No newline at end of file diff --git a/snap/local/stop_web_ui_launcher.sh b/snap/local/stop_web_ui_launcher.sh deleted file mode 100755 index d4dbe39..0000000 --- a/snap/local/stop_web_ui_launcher.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -e - -source $SNAP/usr/bin/utils.sh - -log "Stop Web UI" -snapctl stop --disable ${SNAP_NAME}.web-ui 2>&1 || true -snapctl stop --disable ${SNAP_NAME}.web-ws 2>&1 || true diff --git a/snap/local/teleop_twist_joy_launch.py b/snap/local/teleop_twist_joy_launch.py deleted file mode 100755 index ceca0d0..0000000 --- a/snap/local/teleop_twist_joy_launch.py +++ /dev/null @@ -1,42 +0,0 @@ -import os -from launch import LaunchDescription -from launch_ros.actions import Node -from launch.substitutions import LaunchConfiguration -from launch.actions import DeclareLaunchArgument - -def generate_launch_description(): - - # Retrieve the SNAP_COMMON environment variable - snap_common = os.environ.get('SNAP_COMMON', '/var/snap/rosbot-xl/common/') # Provide a default path in case it's not set - - namespace = LaunchConfiguration("namespace") - declare_namespace_arg = DeclareLaunchArgument( - "namespace", - default_value="", - description="Namespace for all topics", - ) - - # Declare the parameters file launch argument - params_file = LaunchConfiguration("params_file") - declare_params_file_arg = DeclareLaunchArgument( - "params_file", - default_value=os.path.join(snap_common, 'teleop_twist_joy_params.yaml') - ) - - # Node configuration for teleop_twist_joy - teleop_twist_joy_node = Node( - package='teleop_twist_joy', - executable='teleop_node', - name='teleop_twist_joy_node', - parameters=[params_file], - output='screen', - namespace=namespace, - ) - - return LaunchDescription( - [ - declare_namespace_arg, - declare_params_file_arg, - teleop_twist_joy_node, - ] - ) diff --git a/snap/local/teleop_twist_joy_launcher.sh b/snap/local/teleop_twist_joy_launcher.sh deleted file mode 100755 index 680f541..0000000 --- a/snap/local/teleop_twist_joy_launcher.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -e - -LAUNCH_OPTIONS="" - -# Retrieve the namespace using snapctl -NAMESPACE="$(snapctl get ros.namespace)" - -# Check if NAMESPACE is not set or is empty -if [ -n "$NAMESPACE" ]; then - LAUNCH_OPTIONS+="namespace:=${NAMESPACE} " -fi - -ros2 launch $SNAP/usr/bin/teleop_twist_joy_launch.py ${LAUNCH_OPTIONS} diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 877ee14..d7be38a 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -114,14 +114,6 @@ contact: https://github.com/husarion/rosbot-xl-snap/issues issues: https://github.com/husarion/rosbot-xl-snap/issues website: https://husarion.com/manuals/rosbot-xl/overview/ -architectures: - - build-on: amd64 - build-for: amd64 - # - build-on: amd64 - # build-for: arm64 - - build-on: arm64 - build-for: arm64 - slots: shm-slot: interface: shared-memory @@ -173,22 +165,13 @@ apps: command: usr/bin/joy_launcher.sh command-chain: [usr/bin/ros_setup.sh] daemon: simple - install-mode: disable + install-mode: enable environment: LD_LIBRARY_PATH: "$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/pulseaudio:$LD_LIBRARY_PATH" plugs: [hardware-observe, joystick, network, network-bind, shm-plug] slots: [shm-slot] extensions: [ros2-humble-ros-base] - teleop-twist-joy: - command: usr/bin/teleop_twist_joy_launcher.sh - command-chain: [usr/bin/ros_setup.sh] - daemon: simple - install-mode: enable - plugs: [network, network-bind, shm-plug] - slots: [shm-slot] - extensions: [ros2-humble-ros-base] - arm-activate: command: usr/bin/arm_activate_launcher.sh active command-chain: [usr/bin/ros_setup.sh] @@ -224,27 +207,6 @@ apps: command: usr/bin/ftdi_eeprom_conf_launcher.sh plugs: [raw-usb, network-bind] - web-ui: - command: usr/bin/caddy_launcher.sh - daemon: simple - install-mode: disable - plugs: [network, network-bind] - - web-ws: - command: usr/bin/bridge_launcher.sh - command-chain: [usr/bin/ros_setup.sh] - daemon: simple - install-mode: disable - plugs: [network, network-bind, shm-plug] - slots: [shm-slot] - extensions: [ros2-humble-ros-base] - - start-web-ui: - command: usr/bin/start_web_ui_launcher.sh - - stop-web-ui: - command: usr/bin/stop_web_ui_launcher.sh - parts: # rosbot-xl: # plugin: colcon @@ -283,10 +245,12 @@ parts: source-branch: "1.1.2" build-packages: - python3-vcstool + - python3-ftdi stage-packages: - stm32flash - libusb-1.0-0 - usbutils + - python3-ftdi - ros-humble-rmw-cyclonedds-cpp override-pull: | craftctl default @@ -316,70 +280,18 @@ parts: plugin: nil stage-packages: - ros-humble-teleop-twist-keyboard - - ros-humble-teleop-twist-joy - - # web-ui: - # plugin: nil - # build-packages: - # - curl - # build-environment: - # - CADDY_RELEASE: "2.7.4" - # override-build: | - # set -x - # craftctl default - # curl -L https://github.com/caddyserver/caddy/releases/download/v${CADDY_RELEASE}/caddy_${CADDY_RELEASE}_linux_${CRAFT_ARCH_BUILD_FOR}.deb -o caddy.deb - # dpkg -i caddy.deb + # - ros-humble-teleop-twist-joy # 2024-09-13: in apt repository is 2.6.0 version, and stamped messages were introduced in 2.6.1 (https://github.com/ros2/teleop_twist_joy) - web-server: - plugin: dump - source: - - on amd64: https://github.com/caddyserver/caddy/releases/download/v2.7.4/caddy_2.7.4_linux_amd64.deb - - on arm64: https://github.com/caddyserver/caddy/releases/download/v2.7.4/caddy_2.7.4_linux_arm64.deb - source-type: deb - - web-ui: - plugin: nil - build-packages: - - curl - override-build: | - # Use the Snapcraft build directory which is writable - cd $SNAPCRAFT_PART_BUILD - curl -L https://github.com/husarion/foxglove-studio/releases/download/v1.0.1/web-build.tar.gz -o foxglove.tar.gz - mkdir -p www/foxglove - tar -xzf foxglove.tar.gz -C www/foxglove - rm foxglove.tar.gz - mkdir -p $SNAPCRAFT_PART_INSTALL/usr/local - cp -r www $SNAPCRAFT_PART_INSTALL/usr/local - - web-ws: - plugin: nil - stage-packages: - - ros-humble-foxglove-bridge - - ros-humble-rosbridge-server - - ros-humble-bond - - ros-humble-control-msgs - - ros-humble-controller-manager-msgs - - ros-humble-image-transport-plugins - - ros-humble-map-msgs - - ros-humble-nav2-msgs - - ros-humble-tf2-msgs - - ros-humble-robot-localization - - yq: - plugin: nil - override-build: | - craftctl default - - YQ_VERSION="v4.35.1" - TARGETARCH=$CRAFT_ARCH_BUILD_FOR - curl -L "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_${TARGETARCH}" -o $CRAFT_PART_BUILD/yq - override-prime: | - craftctl default - - cp $CRAFT_PART_BUILD/yq $CRAFT_PRIME/usr/bin/yq - chmod +x $CRAFT_PRIME/usr/bin/yq - build-packages: - - curl + # after version 2.6.1+ will be available in apt repository, remove it: + teleop-twist-joy: + plugin: colcon + source: https://github.com/ros2/teleop_twist_joy.git + stage: + - "-opt/ros/snap/local_setup.sh" + - "-opt/ros/snap/setup.bash" + - "-opt/ros/snap/setup.ps1" + - "-opt/ros/snap/setup.sh" + - "-opt/ros/snap/setup.zsh" db-server: plugin: nil @@ -388,22 +300,31 @@ parts: - curl - netcat - pip3-dependencies: - plugin: python - source: . - build-packages: - - python3-pip - python-packages: - - pyftdi - - # copy local scripts to the snap usr/bin - local-files-ros: + husarion-snap-common: plugin: dump - source: snap/local/local-ros/ + source: https://github.com/husarion/husarion-snap-common + source-branch: "0.5.0" + source-type: git + build-environment: + - YQ_VERSION: "v4.35.1" + build-packages: + - curl organize: - '*.sh': usr/bin/ - '*.xml': usr/share/rosbot-xl/config/ - + 'local-ros/*.sh': usr/bin/ + 'local-ros/*.xml': usr/share/husarion-snap-common/config/ + 'local-ros/ros.env': usr/share/husarion-snap-common/config/ + override-build: | + craftctl default + curl -L "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_${CRAFT_ARCH_BUILD_FOR}" -o $CRAFT_PART_BUILD/yq + override-prime: | + craftctl default + cp $CRAFT_PART_BUILD/yq $CRAFT_PRIME/usr/bin/yq + chmod +x $CRAFT_PRIME/usr/bin/yq + rm -rf $CRAFT_PRIME/local-ros + stage: + - "-usr/bin/start_launcher.sh" + - "-usr/bin/stop_launcher.sh" + local-files: plugin: dump source: snap/local/ @@ -413,4 +334,4 @@ parts: '*.yaml': usr/share/rosbot-xl/config/ '*.xml': usr/share/rosbot-xl/config/ '*.json': usr/share/rosbot-xl/config/ - 'Caddyfile': usr/share/rosbot-xl/config/ + 'Caddyfile': usr/share/rosbot-xl/config/ \ No newline at end of file diff --git a/snapcraft_template.yaml.jinja2 b/snapcraft_template.yaml.jinja2 index f22912b..efbb357 100644 --- a/snapcraft_template.yaml.jinja2 +++ b/snapcraft_template.yaml.jinja2 @@ -114,14 +114,6 @@ contact: https://github.com/husarion/rosbot-xl-snap/issues issues: https://github.com/husarion/rosbot-xl-snap/issues website: https://husarion.com/manuals/rosbot-xl/overview/ -architectures: - - build-on: amd64 - build-for: amd64 - # - build-on: amd64 - # build-for: arm64 - - build-on: arm64 - build-for: arm64 - slots: shm-slot: interface: shared-memory @@ -173,22 +165,13 @@ apps: command: usr/bin/joy_launcher.sh command-chain: [usr/bin/ros_setup.sh] daemon: simple - install-mode: disable + install-mode: enable environment: LD_LIBRARY_PATH: "$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/pulseaudio:$LD_LIBRARY_PATH" plugs: [hardware-observe, joystick, network, network-bind, shm-plug] slots: [shm-slot] extensions: [ros2-{{ ros_distro }}-ros-base] - teleop-twist-joy: - command: usr/bin/teleop_twist_joy_launcher.sh - command-chain: [usr/bin/ros_setup.sh] - daemon: simple - install-mode: enable - plugs: [network, network-bind, shm-plug] - slots: [shm-slot] - extensions: [ros2-{{ ros_distro }}-ros-base] - arm-activate: command: usr/bin/arm_activate_launcher.sh active command-chain: [usr/bin/ros_setup.sh] @@ -224,27 +207,6 @@ apps: command: usr/bin/ftdi_eeprom_conf_launcher.sh plugs: [raw-usb, network-bind] - web-ui: - command: usr/bin/caddy_launcher.sh - daemon: simple - install-mode: disable - plugs: [network, network-bind] - - web-ws: - command: usr/bin/bridge_launcher.sh - command-chain: [usr/bin/ros_setup.sh] - daemon: simple - install-mode: disable - plugs: [network, network-bind, shm-plug] - slots: [shm-slot] - extensions: [ros2-{{ ros_distro }}-ros-base] - - start-web-ui: - command: usr/bin/start_web_ui_launcher.sh - - stop-web-ui: - command: usr/bin/stop_web_ui_launcher.sh - parts: # rosbot-xl: # plugin: colcon @@ -283,10 +245,12 @@ parts: source-branch: "1.1.2" build-packages: - python3-vcstool + - python3-ftdi stage-packages: - stm32flash - libusb-1.0-0 - usbutils + - python3-ftdi - ros-{{ ros_distro }}-rmw-cyclonedds-cpp override-pull: | craftctl default @@ -316,70 +280,18 @@ parts: plugin: nil stage-packages: - ros-{{ ros_distro }}-teleop-twist-keyboard - - ros-{{ ros_distro }}-teleop-twist-joy - - # web-ui: - # plugin: nil - # build-packages: - # - curl - # build-environment: - # - CADDY_RELEASE: "2.7.4" - # override-build: | - # set -x - # craftctl default - # curl -L https://github.com/caddyserver/caddy/releases/download/v${CADDY_RELEASE}/caddy_${CADDY_RELEASE}_linux_${CRAFT_ARCH_BUILD_FOR}.deb -o caddy.deb - # dpkg -i caddy.deb + # - ros-{{ ros_distro }}-teleop-twist-joy # 2024-09-13: in apt repository is 2.6.0 version, and stamped messages were introduced in 2.6.1 (https://github.com/ros2/teleop_twist_joy) - web-server: - plugin: dump - source: - - on amd64: https://github.com/caddyserver/caddy/releases/download/v2.7.4/caddy_2.7.4_linux_amd64.deb - - on arm64: https://github.com/caddyserver/caddy/releases/download/v2.7.4/caddy_2.7.4_linux_arm64.deb - source-type: deb - - web-ui: - plugin: nil - build-packages: - - curl - override-build: | - # Use the Snapcraft build directory which is writable - cd $SNAPCRAFT_PART_BUILD - curl -L https://github.com/husarion/foxglove-studio/releases/download/v1.0.1/web-build.tar.gz -o foxglove.tar.gz - mkdir -p www/foxglove - tar -xzf foxglove.tar.gz -C www/foxglove - rm foxglove.tar.gz - mkdir -p $SNAPCRAFT_PART_INSTALL/usr/local - cp -r www $SNAPCRAFT_PART_INSTALL/usr/local - - web-ws: - plugin: nil - stage-packages: - - ros-{{ ros_distro }}-foxglove-bridge - - ros-{{ ros_distro }}-rosbridge-server - - ros-{{ ros_distro }}-bond - - ros-{{ ros_distro }}-control-msgs - - ros-{{ ros_distro }}-controller-manager-msgs - - ros-{{ ros_distro }}-image-transport-plugins - - ros-{{ ros_distro }}-map-msgs - - ros-{{ ros_distro }}-nav2-msgs - - ros-{{ ros_distro }}-tf2-msgs - - ros-{{ ros_distro }}-robot-localization - - yq: - plugin: nil - override-build: | - craftctl default - - YQ_VERSION="v4.35.1" - TARGETARCH=$CRAFT_ARCH_BUILD_FOR - curl -L "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_${TARGETARCH}" -o $CRAFT_PART_BUILD/yq - override-prime: | - craftctl default - - cp $CRAFT_PART_BUILD/yq $CRAFT_PRIME/usr/bin/yq - chmod +x $CRAFT_PRIME/usr/bin/yq - build-packages: - - curl + # after version 2.6.1+ will be available in apt repository, remove it: + teleop-twist-joy: + plugin: colcon + source: https://github.com/ros2/teleop_twist_joy.git + stage: + - "-opt/ros/snap/local_setup.sh" + - "-opt/ros/snap/setup.bash" + - "-opt/ros/snap/setup.ps1" + - "-opt/ros/snap/setup.sh" + - "-opt/ros/snap/setup.zsh" db-server: plugin: nil @@ -388,22 +300,31 @@ parts: - curl - netcat - pip3-dependencies: - plugin: python - source: . - build-packages: - - python3-pip - python-packages: - - pyftdi - - # copy local scripts to the snap usr/bin - local-files-ros: + husarion-snap-common: plugin: dump - source: snap/local/local-ros/ + source: https://github.com/husarion/husarion-snap-common + source-branch: "0.5.0" + source-type: git + build-environment: + - YQ_VERSION: "v4.35.1" + build-packages: + - curl organize: - '*.sh': usr/bin/ - '*.xml': usr/share/rosbot-xl/config/ - + 'local-ros/*.sh': usr/bin/ + 'local-ros/*.xml': usr/share/husarion-snap-common/config/ + 'local-ros/ros.env': usr/share/husarion-snap-common/config/ + override-build: | + craftctl default + curl -L "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_${CRAFT_ARCH_BUILD_FOR}" -o $CRAFT_PART_BUILD/yq + override-prime: | + craftctl default + cp $CRAFT_PART_BUILD/yq $CRAFT_PRIME/usr/bin/yq + chmod +x $CRAFT_PRIME/usr/bin/yq + rm -rf $CRAFT_PRIME/local-ros + stage: + - "-usr/bin/start_launcher.sh" + - "-usr/bin/stop_launcher.sh" + local-files: plugin: dump source: snap/local/ From fe71f14514b2ccd1de904a45caef89b244515f4f Mon Sep 17 00:00:00 2001 From: dominikn Date: Mon, 16 Sep 2024 17:26:11 +0000 Subject: [PATCH 2/3] using husarion-snap-common --- demo/compose.yaml | 13 +------------ demo/config/joy2twist.yaml | 22 ---------------------- demo/net.env | 4 ++-- snap/local/ftdi_eeprom_conf_launcher.sh | 2 ++ snap/local/launcher.sh | 2 +- snap/local/reset_stm32_launcher.sh | 2 ++ snap/snapcraft.yaml | 2 +- snapcraft_template.yaml.jinja2 | 6 ++++-- 8 files changed, 13 insertions(+), 40 deletions(-) delete mode 100644 demo/config/joy2twist.yaml diff --git a/demo/compose.yaml b/demo/compose.yaml index 6cd9d00..abac822 100644 --- a/demo/compose.yaml +++ b/demo/compose.yaml @@ -9,7 +9,7 @@ x-net-config: x-gpu-config: &gpu-config - runtime: nvidia + # runtime: nvidia environment: - DISPLAY=${DISPLAY:?err} - NVIDIA_VISIBLE_DEVICES=all @@ -23,16 +23,5 @@ services: container_name: rviz volumes: - /tmp/.X11-unix:/tmp/.X11-unix:rw - - ./config/rosbot_xl.rviz:/ros2_ws/install/rosbot_xl_manipulation_moveit/share/rosbot_xl_manipulation_moveit/config/moveit.rviz command: ros2 launch rosbot_xl_manipulation_moveit rviz.launch.py - joy2twist: - image: husarion/joy2twist:humble-1.0.0-20230204-stable - <<: *net-config - devices: - - /dev/input - volumes: - - ./config/joy2twist.yaml:/joy2twist.yaml - command: > - ros2 launch joy2twist gamepad_controller.launch.py - joy2twist_params_file:=/joy2twist.yaml \ No newline at end of file diff --git a/demo/config/joy2twist.yaml b/demo/config/joy2twist.yaml deleted file mode 100644 index 4806940..0000000 --- a/demo/config/joy2twist.yaml +++ /dev/null @@ -1,22 +0,0 @@ -/**: - ros__parameters: - linear_velocity_factor: - fast: 1.0 - regular: 0.5 - slow: 0.2 - - angular_velocity_factor: - fast: 1.5 - regular: 0.8 - slow: 0.4 - - # This button mapping should be adjusted to the specific controller - # The following map is suited for Logitech F710 - button_index_map: - axis: - angular_z: 2 # Right joystick - linear_x: 1 # Left joystick - linear_y: 0 # Left joystick - dead_man_switch: 4 # LB - fast_mode: 7 # RT - slow_mode: 5 # RB diff --git a/demo/net.env b/demo/net.env index a498c9c..63b7048 100644 --- a/demo/net.env +++ b/demo/net.env @@ -3,10 +3,10 @@ # ======================================= # 1. Fast DDS + LAN -# RMW_IMPLEMENTATION=rmw_fastrtps_cpp +RMW_IMPLEMENTATION=rmw_fastrtps_cpp # 2. Cyclone DDS + LAN -RMW_IMPLEMENTATION=rmw_cyclonedds_cpp +# RMW_IMPLEMENTATION=rmw_cyclonedds_cpp # 3. Fast DDS + VPN # RMW_IMPLEMENTATION=rmw_fastrtps_cpp diff --git a/snap/local/ftdi_eeprom_conf_launcher.sh b/snap/local/ftdi_eeprom_conf_launcher.sh index 34854ef..e2331fc 100755 --- a/snap/local/ftdi_eeprom_conf_launcher.sh +++ b/snap/local/ftdi_eeprom_conf_launcher.sh @@ -8,4 +8,6 @@ if [ "$(id -u)" -ne 0 ]; then exit 1 fi +export PYTHONPATH=$SNAP/usr/lib/python3/dist-packages + $SNAP/usr/bin/ftdi_eeprom_conf.py \ No newline at end of file diff --git a/snap/local/launcher.sh b/snap/local/launcher.sh index 7c8fe1e..d137056 100755 --- a/snap/local/launcher.sh +++ b/snap/local/launcher.sh @@ -35,7 +35,7 @@ if [ "${VALUE}" == "basic" ]; then ros2 launch rosbot_xl_bringup bringup.launch.py ${LAUNCH_OPTIONS} elif [ "${VALUE}" == "manipulation" ]; then # Check if SERIAL_PORT is set to auto or specified - SERIAL_PORT=$(find_ttyUSB driver.manipulator-serial-port "0403" "6014") + SERIAL_PORT=$(find_usb_device "ttyUSB" driver.manipulator-serial-port "0403" "6014") if [ $? -ne 0 ]; then log_and_echo "Failed to find the serial port." exit 1 diff --git a/snap/local/reset_stm32_launcher.sh b/snap/local/reset_stm32_launcher.sh index 7644967..c57c211 100755 --- a/snap/local/reset_stm32_launcher.sh +++ b/snap/local/reset_stm32_launcher.sh @@ -8,4 +8,6 @@ if [ "$(id -u)" -ne 0 ]; then exit 1 fi +export PYTHONPATH=$SNAP/usr/lib/python3/dist-packages + $SNAP/usr/bin/reset_stm32.py \ No newline at end of file diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index d7be38a..f1b46ae 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -324,7 +324,7 @@ parts: stage: - "-usr/bin/start_launcher.sh" - "-usr/bin/stop_launcher.sh" - + local-files: plugin: dump source: snap/local/ diff --git a/snapcraft_template.yaml.jinja2 b/snapcraft_template.yaml.jinja2 index efbb357..06a3d46 100644 --- a/snapcraft_template.yaml.jinja2 +++ b/snapcraft_template.yaml.jinja2 @@ -11,7 +11,7 @@ description: | To install this snap on the Single Board Computer (SBC) within the ROSbot XL chassis, follow these steps: 1. Connect the SBC to the Digital Board inside ROSbot XL using an Ethernet cable. - 2. Configure the Ethernet Interface with the static IP address `192.168.77.2` (port `8888` on this IP is used by the firmware). + 2. Configure the Ethernet Interface with the static IP address `192.168.77.2`. 3. Run the following command to install the snap: snap install rosbot-xl @@ -25,6 +25,8 @@ description: | * `ros`: `{...}` * `webui`: `{...}` + The `configuration` key can be set to `basic` or `manipulation` (for ROSbot XL with OpenManipulator-X). + The `ros` contains the following keys: * `ros.domain-id`: `0` - Sets the `ROS_DOMAIN_ID` environment variable for the ROS driver. @@ -324,7 +326,7 @@ parts: stage: - "-usr/bin/start_launcher.sh" - "-usr/bin/stop_launcher.sh" - + local-files: plugin: dump source: snap/local/ From ac182c00e8d00286fdb4a60049ea4fbf541dfad2 Mon Sep 17 00:00:00 2001 From: dominikn Date: Mon, 16 Sep 2024 17:29:01 +0000 Subject: [PATCH 3/3] added utility scripts for generating store credentials --- .gitignore | 3 ++- justfile | 14 +++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 98b74d6..8c3a6b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.snap .snapcraft_store_credentials.txt squashfs-root/ -**/snapcraft.yaml \ No newline at end of file +**/snapcraft.yaml +exported.txt \ No newline at end of file diff --git a/justfile b/justfile index d978061..43a696e 100644 --- a/justfile +++ b/justfile @@ -190,4 +190,16 @@ iterate target="jazzy": remove-logs: #!/bin/bash sudo rm -rf /var/log/journal/* - sudo systemctl restart systemd-journald \ No newline at end of file + sudo systemctl restart systemd-journald + +prepare-store-credentials: + #!/bin/bash + snapcraft export-login --snaps=rosbot-xl \ + --acls package_access,package_push,package_update,package_release \ + exported.txt + +publish: + #!/bin/bash + export SNAPCRAFT_STORE_CREDENTIALS=$(cat exported.txt) + snapcraft login + snapcraft upload --release edge rosbot-xl*.snap \ No newline at end of file