Skip to content

Commit

Permalink
New ros common (#2)
Browse files Browse the repository at this point in the history
* better params validation

* small cleanup
  • Loading branch information
DominikN authored Jul 10, 2024
1 parent febfc87 commit 579749b
Show file tree
Hide file tree
Showing 19 changed files with 539 additions and 230 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Snap for OAK-x cameras customized for Husarion robots
| `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 |
| `husarion-depthai.image-view` | Preview the image from the camera |

## Setup FFMPEG

Expand Down
4 changes: 2 additions & 2 deletions demo/rviz.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ def launch_setup(context, *args, **kwargs):
name="republish",
arguments=[
"ffmpeg",
# "in/ffmpeg:=camera/color/image_raw/ffmpeg",
"in/ffmpeg:=abc/xyz/rgb/image_raw/ffmpeg",
"in/ffmpeg:=/image_raw/ffmpeg",
# "in/ffmpeg:=abc/xyz/rgb/image_raw/ffmpeg",
"raw",
"out:=camera/color/image_uncompressed",
],
Expand Down
73 changes: 50 additions & 23 deletions snap/hooks/configure
Original file line number Diff line number Diff line change
@@ -1,34 +1,59 @@
#!/bin/sh -e
#!/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
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"
}
source $SNAP/usr/bin/utils.sh

$SNAP/usr/bin/configure_hook_ros.sh
# # Define the top-level key and the list of valid keys
VALID_DRIVER_KEYS=(
"name"
"parent-frame"
"camera-model"
"cam-pos-x"
"cam-pos-y"
"cam-pos-z"
"cam-roll"
"cam-pitch"
"cam-yaw"
"params-file"
"ffmpeg-image-transport"
)

DEPTHAI_PARAMS_FILE="$(snapctl get driver.params-file)"
VALID_FFMPEG_IMAGE_TRANSPORT_KEYS=(
"encoding"
"preset"
"tune"
)

# Check if the file exists
if [ ! -f "$DEPTHAI_PARAMS_FILE" ]; then
log_and_echo "$DEPTHAI_PARAMS_FILE does not exist."
exit 1
fi
# common

validate_keys "driver" VALID_DRIVER_KEYS[@]
validate_keys "driver.ffmpeg-image-transport" VALID_FFMPEG_IMAGE_TRANSPORT_KEYS[@]

# validate driver.name
validate_regex "driver.name" '^[a-z_-]{1,10}$' "Possible values are text with a maximum length of 10 characters, containing only lowercase letters (a-z), "-" or '_'."

# validate driver.parent-frame
validate_regex "driver.parent-frame" '^[a-z_-]{1,40}$' "Possible values are text with a maximum length of 40 characters, containing only lowercase letters (a-z), "-" or '_'."

# validate driver.camera-model
VALID_CAMERA_MODEL_OPTIONS=("OAK-D" "OAK-D-LITE")
validate_option "driver.camera-model" VALID_CAMERA_MODEL_OPTIONS[@]

# validate driver.cam-x
validate_float "driver.cam-pos-x"
validate_float "driver.cam-pos-y"
validate_float "driver.cam-pos-z"
validate_float "driver.cam-roll"
validate_float "driver.cam-pitch"
validate_float "driver.cam-yaw"

# validate driver.params-file
validate_path "driver.params-file"

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

Expand All @@ -39,8 +64,8 @@ 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}'
log_and_echo "Find available codecs here: $SNAP_COMMON/ffmpeg_codecs.txt"
ffmpeg -encoders 2>/dev/null | awk '/^ V/ {print $0}' > $SNAP_COMMON/ffmpeg_codecs.txt
exit 1
fi

Expand All @@ -60,6 +85,8 @@ else
yq -i './**.ros__parameters.ffmpeg_image_transport = {}' $SNAP_COMMON/ffmpeg_params.yaml
fi

$SNAP/usr/bin/configure_hook_ros.sh

# restart services with new ROS 2 config
for service in daemon; do
if snapctl services ${SNAP_NAME}.${service} | grep -qw active; then
Expand Down
6 changes: 3 additions & 3 deletions snap/hooks/connect-plug-ros-humble-ros-base
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/bin/sh -e
#!/bin/bash -e

# 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
# 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"
2 changes: 1 addition & 1 deletion snap/hooks/disconnect-plug-ros-humble-ros-base
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh -e
#!/bin/bash -e

logger -t ${SNAP_NAME} "Plug 'ros-humble-ros-base' disconnected"
snapctl stop --disable ${SNAP_NAME}.daemon 2>&1 || true
3 changes: 1 addition & 2 deletions snap/hooks/install
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@ 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 joy params
# copy params
cp -r $SNAP/usr/share/husarion-depthai/config/*.yaml ${SNAP_COMMON}/

# # # copy meshes to shared folder
Expand Down
2 changes: 0 additions & 2 deletions snap/local/launcher.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ OPTIONS="\
cam-pitch \
cam-yaw \
params-file \
namespace \
device-namespace \
"

LAUNCH_OPTIONS=""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
#!/usr/bin/bash
#!/bin/bash -e

# Define a function to log and echo messages
log_and_echo() {
local message="$1"
# Log the message with logger
logger -t "${SNAP_NAME}" "${SNAP_NAME}.check_daemon_running.sh: $message"
# Echo the message to standard error
echo >&2 "$message"
}
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:"
Expand Down
176 changes: 176 additions & 0 deletions snap/local/local-ros/configure_hook_ros.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
#!/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}"

Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
#!/bin/sh -e
#!/bin/bash -e

# Define a function to log messages
log() {
local message="$1"
# Log the message with logger
logger -t "${SNAP_NAME}" "install hook: $message"
}
source $SNAP/usr/bin/utils.sh


snapctl set transport="udp"
snapctl set ros-localhost-only=0
snapctl set ros-domain-id=0
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:"
Expand Down
5 changes: 5 additions & 0 deletions snap/local/local-ros/ros_setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash -e

source $SNAP_COMMON/ros.env

exec $@
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
<useBuiltinTransports>false</useBuiltinTransports>
</rtps>
</participant>
</profiles>
</profiles>
Loading

0 comments on commit 579749b

Please sign in to comment.