ROS 2 Jazzy + Python 3.12 + Web 前端案例

综合案例:ROS 2 计数器 Web 界面

  • [注:下面步骤默认已安装ROS2 Jazzy + Anaconda,所有步骤在conda环境下进行](#注:下面步骤默认已安装ROS2 Jazzy + Anaconda,所有步骤在conda环境下进行)
  • [一、后端 ROS 2 环境设置](#一、后端 ROS 2 环境设置)
    • [1. 安装 ROS 2 核心组件和 rosbridge](#1. 安装 ROS 2 核心组件和 rosbridge)
    • [2、安装 Python 依赖(Tornado 和 PyMongo)](#2、安装 Python 依赖(Tornado 和 PyMongo))
  • [二、创建 ROS 2 Python 包](#二、创建 ROS 2 Python 包)
    • 1、创建工作空间和包
    • [2、编写 Python 发布者节点 (simple_publisher.py)](#2、编写 Python 发布者节点 (simple_publisher.py))
    • [3、创建 Launch 文件并修复参数类型(提前避免可能出现的这个问题:Trying to set parameter 'delay_between_messages' to '0' of type 'INTEGER', expecting type 'DOUBLE')](#3、创建 Launch 文件并修复参数类型(提前避免可能出现的这个问题:Trying to set parameter ‘delay_between_messages’ to ‘0’ of type ‘INTEGER’, expecting type ‘DOUBLE’))
    • [4、配置 setup.py 并添加 Launch 文件](#4、配置 setup.py 并添加 Launch 文件)
    • [5、构建并 Source 工作空间](#5、构建并 Source 工作空间)
  • 三、运行系统
    • [1、启动 ROS 2 发布者节点 (终端 A)](#1、启动 ROS 2 发布者节点 (终端 A))
    • [2、启动 rosbridge_server (终端 B)](#2、启动 rosbridge_server (终端 B))
      • [ModuleNotFoundError: No module named 'yaml'](#ModuleNotFoundError: No module named 'yaml')
      • [ModuleNotFoundError: No module named 'tornado'](#ModuleNotFoundError: No module named 'tornado')
      • [no module named 'bson'](#no module named ‘bson’)
  • [四、前端 Web 界面](#四、前端 Web 界面)
    • [1、创建 web_interface.html 文件](#1、创建 web_interface.html 文件)
    • [2、 打开 Web 界面](#2、 打开 Web 界面)

注:下面步骤默认已安装ROS2 Jazzy + Anaconda,所有步骤在conda环境下进行

python 复制代码
# 创建虚拟环境
conda create -n ros2_ws python=3.12
# 激活conda环境
conda activate

一、后端 ROS 2 环境设置

1. 安装 ROS 2 核心组件和 rosbridge

bash 复制代码
# 更新系统
sudo apt update && sudo apt upgrade -y

# 安装 ROS 2 基础环境和 rosbridge
sudo apt install ros-jazzy-ros-base ros-jazzy-rosbridge-server ros-jazzy-rosbridge-suite python3-pip -y

# 确保 rosdep 可用
sudo apt install python3-rosdep -y
sudo rosdep init
rosdep update

2、安装 Python 依赖(Tornado 和 PyMongo)

bash 复制代码
pip3 install tornado pymongo

二、创建 ROS 2 Python 包

1、创建工作空间和包

bash 复制代码
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src

ros2 pkg create web_demo --build-type ament_python --dependencies rclpy std_msgs

cd ~/ros2_ws
colcon build
source install/setup.bash

2、编写 Python 发布者节点 (simple_publisher.py)

bash 复制代码
编辑文件:~/ros2_ws/src/web_demo/web_demo/simple_publisher.py
bash 复制代码
import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class SimplePublisher(Node):
    def __init__(self):
        super().__init__('simple_publisher')
        self.publisher_ = self.create_publisher(String, 'web_counter', 10)
        self.timer_period = 0.5  # 发布频率 (0.5秒一次)
        self.timer = self.create_timer(self.timer_period, self.timer_callback)
        self.i = 0

    def timer_callback(self):
        msg = String()
        msg.data = f'Hello ROS 2 Jazzy Web! Count: {self.i}'
        self.publisher_.publish(msg)
        self.get_logger().info(f'Publishing: "{msg.data}"')
        self.i += 1

def main(args=None):
    rclpy.init(args=args)
    node = SimplePublisher()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

3、创建 Launch 文件并修复参数类型(提前避免可能出现的这个问题:Trying to set parameter 'delay_between_messages' to '0' of type 'INTEGER', expecting type 'DOUBLE')

创建一个 ~/ros2_ws/src/web_demo/launch 目录,并将rosbridge的配置复制过来。

python 复制代码
mkdir -p ~/ros2_ws/src/web_demo/launch
# 复制默认文件并重命名
cp /opt/ros/jazzy/share/rosbridge_server/launch/rosbridge_websocket_launch.xml ~/ros2_ws/src/web_demo/launch/web_bridge.launch.xml

编辑 ~/ros2_ws/src/web_demo/launch/web_bridge.launch.xml 文件。找到 delay_between_messages 参数,确保 value 是 0.0 (浮点数):

xml 复制代码
<!-- ... 文件顶部内容 ... -->
<launch>
  <node pkg="rosbridge_server" exec="rosbridge_websocket" name="rosbridge_websocket">
    <!-- 确保这个值是 "0.0" 而不是 "0" -->
    <param name="delay_between_messages" value="0.0"/>
    <param name="port" value="9090"/>
    <!-- ... 其他参数 ... -->
  </node>
</launch>

4、配置 setup.py 并添加 Launch 文件

编辑 ~/ros2_ws/src/web_demo/setup.py 文件,确保 data_files 和 entry_points 配置正确:

bash 复制代码
from setuptools import find_packages, setup
import os
from glob import glob

package_name = 'web_demo'

setup(
    name=package_name,
    version='0.0.0',
    packages=find_packages(exclude=['test']),
    data_files=[
        ('share/ament_index/resource_index/packages', ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
        # 精确添加 launch 文件,避免 glob(..*.*) 的问题
        (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*.xml'))),
        (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*.launch.py'))),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='your_name',
    maintainer_email='your_email@example.com',
    description='Web Demo Package',
    license='TODO: License declaration',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'simple_publisher = web_demo.simple_publisher:main',
        ],
    },
)

5、构建并 Source 工作空间

xml 复制代码
cd ~/ros2_ws
colcon build
# 每次打开新终端都需要执行 source
source install/setup.bash

三、运行系统

1、启动 ROS 2 发布者节点 (终端 A)

bash 复制代码
source ~/ros2_ws/install/setup.bash
ros2 run web_demo simple_publisher

2、启动 rosbridge_server (终端 B)

bash 复制代码
source ~/ros2_ws/install/setup.bash
ros2 launch web_demo web_bridge.launch.xml

ModuleNotFoundError: No module named 'yaml'

python 复制代码
[rosbridge_websocket-1]     import rclpy
[rosbridge_websocket-1]   File "/opt/ros/jazzy/lib/python3.12/site-packages/rclpy/__init__.py", line 48, in <module>
[rosbridge_websocket-1]     from rclpy.parameter import Parameter
[rosbridge_websocket-1]   File "/opt/ros/jazzy/lib/python3.12/site-packages/rclpy/parameter.py", line 27, in <module>
[rosbridge_websocket-1]     import yaml
[rosbridge_websocket-1] ModuleNotFoundError: No module named 'yaml'

解决------>安装PyYAML:

python 复制代码
pip3 install PyYAML

ModuleNotFoundError: No module named 'tornado'

python 复制代码
[rosbridge_websocket-1]   File "/opt/ros/jazzy/lib/rosbridge_server/rosbridge_websocket", line 45, in <module>
[rosbridge_websocket-1]     from tornado.httpserver import HTTPServer
[rosbridge_websocket-1] ModuleNotFoundError: No module named 'tornado'

解决------> 安装tornado:

python 复制代码
pip install tornado

no module named 'bson'

python 复制代码
# 1. 卸载可能已安装的任何冲突的 bson 或 pymongo 包
pip3 uninstall bson pymongo -y

# 2. 正确安装 pymongo。它会自动包含正确的 bson 模块
pip3 install pymongo

四、前端 Web 界面

1、创建 web_interface.html 文件

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>ROS 2 Jazzy Web Interface</title>
    <!-- 引入 roslibjs 库 -->
    <script src="https://cdn.jsdelivr.net/npm/roslib/build/roslib.min.js"></script>
    <style>
        body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; }
        #status { font-size: 20px; font-weight: bold; }
        #counter_display { font-size: 60px; color: #007BFF; margin-top: 20px; }
        .connected { color: green; }
        .disconnected { color: red; }
    </style>
</head>
<body>
    <h1>ROS 2 Web Counter Demo</h1>
    <p>WebSocket Status: <span id="status" class="disconnected">Disconnected</span></p>
    <div id="counter_display">Waiting for ROS 2 data...</div>

    <script>
        // --- 1. 连接到 rosbridge WebSocket 服务器 ---
        var ros = new ROSLIB.Ros({
            url : 'ws://localhost:9090'
        });

        ros.on('connection', function() {
            document.getElementById('status').innerText = 'Connected';
            document.getElementById('status').className = 'connected';
        });

        ros.on('error', function(error) {
            document.getElementById('status').innerText = 'Error';
            document.getElementById('status').className = 'disconnected';
            console.error(error);
        });

        ros.on('close', function() {
            document.getElementById('status').innerText = 'Disconnected';
            document.getElementById('status').className = 'disconnected';
        });

        // --- 2. 订阅 ROS 话题 ---
        var counterListener = new ROSLIB.Topic({
            ros : ros,
            name : '/web_counter', // 对应 Python 节点发布的话题名
            messageType : 'std_msgs/msg/String'
        });

        counterListener.subscribe(function(message) {
            // 收到消息后更新 HTML 元素
            document.getElementById('counter_display').innerText = message.data;
        });
    </script>
</body>
</html>

2、 打开 Web 界面

在您的浏览器中双击打开 web_interface.html 文件。

您将看到页面连接状态变为"Connected",并且实时显示来自 ROS 2 后端的计数器消息。

相关推荐
Q_Q5110082852 小时前
python+springboot+django/flask基于深度学习的淘宝用户购物可视化与行为预测系统
spring boot·python·django·flask·node.js·php
s9123601012 小时前
【rust】生成带白边的标准二维码
开发语言·后端·rust
高洁012 小时前
向量数据库拥抱大模型
python·深度学习·算法·机器学习·transformer
深度学习lover2 小时前
<数据集>yolo茶叶嫩芽识别数据集<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·茶叶嫩芽识别
G果2 小时前
Modbus CRC16 算法(举例)
can·modbus·ros2·crc16
识途老码2 小时前
python程序替换全局socket
服务器·网络·python
weixin_307779132 小时前
Jenkins Jakarta Mail API 插件:邮件功能的核心库
运维·开发语言·架构·jenkins
BoBoZz192 小时前
DiscreteMarchingCubes离散等值面提取算法
python·vtk·图形渲染·图形处理
秋刀鱼 ..2 小时前
第二届电力电子技术与电网系统国际学术会议(PETGS 2026)
大数据·python·计算机网络·数学建模·机器人·制造