From a506989af6279469107de85478623c7daf80927c Mon Sep 17 00:00:00 2001 From: sl-jetson Date: Tue, 17 Mar 2026 09:49:21 -0400 Subject: [PATCH] feat: CANable 2.0 bringup with udev rule and systemd service (Issue #643) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - udev: 70-canable.rules — gs_usb VID/PID 1d50:606f, names iface can0 and brings it up at 500 kbps on plug-in - systemd: can-bringup.service — oneshot service bound to sys-subsystem-net-devices-can0.device - scripts: can_setup.sh — manual up/down/verify helper; candump verify for VESC IDs 61 (0x3D) and 79 (0x4F) - install_systemd.sh updated to install can-bringup.service and all udev rules Co-Authored-By: Claude Sonnet 4.6 --- .../systemd/can-bringup.service | 21 ++++++++ .../saltybot_bringup/udev/70-canable.rules | 19 +++++++ jetson/scripts/can_setup.sh | 52 +++++++++++++++++++ jetson/systemd/install_systemd.sh | 18 +++++++ 4 files changed, 110 insertions(+) create mode 100644 jetson/ros2_ws/src/saltybot_bringup/systemd/can-bringup.service create mode 100644 jetson/ros2_ws/src/saltybot_bringup/udev/70-canable.rules create mode 100755 jetson/scripts/can_setup.sh diff --git a/jetson/ros2_ws/src/saltybot_bringup/systemd/can-bringup.service b/jetson/ros2_ws/src/saltybot_bringup/systemd/can-bringup.service new file mode 100644 index 0000000..c87cf46 --- /dev/null +++ b/jetson/ros2_ws/src/saltybot_bringup/systemd/can-bringup.service @@ -0,0 +1,21 @@ +[Unit] +Description=CANable 2.0 CAN bus bringup (can0, 500 kbps) +Documentation=https://gitea.vayrette.com/seb/saltylab-firmware/issues/643 +# Wait until the gs_usb net device appears; udev fires After=sys-subsystem-net-devices-can0.device +After=network.target sys-subsystem-net-devices-can0.device +Requires=sys-subsystem-net-devices-can0.device +BindsTo=sys-subsystem-net-devices-can0.device + +[Service] +Type=oneshot +RemainAfterExit=yes + +ExecStart=/usr/sbin/ip link set can0 up type can bitrate 500000 +ExecStop=/usr/sbin/ip link set can0 down + +StandardOutput=journal +StandardError=journal +SyslogIdentifier=can-bringup + +[Install] +WantedBy=multi-user.target diff --git a/jetson/ros2_ws/src/saltybot_bringup/udev/70-canable.rules b/jetson/ros2_ws/src/saltybot_bringup/udev/70-canable.rules new file mode 100644 index 0000000..4b3246a --- /dev/null +++ b/jetson/ros2_ws/src/saltybot_bringup/udev/70-canable.rules @@ -0,0 +1,19 @@ +# CANable 2.0 USB-CAN adapter (gs_usb driver) +# Exposes the adapter as can0 via the SocketCAN subsystem. +# Issue: https://gitea.vayrette.com/seb/saltylab-firmware/issues/643 +# +# Install: +# sudo cp 70-canable.rules /etc/udev/rules.d/ +# sudo udevadm control --reload && sudo udevadm trigger +# +# CANable 2.0 USB IDs (Geschwister Schneider / candleLight firmware): +# idVendor = 1d50 (OpenMoko) +# idProduct = 606f (candleLight / gs_usb) +# +# Verify with: lsusb | grep -i candl +# ip link show can0 + +SUBSYSTEM=="net", ACTION=="add", \ + ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="606f", \ + NAME="can0", \ + RUN+="/sbin/ip link set can0 up type can bitrate 500000" diff --git a/jetson/scripts/can_setup.sh b/jetson/scripts/can_setup.sh new file mode 100755 index 0000000..d5db2fe --- /dev/null +++ b/jetson/scripts/can_setup.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# can_setup.sh — Bring up CANable 2.0 (gs_usb) as can0 at 500 kbps +# Issue: https://gitea.vayrette.com/seb/saltylab-firmware/issues/643 +# +# Usage: +# sudo ./can_setup.sh # bring up +# sudo ./can_setup.sh down # bring down +# sudo ./can_setup.sh verify # candump one-shot check (Ctrl-C to stop) +# +# VESCs on bus: CAN ID 61 (0x3D) and CAN ID 79 (0x4F), 500 kbps +set -euo pipefail + +IFACE="${CAN_IFACE:-can0}" +BITRATE="${CAN_BITRATE:-500000}" + +log() { echo "[can_setup] $*"; } +die() { echo "[can_setup] ERROR: $*" >&2; exit 1; } + +cmd="${1:-up}" + +case "$cmd" in + up) + # Verify the interface exists (gs_usb module loaded by kernel on plug-in) + if ! ip link show "$IFACE" &>/dev/null; then + die "$IFACE not found — is CANable 2.0 plugged in and gs_usb loaded?" + fi + + log "Bringing up $IFACE at ${BITRATE} bps..." + ip link set "$IFACE" down 2>/dev/null || true + ip link set "$IFACE" up type can bitrate "$BITRATE" + ip link set "$IFACE" up + log "$IFACE is up." + ip -details link show "$IFACE" + ;; + + down) + log "Bringing down $IFACE..." + ip link set "$IFACE" down + log "$IFACE is down." + ;; + + verify) + log "Listening on $IFACE — expecting frames from VESC IDs 0x3D (61) and 0x4F (79)" + log "Press Ctrl-C to stop." + exec candump "$IFACE" + ;; + + *) + echo "Usage: $0 [up|down|verify]" + exit 1 + ;; +esac diff --git a/jetson/systemd/install_systemd.sh b/jetson/systemd/install_systemd.sh index fcfc4f8..92a8727 100644 --- a/jetson/systemd/install_systemd.sh +++ b/jetson/systemd/install_systemd.sh @@ -7,6 +7,9 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_DIR="$(dirname "${SCRIPT_DIR}")" SYSTEMD_DIR="/etc/systemd/system" DEPLOY_DIR="/opt/saltybot/jetson" +UDEV_DIR="/etc/udev/rules.d" +BRINGUP_SYSTEMD="${REPO_DIR}/ros2_ws/src/saltybot_bringup/systemd" +BRINGUP_UDEV="${REPO_DIR}/ros2_ws/src/saltybot_bringup/udev" log() { echo "[install_systemd] $*"; } @@ -23,15 +26,30 @@ log "Installing systemd units..." cp "${SCRIPT_DIR}/saltybot.target" "${SYSTEMD_DIR}/" cp "${SCRIPT_DIR}/saltybot-social.service" "${SYSTEMD_DIR}/" cp "${SCRIPT_DIR}/tailscale-vpn.service" "${SYSTEMD_DIR}/" +cp "${BRINGUP_SYSTEMD}/can-bringup.service" "${SYSTEMD_DIR}/" + +# Install udev rules +log "Installing udev rules..." +mkdir -p "${UDEV_DIR}" +cp "${BRINGUP_UDEV}/70-canable.rules" "${UDEV_DIR}/" +cp "${BRINGUP_UDEV}/90-magedok-touch.rules" "${UDEV_DIR}/" +udevadm control --reload +udevadm trigger --subsystem-match=net --action=add # Reload and enable systemctl daemon-reload systemctl enable saltybot.target systemctl enable saltybot-social.service systemctl enable tailscale-vpn.service +systemctl enable can-bringup.service log "Services installed. Start with:" log " systemctl start saltybot-social" log " systemctl start tailscale-vpn" +log " systemctl start can-bringup" log " journalctl -fu saltybot-social" log " journalctl -fu tailscale-vpn" +log " journalctl -fu can-bringup" +log "" +log "Verify CAN bus: candump can0" +log " VESC CAN IDs: 61 (0x3D) and 79 (0x4F)"