电商网站为什么要提高网站友好度智能手机网站开发

张小明 2026/1/9 10:28:01
电商网站为什么要提高网站友好度,智能手机网站开发,百度百度一下你就知道主页,苏州网站托管本节开始#xff0c;我们将以ROS2的核心概念为线索#xff0c;详细讲解ROS2的应用开发方法#xff0c;其中包括但不限于#xff1a;工作空间#xff08;Workspace#xff09;#xff1a;项目文件夹#xff0c;包含所有ROS2包的容器#xff1b;功能包#xff08;Packa…本节开始我们将以ROS2的核心概念为线索详细讲解ROS2的应用开发方法其中包括但不限于工作空间Workspace项目文件夹包含所有ROS2包的容器功能包Package软件模块包含实现特定功能的代码和资源节点Node机器人的工作细胞话题Topic异步通信通道用于发布/订阅数据流服务Service同步请求/响应用于一次性任务通信接口Interface数据传输的标准结构参数Parameter运行时配置可在节点运行时动态调整动作Action完整行为的流程管理分布式通信Distributed Communication多计算平台的任务分配DDSData Distribution Service机器人的神经网络。回到顶部一、工作空间和功能包1.1 工作空间在之前的学习和开发中我们应该有接触过某些集成开发环境比如Visual Studio、Eclipse、Qt Creator等当我们想要编写程序之前都会在这些开发环境的工具栏中点击一个“创建新工程”的选项此时就产生一个文件夹后续所有工作产生的文件都会放置在这个文件夹中这个文件夹以及里边的内容就叫做是工程。1.1.1 什么是工作空间类似的在ROS机器人开发中我们针对机器人某些功能进行代码开始时各种编写的代码、参数、脚本等文件也需要放置在某一个文件夹里进行管理这个文件夹在ROS系统中就叫做工作空间。所以工作空间是一个存放项目开发相关文件的文件夹也是开发过程中存放所有资料的大本营。ROS系统中一个典型的工作空间结构如图所示这个dev_ws就是工作空间的根目录里边会有四个子目录或者叫做四个子空间其中src代码空间未来编写的代码、脚本都需要人为的放置到这里build编译空间保存编译过程中产生的中间文件对于每个包将创建一个子文件夹在其中调用调用编译命令install安装空间是每个软件包将安装到的位置默认情况下每个包都将安装到单独的子目录中log日志空间编译和运行过程中保存各种警告、错误、信息等日志。总体来讲这四个空间的文件夹我们绝大部分操作都是在src中进行的编译成功后就会执行install里边的可执行文件build和log两个文件夹用的很少。1.1.2 创建工作空间了解了工作空间的概念和结果接下来我们可以使用如下命令创建一个工作空间并且下载教程的代码piNanoPC-T6:~$ mkdir -p ~/dev_ws/src注意实际上在上一篇博客中我们已经创建了这个工作目录。下载教程代码piNanoPC-T6:~$ cd ~/dev_ws/srcpiNanoPC-T6:~/dev_ws/src$ pwd/home/pi/dev_ws/srcpiNanoPC-T6:~/dev_ws/src$ git clone https://gitee.com/guyuehome/ros2_21_tutorials.git1.1.3 自动安装依赖我们从社区中下载的各种代码多少都会有一些依赖我们可以手动一个一个安装也可以使用rosdep工具自动安装。rosdep功能能够自动解决依赖关系让ROS开发从依赖地狱变成一键配置是专业ROS开发的必备工具。rosdepc是通过pip安装的Python工具因此需要先安装Python包管理工具pip3piNanoPC-T6:~/dev_ws/src$ sudo apt install -y python3-pip注意该命令需要修改系统级目录 /usr/bin, /usr/lib 等因此需要root权限。安装 rosdepc原版是rosdep但国内访问慢rosdepc使用国内镜像速度快piNanoPC-T6:~/dev_ws/src$ suo pip3 install rosdepc创建配置文件设置国内镜像源piNanoPC-T6:~/dev_ws/src$ sudo rosdepc init注意需要在 /etc/ros/rosdep/sources.list.d/ 创建配置文件因此需要root权限。从配置的源下载最新的包依赖信息下载数据到用户目录 ~/.ros/rosdep/piNanoPC-T6:~/dev_ws/src$ rosdepc update自动安装src目录下所有ROS包的依赖piNanoPC-T6:~/dev_ws/src$ cd ..piNanoPC-T6:~/dev_ws$ rosdepc install -i --from-path src --rosdistro humble -y具体流程如下扫描 src 目录查找所有 package.xml 文件解析依赖读取 depend、exec_depend 等标签映射到系统包将ROS包名映射到ubuntu/debian包名执行安装实际上调用的是sudo apt install ros-humble-package1 ros-humble-package2 ...。1.1.4 编译工作空间依赖安装完成后就可以使用colcon命令编译工作空间。我们首先安装colconcolcon是ROS2的标准化构建工具用于编译ROS2工作空间的所有功能包piNanoPC-T6:~/dev_ws$ sudo apt install python3-colcon-ros执行编译命令piNanoPC-T6:~/dev_ws$ colcon build该命令执行如下操作扫描src/目录下的所有ROS包根据包类型CMake/Python选择构建方式编译所有包安装到install/目录。编译成功后就可以在工作空间中看到自动生成的build、log、install文件夹了1.1.5 设置环境变量系统默认只搜索系统路径 /opt/ros/humble/编译成功后为了让系统能够找到我们的功能包和可执行文件还需要设置环境变量piNanoPC-T6:~/dev_ws$ source install/local_setup.shsource 命令将工作空间的路径添加到环境变量中。为了使所有终端均生效执行如下命令piNanoPC-T6:~/dev_ws$ echo source ~/dev_ws/install/local_setup.sh ~/.bashrc至此我们就完成了工作空间的创建、编译和配置。1.2 功能包想象你正在开发羽绒服分拣机器人它有多个核心功能视觉识别羽绒服控制宇树G1底盘移动操控灵巧手抓取规划最优路径如果把所有代码混在一个文件夹里当你只想分享视觉识别模块给同事时就得像在杂乱的豆子堆里挑出黄豆一样费力。功能包解决了这个痛点一个工作空间下可以有多个功能包一个功能包可以有多个节点存在。如何在ROS2中创建一个功能包呢我们可以使用这个指令ros2 pkg create --build-type build-type package_name其中pkg表示功能包相关的功能create表示创建功能包build-type表示新创建的功能包是C还是Python的如果使用C或者C那这里就跟ament_cmake如果使用Python就跟ament_pythonpackage_name新建功能包的名字。1.2.1 C版本比如我们创建一个视觉识别羽绒服的C版本的功能包piNanoPC-T6:~/dev_ws$ cd src/piNanoPC-T6:~/dev_ws/src$ ros2 pkg create --build-type ament_cmake jacket_detection_pkg_c首先看下C类型的功能包piNanoPC-T6:~/dev_ws/src$ ll jacket_detection_pkg_c/-rw-rw-r-- 1 pi pi 915 Dec 10 14:02 CMakeLists.txtdrwxrwxr-x 3 pi pi 4096 Dec 10 14:02 include/-rw-rw-r-- 1 pi pi 602 Dec 10 14:02 package.xmldrwxrwxr-x 2 pi pi 4096 Dec 10 14:02 src/其中必然存在两个文件package.xml和CMakerLists.txt。1.2.1.1 package.xmlpackage.xml文件的主要内容如下包含功能包的版权描述和各种依赖的声明?xml version1.0??xml-model hrefhttp://download.ros.org/schema/package_format3.xsd schematypenshttp://www.w3.org/2001/XMLSchema?package format3namejacket_detection_pkg_c/nameversion0.0.0/versiondescriptionTODO: Package description/descriptionmaintainer emailroottodo.todoroot/maintainerlicenseTODO: License declaration/licensebuildtool_dependament_cmake/buildtool_dependtest_dependament_lint_auto/test_dependtest_dependament_lint_common/test_dependexportbuild_typeament_cmake/build_type/export/package1.2.1.2 CMakeLists.txtCMakeLists.txt文件是编译规则C代码需要编译才能运行所以必须要在该文件中设置如何编译使用CMake语法cmake_minimum_required(VERSION 3.8)project(jacket_detection_pkg_c)if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES Clang)add_compile_options(-Wall -Wextra -Wpedantic)endif()# find dependenciesfind_package(ament_cmake REQUIRED)# uncomment the following section in order to fill in# further dependencies manually.# find_package(dependency REQUIRED)if(BUILD_TESTING)find_package(ament_lint_auto REQUIRED)# the following line skips the linter which checks for copyrights# comment the line when a copyright and license is added to all source filesset(ament_cmake_copyright_FOUND TRUE)# the following line skips cpplint (only works in a git repo)# comment the line when this package is in a git repo and when# a copyright and license is added to all source filesset(ament_cmake_cpplint_FOUND TRUE)ament_lint_auto_find_test_dependencies()endif()ament_package()1.2.2 Python版本比如我们创建一个视觉识别羽绒服的Python版本的功能包piNanoPC-T6:~/dev_ws$ cd srcpiNanoPC-T6:~/dev_ws/src$ ros2 pkg create --build-type ament_python jacket_detection_pkg_python首先看下Python类型的功能包piNanoPC-T6:~/dev_ws/src$ ll jacket_detection_pkg_python/drwxrwxr-x 2 pi pi 4096 Dec 10 14:03 jacket_detection_pkg_python/-rw-rw-r-- 1 pi pi 637 Dec 10 14:03 package.xmldrwxrwxr-x 2 pi pi 4096 Dec 10 14:03 resource/-rw-rw-r-- 1 pi pi 123 Dec 10 14:03 setup.cfg-rw-rw-r-- 1 pi pi 708 Dec 10 14:03 setup.pydrwxrwxr-x 2 pi pi 4096 Dec 10 14:03 test/C功能包需要将源码编译成可执行文件但是Python语言是解析型的不需要编译所以会有一些不同但也会有这两个文件package.xml和setup.py。1.2.2.1 package.xmlpackage.xml文件的主要内容和C版本功能包一样包含功能包的版权描述和各种依赖的声明?xml version1.0??xml-model hrefhttp://download.ros.org/schema/package_format3.xsd schematypenshttp://www.w3.org/2001/XMLSchema?package format3namejacket_detection_pkg_python/nameversion0.0.0/versiondescriptionTODO: Package description/descriptionmaintainer emailroottodo.todoroot/maintainerlicenseTODO: License declaration/licensetest_dependament_copyright/test_dependtest_dependament_flake8/test_dependtest_dependament_pep257/test_dependtest_dependpython3-pytest/test_dependexportbuild_typeament_python/build_type/export/package1.2.2.2 setup.pysetup.py文件里边也包含一些版权信息除此之外还有entry_points配置的程序入口在后续编程讲解中我们会给介绍如何使用#from setuptools import find_packages, setuppackage_name jacket_detection_pkg_pythonsetup(namepackage_name,version0.0.0,packagesfind_packages(exclude[test]),data_files[(share/ament_index/resource_index/packages,[resource/ package_name]),(share/ package_name, [package.xml]),],install_requires[setuptools],zip_safeTrue,maintainerroot,maintainer_emailroottodo.todo,descriptionTODO: Package description,licenseTODO: License declaration,extras_require{test: [pytest,],},entry_points{console_scripts: [],},)1.3 编译功能包在创建好的功能包中我们可以继续完成代码的编写之后需要编译和配置环境变量才能正常运行piNanoPC-T6:~/dev_ws$ colcon buildpiNanoPC-T6:~/dev_ws$ source install/local_setup.sh回到顶部二、节点机器人是各种功能的综合体每一项功能就像机器人的一个工作细胞众多细胞通过一些机制连接到一起成为了一个机器人整体。2.1 定义在ROS中我们给这些细胞取了一个名字那就是节点。完整的机器人系统可能并不是一个物理上的整体比如这样一个的机器人在机器人身体里搭载了一台计算机A它可以通过机器人的眼睛——摄像头获取外界环境的信息也可以控制机器人的腿——轮子让机器人移动到想要去的地方。除此之外可能还会有另外一台计算机B放在你的桌子上它可以远程监控机器人看到的信息也可以远程配置机器人的速度和某些参数还可以连接一个摇杆人为控制机器人前后左右运动。这些功能虽然位于不同的计算机中但都是这款机器人的工作细胞也就是节点他们共同组成了一个完整的机器人系统节点在机器人系统中的职责就是执行某些具体的任务从计算机操作系统的角度来看也叫做进程每个节点都是一个可以独立运行的可执行文件比如执行某一个python程序或者执行C编译生成的结果都算是运行了一个节点既然每个节点都是独立的执行文件那自然就可以想到得到这个执行文件的编程语言可以是不同的比如C、Python乃至Java、Ruby等更多语言这些节点是功能各不相同的细胞根据系统设计的不同可能位于计算机A也可能位于计算机B还有可能运行在云端这叫做分布式也就是可以分布在不同的硬件载体上每一个节点都需要有唯一的命名当我们想要去找到某一个节点的时候或者想要查询某一个节点的状态时可以通过节点的名称来做查询。节点也可以比喻是一个一个的工人分别完成不同的任务他们有的在一线厂房工作有的在后勤部门提供保障他们互相可能并不认识但却一起推动机器人这座“工厂”完成更为复杂的任务。2.2 创建功能包接下来我们就来看看 节点这个工作细胞到底该如何实现。创建my_learning_node的Python版本的功能包piNanoPC-T6:~/dev_ws$ cd srcpiNanoPC-T6:~/dev_ws/src$ ros2 pkg create --build-type ament_python my_learning_node2.3 Hello World节点面向过程2.3.1 代码实现使用VS Code加载功能包my_learning_node在my_learning_node文件夹下创建node_helloworld.pyROS2节点示例-发布“Hello ROS2”日志信息, 使用面向过程的实现方式author: zysince 2025/12/10import rclpy # ROS2 Python接口库from rclpy.node import Node # ROS2 节点类import timedef main(argsNone): # ROS2节点主入口main函数rclpy.init(argsargs) # ROS2 Python接口初始化node Node(node_helloworld) # 创建ROS2节点对象并进行初始化while rclpy.ok(): # ROS2系统是否正常运行node.get_logger().info(Hello ROS2) # ROS2日志输出time.sleep(0.5) # 休眠控制循环时间node.destroy_node() # 销毁节点对象rclpy.shutdown() # 关闭ROS2 Python接口完成代码的编写后需要设置功能包的编译选项让系统知道Python程序的入口打开功能包的setup.py文件加入如下入口点的配置entry_points{console_scripts: [node_helloworld my_learning_node.node_helloworld:main,],},2.3.2 编译运行编译程序piNanoPC-T6:~/dev_ws$ colcon build --paths src/my_learning_node运行程序piNanoPC-T6:~/dev_ws$ ros2 run my_learning_node node_helloworld[INFO] [1765376447.481679427] [node_helloworld]: Hello ROS2[INFO] [1765376447.984952328] [node_helloworld]: Hello ROS2[INFO] [1765376448.487107243] [node_helloworld]: Hello ROS2[INFO] [1765376448.989235494] [node_helloworld]: Hello ROS2[INFO] [1765376449.492952293] [node_helloworld]: Hello ROS2[INFO] [1765376449.996062841] [node_helloworld]: Hello ROS22.3.3 流程分析代码中出现的函数未来会经常用到我们先不用纠结函数的具体使用方法更重要的是理解节点的编码流程。总结一下想要实现一个节点代码的实现流程是这样做编程接口初始化创建节点并初始化实现节点功能销毁节点并关闭接口如果有学习过C或者Pyhton的话应该可以发现这里我们使用的是面向过程的编程方法这种方式虽然实现简单但是对于稍微复杂一点的机器人系统就很难做到模块化编码。2.4 Hello World节点面向对象在ROS2的开发中我们更推荐使用面向对象的编程方式比如刚才的代码就可以改成这样虽然看上去复杂了一些但是代码会具备更好的可读性和可移植性调试起来也会更加方便。2.4.1 代码实现在my_learning_node文件夹下创建node_helloworld_class.pyROS2节点示例-发布“Hello ROS2”日志信息, 使用面向对象的实现方式author: zysince 2025/12/10import rclpy # ROS2 Python接口库from rclpy.node import Node # ROS2 节点类import time创建一个HelloWorld节点, 初始化时输出“hello ROS2”日志class HelloWorldNode(Node):def __init__(self, name):super().__init__(name) # ROS2节点父类初始化while rclpy.ok(): # ROS2系统是否正常运行self.get_logger().info(Hello ROS2) # ROS2日志输出time.sleep(0.5) # 休眠控制循环时间def main(argsNone): # ROS2节点主入口main函数rclpy.init(argsargs) # ROS2 Python接口初始化node HelloWorldNode(node_helloworld_class) # 创建ROS2节点对象并进行初始化rclpy.spin(node) # 循环等待ROS2退出node.destroy_node() # 销毁节点对象rclpy.shutdown() # 关闭ROS2 Python接口完成代码的编写后需要设置功能包的编译选项让系统知道Python程序的入口打开功能包的setup.py文件加入如下入口点的配置entry_points{console_scripts: [node_helloworld my_learning_node.node_helloworld:main,node_helloworld_class my_learning_node.node_helloworld_class:main],},2.4.2 编译运行编译程序piNanoPC-T6:~/dev_ws$ colcon build --paths src/my_learning_node运行程序piNanoPC-T6:~/dev_ws$ ros2 run my_learning_node node_helloworld_class[INFO] [1765377767.127477791] [node_helloworld_class]: Hello ROS2[INFO] [1765377767.630748912] [node_helloworld_class]: Hello ROS2[INFO] [1765377768.134523430] [node_helloworld_class]: Hello ROS2[INFO] [1765377768.637336571] [node_helloworld_class]: Hello ROS22.4.3 流程分析所以总体而言节点的实现方式依然是这四个步骤只不过编码方式做了一些改变而已编程接口初始化创建节点并初始化实现节点功能销毁节点并关闭接口到这里为止大家是不是心里还有一个疑惑机器人中的节点不能只是打印Hello ROS2吧是不是得完成一些具体的任务。2.5 物体识别节点接下来我们就以机器视觉的任务为例模拟实际机器人中节点的实现过程。我们先从网上找到一张苹果的图片通过编写一个节点来识别图片中的苹果2.5.1 代码实现在my_learning_node文件夹下创建node_object.pyROS2节点示例-通过颜色识别检测图片中出现的苹果author: zysince 2025/12/10import rclpy # ROS2 Python接口库from rclpy.node import Node # ROS2 节点类import cv2 # OpenCV图像处理库import numpy as np # Python数值计算库lower_red np.array([0, 90, 128]) # 红色的HSV阈值下限upper_red np.array([180, 255, 255]) # 红色的HSV阈值上限def object_detect(image):hsv_img cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 图像从BGR颜色模型转换为HSV模型mask_red cv2.inRange(hsv_img, lower_red, upper_red) # 图像二值化contours, hierarchy cv2.findContours(mask_red, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) # 图像中轮廓检测for cnt in contours: # 去除一些轮廓面积太小的噪声if cnt.shape[0] 150:continue(x, y, w, h) cv2.boundingRect(cnt) # 得到苹果所在轮廓的左上角xy像素坐标及轮廓范围的宽和高cv2.drawContours(image, [cnt], -1, (0, 255, 0), 2)# 将苹果的轮廓勾勒出来cv2.circle(image, (int(xw/2), int(yh/2)), 5, (0, 255, 0), -1)# 将苹果的图像中心点画出来cv2.imshow(object, image) # 使用OpenCV显示处理后的图像效果cv2.waitKey(0)cv2.destroyAllWindows()def main(argsNone): # ROS2节点主入口main函数rclpy.init(argsargs) # ROS2 Python接口初始化node Node(node_object) # 创建ROS2节点对象并进行初始化node.get_logger().info(ROS2节点示例检测图片中的苹果)image cv2.imread(/home/pi/dev_ws/src/my_learning_node/my_learning_node/apple.png) # 读取图像object_detect(image) # 苹果检测rclpy.spin(node) # 循环等待ROS2退出node.destroy_node() # 销毁节点对象rclpy.shutdown() # 关闭ROS2 Python接口这里主要使用了轮廓检测算法有关轮廓检测可以参考我们之前的文章《第五节、轮廓检测、直线和圆、多边形检测》。完成代码的编写后需要设置功能包的编译选项让系统知道Python程序的入口打开功能包的setup.py文件加入如下入口点的配置entry_points{console_scripts: [node_helloworld my_learning_node.node_helloworld:main,node_helloworld_class my_learning_node.node_helloworld_class:main,node_object my_learning_node.node_object:main,],},2.5.2 编译运行在这个例程中我们将用到一个图像处理的库OpenCV运行前请使用如下指令安装piNanoPC-T6:~/dev_ws$ sudo apt install python3-opencv注意这里通过系统级apt包管理器进行安装安装到系统标准目录与使用Python的pip包管理器安装的相比更加稳定。查看已安装的包文件piNanoPC-T6:~/dev_ws$ dpkg -L python3-opencv/usr/usr/lib/usr/lib/python3/usr/lib/python3/dist-packages/usr/lib/python3/dist-packages/cv2.cpython-310-aarch64-linux-gnu.so/usr/share/usr/share/doc/usr/share/doc/python3-opencv/usr/share/doc/python3-opencv/copyright/usr/share/doc/python3-opencv/changelog.Debian.gz编译程序piNanoPC-T6:~/dev_ws$ colcon build --paths src/my_learning_node运行程序piNanoPC-T6:~/dev_ws$ ros2 run my_learning_node node_object[INFO] [1765380073.155551331] [node_object]: ROS2节点示例检测图片中的苹果运行结果如下2.6 机器视觉识别节点用图片进行识别好像还不太合理机器人应该有眼睛呀没问题接下来我们就让节点读取摄像头的图像动态识别其中的橘子或者类似颜色的物体。2.6.1 代码实现在my_learning_node文件夹下创建node_object_webcam.pyROS2节点示例-通过摄像头识别检测图片中出现的橘子author: zysince 2025/12/10import rclpy # ROS2 Python接口库from rclpy.node import Node # ROS2 节点类import cv2 # OpenCV图像处理库import numpy as np # Python数值计算库# 橘子的HSV颜色范围lower_orange np.array([10, 100, 100]) # 橙色的HSV阈值下限upper_orange np.array([25, 255, 255]) # 橙色的HSV阈值上限def object_detect(image):hsv_img cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 图像从BGR颜色模型转换为HSV模型mask_orange cv2.inRange(hsv_img, lower_orange, upper_orange) # 图像二值化contours, hierarchy cv2.findContours(mask_orange, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) # 图像中轮廓检测for cnt in contours: # 去除一些轮廓面积太小的噪声if cnt.shape[0] 150:continue(x, y, w, h) cv2.boundingRect(cnt) # 得到橘子所在轮廓的左上角xy像素坐标及轮廓范围的宽和高cv2.drawContours(image, [cnt], -1, (0, 255, 0), 2) # 将橘子的轮廓勾勒出来cv2.circle(image, (int(xw/2), int(yh/2)), 5, (0, 255, 0), -1) # 将橘子的图像中心点画出来cv2.imshow(object, image) # 使用OpenCV显示处理后的图像效果cv2.waitKey(50)def main(argsNone): # ROS2节点主入口main函数rclpy.init(argsargs) # ROS2 Python接口初始化node Node(node_object_webcam) # 创建ROS2节点对象并进行初始化node.get_logger().info(ROS2节点示例检测图片中的橘子)cap cv2.VideoCapture(/dev/video21) # 使用设备路径while rclpy.ok():ret, image cap.read() # 读取一帧图像if ret True:object_detect(image) # 橘子检测cap.release() # 释放摄像头cv2.destroyAllWindows() # 关闭所有窗口node.destroy_node() # 销毁节点对象rclpy.shutdown() # 关闭ROS2 Python接口if __name__ __main__:main()完成代码的编写后需要设置功能包的编译选项让系统知道Python程序的入口打开功能包的setup.py文件加入如下入口点的配置entry_points{console_scripts: [node_helloworld my_learning_node.node_helloworld:main,node_helloworld_class my_learning_node.node_helloworld_class:main,node_object my_learning_node.node_object:main,node_object_webcam my_learning_node.node_object_webcam:main,],},2.6.2 硬件连接接着我们给开发板接上USB摄像头使用dmeg查看内核打印信息piNanoPC-T6:~/dev_ws$ dmesg......[12731.276915] usb 1-1.1: new high-speed USB device number 19 using xhci-hcd[12731.408824] usb 1-1.1: New USB device found, idVendor0c45, idProduct6340, bcdDevice 0.00[12731.408879] usb 1-1.1: New USB device strings: Mfr2, Product1, SerialNumber0[12731.408903] usb 1-1.1: Product: USB 2.0 Camera[12731.408922] usb 1-1.1: Manufacturer: Sonix Technology Co., Ltd.[12731.452930] usb 1-1.1: Found UVC 1.00 device USB 2.0 Camera (0c45:6340)在Linux中USB摄像头通常对应/dev/videoX设备文件。我们可以通过下面的方法查找摄像头设备文件查看所有视频设备及其信息piNanoPC-T6:~/dev_ws$ v4l2-ctl --list-devicesrk_hdmirx (fdee0000.hdmirx-controller):/dev/video20rkisp-statistics (platform: rkisp):/dev/video18/dev/video19rkcif-mipi-lvds2 (platform:rkcif-mipi-lvds2):/dev/media0rkisp_mainpath (platform:rkisp0-vir0):/dev/video11/dev/video12/dev/video13/dev/video14/dev/video15/dev/video16/dev/video17/dev/media1USB 2.0 Camera: USB Camera (usb-xhci-hcd.3.auto-1.1):/dev/video21/dev/video22/dev/media2Failed to open /dev/video0: No such device查看特定摄像头的详细信息piNanoPC-T6:~/dev_ws$ v4l2-ctl -d /dev/video21 --allDriver Info:Driver name : uvcvideoCard type : USB 2.0 Camera: USB CameraBus info : usb-xhci-hcd.3.auto-1.1Driver version : 6.1.118Capabilities : 0x84a00001Video CaptureMetadata CaptureStreamingExtended Pix FormatDevice CapabilitiesDevice Caps : 0x04200001Video CaptureStreamingExtended Pix FormatMedia Driver Info:Driver name : uvcvideoModel : USB 2.0 Camera: USB CameraSerial :Bus info : usb-xhci-hcd.3.auto-1.1Media version : 6.1.118Hardware revision: 0x00000000 (0)Driver version : 6.1.118Interface Info:ID : 0x03000002Type : V4L VideoEntity Info:ID : 0x00000001 (1)Name : USB 2.0 Camera: USB CameraFunction : V4L2 I/OFlags : defaultPad 0x01000007 : 0: SinkLink 0x02000010: from remote pad 0x100000a of entity Extension 4 (Video Pixel Formatter): Data, Enabled, ImmutablePriority: 2Video input : 0 (Input 1: ok)Format Video Capture:Width/Height : 640/480Pixel Format : YUYV (YUYV 4:2:2)Field : NoneBytes per Line : 1280Size Image : 614400Colorspace : sRGBTransfer Function : Rec. 709YCbCr/HSV Encoding: ITU-R 601Quantization : Default (maps to Limited Range)Flags :Crop Capability Video Capture:Bounds : Left 0, Top 0, Width 640, Height 480Default : Left 0, Top 0, Width 640, Height 480Pixel Aspect: 1/1Selection Video Capture: crop_default, Left 0, Top 0, Width 640, Height 480, Flags:Selection Video Capture: crop_bounds, Left 0, Top 0, Width 640, Height 480, Flags:Streaming Parameters Video Capture:Capabilities : timeperframeFrames per second: 25.000 (25/1)Read buffers : 0User Controlsbrightness 0x00980900 (int) : min-64 max64 step1 default-20 value-20contrast 0x00980901 (int) : min0 max64 step1 default32 value32saturation 0x00980902 (int) : min1 max128 step1 default65 value65hue 0x00980903 (int) : min-40 max40 step1 default-6 value-6white_balance_automatic 0x0098090c (bool) : default1 value1gamma 0x00980910 (int) : min72 max500 step1 default110 value110gain 0x00980913 (int) : min0 max100 step1 default0 value0power_line_frequency 0x00980918 (menu) : min0 max2 default1 value1 (50 Hz)0: Disabled1: 50 Hz2: 60 Hzwhite_balance_temperature 0x0098091a (int) : min2800 max6500 step1 default4600 value4600 flagsinactivesharpness 0x0098091b (int) : min0 max5 step1 default1 value1backlight_compensation 0x0098091c (int) : min0 max2 step1 default1 value1piNanoPC-T6:~/dev_ws$ v4l2-ctl -d /dev/video22 --allDriver Info:Driver name : uvcvideoCard type : USB 2.0 Camera: USB CameraBus info : usb-xhci-hcd.3.auto-1.1Driver version : 6.1.118Capabilities : 0x84a00001Video CaptureMetadata CaptureStreamingExtended Pix FormatDevice CapabilitiesDevice Caps : 0x04a00000Metadata CaptureStreamingExtended Pix FormatMedia Driver Info:Driver name : uvcvideoModel : USB 2.0 Camera: USB CameraSerial :Bus info : usb-xhci-hcd.3.auto-1.1Media version : 6.1.118Hardware revision: 0x00000000 (0)Driver version : 6.1.118Interface Info:ID : 0x03000005Type : V4L VideoEntity Info:ID : 0x00000004 (4)Name : USB 2.0 Camera: USB CameraFunction : V4L2 I/OPriority: 2Format Metadata Capture:Sample Format : UVCH (UVC Payload Header Metadata)Buffer Size : 10240在UVCUSB Video Class摄像头中通常会创建多个设备文件每个对应不同的功能其中特性 主视频流设备 (/dev/video21) 元数据设备 (/dev/video22)主要功能 传输实际的视频帧数据 传输视频帧的元数据信息数据内容 YUYV/MJPG等编码的视频像素数据 时间戳、帧类型、错误标志等使用场景 OpenCV、视频录制、实时显示 帧同步、时间戳对齐、错误检测数据量 较大如640x480 YUYV ≈ 614KB/帧 较小如10240字节/帧OpenCV支持 ✅ 完全支持 ❌ 不支持特殊用途典型用户 应用程序开发者 系统级/底层开发者我们如果要拍照使用的设备应该是/dev/video21因此我们需要修改node_object_webcam.py文件中使用的摄像头。2.6.3 编译运行编译程序piNanoPC-T6:~/dev_ws$ colcon build --paths src/my_learning_node运行程序piNanoPC-T6:~/dev_ws$ ros2 run my_learning_node node_object_webcam[INFO] [1765382534.514690053] [node_object_webcam]: ROS2节点示例检测图片中的橘子[ WARN:0] global ./modules/videoio/src/cap_gstreamer.cpp (2075) handleMessage OpenCV | GStreamer warning: Embedded video playback halted; module source reported: Could not read from resource.[ WARN:0] global ./modules/videoio/src/cap_gstreamer.cpp (1053) open OpenCV | GStreamer warning: unable to start pipeline[ WARN:0] global ./modules/videoio/src/cap_gstreamer.cpp (616) isPipelinePlaying OpenCV | GStreamer warning: GStreamer: pipeline have not been created运行结果如下2.7 节点命令操作查看节点列表piNanoPC-T6:~/dev_ws$ ros2 node list/node_object_webcam查看节点信息piNanoPC-T6:~/dev_ws$ ros2 node info /node_object_webcam/node_object_webcamSubscribers:Publishers:/parameter_events: rcl_interfaces/msg/ParameterEvent/rosout: rcl_interfaces/msg/LogService Servers:/node_object_webcam/describe_parameters: rcl_interfaces/srv/DescribeParameters/node_object_webcam/get_parameter_types: rcl_interfaces/srv/GetParameterTypes/node_object_webcam/get_parameters: rcl_interfaces/srv/GetParameters/node_object_webcam/list_parameters: rcl_interfaces/srv/ListParameters/node_object_webcam/set_parameters: rcl_interfaces/srv/SetParameters/node_object_webcam/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomicallyService Clients:Action Servers:Action Clients:2.8 思考题现在我们已经熟悉节点这个工作细胞的概念和实现方法了回到这个机器人系统的框架图我们还会发现另外一个问题。电脑B中的摇杆要控制机器人运动这两个节点岂不是应该有某种连接比如摇杆节点发送一个速度指令给运动节点收到后机器人开始运动。同理如果我们想要改变机器人的速度负责配置参数的节点就得发送一个指令给运动节点如果电脑B想要显示机器人看到的图像电脑A中的摄像头节点就得把图像发送过来。没错在一个ROS机器人的系统中节点并不是孤立的他们之间会有很多种机制保持联系接下来我们将介绍这些机制中最为常用的一种。回到顶部三、话题节点实现了机器人各种各样的功能但这些功能并不是独立的之间会有千丝万缕的联系其中最重要的一种联系方式就是话题它是节点间传递数据的桥梁。3.1 通信模型以两个机器人节点为例。A节点的功能是驱动相机这个硬件设备获取得到相机拍摄的图像信息B节点的功能是视频监控将相机拍摄到的图像实时显示给用户查看。我们可以想一下这两个节点是不是必然存在某种关系没错节点A要将获取的图像数据传输给节点B有了数据节点B才能做这样可视化的渲染。此时从节点A到节点B传递图像数据的方式在ROS中我们就称之为话题它作为一个桥梁实现了节点之间某一个方向上的数据传输。3.1.1 发布/订阅模型从话题本身的实现角度来看使用了基于DDS的发布/订阅模型什么叫发布和订阅呢话题数据传输的特性是从一个节点到另外一个节点发送数据的对象称之为发布者接收数据的对象称之为订阅者每一个话题都需要有一个名字传输的数据也需要有固定的数据类型。打一个比方我们平时会看微信公众号比如有一个公众号它的名字叫做“硕博直通车”这个硕博直通车就是话题名称公众号的发布者是硕博直通车的小编他会把组织好的机器人知识排版成要求格式的公众号文章发布出去这个文章格式就是话题的数据类型如果大家对这个话题感兴趣就可以订阅“硕博直通车”成为订阅者之后自然就可以收到硕博直通车的公众号文章没有订阅的话也就无法收到。类似这样的发布/订阅模型在生活中随处可见比如订阅报纸、订阅杂志等等。3.1.2 多对多通信我们再仔细想下这些可以订阅的东西是不是并不是唯一的我们每个人可以订阅很多公众号、报纸、杂志这些公众号、报纸、杂志也可以被很多人订阅没错ROS里的话题也是一样发布者和订阅者的数量并不是唯一的可以称之为是多对多的通信模型。因为话题是多对多的模型发布控制指令的摇杆可以有1个也可以有2个、3个订阅控制指令的机器人可以有1个也可以有2个、3个如果存在多个发送指令的节点建议大家要注意区分优先级不然机器人可能不知道该听谁的了。3.1.3 异步通信话题通信还有一个特性那就是异步这个词可能有同学是第一次听说所谓异步只要是指发布者发出数据后并不知道订阅者什么时候可以收到类似硕博直通车公众号发布一篇文章你什么时候阅读的硕博直通车根本不知道报社发出一份报纸你什么时候收到报社也是不知道的。这就叫做异步。异步的特性也让话题更适合用于一些周期发布的数据比如传感器的数据运动控制的指令等等如果某些逻辑性较强的指令比如修改某一个参数用话题传输就不太合适了。3.1.4 消息接口最后既然是数据传输发布者和订阅者就得统一数据的描述格式不能一个说英文一个理解成了中文。在ROS中话题通信数据的描述格式称之为消息对应编程语言中数据结构的概念。比如这里的一个图像数据就会包含图像的长宽像素值、每个像素的RGB等等在ROS中都有标准定义。消息是ROS中的一种接口定义方式与编程语言无关我们也可以通过.msg后缀的文件自行定义有了这样的接口各种节点就像积木块一样通过各种各样的接口进行拼接组成复杂的机器人系统。3.2 创建功能包创建my_learning_topic的Python版本的功能包piNanoPC-T6:~/dev_ws$ cd srcpiNanoPC-T6:~/dev_ws/src$ ros2 pkg create --build-type ament_python my_learning_topic3.3 Hello World话题了解了话题的基本原理接下来我们就要开始编写代码啦。还是从Hello World例程开始我们来创建一个发布者发布话题chatter周期发送Hello World这个字符串消息类型是ROS中标准定义的String再创建一个订阅者订阅chatter这个话题从而接收到Hello World这个字符串。3.3.1 发布者使用VS Code加载功能包my_learning_topic在my_learning_topic文件夹下创建topic_helloworld_pub.pyOS2话题示例-发布“Hello World”话题author: zysince 2025/12/11import rclpy # ROS2 Python接口库from rclpy.node import Node # ROS2 节点类from std_msgs.msg import String # 字符串消息类型创建一个发布者节点class PublisherNode(Node):def __init__(self, name):super().__init__(name) # ROS2节点父类初始化self.pub self.create_publisher(String, chatter, 10) # 创建发布者对象消息类型、话题名、队列长度self.timer self.create_timer(0.5, self.timer_callback) # 创建一个定时器单位为秒的周期定时执行的回调函数def timer_callback(self): # 创建定时器周期执行的回调函数msg String() # 创建一个String类型的消息对象msg.data Hello World # 填充消息对象中的消息数据self.pub.publish(msg) # 发布话题消息self.get_logger().info(Publishing: %s % msg.data) # 输出日志信息提示已经完成话题发布def main(argsNone): # ROS2节点主入口main函数rclpy.init(argsargs) # ROS2 Python接口初始化node PublisherNode(topic_helloworld_pub) # 创建ROS2节点对象并进行初始化rclpy.spin(node) # 循环等待ROS2退出node.destroy_node() # 销毁节点对象rclpy.shutdown() # 关闭ROS2 Python接口完成代码的编写后需要设置功能包的编译选项让系统知道Python程序的入口打开功能包的setup.py文件加入如下入口点的配置entry_points{console_scripts: [topic_helloworld_pub my_learning_topic.topic_helloworld_pub:main,],},对以上程序进行分析如果我们想要实现一个发布者流程如下编程接口初始化创建节点并初始化创建发布者对象创建并填充话题消息发布话题消息销毁节点并关闭接口。3.3.2 订阅者在my_learning_topic文件夹下创建topic_helloworld_sub.pyOS2话题示例-订阅“Hello World”话题消息author: zysince 2025/12/11import rclpy # ROS2 Python接口库from rclpy.node import Node # ROS2 节点类from std_msgs.msg import String # ROS2标准定义的String消息创建一个订阅者节点class SubscriberNode(Node):def __init__(self, name):super().__init__(name) # ROS2节点父类初始化self.sub self.create_subscription(\String, chatter, self.listener_callback, 10) # 创建订阅者对象消息类型、话题名、订阅者回调函数、队列长度def listener_callback(self, msg): # 创建回调函数执行收到话题消息后对数据的处理self.get_logger().info(I heard: %s % msg.data) # 输出日志信息提示订阅收到的话题消息def main(argsNone): # ROS2节点主入口main函数rclpy.init(argsargs) # ROS2 Python接口初始化node SubscriberNode(topic_helloworld_sub) # 创建ROS2节点对象并进行初始化rclpy.spin(node) # 循环等待ROS2退出node.destroy_node() # 销毁节点对象rclpy.shutdown() # 关闭ROS2 Python接口完成代码的编写后需要设置功能包的编译选项让系统知道Python程序的入口打开功能包的setup.py文件加入如下入口点的配置entry_points{console_scripts: [topic_helloworld_pub my_learning_topic.topic_helloworld_pub:main,topic_helloworld_sub my_learning_topic.topic_helloworld_sub:main,],},对以上程序进行分析如果我们想要实现一个订阅者流程如下编程接口初始化创建节点并初始化创建订阅者对象回调函数处理话题数据销毁节点并关闭接口。3.3.3 编译运行编译程序piNanoPC-T6:~/dev_ws$ colcon build --paths src/my_learning_topic启动第一个终端运行话题的发布者节点piNanoPC-T6:~/dev_ws$ ros2 run my_learning_topic topic_helloworld_pub[INFO] [1765463674.845518990] [topic_helloworld_pub]: Publishing: Hello World[INFO] [1765463675.317160733] [topic_helloworld_pub]: Publishing: Hello World[INFO] [1765463675.817255529] [topic_helloworld_pub]: Publishing: Hello World[INFO] [1765463676.316123657] [topic_helloworld_pub]: Publishing: Hello World启动第二个终端运行话题的订阅者节点piNanoPC-T6:~/dev_ws$ ros2 run my_learning_topic topic_helloworld_sub[INFO] [1765463719.846173171] [topic_helloworld_sub]: I heard: Hello World[INFO] [1765463720.318453637] [topic_helloworld_sub]: I heard: Hello World[INFO] [1765463720.818542895] [topic_helloworld_sub]: I heard: Hello World[INFO] [1765463721.318709238] [topic_helloworld_sub]: I heard: Hello World好啦Hello World例程大家一定还不过瘾接下来我们基于话题通信继续优化下之前的机器视觉例程。3.4 机器视觉识别在节点概念的讲解过程中我们通过一个节点驱动了相机并且实现了对橙色物体的识别。功能虽然没问题但是对于机器人开发来讲并没有做到程序的模块化更好的方式是将相机驱动和视觉识别做成两个节点节点间的联系就是这个图像数据通过话题周期传输即可。这个图像消息在ROS中是标准定义好的如果未来要更换另一个相机只需要修改驱动节点视觉识别节点完全是软件功能就可以保持不变了这种模块化的设计思想可以更好的保证软件的可移植性。3.4.1 发布者在my_learning_topic文件夹下创建topic_webcam_pub.pyROS2话题示例-发布图像话题author: zysince 2025/12/11import rclpy # ROS2 Python接口库from rclpy.node import Node # ROS2 节点类from sensor_msgs.msg import Image # 图像消息类型from cv_bridge import CvBridge # ROS与OpenCV图像转换类import cv2 # Opencv图像处理库创建一个发布者节点class ImagePublisher(Node):def __init__(self, name):super().__init__(name) # ROS2节点父类初始化self.publisher_ self.create_publisher(Image, image_raw, 10) # 创建发布者对象消息类型、话题名、队列长度self.timer self.create_timer(0.1, self.timer_callback) # 创建一个定时器单位为秒的周期定时执行的回调函数self.cap cv2.VideoCapture(21) # 创建一个视频采集对象驱动相机采集图像相机设备号self.cv_bridge CvBridge() # 创建一个图像转换对象用于稍后将OpenCV的图像转换成ROS的图像消息def timer_callback(self):ret, frame self.cap.read() # 一帧一帧读取图像if ret True: # 如果图像读取成功self.publisher_.publish(self.cv_bridge.cv2_to_imgmsg(frame, bgr8)) # 发布图像消息self.get_logger().info(Publishing video frame) # 输出日志信息提示已经完成图像话题发布def main(argsNone): # ROS2节点主入口main函数rclpy.init(argsargs) # ROS2 Python接口初始化node ImagePublisher(topic_webcam_pub) # 创建ROS2节点对象并进行初始化rclpy.spin(node) # 循环等待ROS2退出node.destroy_node() # 销毁节点对象rclpy.shutdown() # 关闭ROS2 Python接口完成代码的编写后需要设置功能包的编译选项让系统知道Python程序的入口打开功能包的setup.py文件加入如下入口点的配置entry_points{console_scripts: [topic_helloworld_pub my_learning_topic.topic_helloworld_pub:main,topic_helloworld_sub my_learning_topic.topic_helloworld_sub:main,topic_webcam_pub my_learning_topic.topic_webcam_pub:main,],},3.4.2 订阅者在my_learning_topic文件夹下创建topic_webcam_sub.pyROS2话题示例-订阅图像话题author: zysince 2025/12/11import rclpy # ROS2 Python接口库from rclpy.node import Node # ROS2 节点类from sensor_msgs.msg import Image # 图像消息类型from cv_bridge import CvBridge # ROS与OpenCV图像转换类import cv2 # Opencv图像处理库import numpy as np # Python数值计算库# 橘子的HSV颜色范围lower_orange np.array([10, 100, 100]) # 橙色的HSV阈值下限upper_orange np.array([25, 255, 255]) # 橙色的HSV阈值上限创建一个订阅者节点class ImageSubscriber(Node):def __init__(self, name):super().__init__(name) # ROS2节点父类初始化self.sub self.create_subscription(Image, image_raw, self.listener_callback, 10) # 创建订阅者对象消息类型、话题名、订阅者回调函数、队列长度self.cv_bridge CvBridge() # 创建一个图像转换对象用于OpenCV图像与ROS的图像消息的互相转换def object_detect(self, image):hsv_img cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 图像从BGR颜色模型转换为HSV模型mmask_orange cv2.inRange(hsv_img, lower_orange, upper_orange) # 图像二值化contours, hierarchy cv2.findContours(mmask_orange, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) # 图像中轮廓检测for cnt in contours: # 去除一些轮廓面积太小的噪声if cnt.shape[0] 150:continue(x, y, w, h) cv2.boundingRect(cnt) # 得到橘子所在轮廓的左上角xy像素坐标及轮廓范围的宽和高cv2.drawContours(image, [cnt], -1, (0, 255, 0), 2)# 将橘子的轮廓勾勒出来cv2.circle(image, (int(xw/2), int(yh/2)), 5,(0, 255, 0), -1) # 将橘子的图像中心点画出来cv2.imshow(object, image) # 使用OpenCV显示处理后的图像效果cv2.waitKey(10)def listener_callback(self, data):self.get_logger().info(Receiving video frame) # 输出日志信息提示已进入回调函数image self.cv_bridge.imgmsg_to_cv2(data, bgr8) # 将ROS的图像消息转化成OpenCV图像self.object_detect(image) # 橘子检测def main(argsNone): # ROS2节点主入口main函数rclpy.init(argsargs) # ROS2 Python接口初始化node ImageSubscriber(topic_webcam_sub) # 创建ROS2节点对象并进行初始化rclpy.spin(node) # 循环等待ROS2退出node.destroy_node() # 销毁节点对象rclpy.shutdown() # 关闭ROS2 Python接口完成代码的编写后需要设置功能包的编译选项让系统知道Python程序的入口打开功能包的setup.py文件加入如下入口点的配置
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

如何撤销网站备案电力建设官方网站

人工智能技术正深刻改变各行各业,掌握相关技能成为许多职场人提升竞争力的选择。各类专业认证为学习者提供了系统的学习路径和能力证明。本文将梳理在上海地区报考人工智能认证的主要流程,并介绍一项适合广泛人群的认证选择。一、人工智能领域主要认证简…

张小明 2026/1/7 23:48:03 网站建设

自己用自己电脑做网站空间wordpress注册美化

ok啊朋友们,咱们的教程不知不觉以及来到了第六节,所有说呢,以后的难度,会建立在前面的基础上,所以没有看过的朋友们我建议那么看一下,当然如果来大神了,算我没说。那么我们就开始这一章的学习。…

张小明 2026/1/7 23:58:52 网站建设

车陂网站建设自己搭建域名服务器

第一章:Open-AutoGLM手机AI助手进化路径Open-AutoGLM作为开源移动端AI助手框架,正逐步演变为支持多模态交互、自主任务规划与本地化推理的智能系统。其进化路径聚焦于轻量化模型部署、持续学习机制与用户隐私保护三大核心方向,推动AI助手从“…

张小明 2026/1/8 1:49:32 网站建设

做网站有用没wordpress 建多站

第一章:为什么我们需要类型转换?(现实生活的启示)生活场景想象想象一下这些情况:场景一:你有3.5升水,但瓶子只标有整数刻度,你会说“大约3升”场景二:温度计显示25.5C&am…

张小明 2026/1/8 1:59:04 网站建设

域名和网站空间怎么做解析域名访问网址

第一步,远程登录服务器第二步,在服务器管理器>仪表板界面,点击“文件和存储服务”第三步,在服务器管理器>文件和存储服务界面,点击券下面的“磁盘”,选择未分区的磁盘第四步,选择默认配置…

张小明 2026/1/8 3:44:11 网站建设

o2o网站建设报价网上设计兼职平台有哪些

毕业论文(设计)开题报告 题目 基于SSM的高校大学生就业平台的设计与实现 题目类别 毕业设计 姓名 专业 计算机科学与技术 班级 计科 学号 一、选题背景及依据(简述国内外研究状况和相关领域中已有的研究成果(文献综述),选题目的、意义,列出主要参考文献) (一)选题背…

张小明 2026/1/8 5:19:21 网站建设