返回教程正文

配套源码

main.py

app/python/main.py
ros-gateway-loopback:用 Custom Brick 打通 App Lab 与 ROS 2app/python/main.py
Python93 行
# SPDX-License-Identifier: MIT

import time

from arduino.app_utils import App
from ros_gateway import RosGateway


gateway = RosGateway()
last_state_publish = 0.0
last_status_signature = None


def handle_cmd_vel(command):
    """
    @description         : 将经过协议校验的速度指令写入 App Lab 日志,本阶段不控制真实电机
    @param command       : 包含 vx、vy、wz、seq 和 timestamp_ms 的速度指令
    @return              : 无返回值
    """
    print(
        "[loopback] cmd_vel accepted: "
        f"seq={command['seq']} vx={command['vx']:.3f} "
        f"vy={command['vy']:.3f} wz={command['wz']:.3f}",
        flush=True,
    )


def handle_mode_change(mode):
    """
    @description         : 记录 ROS 2 请求的底盘模式切换
    @param mode          : 新的底盘模式字符串
    @return              : True 表示允许本次模式切换
    """
    print(f"[loopback] mode changed: {mode}", flush=True)
    return True


def handle_safe_stop(reason):
    """
    @description         : 处理通信超时或断线产生的安全停车事件,本阶段只记录日志
    @param reason        : 触发安全停车的原因
    @return              : 无返回值
    """
    print(f"[loopback] SAFE_STOP: {reason}; no CAN command sent", flush=True)


def loop():
    """
    @description         : 周期发布模拟底盘状态并保持 App 主循环非阻塞运行
    @param               : 无参数
    @return              : 无返回值
    """
    global last_state_publish, last_status_signature

    current_time = time.monotonic()
    if current_time - last_state_publish >= 1.0:
        status = gateway.get_status()
        gateway.publish_base_state(
            {
                "mode": status["mode"],
                "enabled": False,
                "wheel_position": [0.0, 0.0, 0.0, 0.0],
                "wheel_velocity": [0.0, 0.0, 0.0, 0.0],
                "battery_voltage": 0.0,
                "estop": False,
                "fault_code": 0,
            }
        )
        status_signature = (
            status["connected"],
            status["mode"],
            status["client_node"],
            status["server_error"],
        )
        if status_signature != last_status_signature:
            print(
                "[loopback] status changed: "
                f"connected={status['connected']} mode={status['mode']} "
                f"client={status['client_node'] or '-'} "
                f"server_error={status['server_error'] or '-'}",
                flush=True,
            )
            last_status_signature = status_signature
        last_state_publish = current_time

    time.sleep(0.05)


gateway.on_cmd_vel(handle_cmd_vel)
gateway.on_mode_change(handle_mode_change)
gateway.on_stop(handle_safe_stop)

App.run(user_loop=loop)