实验编号: 实验指导书 实验项目: 外部设备的使用 所属课程: ROS机器人操作系统基础与实战 课程代码: 面向专业: 机电专业 课程负责人: 朱笑笑 年月 日
实验编号: 实 验 指 导 书 实验项目: 外部设备的使用 所属课程: ROS 机器人操作系统基础与实战 课程代码: 面向专业: 机电专业 课程负责人: 朱笑笑 年 月 日
”、 实验目的 理解外部设备驱动的概念,掌握调用方法 2, 掌握利用RVIZ对传感器数据的读取 3, 掌握遥控手柄的使用 二、 实验内容 三、 实验过程或其他示意图 1. 游戏手柄的使用 游戏手柄包含一组多个开关型按钮和定位计型的遥感,可以用来对游戏角色进行各种 运动控制。 在OS中可以利用手柄来对机器人进行要操作改变机器人的速度或方向。比使用键盘和 鼠标要方便很多。 Step1.手柄驱动RoS包、手柄例程包安装。 S sudo apt-get install ros-kinectic-joy* 将手柄USB插入电脑,并检查设备文件,看是系统是否检测到合适的硬件。 S Is /dev/input/ 一般会输出以下内容,其中js0就是我们的手柄(joystick) by-id evento event2 event4 event6 event8 js0 mouse0 by-path eventl event3 event5 event7 event9 mice 我们可以用手柄驱动自带的命令来测试手柄是否可以正常工作。 S sudo jstest/dev/input/js0 有以下输出 Axes:0:0 1:0 2:0 Buttons:0:off 1:off 2:off 3:off 4:off 5:off 6:off 7:off 8:off 9:off 10:off 这里用的手柄罗技F710有8个遥感轴和11个按钮,如果按下按钮或者拨动摇杆可以 看到相应数字的变动。 Step2.利用joy node发出手柄的运动topic。 joy_node包可以将手柄的参数以topic的形式发出来,利用以下指令可以查看发出的topic -2
- 2 - 一、 实验目的 1, 理解外部设备驱动的概念,掌握调用方法 2, 掌握利用RVIZ对传感器数据的读取 3, 掌握遥控手柄的使用 二、 实验内容 三、 实验过程或其他示意图 1. 游戏手柄的使用 游戏手柄包含一组多个开关型按钮和定位计型的遥感,可以用来对游戏角色进行各种 运动控制。 在ROS中可以利用手柄来对机器人进行要操作改变机器人的速度或方向。比使用键盘和 鼠标要方便很多。 Step1. 手柄驱动ROS包、手柄例程包安装。 $ sudo apt-get install ros-kinectic-joy* 将手柄USB插入电脑,并检查设备文件,看是系统是否检测到合适的硬件。 $ ls /dev/input/ 一般会输出以下内容,其中js0就是我们的手柄(joystick) by-id event0 event2 event4 event6 event8 js0 mouse0 by-path event1 event3 event5 event7 event9 mice 我们可以用手柄驱动自带的命令来测试手柄是否可以正常工作。 $ sudo jstest /dev/input/js0 有以下输出 Axes: 0: 0 1: 0 2: 0 Buttons: 0:off 1:off 2:off 3:off 4:off 5:off 6:off 7:off 8:off 9:off 10:off 这里用的手柄罗技 F710 有 8 个遥感轴和 11 个按钮,如果按下按钮或者拨动摇杆可以 看到相应数字的变动。 Step2. 利用joy_node发出手柄的运动topic。 joy_node包可以将手柄的参数以topic的形式发出来,利用以下指令可以查看发出的topic
信息。 S rostopic echo /joy 将会看到输出结果 header: seq:157 stamp: secs:1357571648 nsecs::430257462 frame id:" axes:-0.0,-0.0,0.0,-0.0,-0.0,0.0-0.0,-0.01 buttons:I00,0,0,0,0,0,0,0,0,0l 可以看到主要的数据在两个向量中。 利用rosnode命令可以看到该topic的参数类型,这样可以方便后续的使用。 S rosnode type /joy 可以看到输出为sensor msgs/Joy类型。这是一个ROS系统的标准类型,进一步可以通 过rosmsg命令查看具体该类型。 S rosmsg show sensor_msgs/Joy 会有以下输出 uint32 seq time stamp string frane id float32[]axes int32[]buttons 这个消息在开发的时候是必须用到的,可以看到axes是一个float32的数组而buttons.是一 个int32的数组 Step3.利用joystick数据来在turtlesim中控制一个turtle 这里将创建一个node从joy node中获得数据然后发布topic来控制turtlesim。上面己经知 道手柄的消息类型,这里还需要查看控制turtle需要用的topic类型。 首先利用rosrun启动turtlesim turtlesim_node S rosrun turtlesim turtlesim node 观察当前的topic列表 S rostopic list 会有以下结果输出,其中turtlel/command_velocity就是我们将用到的topic -3-
- 3 - 信息。 $ rostopic echo /joy 将会看到输出结果 --- header: seq: 157 stamp: secs: 1357571648 nsecs: 430257462 frame_id: '' axes: [-0.0, -0.0, 0.0, -0.0, -0.0, 0.0, -0.0, -0.0] buttons: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] --- 可以看到主要的数据在两个向量中。 利用rosnode命令可以看到该topic的参数类型,这样可以方便后续的使用。 $ rosnode type /joy 可以看到输出为sensor_msgs/ Joy 类型。这是一个ROS系统的标准类型,进一步可以通 过rosmsg命令查看具体该类型。 $ rosmsg show sensor_msgs/Joy 会有以下输出 这个消息在开发的时候是必须用到的,可以看到axes是一个float32的数组而buttons是一 个int32的数组 Step3. 利用joystick数据来在turtlesim中控制一个turtle 这里将创建一个node从joy_node中获得数据然后发布topic来控制turtlesim。上面已经知 道手柄的消息类型,这里还需要查看控制turtle需要用的topic类型。 首先利用rosrun 启动 turtlesim turtlesim_node $ rosrun turtlesim turtlesim_node 观察当前的topic列表 $ rostopic list 会有以下结果输出,其中turtle1/command_velocity 就是我们将用到的topic
/rosout /rosout agg /turtle1/colar sensor /turtle1/conrand_velocity /turtlel/pose 利用rostopici查看topic类型 S rostopic type/turtlel/command velocity 输出 turtlesim/Velocity 同样再利用rosmsg可以查看该topic类型的具体内容 S rosmsg show turtlesim/Velocity 输出: float32 linear float32 angular 这里linear是速度的大小,angular是速度的方向 在了解输入和输出的topic类型信息后,可以开始编写node了。 创建一个joystic_turtle包,创建一个examle..cpp.输入以下代码。 #include #include //turtlesim速度控制消息类型 #include //joystick消息类型 #include using namespace std; class TeleopJoy{ public: TeleopJoy(); private: void callBack(const sensor_msgs:Joy:ConstPtr&joy吵,/joystick消息回调函数 ros:NodeHandle n; ros::Publisher pub; ros::Subscriber sub; int i_velLinear,i_velAngular; TeleopJoy::TeleopJoy() n.param("axis_linear",i_velLinear,i velLinear); n.param("axis angular",i velAngular,i velAngular): pub=n.advertise("turtlel/command_velocity",1); sub=n.subscribe("joy",10,&TeleopJoy::callBack, this): void TeleopJoy::callBack(const sensor_msgs::Joy::ConstPtr&joy) turtlesim::Velocity vel; vel.angular =joy->axes[i_velAngular]; vel.linear=joy->axes[i_velLinear]; pub.publish(vel); -4-
- 4 - 利用rostopic查看topic类型 $ rostopic type /turtle1/command_velocity 输出 turtlesim/Velocity 同样再利用rosmsg可以查看该topic类型的具体内容 $ rosmsg show turtlesim/Velocity 输出: float32 linear float32 angular 这里linear是速度的大小,angular是速度的方向 在了解输入和输出的topic类型信息后,可以开始编写node了。 创建一个joystic_turtle包,创建一个examle.cpp.输入以下代码。 #include #include //turtlesim速度控制消息类型 #include //joystick消息类型 #include using namespace std; class TeleopJoy{ public: TeleopJoy(); private: void callBack(const sensor_msgs::Joy::ConstPtr& joy); //joystick消息回调函数 ros::NodeHandle n; ros::Publisher pub; ros::Subscriber sub; int i_velLinear, i_velAngular; }; TeleopJoy::TeleopJoy() { n.param("axis_linear",i_velLinear,i_velLinear); n.param("axis_angular",i_velAngular,i_velAngular); pub = n.advertise("turtle1/command_velocity",1); sub = n.subscribe("joy", 10, &TeleopJoy::callBack, this); } void TeleopJoy::callBack(const sensor_msgs::Joy::ConstPtr& joy) { turtlesim::Velocity vel; vel.angular = joy->axes[i_velAngular]; vel.linear = joy->axes[i_velLinear]; pub.publish(vel); }
int main(int argc,char**argv) ros::init(argc,argv,"teleopJoy"); TeleopJoy teleop turtle; ros::spin(); 另外,需要创建一个launch文件来实现对joystick_turtle、sim、joy三个node的调用。 在这个launch文件中还定义了4个参数,这些参数将自动添加到参数服务器中,供node 调用。其中axis linear和axis angular参数用来配置手柄的轴。Dev和deadzone参数用来配置手 柄的端口号和非识别区域(即微小的移动会被作为干扰项滤除)。 Step4.利用roslaunch命令运行launch文件。利用手柄控制仿真的turtle运动。 S roslaunch chapter4_tutorials example1.launch Step5.利用rqt_graph,,rosnode list,,或者rostopic list来观察整个系统。 2. 完成Ros Kinect的安装 Kinect是一种用于微软的Xbox360体感游戏的附件设备,具有以下的3中传感器可以用 来进行相关机器人的任务开发。 只 一个彩色VGA视频相机可以采集环境颜色信息 B. 深度相机,由一个红外投影器和一个灰度CMOS传感器一起工作,能感知环境的距离 信息。 ,个麦克风阵列用来将用于的声音从环境噪声中隔离出来。 KINECT 在这里我们将使用其中两个传感器:RGB彩色相机和深度传感器。 Step1.安装包和驱动。 sudo apt-get install ros-kinetic-openni-camera ros-kinetic-openni-launch rosstack profile rospackage profile 安装完成后插入Kinect传感器,运行node可以开始使用。首先运行roscore,.然后在新 -5-
- 5 - int main(int argc, char** argv) { ros::init(argc, argv, "teleopJoy"); TeleopJoy teleop_turtle; ros::spin(); } 另外,需要创建一个launch文件来实现对joystick_turtle、sim、joy三个node的调用。 在这个launch文件中还定义了4个参数,这些参数将自动添加到参数服务器中,供node 调用。其中axis_linear和axis_angular参数用来配置手柄的轴。Dev和deadzone参数用来配置手 柄的端口号和非识别区域(即微小的移动会被作为干扰项滤除)。 Step4. 利用roslaunch命令运行launch文件。利用手柄控制仿真的turtle运动。 $ roslaunch chapter4_tutorials example1.launch Step5.利用rqt_graph,rosnode list,或者rostopic list 来观察整个系统。 2. 完成Ros Kinect的安装 Kinect 是一种用于微软的Xbox360体感游戏的附件设备,具有以下的3中传感器可以用 来进行相关机器人的任务开发。 A. 一个彩色VGA视频相机可以采集环境颜色信息 B. 深度相机,由一个红外投影器和一个灰度CMOS传感器一起工作,能感知环境的距离 信息。 C. 一个麦克风阵列用来将用于的声音从环境噪声中隔离出来。 在这里我们将使用其中两个传感器:RGB彩色相机和深度传感器。 Step1.安装包和驱动。 $ sudo apt-get install ros-kinetic-openni-camera ros-kinetic-openni-launch $ rosstack profile $ rospackage profile 安装完成后插入Kinect传感器,运行node可以开始使用。首先运行roscore,然后在新
的终端里运行以下命令。 S roslaunch openni_launch openni.launch Step2.观察Kinect.发出的数据 首先利用rostopic list命令显示所有topic,结果有很多,注意观察以下几个 /camera/rgb/image_color /camera/rgb/image mono /camera/rgb/image_raw /camera/rgb/image_rect /camera/rgb/image_rect_color 利用iage_view包查看图像数据 S rosrun image_view image_view image:=/rgb/image_raw 注意这里将图像的topic.重映射到了/camera/rgb/image_colori这样可以直接显示该topic的 图像。系统应该会有以下输出。 另一个重要的topic是那个直接发送点云数据的。这种数据是对深度图的一个3D的表示。 该数据在/camera/depth/points,/camera/depth registered/points这类的topic中。 利用rostipic type命令查看该topicl的类型。 S rostopic type/camera/depth/points rosmsg show 可以到官网查看相应的类型说明 http://ros.org/doc/api/sensor msgs/html/msg/PointCloud2.html. 利用rviz可以显示该数据,在一个新终端中运行rviz添加一个新的PointCloud:2数据的 显示项,即可以看到点云数据。 -6-
- 6 - 的终端里运行以下命令。 $ roslaunch openni_launch openni.launch Step2.观察Kinect发出的数据 首先利用rostopic list命令显示所有topic,结果有很多,注意观察以下几个 ... /camera/rgb/image_color /camera/rgb/image_mono /camera/rgb/image_raw /camera/rgb/image_rect /camera/rgb/image_rect_color ... 利用iage_view包查看图像数据 $ rosrun image_view image_view image:=/rgb/image_raw 注意这里将图像的topic重映射到了/camera/rgb/image_color这样可以直接显示该topic的 图像。系统应该会有以下输出。 另一个重要的topic是那个直接发送点云数据的。这种数据是对深度图的一个3D的表示。 该数据在/camera/depth/points, /camera/depth_registered/points 这类的topic中。 利用rostipic type 命令查看该topic的类型。 $ rostopic type /camera/depth/points | rosmsg show 可以到官网查看相应的类型说明 http://ros.org/doc/api/sensor_msgs/html/msg/PointCloud2.html. 利用rviz 可以显示该数据,在一个新终端中运行rviz添加一个新的PointCloud2数据的 显示项,即可以看到点云数据
E Fw Nthe T23 MnCol .ctaTp.. T积c米 h T2prw:E人w Cutr Trera..Ahoder 12k tnAb:3发 Daty Tire HEvie HrVAM Iouer T..XZ w G状w 14k "4山xK (4i)21n 1m% Y有m名 作 cent cn 41Tt维nl口:t44壮纪 0GTE22以3社35T士44M5 Step3.利用Kinect数据。 这里创建一个程序产生一个节点来对Kienct传感器获得的点云数据进行滤波。这个node 将会在原始数据上添加一个过滤器,来减少点的数量。相当于对数据做了下采样。 创建一个DownSmapling..cpp,在src文件夹中输入以下程序 #include #include #include #include #include #include ros::Publisher pub; void cloud cb(const sensor msgs::PointCloud2ConstPtr&input) //..do data processing sensor msgs:PointCloud2 output: pcl::VoxelGridsor; sor.setInputCloud(input); sor.setLeafSize(0.02f,0.02f,0.02f); sor.filter(output); ∥Publish the data pub.publish(); intmain (int argc,char**argv) ∥Initialize ROS ros::init(argc,argv,"my_pcl_tutorial"); ros::NodeHandle nh; /Create a ROS subscriber for the input point cloud ros::Subscriber sub=nh.subscribe("/camera/depth/points",1,cloud cb), /Create a ROS publisher for the output point cloud pub=nh.advertise("output",1); -7
- 7 - Step3.利用Kinect数据。 这里创建一个程序产生一个节点来对Kienct传感器获得的点云数据进行滤波。这个node 将会在原始数据上添加一个过滤器,来减少点的数量。相当于对数据做了下采样。 创建一个DownSmapling.cpp,在src文件夹中输入以下程序 #include #include #include #include #include #include ros::Publisher pub; void cloud_cb (const sensor_msgs::PointCloud2ConstPtr& input) { // ... do data processing sensor_msgs::PointCloud2 output; pcl::VoxelGrid sor; sor.setInputCloud(input); sor.setLeafSize(0.02f,0.02f,0.02f); sor.filter(output); // Publish the data pub.publish (); } intmain (int argc, char** argv) { // Initialize ROS ros::init (argc, argv, "my_pcl_tutorial"); ros::NodeHandle nh; // Create a ROS subscriber for the input point cloud ros::Subscriber sub = nh.subscribe ("/camera/depth/points", 1, cloud_ cb); // Create a ROS publisher for the output point cloud pub = nh.advertise ("output", 1);
//Spin ros::spin(); } 程序理解:这个程序是基于Point Cloud Library(PCL)函数库的。 和以前的实践程序一样所有的工作都在cb()回调函数完成。我们创建了一个Voxelgrid类 型的变量sor,栅格的范围在sor.setLeafSize()中改变。这些值可以改变用来进行滤波的栅 格。这个值如果增大会滤除更多的点。 程序运行的结果将会发布一个名为“output”的点云,我同样可以使用rviz来进行显示。 请修改sor.setLeafSize()的值观察点云的变化。 在这里点云作为一个整体然后用PCL库的函数来进行处理,实际上我们也可以获得里面 每个点的信息来做相应的处理。 3. 利用arduino添加其他低成本的传感器和执行器 Arduino是一种开源的电子开发平台基于柔性易用的硬件和软件。它旨在为艺术家,设 计师,爱好者以及任何对创建交互式对象或环境感兴趣的人士提供便利。 ROS可以通过rosserial包使用来这种类型的设备。Arduino使用串行连接连接到计算 机,并使用此端口传输数据。当然使用rosserial,你不仅可以使用arduino,也可以使用 很多其它由串行连接控制的设备:例如GPS,伺服控制器等等。 Step1.安装rosserial软件包几arduino IDE sudo apt-get install ros-kinetic-rosserial S rosstack profile rospackage profile 网下下载和安装Arduino IDE。完成安装后需要将rosserial包中的ros_lib类库复制到 Arduinof的sketchbook文件目录下的library文件夹中。该sketchbook文件目录将在首次运行 Arduino IDE后自动产生。 S roscd rosserial_arduino/libraries S cp-r ros_lib /libraries/ros_lib Step2.在Arduino中创建一个程序,想ROS发送一个topic 可以看到在Arduinof的例程中己经包含了我们复制过来的ros lib的内容。我吗打开一个 string_test的例程。 -8-
- 8 - // Spin ros::spin (); } 程序理解:这个程序是基于Point Cloud Library(PCL)函数库的。 和以前的实践程序一样所有的工作都在cb()回调函数完成。我们创建了一个Voxelgrid类 型的变量sor,栅格的范围在sor.setLeafSize()中改变。这些值可以改变用来进行滤波的栅 格。这个值如果增大会滤除更多的点。 程序运行的结果将会发布一个名为“output”的点云,我同样可以使用rviz来进行显示。 请修改sor.setLeafSize()的值观察点云的变化。 在这里点云作为一个整体然后用PCL库的函数来进行处理,实际上我们也可以获得里面 每个点的信息来做相应的处理。 3. 利用arduino添加其他低成本的传感器和执行器 Arduino是一种开源的电子开发平台基于柔性易用的硬件和软件。 它旨在为艺术家,设 计师,爱好者以及任何对创建交互式对象或环境感兴趣的人士提供便利。 ROS可以通过rosserial包使用来这种类型的设备。 Arduino使用串行连接连接到计算 机,并使用此端口传输数据。 当然使用rosserial,你不仅可以使用arduino,也可以使用 很多其它由串行连接控制的设备; 例如GPS,伺服控制器等等。 Step1. 安装rosserial软件包几arduino IDE $ sudo apt-get install ros-kinetic-rosserial $ rosstack profile $ rospackage profile 网下下载和安装Arduino IDE。完成安装后需要将rosserial包中的ros_lib类库复制到 Arduino的sketchbook文件目录下的library文件夹中。该sketchbook文件目录将在首次运行 Arduino IDE后自动产生。 $ roscd rosserial_arduino/libraries $ cp -r ros_lib /libraries/ros_lib Step2.在Arduino中创建一个程序,想ROS发送一个topic 可以看到在Arduino的例程中已经包含了我们复制过来的ros_lib的内容。我吗打开一个 string_test的例程
Ct+N Open. ⊙ 05e Ctrl+w 2Digtal Ctrl+S 3Analog Save As Ctl+Shit+S 4.Communication Ctr+U 5.Control Page Setup Curl+P 7.Diiplay Ctrl+Comma 8.Strnge Ctrl+Q Arduinoisp 月h-v(chater) ArduinoTest Suite oid lomp "button exam EEPROM ·o过6tet nce(): m 1y(1000]1 me test 代码如下。其中包含的头文件ros.h实际上是我们复制进去的rosserial类库。另外这个程 序里创建了一个名为chatter的类型为std msgs/String的topic #include #include ros::NodeHandle nh; std msgs::String str_msg; ros::Publisher chatter("chatter",&str msg); char hello[19]="chapter4 tutorials"; void setup() nh.initNode(); nh.advertise(chatter): } void loop(){ str_msg.data=hello; chatter.publish(&str_msg ) nh.spinOnce(); delay(1000); } 现在我们可以创建一个node来监听这个串口端口,并且将Arduino发出的这个topic发送 到ROS的网络中。首先运行roscore,然后运行以下命令 S rosrun rosserial_python serial_node.py /dev/ttyUSBO 利用rostopic echot命令查看Arduino发出的名为chatter的topic S rostopic echo chatter 可以在终端中开发输出内容为 data:chapter4 tutorials 通过这个方法我们就可以将Ardunio中的数据,可以是其采集到的各种传感器数据等, 发送到ROS网络。 -9-
- 9 - 代码如下。其中包含的头文件ros.h实际上是我们复制进去的rosserial类库。另外这个程 序里创建了一个名为chatter的类型为std_msgs/String的topic #include #include ros::NodeHandle nh; std_msgs::String str_msg; ros::Publisher chatter("chatter", &str_msg); char hello[19] = "chapter4_tutorials"; void setup() { nh.initNode(); nh.advertise(chatter); } void loop() { str_msg.data = hello; chatter.publish( &str_msg ); nh.spinOnce(); delay(1000); } 现在我们可以创建一个node来监听这个串口端口,并且将Arduino发出的这个topic发送 到ROS的网络中。首先运行roscore,然后运行以下命令 $ rosrun rosserial_python serial_node.py /dev/ttyUSB0 利用rostopic echo命令查看Arduino发出的名为chatter的topic $ rostopic echo chatter 可以在终端中开发输出内容为 data: chapter4_tutorials 通过这个方法我们就可以将Ardunio中的数据,可以是其采集到的各种传感器数据等, 发送到ROS网络
Step3.在Arduinot中创建一个程序,接受ROS的topic 我们将测试让Arduino从ROS接受topic并且改变一个LED灯的状态(Arduino开发板提供 一个内建的LED供开发使用,连接到了第13号端口)。我们同样的打开Examples|ros lib| Blink.例程。 #include #include ros::NodeHandle nh: void messageCb(const std msgs::Empty&toggle msg){ digitalWrite(13,HIGH-digitalRead(13));/blink the led ros::Subscribersub("toggle_led",&messageCb ) void setup() { pinMode(13,OUTPUT); nh.initNode(): nh.subscribe(sub); void loop(){ nh.spinOnce(); delay(1);} 打开rosserial S rosrun rosserial_python serial_node.py /dev/ttyUSBO 现在通过发送名为toggle_1ed类型为std msgs/.Empty的topic来控制LED灯的状态。可以 使用rostopic pubi命令来实现。 S rostopic pub toggle_led std_msgs/Empty -once publishing and latching message for 3.0 seconds 可以观察到我们可以改变LED的状态了。 四、实验原理及原始计算数据、所应用的公式 ROS对硬件包括传感器,执行器等的调用一般具有以下的层次结构。 利用Arduino我们可以使用arduino能够使用的所有传感器执行器等资源, 大大方便我们的开发选型。 五、实验数据记录 -10-
- 10 - Step3.在Arduino中创建一个程序,接受ROS的topic 我们将测试让Arduino从ROS接受topic并且改变一个LED灯的状态(Arduino开发板提供 一个内建的LED供开发使用,连接到了第13号端口)。我们同样的打开Examples | ros_lib | Blink. 例程。 #include #include ros::NodeHandle nh; void messageCb( const std_msgs::Empty& toggle_msg){ digitalWrite(13, HIGH-digitalRead(13)); // blink the led } ros::Subscriber sub("toggle_led", &messageCb ); void setup() { pinMode(13, OUTPUT); nh.initNode(); nh.subscribe(sub); } void loop() { nh.spinOnce(); delay(1); } 打开rosserial $ rosrun rosserial_python serial_node.py /dev/ttyUSB0 现在通过发送名为toggle_led类型为std_msgs/Empty的topic来控制LED灯的状态。可以 使用rostopic pub命令来实现。 $ rostopic pub toggle_led std_msgs/Empty –once publishing and latching message for 3.0 seconds 可以观察到我们可以改变LED的状态了。 四、 实验原理及原始计算数据、所应用的公式 ROS 对硬件包括传感器,执行器等的调用一般具有以下的层次结构。 利用 Arduino 我们可以使用 arduino 能够使用的所有传感器执行器等资源, 大大方便我们的开发选型。 五、 实验数据记录