From 21e685807b73d3244f673860c39f8766f5c5a9ef Mon Sep 17 00:00:00 2001 From: Dominik Nowak Date: Fri, 31 May 2024 17:48:52 +0200 Subject: [PATCH] Dev (#1) * working ffmpeg and namespaces --- .github/workflows/snap.yaml | 61 +++++++ .gitignore | 3 +- README.md | 151 +++++++++++++++- compose.yaml | 11 -- demo/compose.yaml | 40 +++++ demo/default.rviz | 149 ++++++++++++++++ demo/rviz.launch.py | 52 ++++++ justfile | 83 +++++++++ snap/hooks/configure | 104 ++++------- snap/hooks/connect-plug-ros-humble-ros-base | 6 +- .../hooks/disconnect-plug-ros-humble-ros-base | 2 - snap/hooks/install | 45 +++-- snap/local/depthai.launch.py | 164 ++++++++++++++++++ ...low-bandwidth.yaml => depthai_params.yaml} | 6 +- snap/local/ffmpeg_params_template.yaml | 11 ++ snap/local/launcher.sh | 55 ++++-- .../{ => ros_common}/check_daemon_running.sh | 2 +- snap/local/ros_common/configure_hook_ros.sh | 76 ++++++++ snap/local/ros_common/install_hook_ros.sh | 26 +++ snap/local/ros_common/ros_setup.sh | 28 +++ .../{shm-only.xml => ros_common/shm.xml} | 0 .../{udp-only.xml => ros_common/udp.xml} | 0 snap/local/ros_setup.sh | 46 ----- snap/snapcraft.yaml | 97 +++++++++-- 24 files changed, 1023 insertions(+), 195 deletions(-) create mode 100644 .github/workflows/snap.yaml delete mode 100644 compose.yaml create mode 100644 demo/compose.yaml create mode 100644 demo/default.rviz create mode 100644 demo/rviz.launch.py create mode 100644 justfile create mode 100755 snap/local/depthai.launch.py rename snap/local/{oak-1-low-bandwidth.yaml => depthai_params.yaml} (96%) create mode 100644 snap/local/ffmpeg_params_template.yaml rename snap/local/{ => ros_common}/check_daemon_running.sh (84%) create mode 100755 snap/local/ros_common/configure_hook_ros.sh create mode 100755 snap/local/ros_common/install_hook_ros.sh create mode 100755 snap/local/ros_common/ros_setup.sh rename snap/local/{shm-only.xml => ros_common/shm.xml} (100%) rename snap/local/{udp-only.xml => ros_common/udp.xml} (100%) delete mode 100755 snap/local/ros_setup.sh diff --git a/.github/workflows/snap.yaml b/.github/workflows/snap.yaml new file mode 100644 index 0000000..a3ac628 --- /dev/null +++ b/.github/workflows/snap.yaml @@ -0,0 +1,61 @@ +name: snap +on: + push: + tags: + - '*' + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + outputs: + snap-file: ${{ steps.build-snap.outputs.snap }} + steps: + + - uses: actions/checkout@v3 + with: + fetch-tags: true + + # Build the snap + - uses: snapcore/action-build@v1 + with: + snapcraft-channel: latest/edge + id: build-snap + env: + SNAPCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS: 1 + + # Make sure the snap is installable + - run: | + sudo snap install --dangerous ${{ steps.build-snap.outputs.snap }} + + # Save snap for subsequent job(s) + - uses: actions/upload-artifact@v3 + with: + name: husarion-depthai-snap + path: ${{ steps.build-snap.outputs.snap }} + + publish: + if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') + needs: build + runs-on: ubuntu-latest + steps: + + # Retrieve the snap + - uses: actions/download-artifact@v3 + with: + name: husarion-depthai-snap + path: . + + # Publish the snap on the store + # by default on 'edge' but on 'candidate' for tags + - uses: snapcore/action-publish@v1 + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.STORE_LOGIN }} + with: + snap: ${{needs.build.outputs.snap-file}} + release: ${{ startsWith(github.ref, 'refs/tags/') && 'candidate' || 'edge'}} diff --git a/.gitignore b/.gitignore index 4817425..3542432 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ squashfs-root/ -husarion-depthai* \ No newline at end of file +husarion-depthai* +exported.txt \ No newline at end of file diff --git a/README.md b/README.md index fb9ad60..91403e2 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,149 @@ -# depthai-snap -Building husarion-depthai snap for depthai-ros package +# husarion-depthai-snap + +Snap for OAK-x cameras customized for Husarion robots + +## Apps + +| app | description | +| - | - | +| `husarion-depthai.start` | Start the `husarion-depthai.daemon` service | +| `husarion-depthai.stop` | Stop the `husarion-depthai.daemon` service | +| `husarion-depthai` | Start the application in the foreground (run in the current terminal). Remember to stop the daemon first | + +## Setup FFMPEG + +The default values for `ffmpeg-image-transport` are: + +```bash +$ sudo snap get husarion-depthai driver.ffmpeg-image-transport +Key Value +driver.ffmpeg-image-transport.encoding libx264 +driver.ffmpeg-image-transport.preset ultrafast +driver.ffmpeg-image-transport.tune zerolatency +``` + +to check available options run: + +```bash +ffmpeg -encoders +``` + +find the list of available presets by running + +```bash +ffmpeg -h encoder=$SELECTED_ENCODER` +``` + +## Setup Astra Params + +Default astra params are stored in the following file: + +```bash +$ sudo snap get husarion-depthai driver.params-file +/var/snap/husarion-depthai/common/depthai_params.yaml +``` + +The default `depthai_params.yaml` file content: + +```yaml +--- +/**: + ros__parameters: + camera: + i_calibration_dump: false + i_enable_imu: false + i_enable_ir: false + i_external_calibration_path: '' + i_floodlight_brightness: 0 + i_ip: '' + i_laser_dot_brightness: 800 + i_mx_id: '' + i_nn_type: none + i_pipeline_dump: false + i_pipeline_type: RGB + i_publish_tf_from_calibration: false + i_restart_on_diagnostics_error: false + i_usb_port_id: '' + i_usb_speed: SUPER_PLUS + diagnostic_updater: + period: 1.0 + imu: + i_acc_cov: 0.0 + i_acc_freq: 400 + i_batch_report_threshold: 5 + i_enable_rotation: false + i_get_base_device_timestamp: false + i_gyro_cov: 0.0 + i_gyro_freq: 400 + i_mag_cov: 0.0 + i_max_batch_reports: 10 + i_message_type: IMU + i_rot_cov: -1.0 + i_sync_method: LINEAR_INTERPOLATE_ACCEL + i_update_ros_base_time_on_ros_msg: false + rgb: + i_add_exposure_offset: false + i_board_socket_id: 0 + i_calibration_file: '' + i_disable_node: false + i_enable_feature_tracker: false + i_enable_lazy_publisher: false #true + i_enable_nn: false + i_enable_preview: false + i_exposure_offset: 0 + i_fps: 20.0 + i_fsync_continuous: false + i_fsync_trigger: false + i_get_base_device_timestamp: false + i_height: 432 #720 + i_interleaved: false + i_isp_den: 5 #3 #3 valid if i_output_isp: true + i_isp_num: 2 #2 valid if i_output_isp: true + i_keep_preview_aspect_ratio: true + i_low_bandwidth: true #false + i_low_bandwidth_quality: 20 + i_max_q_size: 30 + i_output_isp: true + i_preview_height: 300 + i_preview_size: 300 + i_preview_width: 300 + i_publish_topic: true + i_resolution: 1080P + i_reverse_stereo_socket_order: false + i_sensor_img_orientation: AUTO + i_set_isp3a_fps: false + i_set_isp_scale: true + i_simulate_from_topic: false + i_simulated_topic_name: '' + i_update_ros_base_time_on_ros_msg: false + i_width: 768 #1280 + r_exposure: 20000 + r_focus: 1 + r_iso: 800 + r_set_man_exposure: false + r_set_man_focus: false + r_set_man_whitebalance: false + r_whitebalance: 3300 + use_sim_time: false + +``` + +To set a new params create a copy of the `astra-params.yaml` file: + +```bash +sudo cp \ +/var/snap/husarion-depthai/common/depthai_params.yaml \ +/var/snap/husarion-depthai/common/depthai_params2.yaml +``` + +Modify the content of the `astra-params2.yaml` file, eg: + +```bash +sudo vim /var/snap/husarion-depthai/common/depthai_params2.yaml +``` + +And set the new path to the config file: + +```bash +sudo snap set husarion-depthai driver.params-file=/var/snap/husarion-depthai/common/depthai_params2.yaml +``` \ No newline at end of file diff --git a/compose.yaml b/compose.yaml deleted file mode 100644 index b5a953d..0000000 --- a/compose.yaml +++ /dev/null @@ -1,11 +0,0 @@ -services: - luxonis: - image: husarion/depthai:humble-2.8.1-20240127 - volumes: - - /dev/bus/usb:/dev/bus/usb - - ./squashfs-root/usr/share/husarion-depthai/config/oak-1-low-bandwidth.yaml:/params.yaml - device_cgroup_rules: - - 'c 189:* rmw' - command: > - ros2 launch depthai_ros_driver camera.launch.py - params_file:=/params.yaml \ No newline at end of file diff --git a/demo/compose.yaml b/demo/compose.yaml new file mode 100644 index 0000000..421c726 --- /dev/null +++ b/demo/compose.yaml @@ -0,0 +1,40 @@ +# services: +# luxonis: +# image: husarion/depthai:humble-2.8.1-20240127 +# volumes: +# - /dev/bus/usb:/dev/bus/usb +# - ./squashfs-root/usr/share/husarion-depthai/config/oak-1-low-bandwidth.yaml:/params.yaml +# device_cgroup_rules: +# - 'c 189:* rmw' +# command: > +# ros2 launch depthai_ros_driver camera.launch.py +# params_file:=/params.yaml + +# x-common-config: +# &common-config +# network_mode: host +# ipc: host +# restart: unless-stopped + +# x-dds-envs: +# &dds-envs +# env_file: .env.dds + +services: + + rviz: + image: husarion/rviz2:humble-11.2.9-20240111 + network_mode: host + ipc: host + runtime: ${DOCKER_RUNTIME:-runc} + volumes: + - /tmp/.X11-unix:/tmp/.X11-unix:rw + - ./default.rviz:/default.rviz + - ./rviz.launch.py:/rviz.launch.py + environment: + - DISPLAY=${DISPLAY:?err} + - LIBGL_ALWAYS_SOFTWARE=${LIBGL_ALWAYS_SOFTWARE:-1} + - NVIDIA_VISIBLE_DEVICES=all # if LIBGL_ALWAYS_SOFTWARE=1 this env var is ignored + - NVIDIA_DRIVER_CAPABILITIES=all # if LIBGL_ALWAYS_SOFTWARE=1 this env var is ignored + command: ros2 launch /rviz.launch.py + diff --git a/demo/default.rviz b/demo/default.rviz new file mode 100644 index 0000000..cc5dce0 --- /dev/null +++ b/demo/default.rviz @@ -0,0 +1,149 @@ +Panels: + - Class: rviz_common/Displays + Help Height: 0 + Name: Displays + Property Tree Widget: + Expanded: + - /Image1 + - /Image1/Topic1 + Splitter Ratio: 0.5 + Tree Height: 415 + - Class: rviz_common/Selection + Name: Selection + - Class: rviz_common/Tool Properties + Expanded: + - /2D Goal Pose1 + - /Publish Point1 + Name: Tool Properties + Splitter Ratio: 0.5886790156364441 + - Class: rviz_common/Views + Expanded: + - /Current View1 + Name: Views + Splitter Ratio: 0.5 + - Class: rviz_common/Time + Experimental: false + Name: Time + SyncMode: 0 + SyncSource: "" +Visualization Manager: + Class: "" + Displays: + - Alpha: 0.5 + Cell Size: 1 + Class: rviz_default_plugins/Grid + Color: 160; 160; 164 + Enabled: true + Line Style: + Line Width: 0.029999999329447746 + Value: Lines + Name: Grid + Normal Cell Count: 0 + Offset: + X: 0 + Y: 0 + Z: 0 + Plane: XY + Plane Cell Count: 10 + Reference Frame: + Value: true + - Class: rviz_default_plugins/Image + Enabled: true + Max Value: 1 + Median window: 5 + Min Value: 0 + Name: Image + Normalize Range: true + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Best Effort + Value: camera/color/image_uncompressed + Value: true + Enabled: true + Global Options: + Background Color: 48; 48; 48 + Fixed Frame: map + Frame Rate: 30 + Name: root + Tools: + - Class: rviz_default_plugins/Interact + Hide Inactive Objects: true + - Class: rviz_default_plugins/MoveCamera + - Class: rviz_default_plugins/Select + - Class: rviz_default_plugins/FocusCamera + - Class: rviz_default_plugins/Measure + Line color: 128; 128; 0 + - Class: rviz_default_plugins/SetInitialPose + Covariance x: 0.25 + Covariance y: 0.25 + Covariance yaw: 0.06853891909122467 + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /initialpose + - Class: rviz_default_plugins/SetGoal + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /goal_pose + - Class: rviz_default_plugins/PublishPoint + Single click: true + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /clicked_point + Transformation: + Current: + Class: rviz_default_plugins/TF + Value: true + Views: + Current: + Class: rviz_default_plugins/Orbit + Distance: 10 + Enable Stereo Rendering: + Stereo Eye Separation: 0.05999999865889549 + Stereo Focal Distance: 1 + Swap Stereo Eyes: false + Value: false + Focal Point: + X: 0 + Y: 0 + Z: 0 + Focal Shape Fixed Size: true + Focal Shape Size: 0.05000000074505806 + Invert Z Axis: false + Name: Current View + Near Clip Distance: 0.009999999776482582 + Pitch: 0.785398006439209 + Target Frame: + Value: Orbit (rviz) + Yaw: 0.7903980016708374 + Saved: ~ +Window Geometry: + Displays: + collapsed: false + Height: 1016 + Hide Left Dock: false + Hide Right Dock: false + Image: + collapsed: false + QMainWindow State: 000000ff00000000fd0000000400000000000004d40000035efc020000000afb0000000a0049006d006100670065010000003b0000035e0000002800fffffffb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000c00430061006d00650072006100000002a1000000e70000000000000000fb0000000c00430061006d0065007200610000000434000000d7000000000000000000000001000001560000035efc0200000004fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003b0000017e000000a000fffffffb000000100044006900730070006c00610079007301000001bf000001da000000c700fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073a0000003efc0100000002fb0000000800540069006d006501000000000000073a0000025300fffffffb0000000800540069006d00650100000000000004500000000000000000000001040000035e00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Selection: + collapsed: false + Time: + collapsed: false + Tool Properties: + collapsed: false + Views: + collapsed: false + Width: 1850 + X: 747 + Y: 398 diff --git a/demo/rviz.launch.py b/demo/rviz.launch.py new file mode 100644 index 0000000..c1f202b --- /dev/null +++ b/demo/rviz.launch.py @@ -0,0 +1,52 @@ +from launch import LaunchDescription +from launch_ros.actions import Node, PushRosNamespace +from launch.actions import DeclareLaunchArgument, OpaqueFunction +from launch.substitutions import EnvironmentVariable, LaunchConfiguration + + +def launch_setup(context, *args, **kwargs): + robot_namespace = LaunchConfiguration("robot_namespace").perform(context) + + tf_remap = [] + if robot_namespace: + tf_remap.append(("/tf", f"/{robot_namespace}/tf")) + tf_remap.append(("/tf_static", f"/{robot_namespace}/tf_static")) + + rviz = Node( + package="rviz2", + executable="rviz2", + name="rviz2", + arguments=["-d", "/default.rviz"], + remappings=tf_remap, + output="screen", + ) + + decoder = Node( + package="image_transport", + executable="republish", + name="republish", + arguments=[ + "ffmpeg", + # "in/ffmpeg:=camera/color/image_raw/ffmpeg", + "in/ffmpeg:=abc/xyz/rgb/image_raw/ffmpeg", + "raw", + "out:=camera/color/image_uncompressed", + ], + remappings=tf_remap, + output="screen", + ) + + return [PushRosNamespace(robot_namespace), rviz, decoder] + + +def generate_launch_description(): + return LaunchDescription( + [ + DeclareLaunchArgument( + "robot_namespace", + default_value=EnvironmentVariable("ROBOT_NAMESPACE", default_value=""), + description="Namespace which will appear in front of all topics (including /tf and /tf_static).", + ), + OpaqueFunction(function=launch_setup), + ] + ) \ No newline at end of file diff --git a/justfile b/justfile new file mode 100644 index 0000000..bef366c --- /dev/null +++ b/justfile @@ -0,0 +1,83 @@ +build: + #!/bin/bash + export SNAPCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS=1 + snapcraft + +install: + #!/bin/bash + unsquashfs husarion-depthai*.snap + sudo snap try squashfs-root/ + sudo snap connect husarion-depthai:raw-usb + sudo snap connect husarion-depthai:c189-plug + sudo husarion-depthai.stop + +remove: + #!/bin/bash + sudo snap remove husarion-depthai + sudo rm -rf squashfs-root/ + +clean: + #!/bin/bash + export SNAPCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS=1 + snapcraft clean + +iterate: + #!/bin/bash + start_time=$(date +%s) + + echo "Starting script..." + + sudo snap remove husarion-depthai + sudo rm -rf squashfs-root/ + sudo rm -rf husarion-depthai*.snap + export SNAPCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS=1 + snapcraft clean + snapcraft + unsquashfs husarion-depthai*.snap + sudo snap try squashfs-root/ + sudo snap connect husarion-depthai:raw-usb + # sudo snap connect husarion-depthai:c189-plug rosbot:c189-slot + + end_time=$(date +%s) + duration=$(( end_time - start_time )) + + hours=$(( duration / 3600 )) + minutes=$(( (duration % 3600) / 60 )) + seconds=$(( duration % 60 )) + + printf "Script completed in %02d:%02d:%02d (hh:mm:ss)\n" $hours $minutes $seconds + +swap-enable: + #!/bin/bash + sudo fallocate -l 3G /swapfile + sudo chmod 600 /swapfile + sudo mkswap /swapfile + sudo swapon /swapfile + sudo swapon --show + + # Make the swap file permanent: + sudo bash -c "echo '/swapfile swap swap defaults 0 0' >> /etc/fstab" + + # Adjust swappiness: + sudo sysctl vm.swappiness=10 + sudo bash -c "echo 'vm.swappiness=10' >> /etc/sysctl.conf" + +swap-disable: + #!/bin/bash + sudo swapoff /swapfile + sudo rm /swapfile + sudo sed -i '/\/swapfile swap swap defaults 0 0/d' /etc/fstab # Remove the swap file entry + sudo sed -i '/vm.swappiness=10/d' /etc/sysctl.conf # Remove or comment out the swappiness setting + sudo sysctl -p # Reload sysctl configuration + +prepare-store-credentials: + #!/bin/bash + snapcraft export-login --snaps=husarion-depthai \ + --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 husarion-astra*.snap \ No newline at end of file diff --git a/snap/hooks/configure b/snap/hooks/configure index ea29682..b19934b 100755 --- a/snap/hooks/configure +++ b/snap/hooks/configure @@ -20,82 +20,52 @@ log() { logger -t "${SNAP_NAME}" "configure hook: $message" } -# # Make sure ROS 2 nodes parameters value is a boolean -# OPTS="mecanum include-camera-mount" -# for OPT in ${OPTS}; do -# VALUE="$(snapctl get driver.${OPT})" -# if [ -n "${VALUE}" ]; then -# case "${VALUE}" in -# "True") ;; -# "False") ;; -# *) -# log_and_echo "configure hook: '${VALUE}' is not a supported value for ${OPT}." \ -# "Possible values are True or False." -# exit 1 -# ;; -# esac -# fi -# done +$SNAP/usr/bin/configure_hook_ros.sh -# Make sure ROS_LOCALHOST_ONLY is valid -OPT="ros-localhost-only" -ROS_LOCALHOST_ONLY="$(snapctl get ${OPT})" -if [ -n "${ROS_LOCALHOST_ONLY}" ]; then - case "${ROS_LOCALHOST_ONLY}" in - 1) ;; - 0) ;; - *) - log_and_echo "'${ROS_LOCALHOST_ONLY}' is not a supported value for '${OPT}'." \ - "Possible values are 0 or 1." - exit 1 - ;; - esac -fi - -# Make sure ROS_DOMAIN_ID is valid -OPT="ros-domain-id" -ROS_DOMAIN_ID="$(snapctl get ${OPT})" +DEPTHAI_PARAMS_FILE="$(snapctl get driver.params-file)" -is_integer() { - expr "$1" : '-\?[0-9][0-9]*$' >/dev/null 2>&1 -} - -if ! is_integer "${ROS_DOMAIN_ID}" || [ "${ROS_DOMAIN_ID}" -lt 0 ] || [ "${ROS_DOMAIN_ID}" -gt 232 ]; then - log_and_echo "'${ROS_DOMAIN_ID}' is not a supported value for '${OPT}'. Possible values are integers between 0 and 232." +# Check if the file exists +if [ ! -f "$DEPTHAI_PARAMS_FILE" ]; then + log_and_echo "$DEPTHAI_PARAMS_FILE does not exist." exit 1 fi -# Get the transport setting using snapctl -OPT="transport" -TRANSPORT_SETTING="$(snapctl get ${OPT})" +export LD_LIBRARY_PATH=$SNAP/usr/lib/$(uname -m)-linux-gnu/pulseaudio:$SNAP/usr/lib/$(uname -m)-linux-gnu/blas:$SNAP/usr/lib/$(uname -m)-linux-gnu/lapack:$LD_LIBRARY_PATH + +export FFMPEG_ENCODING=$(snapctl get driver.ffmpeg-image-transport.encoding) -# Check if the transport setting is valid -case "$TRANSPORT_SETTING" in -"udp") - log "'$TRANSPORT_SETTING' transport set." - ;; -"shm" | "builtin") - if snapctl is-connected shm-plug; then - log "'$TRANSPORT_SETTING' transport set." - else - log_and_echo "to use 'builtin' 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" +# Check if FFMPEG_ENCODING is set +if [ -n "$FFMPEG_ENCODING" ]; then + # Run ffmpeg -codecs and check if the codec is available + if ! ffmpeg -encoders 2>/dev/null | awk '{print $2}' | grep -q "$FFMPEG_ENCODING"; then + log_and_echo "Error: Codec $FFMPEG_ENCODING is not available:" + # log_and_echo "Available codecs:" + # ffmpeg -encoders 2>/dev/null | awk '/^ V/ {print $0}' exit 1 fi - ;; -*) - log_and_echo "'${TRANSPORT_SETTING}' is not a supported value for '${OPT}'. Possible values are: udp, shm, builtin." - exit 1 - ;; -esac -# Make sure ros-humble-ros-base is connected -ROS_PLUG="ros-humble-ros-base" + cp $SNAP_COMMON/ffmpeg_params_template.yaml $SNAP_COMMON/ffmpeg_params.yaml + yq -i './**.ros__parameters.ffmpeg_image_transport = {}' $SNAP_COMMON/ffmpeg_params.yaml -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 + # Get all options in JSON format + OPTIONS=$(snapctl get driver.ffmpeg-image-transport) + keys=$(echo $OPTIONS | yq '. | to_entries | .[].key') + for key in $keys; do + export FFMPEG_KEY=$key + export FFMPEG_VALUE=$(snapctl get driver.ffmpeg-image-transport.$FFMPEG_KEY) + yq -i './**.ros__parameters.ffmpeg_image_transport += {env(FFMPEG_KEY): env(FFMPEG_VALUE)}' $SNAP_COMMON/ffmpeg_params.yaml + done +else + cp $SNAP_COMMON/ffmpeg_params_template.yaml $SNAP_COMMON/ffmpeg_params.yaml + yq -i './**.ros__parameters.ffmpeg_image_transport = {}' $SNAP_COMMON/ffmpeg_params.yaml fi -snapctl restart ${SNAP_NAME}.daemon +# restart services with new ROS 2 config +for service in daemon; do + if snapctl services ${SNAP_NAME}.${service} | grep -qw active; then + snapctl restart ${SNAP_NAME}.${service} + log "Restarted ${SNAP_NAME}.${service}" + fi +done + + diff --git a/snap/hooks/connect-plug-ros-humble-ros-base b/snap/hooks/connect-plug-ros-humble-ros-base index b1e2cb1..fbc9bc6 100755 --- a/snap/hooks/connect-plug-ros-humble-ros-base +++ b/snap/hooks/connect-plug-ros-humble-ros-base @@ -1,4 +1,8 @@ #!/bin/sh -e -snapctl start --enable ${SNAP_NAME}.daemon 2>&1 || true +# now we can start the service +# if snapctl services ${SNAP_NAME}.daemon | grep -q inactive; then +# snapctl start --enable ${SNAP_NAME}.daemon 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 index 395c71a..35cc834 100755 --- a/snap/hooks/disconnect-plug-ros-humble-ros-base +++ b/snap/hooks/disconnect-plug-ros-humble-ros-base @@ -2,5 +2,3 @@ logger -t ${SNAP_NAME} "Plug 'ros-humble-ros-base' disconnected" snapctl stop --disable ${SNAP_NAME}.daemon 2>&1 || true -# snapctl stop --disable ${SNAP_NAME}.udp-daemon 2>&1 || true -# snapctl stop --disable ${SNAP_NAME}.shm-daemon 2>&1 || true \ No newline at end of file diff --git a/snap/hooks/install b/snap/hooks/install index 8bc4f4e..9967502 100755 --- a/snap/hooks/install +++ b/snap/hooks/install @@ -7,37 +7,32 @@ log() { logger -t "${SNAP_NAME}" "install hook: $message" } +$SNAP/usr/bin/install_hook_ros.sh -# Parameters are 'unset'. -# Default configuration values is left to the launch file. -# snapctl set driver.mecanum=True -# snapctl set driver.include-camera-mount=True -# snapctl set driver.camera-model! -# snapctl set driver.lidar-model! -# snapctl set driver.namespace! # unset -# snapctl set serial-port="/dev/ttyUSBDB" -snapctl set transport="udp" -snapctl set ros-localhost-only=0 -snapctl set ros-domain-id=0 -snapctl set fastdds-default-profiles-file="fastdds.xml" - -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 +snapctl set driver.name=oak +snapctl set driver.parent-frame=oak-d-base-frame +snapctl set driver.camera-model=OAK-D +snapctl set driver.cam-pos-x=0.0 +snapctl set driver.cam-pos-y=0.0 +snapctl set driver.cam-pos-z=0.0 +snapctl set driver.cam-roll=0.0 +snapctl set driver.cam-pitch=0.0 +snapctl set driver.cam-yaw=0.0 +snapctl set driver.params-file=$SNAP_COMMON/depthai_params.yaml +snapctl set driver.ffmpeg-image-transport.encoding=libx264 +snapctl set driver.ffmpeg-image-transport.preset=ultrafast +snapctl set driver.ffmpeg-image-transport.tune=zerolatency +snapctl set driver.namespace! if ! snapctl is-connected raw-usb; then log "Plug 'raw-usb' isn't connected, please run:" log "sudo snap connect ${SNAP_NAME}:raw-usb" fi -# # copy meshes to shared folder +# copy joy params +cp -r $SNAP/usr/share/husarion-depthai/config/*.yaml ${SNAP_COMMON}/ + +# # # 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 +# cp -r $SNAP/opt/ros/humble/share/depthai_descriptions ${SNAP_COMMON}/ros2_ws/depthai_descriptions diff --git a/snap/local/depthai.launch.py b/snap/local/depthai.launch.py new file mode 100755 index 0000000..8deb7fd --- /dev/null +++ b/snap/local/depthai.launch.py @@ -0,0 +1,164 @@ +import os + +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, OpaqueFunction +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.substitutions import LaunchConfiguration, EnvironmentVariable +from launch.conditions import IfCondition +from launch_ros.actions import ComposableNodeContainer, Node, PushRosNamespace +from launch_ros.descriptions import ComposableNode + + +def launch_setup(context, *args, **kwargs): + log_level = 'info' + if(context.environment.get('DEPTHAI_DEBUG')=='1'): + log_level='debug' + + urdf_launch_dir = os.path.join(get_package_share_directory('depthai_descriptions'), 'launch') + + params_file = LaunchConfiguration("params_file") + + # ========== added in snap ========== + ffmpeg_params_file = LaunchConfiguration("ffmpeg_params_file") + namespace = LaunchConfiguration("namespace") + + remapping = [] + if namespace: + remapping.append(("/tf", f"/{namespace}/tf")) + remapping.append(("/tf_static", f"/{namespace}/tf_static")) + # =================================== + + camera_model = LaunchConfiguration('camera_model', default = 'OAK-D') + + name = LaunchConfiguration('name').perform(context) + + parent_frame = LaunchConfiguration('parent_frame', default = 'oak-d-base-frame') + cam_pos_x = LaunchConfiguration('cam_pos_x', default = '0.0') + cam_pos_y = LaunchConfiguration('cam_pos_y', default = '0.0') + cam_pos_z = LaunchConfiguration('cam_pos_z', default = '0.0') + cam_roll = LaunchConfiguration('cam_roll', default = '0.0') + cam_pitch = LaunchConfiguration('cam_pitch', default = '0.0') + cam_yaw = LaunchConfiguration('cam_yaw', default = '0.0') + use_composition = LaunchConfiguration('rsp_use_composition', default='true') + imu_from_descr = LaunchConfiguration('imu_from_descr', default='false') + publish_tf_from_calibration = LaunchConfiguration('publish_tf_from_calibration', default='false') + override_cam_model = LaunchConfiguration('override_cam_model', default='false') + + tf_params = {} + if(publish_tf_from_calibration.perform(context) == 'true'): + cam_model = '' + if override_cam_model.perform(context) == 'true': + cam_model = camera_model.perform(context) + tf_params = {'camera': { + 'i_publish_tf_from_calibration': True, + 'i_tf_tf_prefix': name, + 'i_tf_camera_model': cam_model, + 'i_tf_base_frame': name, + 'i_tf_parent_frame': parent_frame.perform(context), + 'i_tf_cam_pos_x': cam_pos_x.perform(context), + 'i_tf_cam_pos_y': cam_pos_y.perform(context), + 'i_tf_cam_pos_z': cam_pos_z.perform(context), + 'i_tf_cam_roll': cam_roll.perform(context), + 'i_tf_cam_pitch': cam_pitch.perform(context), + 'i_tf_cam_yaw': cam_yaw.perform(context), + 'i_tf_imu_from_descr': imu_from_descr.perform(context), + } + } + + use_gdb = LaunchConfiguration('use_gdb', default = 'false') + use_valgrind = LaunchConfiguration('use_valgrind', default = 'false') + use_perf = LaunchConfiguration('use_perf', default = 'false') + + launch_prefix = '' + + if (use_gdb.perform(context) == 'true'): + launch_prefix += "gdb -ex run --args " + if (use_valgrind.perform(context) == 'true'): + launch_prefix += "valgrind --tool=callgrind" + if (use_perf.perform(context) == 'true'): + launch_prefix += "perf record -g --call-graph dwarf --output=perf.out.node_name.data --" + return [ + PushRosNamespace(namespace), + Node( + condition=IfCondition(LaunchConfiguration("use_rviz").perform(context)), + package="rviz2", + executable="rviz2", + name="rviz2", + output="log", + arguments=["-d", LaunchConfiguration("rviz_config")], + ), + IncludeLaunchDescription( + PythonLaunchDescriptionSource( + os.path.join(urdf_launch_dir, 'urdf_launch.py')), + launch_arguments={'tf_prefix': name, + 'camera_model': camera_model, + 'base_frame': name, + 'parent_frame': parent_frame, + 'cam_pos_x': cam_pos_x, + 'cam_pos_y': cam_pos_y, + 'cam_pos_z': cam_pos_z, + 'cam_roll': cam_roll, + 'cam_pitch': cam_pitch, + 'cam_yaw': cam_yaw, + 'use_composition': use_composition, + 'use_base_descr': publish_tf_from_calibration}.items()), + + ComposableNodeContainer( + name=name+"_container", + namespace="", + package="rclcpp_components", + executable="component_container", + composable_node_descriptions=[ + ComposableNode( + package="depthai_ros_driver", + plugin="depthai_ros_driver::Camera", + name=name, + parameters=[params_file, ffmpeg_params_file, tf_params], + ) + ], + # remappings=remapping, + arguments=['--ros-args', '--log-level', log_level], + prefix=[launch_prefix], + output="both", + ), + + ] + + +def generate_launch_description(): + depthai_prefix = get_package_share_directory("depthai_ros_driver") + + declared_arguments = [ + DeclareLaunchArgument("name", default_value="oak"), + DeclareLaunchArgument("parent_frame", default_value="oak-d-base-frame"), + DeclareLaunchArgument("camera_model", default_value="OAK-D"), + DeclareLaunchArgument("cam_pos_x", default_value="0.0"), + DeclareLaunchArgument("cam_pos_y", default_value="0.0"), + DeclareLaunchArgument("cam_pos_z", default_value="0.0"), + DeclareLaunchArgument("cam_roll", default_value="0.0"), + DeclareLaunchArgument("cam_pitch", default_value="0.0"), + DeclareLaunchArgument("cam_yaw", default_value="0.0"), + DeclareLaunchArgument("params_file", default_value="/var/snap/husarion-depthai/common/depthai_params.yaml"), + DeclareLaunchArgument("use_rviz", default_value='false'), + DeclareLaunchArgument("rviz_config", default_value=os.path.join(depthai_prefix, "config", "rviz", "rgbd.rviz")), + DeclareLaunchArgument("rsp_use_composition", default_value='true'), + DeclareLaunchArgument("publish_tf_from_calibration", default_value='false', description='Enables TF publishing from camera calibration file.'), + DeclareLaunchArgument("imu_from_descr", default_value='false', description='Enables IMU publishing from URDF.'), + DeclareLaunchArgument("override_cam_model", default_value='false', description='Overrides camera model from calibration file.'), + DeclareLaunchArgument("use_gdb", default_value='false'), + DeclareLaunchArgument("use_valgrind", default_value='false'), + DeclareLaunchArgument("use_perf", default_value='false'), + + # ========== added in snap ========== + DeclareLaunchArgument("ffmpeg_params_file", default_value="/var/snap/husarion-depthai/common/ffmpeg_params.yaml", description="Full path to the FFMPEG plugin parameters file"), + DeclareLaunchArgument("namespace",default_value=EnvironmentVariable("namespace", default_value=""), description="Namespace which will appear in front of all topics (including /tf and /tf_static)."), + # =================================== + ] + + return LaunchDescription( + declared_arguments + [OpaqueFunction(function=launch_setup)] + ) + + + diff --git a/snap/local/oak-1-low-bandwidth.yaml b/snap/local/depthai_params.yaml similarity index 96% rename from snap/local/oak-1-low-bandwidth.yaml rename to snap/local/depthai_params.yaml index 4a4c96f..e7c351e 100644 --- a/snap/local/oak-1-low-bandwidth.yaml +++ b/snap/local/depthai_params.yaml @@ -1,5 +1,5 @@ --- -/oak: +/**: ros__parameters: # qos_overrides: # /oak/rgb/image_raw: @@ -89,8 +89,4 @@ r_set_man_focus: false r_set_man_whitebalance: false r_whitebalance: 3300 - ffmpeg_image_transport: - encoding: libx264 - preset: ultrafast - tune: zerolatency use_sim_time: false diff --git a/snap/local/ffmpeg_params_template.yaml b/snap/local/ffmpeg_params_template.yaml new file mode 100644 index 0000000..c779840 --- /dev/null +++ b/snap/local/ffmpeg_params_template.yaml @@ -0,0 +1,11 @@ +--- +/**: + ros__parameters: + ffmpeg_image_transport: + + # find the list of available encoders by running `ffmpeg -encoders` + encoding: libx264 + + # find the list of available presets by running `ffmpeg -h encoder=libx264` + preset: ultrafast + tune: zerolatency \ No newline at end of file diff --git a/snap/local/launcher.sh b/snap/local/launcher.sh index 686d46e..613b28d 100755 --- a/snap/local/launcher.sh +++ b/snap/local/launcher.sh @@ -6,26 +6,45 @@ log() { logger -t "${SNAP_NAME}" "launcher: $message" } -ros2 launch depthai_ros_driver camera.launch.py params_file:=$SNAP/usr/share/${SNAP_NAME}/config/oak-1-low-bandwidth.yaml +log_and_echo() { + local message="$1" + # Log the message with logger + logger -t "${SNAP_NAME}" "configure hook: $message" + # Echo the message to standard error + echo >&2 "$message" +} + +# Iterate over the snap parameters and retrieve their value. +# If a value is set, it is forwarded to the launch file. -# # Iterate over the snap parameters and retrieve their value. -# # If a value is set, it is forwarded to the launch file. -# OPTIONS="namespace mecanum include-camera-mount camera-model lidar-model" -# LAUNCH_OPTIONS="" +OPTIONS="\ + name \ + parent-frame \ + camera-model \ + cam-pos-x \ + cam-pos-y \ + cam-pos-z \ + cam-roll \ + cam-pitch \ + cam-yaw \ + params-file \ + namespace \ + device-namespace \ +" -# for OPTION in ${OPTIONS}; do -# VALUE="$(snapctl get driver.${OPTION})" -# if [ -n "${VALUE}" ]; then -# LAUNCH_OPTIONS+="${OPTION}:=${VALUE} " -# fi -# done +LAUNCH_OPTIONS="" -# # Replace '-' with '_' -# LAUNCH_OPTIONS=$(echo ${LAUNCH_OPTIONS} | tr - _) +for OPTION in ${OPTIONS}; do + VALUE="$(snapctl get driver.${OPTION})" + if [ -n "${VALUE}" ]; then + OPTION_WITH_UNDERSCORE=$(echo ${OPTION} | tr - _) + LAUNCH_OPTIONS+="${OPTION_WITH_UNDERSCORE}:=${VALUE} " + fi +done -# if [ "${LAUNCH_OPTIONS}" ]; then -# # watch the log with: "journalctl -t rosbot-xl" -# log "Running with options: ${LAUNCH_OPTIONS}" -# fi +if [ "${LAUNCH_OPTIONS}" ]; then + # watch the log with: "journalctl -t husarion-depthai" + log_and_echo "Running with options: ${LAUNCH_OPTIONS}" +fi -# ros2 launch rosbot_xl_bringup combined.launch.py ${LAUNCH_OPTIONS} +ros2 launch $SNAP/usr/bin/depthai.launch.py ${LAUNCH_OPTIONS} ffmpeg_params_file:=$SNAP_COMMON/ffmpeg_params.yaml diff --git a/snap/local/check_daemon_running.sh b/snap/local/ros_common/check_daemon_running.sh similarity index 84% rename from snap/local/check_daemon_running.sh rename to snap/local/ros_common/check_daemon_running.sh index d6fdd10..3f7b8d4 100755 --- a/snap/local/check_daemon_running.sh +++ b/snap/local/ros_common/check_daemon_running.sh @@ -4,7 +4,7 @@ log_and_echo() { local message="$1" # Log the message with logger - logger -t "${SNAP_NAME}" "check_daemon_running: $message" + logger -t "${SNAP_NAME}" "${SNAP_NAME}.check_daemon_running.sh: $message" # Echo the message to standard error echo >&2 "$message" } diff --git a/snap/local/ros_common/configure_hook_ros.sh b/snap/local/ros_common/configure_hook_ros.sh new file mode 100755 index 0000000..6c396b4 --- /dev/null +++ b/snap/local/ros_common/configure_hook_ros.sh @@ -0,0 +1,76 @@ +#!/bin/sh -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 +log_and_echo() { + local message="$1" + # Log the message with logger + logger -t "${SNAP_NAME}" "configure hook: $message" + # Echo the message to standard error + echo >&2 "$message" +} + +log() { + local message="$1" + # Log the message with logger + logger -t "${SNAP_NAME}" "configure hook: $message" +} + +# Make sure ROS_LOCALHOST_ONLY is valid +OPT="ros-localhost-only" +ROS_LOCALHOST_ONLY="$(snapctl get ${OPT})" +if [ -n "${ROS_LOCALHOST_ONLY}" ]; then + case "${ROS_LOCALHOST_ONLY}" in + 1) ;; + 0) ;; + *) + log_and_echo "'${ROS_LOCALHOST_ONLY}' is not a supported value for '${OPT}'." \ + "Possible values are 0 or 1." + exit 1 + ;; + esac +fi + +# Make sure ROS_DOMAIN_ID is valid +OPT="ros-domain-id" +ROS_DOMAIN_ID="$(snapctl get ${OPT})" + +is_integer() { + expr "$1" : '-\?[0-9][0-9]*$' >/dev/null 2>&1 +} + +if ! is_integer "${ROS_DOMAIN_ID}" || [ "${ROS_DOMAIN_ID}" -lt 0 ] || [ "${ROS_DOMAIN_ID}" -gt 232 ]; then + log_and_echo "'${ROS_DOMAIN_ID}' is not a supported value for '${OPT}'. Possible values are integers between 0 and 232." + exit 1 +fi + +# Get the transport setting using snapctl +OPT="transport" +TRANSPORT_SETTING="$(snapctl get ${OPT})" + +# Only exit with status 1 if conditions are not met +if [ "$TRANSPORT_SETTING" != "builtin" ] && [ ! -f "${SNAP_COMMON}/${TRANSPORT_SETTING}.xml" ]; then + log_and_echo "'${SNAP_COMMON}/${TRANSPORT_SETTING}.xml' does not exist." + exit 1 +fi + +if [ "$TRANSPORT_SETTING" = "builtin" ] || [ "$TRANSPORT_SETTING" = "shm" ]; then + if ! snapctl is-connected shm-plug; then + log_and_echo "to use 'builtin' 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 diff --git a/snap/local/ros_common/install_hook_ros.sh b/snap/local/ros_common/install_hook_ros.sh new file mode 100755 index 0000000..9d48a98 --- /dev/null +++ b/snap/local/ros_common/install_hook_ros.sh @@ -0,0 +1,26 @@ +#!/bin/sh -e + +# Define a function to log messages +log() { + local message="$1" + # Log the message with logger + logger -t "${SNAP_NAME}" "install hook: $message" +} + + +snapctl set transport="udp" +snapctl set ros-localhost-only=0 +snapctl set ros-domain-id=0 + +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/ros_common/ros_setup.sh b/snap/local/ros_common/ros_setup.sh new file mode 100755 index 0000000..ee6d3b5 --- /dev/null +++ b/snap/local/ros_common/ros_setup.sh @@ -0,0 +1,28 @@ +#!/usr/bin/bash -e + +log() { + local message="$1" + # Log the message with logger + logger -t "${SNAP_NAME}" "ros_setup: $message" +} + +TRANSPORT="$(snapctl get transport)" +# watch the log with: "journalctl -t ${SNAP_NAME}" +log "transport: ${TRANSPORT}" + +if [ "$TRANSPORT" = "builtin" ]; then + log "using builtin transport setting" +else + PROFILE_FILE="${SNAP_COMMON}/${TRANSPORT}.xml" + export FASTRTPS_DEFAULT_PROFILES_FILE=$PROFILE_FILE + log "using ${PROFILE_FILE} transport setting" + log "$(cat $FASTRTPS_DEFAULT_PROFILES_FILE)" +fi + +export ROS_LOCALHOST_ONLY="$(snapctl get ros-localhost-only)" +export ROS_DOMAIN_ID="$(snapctl get ros-domain-id)" + +log "ROS_LOCAHOST_ONLY=${ROS_LOCALHOST_ONLY}" +log "ROS_DOMAIN_ID=${ROS_DOMAIN_ID}" + +exec $@ \ No newline at end of file diff --git a/snap/local/shm-only.xml b/snap/local/ros_common/shm.xml similarity index 100% rename from snap/local/shm-only.xml rename to snap/local/ros_common/shm.xml diff --git a/snap/local/udp-only.xml b/snap/local/ros_common/udp.xml similarity index 100% rename from snap/local/udp-only.xml rename to snap/local/ros_common/udp.xml diff --git a/snap/local/ros_setup.sh b/snap/local/ros_setup.sh deleted file mode 100755 index 2e9c5fc..0000000 --- a/snap/local/ros_setup.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/bash -e - -log() { - local message="$1" - # Log the message with logger - logger -t "${SNAP_NAME}" "ros_setup: $message" -} - -FASTDDS_FILE=$(snapctl get fastdds-default-profiles-file) - -if [ ! -f "${SNAP_COMMON}/${FASTDDS_FILE}" ]; then - # eg. /var/snap/${SNAP_NAME}/common/fastdds.xml - log "${SNAP_COMMON}/${FASTDDS_FILE} does not exist." -fi - -if [ -n "${FASTDDS_FILE}" ] && [ -f "${SNAP_COMMON}/${FASTDDS_FILE}" ]; then - export FASTRTPS_DEFAULT_PROFILES_FILE=${SNAP_COMMON}/${FASTDDS_FILE} - log "Using FASTRTPS profile: ${FASTRTPS_DEFAULT_PROFILES_FILE}" - log "$(cat $FASTRTPS_DEFAULT_PROFILES_FILE)" -else - TRANSPORT="$(snapctl get transport)" - # watch the log with: "journalctl -t ${SNAP_NAME}" - log "transport: ${TRANSPORT}" - - case "$TRANSPORT" in - shm) - export FASTRTPS_DEFAULT_PROFILES_FILE=$SNAP/usr/share/${SNAP_NAME}/config/shm-only.xml - log "$(cat $FASTRTPS_DEFAULT_PROFILES_FILE)" - ;; - udp) - export FASTRTPS_DEFAULT_PROFILES_FILE=$SNAP/usr/share/${SNAP_NAME}/config/udp-only.xml - log "$(cat $FASTRTPS_DEFAULT_PROFILES_FILE)" - ;; - builtin) - log "using builtin transport" - ;; - esac -fi - -export ROS_LOCALHOST_ONLY="$(snapctl get ros-localhost-only)" -export ROS_DOMAIN_ID="$(snapctl get ros-domain-id)" - -log "ROS_LOCAHOST_ONLY=${ROS_LOCALHOST_ONLY}" -log "ROS_DOMAIN_ID=${ROS_DOMAIN_ID}" - -exec $@ \ No newline at end of file diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index f612dfe..81ecb9a 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -36,6 +36,12 @@ slots: shm-slot: interface: shared-memory write: ['*'] # paths are relative to /dev/shm + c189-slot: + interface: custom-device + custom-device: c189 + files: + write: + - /run/udev/data/c189:* plugs: shm-plug: @@ -43,6 +49,10 @@ plugs: shared-memory: shm-slot private: false + c189-plug: + interface: custom-device + custom-device: c189 + apps: daemon: @@ -50,16 +60,17 @@ apps: command-chain: [usr/bin/ros_setup.sh] daemon: simple install-mode: disable - plugs: [network, network-bind, shm-plug, raw-usb] - slots: [shm-slot] + plugs: [network, network-bind, shm-plug, raw-usb, c189-plug] + slots: [shm-slot, c189-slot] extensions: [ros2-humble-ros-base] husarion-depthai: command: usr/bin/launcher.sh command-chain: [usr/bin/check_daemon_running.sh, usr/bin/ros_setup.sh] - plugs: [network, network-bind, shm-plug, raw-usb, system-observe, hardware-observe, network-control, network-observe, camera, browser-support] + plugs: [network, network-bind, shm-plug, raw-usb, c189-plug] + # plugs: [network, network-bind, shm-plug, raw-usb, system-observe, hardware-observe, network-control, network-observe, camera, browser-support] # block-devices, - slots: [shm-slot] + slots: [shm-slot, c189-slot] extensions: [ros2-humble-ros-base] start: @@ -68,34 +79,65 @@ apps: stop: command: usr/bin/stop_launcher.sh -layout: - /run/udev/data: - bind: $SNAP_DATA/run/udev/data - parts: husarion-depthai: plugin: nil stage-packages: - ros-humble-depthai-ros - # override-stage: | - override-prime: | + - ros-humble-image-transport + - ros-humble-image-transport-plugins + # https://index.ros.org/p/ffmpeg_image_transport/github-ros-misc-utilities-ffmpeg_image_transport/#humble + - ros-humble-ffmpeg-image-transport + - ffmpeg + - ros-humble-cv-bridge + # needed to run ffmpeg without errors: + - libpulse-dev + - libblas3 + - libjpeg-turbo8-dev + override-stage: | craftctl default - - #version="$(dpkg -s ros-humble-depthai-ros-driver | grep Version | awk '{print $2}')" - #craftctl set version="$version" - craftctl set version="2.9.0-1jammy.20240415.141623" + version="$(apt-cache policy ros-humble-depthai-ros-driver | grep Candidate | awk '{print $2}')" + craftctl set version="$version" craftctl set grade="stable" + # ffmpeg: + # plugin: colcon + # source: https://github.com/ros-misc-utilities/ffmpeg_image_transport.git + # # source-branch: v2.9.0-humble + # build-packages: + # - python3-catkin-pkg-modules + # - python3-vcstool + # stage-packages: + # - ros-humble-image-transport + # - ros-humble-image-transport-plugins + # - ffmpeg + # - ros-humble-cv-bridge + # # needed to run ffmpeg without errors: + # - libpulse-dev + # - libblas3 + # - libjpeg-turbo8-dev + # override-pull: | + # craftctl default + # cd $CRAFT_PART_SRC + # vcs import $CRAFT_PART_SRC < $CRAFT_PART_SRC/ffmpeg_image_transport.repos + + # husarion-depthai: # plugin: colcon # source: https://github.com/luxonis/depthai-ros.git - # source-branch: v2.8.1-humble + # source-branch: v2.9.0-humble # build-packages: # - python3-catkin-pkg-modules + # - python3-vcstool # override-pull: | # craftctl default + # cd $CRAFT_PART_SRC + + # git clone https://github.com/ros-misc-utilities/ffmpeg_image_transport.git + # vcs import $CRAFT_PART_SRC < $CRAFT_PART_SRC/ffmpeg_image_transport/ffmpeg_image_transport.repos + # # Set the snap version from the git tag # # The grade is set to 'stable' if the latest entry in the git history # # is the tag itself, otherwise set to devel @@ -123,8 +165,30 @@ parts: # craftctl default # vcs import $CRAFT_PART_SRC < $CRAFT_PART_SRC/ffmpeg_image_transport.repos + 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 # copy local scripts to the snap usr/bin + local-files-ros: + plugin: dump + source: snap/local/ros_common/ + organize: + '*.sh': usr/bin/ + '*.xml': usr/share/husarion-depthai/config/ + local-files: plugin: dump source: snap/local/ @@ -132,4 +196,5 @@ parts: '*.sh': usr/bin/ '*.py': usr/bin/ '*.yaml': usr/share/husarion-depthai/config/ - '*.xml': usr/share/husarion-depthai/config/ + # '*.xml': usr/share/husarion-depthai/config/ + # '*.json': usr/share/husarion-depthai/config/