返回教程正文

配套源码

main.py

app/python/main.py
ros_gateway Brick:在 App Lab 中建立可靠的 WebSocket 通道app/python/main.py
Python94 行
  1. # SPDX-License-Identifier: MIT
  2. import time
  3. from arduino.app_utils import App
  4. from ros_gateway import RosGateway
  5. gateway = RosGateway()
  6. last_state_publish = 0.0
  7. last_status_signature = None
  8. def handle_cmd_vel(command):
  9. """
  10. @description : 将经过协议校验的速度指令写入 App Lab 日志,本阶段不控制真实电机
  11. @param command : 包含 vx、vy、wz、seq 和 timestamp_ms 的速度指令
  12. @return : 无返回值
  13. """
  14. print(
  15. "[loopback] cmd_vel accepted: "
  16. f"seq={command['seq']} vx={command['vx']:.3f} "
  17. f"vy={command['vy']:.3f} wz={command['wz']:.3f}",
  18. flush=True,
  19. )
  20. def handle_mode_change(mode):
  21. """
  22. @description : 记录 ROS 2 请求的底盘模式切换
  23. @param mode : 新的底盘模式字符串
  24. @return : True 表示允许本次模式切换
  25. """
  26. print(f"[loopback] mode changed: {mode}", flush=True)
  27. return True
  28. def handle_safe_stop(reason):
  29. """
  30. @description : 处理通信超时或断线产生的安全停车事件,本阶段只记录日志
  31. @param reason : 触发安全停车的原因
  32. @return : 无返回值
  33. """
  34. print(f"[loopback] SAFE_STOP: {reason}; no CAN command sent", flush=True)
  35. def loop():
  36. """
  37. @description : 周期发布模拟底盘状态并保持 App 主循环非阻塞运行
  38. @param : 无参数
  39. @return : 无返回值
  40. """
  41. global last_state_publish, last_status_signature
  42. current_time = time.monotonic()
  43. if current_time - last_state_publish >= 1.0:
  44. status = gateway.get_status()
  45. gateway.publish_base_state(
  46. {
  47. "mode": status["mode"],
  48. "enabled": False,
  49. "wheel_position": [0.0, 0.0, 0.0, 0.0],
  50. "wheel_velocity": [0.0, 0.0, 0.0, 0.0],
  51. "battery_voltage": 0.0,
  52. "estop": False,
  53. "fault_code": 0,
  54. }
  55. )
  56. status_signature = (
  57. status["connected"],
  58. status["mode"],
  59. status["client_node"],
  60. status["server_error"],
  61. )
  62. if status_signature != last_status_signature:
  63. print(
  64. "[loopback] status changed: "
  65. f"connected={status['connected']} mode={status['mode']} "
  66. f"client={status['client_node'] or '-'} "
  67. f"server_error={status['server_error'] or '-'}",
  68. flush=True,
  69. )
  70. last_status_signature = status_signature
  71. last_state_publish = current_time
  72. time.sleep(0.05)
  73. gateway.on_cmd_vel(handle_cmd_vel)
  74. gateway.on_mode_change(handle_mode_change)
  75. gateway.on_stop(handle_safe_stop)
  76. App.run(user_loop=loop)