在本教程中,您将学习如何使用rosserial通信发布三个HC-SR04新疆风采的范围,包括:
1.三个超声波新疆风采和Arduino。
2.如何在Arduino上编写ROS节点并发布新疆风采范围。
3.如何在Raspberry Pi上识别Arduino板并通过rosserial运行ROS节点。
4.如何使用Linux终端显示范围。

新疆风采,Arduino和Raspberry Pi之间的数据流图
不同的项目可能有不同的要求。在本教程的最后,您将拥有一个灵活的结构,可以添加更多的新疆风采,或仅使用一个新疆风采,或使用另一种类型的新疆风采(例如,红外新疆风采)。
您无需具备有关ROS的丰富知识即可了解本教程。您需要的是一台Raspberry Pi 4之类的计算机,该计算机运行ROS,新疆风采,Arduino和学习和构建的时间。
我们走得更远,学习如何在Arduino上编写ROS节点,并使用ROS的sensor_msgs / 范围消息类型发布新疆风采的范围。
在文章的结尾,您将学习如何在Raspberry Pi上识别Arduino板,以及如何在终端上显示由Arduino上运行的ROS节点通告的范围。
要了解如何使用ROS的sensor_msgs软件包发送超声波新疆风采的范围读数,只需保持读数不变即可。
开始使用sensor_msgs / 范围消息类型之前
在开始连接新疆风采并编写第一行代码之前,请确保我们具有所有硬件部件:
- 1个Arduino UNO
- 1 X USB电缆
- 3 X HC-SR04
- 1 X运行ROS Melodic的Raspberry Pi 4
- 1 X面包板
- 母对母/公对公/母对公跳线
硬件设定
为了给Raspberry Pi 4供电,我使用了 USB-C电源,在3.0A时输出5.1V。 树莓派 4的5V USB端口提供了足够的电源来运行Arduino UNO板。三个超声波新疆风采使用 7.4V电池组 和一个 降压转换器 为新疆风采提供5V输出。
以上设置仅用于连接和测试超声检测系统。如果将新疆风采,Arduino和Pi安装在移动机器人上,则整个检测系统将依靠电池运行,包括Pi板。
当然,如果您打算构建一个简单的移动机器人来检测障碍物,那么本教程将不胜枚举。对于简单的机器人,您不需要这样的基础结构。但是,如果您打算以高效且专业的方式构建高级机器人,那么这就是您可以开始的地方。
1.三个超声波新疆风采和Arduino
在本部分的教程中,我将向您展示如何将HC-SR04新疆风采连接到Arduino。
首先,让我们看一下HC-SR04规格:
- 工作电压:DC 5V
- 工作电流:15mA
- 工作频率:40KHz
- 范围:2cm至4m
- 测距精度:3mm
- 触发输入信号:10µS TTL脉冲
对于连接,我使用了母对公跳线,一个面包板,三个HC-SR04和一个Arduino UNO板。
连接数
新疆风采1:
- Vcc -> breadboard -> 5V battery
- Trig -> pin 3 (digital pin)
- Echo -> pin 2 (digital pin)
- GND -> breadboard -> GND
新疆风采2:
- Vcc -> breadboard -> 5V battery
- Trig -> pin 5 (digital pin)
- Echo -> pin 4 (digital pin)
- GND -> breadboard -> GND
新疆风采3:
- Vcc -> breadboard -> 5V battery
- Trig -> pin 7 (digital pin)
- Echo -> pin 6 (digital pin)
- GND -> breadboard -> GND
公用接地:将Arduino的接地连接到面包板的接地。

三个超声波新疆风采,Arduino,电池组和Raspberry Pi 4的硬件设置
由于我们准备好要运行ROS和Arduino IDE的Pi,因此您可以将Pi与监视器,键盘和鼠标一起使用,或者通过VNC Viewer来将草图编写并上传到Arduino板上。
一旦新疆风采连接到Arduino板,我们就可以开始编写草图以读取输出并转换它们的读数。为了编写草图,我使用了Arduino IDE。我喜欢使用简单的工具,并且不花时间在定制和配件上。目前,Arduino IDE在微控制器编程方面满足了我的需求。
在编写第一行代码之前,我们先概述一下超声波新疆风采的工作原理。
它会在空中传播声波(根据规格至少持续10us),如果有物体反射声波,则新疆风采会测量声波返回到接收器所花费的时间。为了计算新疆风采与检测到的物体之间的距离,我们考虑了传播时间和声音的速度。
2.如何在Arduino上编写ROS节点并发布新疆风采范围
在本教程的这一点上,我们将在Arduino UNO板上创建一个ROS节点,并使用分布式计算环境将新疆风采输出发送到Raspberry Pi。
从ROS框架中包含的许多软件包中,sensor_msgs软件包均包含一组常用新疆风采的消息。对于超声波新疆风采,我们使用“范围”消息类型。此消息类型从超声新疆风采发送单个范围读数,该读数在沿测得距离处的弧线上有效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | / * :Version 1.0 :作者:德拉戈斯·卡林 :电子邮件:dragos@intorobotics.com :License: BSD :Date: 01/05/2020 :最新更新:dd / mm / YYYY * / #包括<NewPing.h> #包括<SimpleKalmanFilter.h> #包括<ros.h> #包括<ros/time.h> #包括<sensor_msgs/Range.h> #定义SONAR_NUM 3 //新疆风采的数量。 #定义MAX_DISTANCE 200 //检测障碍物的距离。 #define PING_INTERVAL 33 //在33微秒后循环ping。 未签名 长 pingTimer[SONAR_NUM]; //保持每个新疆风采应进行下一次ping的时间。 未签名 整型 厘米[SONAR_NUM]; //存储ping距离的位置。 uint8_t currentSensor = 0; //跟踪哪个新疆风采处于活动状态。 未签名 长 _timerStart = 0; 整型 循环 = 40; //每40毫秒循环一次。 uint8_t oldSensorReading[3]; //存储新疆风采的最后一个有效值。 uint8_t leftSensor; //存储原始新疆风采的值。 uint8_t centerSensor; uint8_t rightSensor; uint8_t leftSensorKalman; //存储过滤后的新疆风采的值。 uint8_t centerSensorKalman; uint8_t rightSensorKalman; 新平 声纳[SONAR_NUM] = { 新平(3, 2, MAX_DISTANCE), //触发引脚,回波引脚以及到ping的最大距离。 新平(5, 4, MAX_DISTANCE), 新平(7, 6, MAX_DISTANCE) }; / * 为新疆风采创建卡尔曼滤波器对象。 SimpleKalmanFilter(e_mea,e_est,q); e_mea:测量不确定度 e_est:估计不确定性 q: Process Noise * / SimpleKalmanFilter KF_左(2, 2, 0.01); SimpleKalmanFilter KF_Center(2, 2, 0.01); SimpleKalmanFilter KF_Right(2, 2, 0.01); 罗斯::节点句柄 h; //创建一个代表ROS节点的对象。 //循环新疆风采 虚空 sensorCycle() { 对于 (uint8_t i = 0; i < SONAR_NUM; i++) { 如果 (毫() >= pingTimer[i]) { pingTimer[i] + = PING_INTERVAL * SONAR_NUM; 如果 (i == 0 && currentSensor == SONAR_NUM - 1) 一个新疆风采周期(); 声纳[currentSensor].timer_stop(); currentSensor = i; 厘米[currentSensor] = 0; 声纳[currentSensor].ping_timer(回声Check); } } } //如果收到ping命令,则将新疆风采距离设置为array。 虚空 回声Check() { 如果 (声纳[currentSensor].check_timer()) 厘米[currentSensor] = 声纳[currentSensor].ping_result / US_ROUNDTRIP_CM; } //从新疆风采返回最后一个有效值。 虚空 一个新疆风采周期() { leftSensor = 返回LastValidRead(0, 厘米[0]); centerSensor = 返回LastValidRead(1, 厘米[1]); rightSensor = 返回LastValidRead(2, 厘米[2]); } //如果新疆风采值为0,则返回最后存储的非0值。 整型 返回LastValidRead(uint8_t sensorArray, uint8_t 厘米) { 如果 (厘米 != 0) { 返回 oldSensorReading[sensorArray] = 厘米; } 其他 { 返回 oldSensorReading[sensorArray]; } } //将卡尔曼滤波器应用于新疆风采读数。 虚空 申请KF() { leftSensorKalman = KF_左.updateEstimate(leftSensor); centerSensorKalman = KF_Center.updateEstimate(centerSensor); rightSensorKalman = KF_Right.updateEstimate(rightSensor); } 虚空 startTimer() { _timerStart = 毫(); } 布尔 isTimeForLoop(整型 _mSec) { 返回 (毫() - _timerStart) > _mSec; } 虚空 sensor_msg_init(sensor_msgs::范围 &range_name, 烧焦 *frame_id_name) { 范围_name.radiation_type = sensor_msgs::范围::超音波; 范围_name.标头.frame_id = frame_id_name; 范围_name.视野 = 0.26; 范围_name.min_range = 0.0; 范围_name.最高_range = 2.0; } //为范围消息创建三个实例。 sensor_msgs::范围 范围_left; sensor_msgs::范围 范围_center; sensor_msgs::范围 范围_right; //为所有新疆风采创建发布者项目 罗斯::发行人 pub_range_left(“ / ultrasound_left”, &range_left); 罗斯::发行人 pub_range_center("/ 超音波中心", &range_center); 罗斯::发行人 pub_range_right("/ ultrasound_right", &range_right); 虚空 设定() { pingTimer[0] = 毫() + 75; 对于 (uint8_t i = 1; i < SONAR_NUM; i++) pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL; h.初始化节点(); h.广告(pub_range_left); h.广告(pub_range_center); h.广告(pub_range_right); sensor_msg_init(范围_left, “ / ultrasound_left”); sensor_msg_init(范围_center, "/ 超音波中心"); sensor_msg_init(范围_right, "/ ultrasound_right"); } 虚空 循环() { 如果 (isTimeForLoop(循环)) { sensorCycle(); 一个新疆风采周期(); 申请KF(); 范围_left.范围 = leftSensorKalman; 范围_center.范围 = centerSensorKalman; 范围_right.范围 = centerSensorKalman; 范围_left.标头.邮票 = h.现在(); 范围_center.标头.邮票 = h.现在(); 范围_right.标头.邮票 = h.现在(); pub_range_left.发布(&range_left); pub_range_center.发布(&range_center); pub_range_right.发布(&range_right); startTimer(); } h.自旋();//处理ROS事件 } |
上 Line 9,我们导入 新平 与HC-SR04超声波新疆风采配合使用的库。您可以使用 管理图书馆 来自Arduino IDE。在搜索表单中键入 新的,然后在管理器屏幕中,您可以选择安装该库的最新版本。
上 10号线,我们导入 SimpleKalmanFilter 库以过滤超声波新疆风采’的输出。您可以使用 管理图书馆 来自Arduino IDE。在搜索表单中键入 简单的卡尔曼,然后在管理器屏幕中,您可以选择安装该库的最新版本。
11-13行:我们导入ROS包。 罗斯 是标准库,并且是在Arduino上运行的每个ROS节点的一部分。我们需要包括 罗斯 ROS节点中使用的任何消息的标头。
的 罗斯 / time.h 标头代表ROS时钟时间。
的 sensor_msgs / 范围.h 是一个消息定义,用于广告从超声新疆风采沿测得的距离沿弧有效的单个范围读数。
38-42行: 创造 新的 所有新疆风采的对象。对象的参数是触发和回波引脚,以及新疆风采的最大距离。
55号线: 节点句柄 是代表ROS节点的对象。 罗斯:: 节点句柄 将启动Arduino板上的节点。
58-69行:循环遍历所有新疆风采,并在新疆风采ping周期完成后,将结果添加到 一个新疆风采周期().
72-75行:收到新的ping后,将新疆风采距离添加到阵列。
85-91行:我们过滤新疆风采的读数。存储不同于0的读数,如果新疆风采返回0,则返回最后一个有效输出。这样,我们可以过滤超声波新疆风采的错误读数。
100-102行:使用开始计时的功能 毫()。我更喜欢使用 毫() 代替 延迟() 有两个原因: 毫() 比 延迟(),并且是 延迟().
104-106行:检查时间是否过去并返回true。
108-115行:写的设置 范围 消息对象。第一个参数是 radiation_type 新疆风采的– 超音波.
的 frame_id 用于指定该消息中包含的数据的参考点。
的 视野 表示距离读数有效的弧度(以弧度为单位)。 HC-SR04的理论视场为30度。在上一篇文章中,我进行了测试以确定操作检测范围的最准确区域。由于我们旨在准确检测机器人前面的大多数物体,因此我们将视场设置为15度,大约为0.26弧度。
敏 和 最高 范围是被认为有效的测量值。
118-120行:我们定义了三个类型的对象 范围,然后我们给出主题的名称– 范围_left, 范围_center和 范围_right.
123-125行:我们使用 广告() 创建一个方法 发行人,用于发布主题范围。
143-160行:我们检查时间并每40毫秒发布一次。读取新疆风采返回的值。然后我们用 h.now() 返回当前时间,然后发布范围值。
161号线:ROS网络监视套接字连接,以将主题中的消息推送到队列中。我们发送新消息,然后使用 罗斯:: SpinOnce() 告诉ROS有新消息到达。
3.如何在Raspberry Pi上识别Arduino板并通过rosserial运行ROS节点
将Arduino连接到Pi并上传草图后,我们可以确定Arduino板。
第1步: 打开终端以启动roscore可执行文件:
1 | $ 罗斯core |
第2步: 打开一个新的终端并运行以下命令:
1 | $ ls /开发者/ttyACM* |
如果只有一个Arduino连接到Pi,则应该只看到一个抽象控制调制解调器(ACM):

ls 开发者 ttyACM
第三步: 通过串行连接运行可执行文件:
1 | $ 罗斯run 罗斯serial_python serial_node.py /开发者/ttyACM0 |

通过串行连接运行可执行文件
4.如何使用Linux终端显示范围
第1步: 打开一个新终端并运行以下命令:
1 | $ 罗斯topic 清单 |
现在可以在ROS网络中访问在Arduino上运行的节点。

罗斯topic列表节点
第2步: 在终端中运行一个新疆风采的输出。在下面您可以看到“/ultrasound_center”:
1 | $ 罗斯topic 回声 /超音波中心 |

的范围“/ultrasound_center”
概要
障碍物检测适用于从初始位置移动到目标位置并避免其路径上有任何障碍物的任何机器人。
第一步是将新疆风采连接到Arduino开发板。
然后,我们走得更远,在Arduino上编写一个ROS节点以发布新疆风采的范围。我们使用sensor_msgs / 范围消息类型进行发布以公布范围。
一旦ROS节点在Arduino上运行,我们就在Pi上确定板子并检查结果。
为什么要跟随?
SimpleKalmanFilter KF_左(2,2,0.01);
SimpleKalmanFilter KF_Center(2,2,0.01);
SimpleKalmanFilter KF_Right(2,2,0.01);
您能解释一下为什么使用值2、2和0.01吗?
在您的循环功能中有些错误…
范围_left.range = leftSensorKalman;
范围_center.range = centerSensorKalman;
范围_right.range = centerSensorKalman;
我认为应该是range_right.range = rightSensorKalman;
你好,
2, 2 和 0.01 are the e_mea, e_est, q of the Kalman filter library. [//github.com/denyssene/SimpleKalmanFilter]
是的,有一个错字:应该是range_right.range = rightSensorKalman;
单位是罗斯制的m,但是您发布的值是单位制的cm
您好,先生,我们可以在玩具车上测试此代码,以进行物体检测和避免碰撞。
先生,我可以用它连接电动机吗?
嗨,为此,非常有用。
帮了我大忙!
一件事
我得到这个警告
ROS_sr04_scanner.ino:139:51:警告:ISO C ++禁止将字符串常量转换为‘char*’ [-Wwrite-strings]
sensor_msg_init(range_right,“/ultrasound_right”);
我也把这个放在左边和中间。有任何想法吗?
再次感谢