Compare commits
No commits in common. "7a100b2d140c0732393a48b162aa7e9bbe1aedba" and "37b646780d83f3068a8ef67b15af7475fdf24da3" have entirely different histories.
7a100b2d14
...
37b646780d
@ -49,9 +49,6 @@ rosbridge_websocket:
|
|||||||
"/cmd_vel",
|
"/cmd_vel",
|
||||||
"/saltybot/imu",
|
"/saltybot/imu",
|
||||||
"/saltybot/balance_state",
|
"/saltybot/balance_state",
|
||||||
"/saltybot/barometer",
|
|
||||||
"/vesc/left/state",
|
|
||||||
"/vesc/right/state",
|
|
||||||
"/tf",
|
"/tf",
|
||||||
"/tf_static"]
|
"/tf_static"]
|
||||||
|
|
||||||
|
|||||||
@ -1,70 +0,0 @@
|
|||||||
"""
|
|
||||||
can_monitor.launch.py — Lightweight rosbridge server for CAN sensor dashboard (Issue #697)
|
|
||||||
|
|
||||||
Starts rosbridge_websocket on port 9090 with a whitelist limited to the five
|
|
||||||
topics consumed by can_monitor_panel.html:
|
|
||||||
|
|
||||||
/saltybot/imu sensor_msgs/Imu — IMU attitude
|
|
||||||
/saltybot/balance_state std_msgs/String (JSON) — balance PID state
|
|
||||||
/saltybot/barometer std_msgs/String (JSON) — pressure / temp / altitude
|
|
||||||
/vesc/left/state std_msgs/String (JSON) — left VESC telemetry
|
|
||||||
/vesc/right/state std_msgs/String (JSON) — right VESC telemetry
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
ros2 launch saltybot_bringup can_monitor.launch.py
|
|
||||||
|
|
||||||
# Override port if needed:
|
|
||||||
ros2 launch saltybot_bringup can_monitor.launch.py port:=9091
|
|
||||||
|
|
||||||
Verify:
|
|
||||||
# From a browser on the same LAN:
|
|
||||||
# var ros = new ROSLIB.Ros({ url: 'ws://<jetson-ip>:9090' });
|
|
||||||
# ros.on('connection', () => console.log('connected'));
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
from launch import LaunchDescription
|
|
||||||
from launch.actions import DeclareLaunchArgument
|
|
||||||
from launch.substitutions import LaunchConfiguration
|
|
||||||
from launch_ros.actions import Node
|
|
||||||
|
|
||||||
|
|
||||||
# Topics exposed to the CAN monitor WebUI panel.
|
|
||||||
_TOPICS = [
|
|
||||||
'/saltybot/imu',
|
|
||||||
'/saltybot/balance_state',
|
|
||||||
'/saltybot/barometer',
|
|
||||||
'/vesc/left/state',
|
|
||||||
'/vesc/right/state',
|
|
||||||
]
|
|
||||||
|
|
||||||
_TOPICS_GLOB = '[' + ', '.join(f'"{t}"' for t in _TOPICS) + ']'
|
|
||||||
|
|
||||||
|
|
||||||
def generate_launch_description():
|
|
||||||
port_arg = DeclareLaunchArgument(
|
|
||||||
'port',
|
|
||||||
default_value='9090',
|
|
||||||
description='WebSocket port for rosbridge (default 9090)',
|
|
||||||
)
|
|
||||||
|
|
||||||
rosbridge = Node(
|
|
||||||
package='rosbridge_server',
|
|
||||||
executable='rosbridge_websocket',
|
|
||||||
name='rosbridge_websocket',
|
|
||||||
parameters=[{
|
|
||||||
'port': LaunchConfiguration('port'),
|
|
||||||
'host': '0.0.0.0',
|
|
||||||
'authenticate': False,
|
|
||||||
'max_message_size': 1000000, # 1 MB — no large map payloads needed
|
|
||||||
'topics_glob': _TOPICS_GLOB,
|
|
||||||
'services_glob': '[]',
|
|
||||||
'params_glob': '[]',
|
|
||||||
'unregister_timeout': 10.0,
|
|
||||||
'fragment_timeout': 600,
|
|
||||||
'delay_between_messages': 0,
|
|
||||||
}],
|
|
||||||
output='screen',
|
|
||||||
)
|
|
||||||
|
|
||||||
return LaunchDescription([port_arg, rosbridge])
|
|
||||||
@ -293,51 +293,11 @@ function drawCompass(yaw) {
|
|||||||
|
|
||||||
// ── ROS connection ────────────────────────────────────────────────────────────
|
// ── ROS connection ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
// ── Auto-reconnect state ──────────────────────────────────────────────────────
|
function connect(url) {
|
||||||
|
|
||||||
const RECONNECT_BASE_MS = 2000;
|
|
||||||
const RECONNECT_MAX_MS = 30000;
|
|
||||||
const RECONNECT_FACTOR = 1.5;
|
|
||||||
|
|
||||||
let reconnectDelay = RECONNECT_BASE_MS;
|
|
||||||
let reconnectTimer = null;
|
|
||||||
let reconnectTick = null;
|
|
||||||
let reconnectTarget = null;
|
|
||||||
|
|
||||||
function cancelReconnect() {
|
|
||||||
if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
|
|
||||||
if (reconnectTick) { clearInterval(reconnectTick); reconnectTick = null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
function scheduleReconnect(url) {
|
|
||||||
cancelReconnect();
|
|
||||||
let secs = Math.round(reconnectDelay / 1000);
|
|
||||||
$('conn-label').textContent = `Retry in ${secs}s…`;
|
|
||||||
|
|
||||||
reconnectTick = setInterval(() => {
|
|
||||||
secs = Math.max(0, secs - 1);
|
|
||||||
if (secs > 0) $('conn-label').textContent = `Retry in ${secs}s…`;
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
reconnectTimer = setTimeout(() => {
|
|
||||||
reconnectTimer = null;
|
|
||||||
connect(url, true);
|
|
||||||
}, reconnectDelay);
|
|
||||||
|
|
||||||
reconnectDelay = Math.min(reconnectDelay * RECONNECT_FACTOR, RECONNECT_MAX_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
function connect(url, isAutoRetry) {
|
|
||||||
cancelReconnect();
|
|
||||||
reconnectTarget = url;
|
|
||||||
if (!isAutoRetry) reconnectDelay = RECONNECT_BASE_MS;
|
|
||||||
|
|
||||||
if (ros) { try { ros.close(); } catch(_) {} }
|
if (ros) { try { ros.close(); } catch(_) {} }
|
||||||
ros = new ROSLIB.Ros({ url });
|
ros = new ROSLIB.Ros({ url });
|
||||||
|
|
||||||
ros.on('connection', () => {
|
ros.on('connection', () => {
|
||||||
reconnectDelay = RECONNECT_BASE_MS;
|
|
||||||
cancelReconnect();
|
|
||||||
$('conn-dot').className = 'connected';
|
$('conn-dot').className = 'connected';
|
||||||
$('conn-label').style.color = '#22c55e';
|
$('conn-label').style.color = '#22c55e';
|
||||||
$('conn-label').textContent = 'Connected';
|
$('conn-label').textContent = 'Connected';
|
||||||
@ -355,7 +315,7 @@ function connect(url, isAutoRetry) {
|
|||||||
ros.on('close', () => {
|
ros.on('close', () => {
|
||||||
$('conn-dot').className = '';
|
$('conn-dot').className = '';
|
||||||
$('conn-label').style.color = '#6b7280';
|
$('conn-label').style.color = '#6b7280';
|
||||||
scheduleReconnect(reconnectTarget || $('ws-input').value.trim());
|
$('conn-label').textContent = 'Disconnected';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,8 +405,8 @@ function setupTopics() {
|
|||||||
|
|
||||||
// ── UI wiring ─────────────────────────────────────────────────────────────────
|
// ── UI wiring ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
$('btn-connect').addEventListener('click', () => connect($('ws-input').value.trim(), false));
|
$('btn-connect').addEventListener('click', () => connect($('ws-input').value.trim()));
|
||||||
$('ws-input').addEventListener('keydown', e => { if (e.key === 'Enter') connect($('ws-input').value.trim(), false); });
|
$('ws-input').addEventListener('keydown', e => { if (e.key === 'Enter') connect($('ws-input').value.trim()); });
|
||||||
|
|
||||||
// ── Auto-connect on load ──────────────────────────────────────────────────────
|
// ── Auto-connect on load ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user