在本教程中,您将学习如何使用Arduino和三个HC-SR04超声波传感器构建障碍物检测和躲避新疆风采。该新疆风采是具有两个驱动轮和一个后脚轮的低成本移动平台。它包括三个传感器,可感知环境中的障碍。
新疆风采在不知道周围详细地图的情况下导航。如果在其路径中检测到障碍物,则新疆风采会调整其速度以避免碰撞。如果周围环境没有障碍物,则新疆风采只会向前移动,直到在传感器范围内检测到障碍物为止。
主要组件清单:
- 1 X 2WD新疆风采机箱套件[ 亚马孙 ]
- 1 X L298N电机驱动器[ 亚马孙 ]
- 1个Arduino UNO [ 亚马孙 ]
- 3 X HC-SR04超声波传感器[ 亚马孙 ]
- 1 X 5V电池组[ 亚马孙 ]
- 1个用于4个AA电池的电池座[ 亚马孙 ]
首先,我们需要定义输入以了解新疆风采从何处将信息带入其系统。该检测和避免新疆风采将具有两种类型的输入。
1. 最直接的输入是将用于打开和关闭电动机驱动器的开关按钮,以及用于电池组为Arduino板和传感器供电的电源开/关按钮。
2. 新疆风采通过传感器看到世界,这是将信息带入控制系统的方式。传感器是新疆风采的第二个输入。传感器使新疆风采能够检测并响应周围的环境。传感器使新疆风采能够安全地操作,自动检测障碍物并动态改变其路线。
新疆风采使用传感器来测量新疆风采和障碍物之间的距离。如您所知,房屋内部是大小不同的不同物体,它们是由多种材料制成的。新疆风采可以检测来自不同材料的物体,例如木椅或沙发床。
一旦新疆风采检测到障碍物,该算法就会根据传感器的最新输出来计算替代路径。如果对象位于平台的左侧,则新疆风采会动态地将其方向向右移动,直到传感器不再检测到障碍物为止。当传感器检测到右侧的障碍物时,行为相同。
如果传感器在新疆风采中间检测到障碍物’路径,然后算法会随机地向左或向右更改方向,直到传感器不再检测到障碍物为止。
我们完成了为自主新疆风采定义输入类型的操作。输入是必不可少的,输出也是必不可少的。
障碍物检测和躲避新疆风采具有一种输出。
3. 移动新疆风采使用两个直流电动机,平台的每一侧各一个。每个电动机都经过单独编程,可以使新疆风采沿任何方向移动以进行旋转和枢转。
为了完全控制直流电动机,我们必须控制速度和旋转方向。这可以通过组合用于控制速度的PWM方法和用于控制方向旋转的H桥电子电路来实现。
一旦完成输入和输出的定义,我们便会进一步将障碍检测和躲避新疆风采分解为简单的片段,并一步一步地对其进行处理。
对于此新疆风采,我使用了灵活的体系结构,这意味着允许用户执行以下操作:
- 添加多个传感器和组件。
- 可以用其他传感器替换实际的传感器。
- 轻松编写自己的软件。
第1部分:检测系统
这一部分是关于将传感器输出的原始数据转换为导航中使用的精确测量值。
第2部分:导航
在这一部分中,我们将构建算法来计算转向,以便在移动新疆风采的周围环境中找到无碰撞的路径。
第三部分:驱动系统
在这一部分中,我们将使用导航中的数据来引导新疆风采。
一旦知道了必须要做的事情,我们就会进一步使事情变得简单易懂。我们将从解释如何做,构建电路和编写程序开始。
第1部分:检测系统
在这一步,我们必须赋予新疆风采感应功能。我们必须创建一个能够查看周围环境的检测系统。的 超声波传感器 在感知内部和外部环境时非常有效。
我们没有使用单个超声波传感器来解决感测问题,而是使用三个传感器在复杂的环境中引导新疆风采。我们将在近距离观察任务中使用所有传感器。这是因为新疆风采将在内部工作,并且操纵空间有限。例如,HC-SR04提供2 厘米 至400 厘米 的非接触式测量功能。利用传感器的最大范围,新疆风采将始终在房间内的路径中检测到物体,并且完全不会移动。
1.1设置Arduino和HC-SR04超声波传感器
根据规格,HC-SR04的工作电压为5V。 Arduino的具有提供5V输出的接口引脚。
一个超声传感器的工作电流为15mA。三个传感器将消耗45mA的电流,即使将Arduino连接到5V电池组的USB端口也可以支持。 Arduino的 UNO的5V输出引脚适用于USB上的〜400 mA,与外部电源适配器一起使用时,其两倍以上(〜900 mA)。
对于传感器和Arduino之间的连接,我使用跳线。
用一个5V引脚为传感器供电是一个挑战,需要切割和焊接导线。解决方法是,可以使用试验板将Arduino的5V和接地引脚连接到传感器的5V和接地引脚。
这是我为传感器供电的最终设置。红色/橙色线为5V,黑色/蓝色线为接地。

三个超声波传感器的电源设置
连接电源线后,我们走得更远,使用母对公跳线连接触发和回波引脚。
传感器左侧:
Echo -> pin 2 Arduino的
Trig -> pin 3 Arduino的
传感器中心:
Echo -> pin 4 Arduino的
Trig -> pin 5 Arduino的
右传感器:
Echo -> pin 6 Arduino的
Trig -> pin 7 Arduino的
传感器和Arduino的最终设置:

设置3XHC-SR04,Arduino和5V电池组
将所有传感器连接到Arduino之后,就该从它们读取输出信号,并将输出信号转换为厘米了。
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | 虚空 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(echoCheck); } } } //如果收到ping命令,则将传感器距离设置为array。 虚空 echoCheck() { 如果 ( 声纳 [currentSensor].check_timer()) 厘米 [currentSensor] = 声纳 [currentSensor].ping_result / US_ROUNDTRIP_CM; } |
第100到109行:我们’re using the 新平图书馆。循环遍历每个传感器,并在传感器ping周期完成后返回读数;
114至115行:如果收到ping,则将测量的距离添加到数组;
1.2应用过滤器以消除嘈杂,跳动或不稳定的读数
我们的任务 过滤传感器的输出 包括几个步骤。我们应用了过滤器,以删除一些不需要的读数,并获得更平滑的结果。然后,使用卡尔曼滤波器删除传感器的跳变或不稳定的读数。
126 127 128 129 130 131 132 133 134 135 136 137 138 139 | 整型 返回 LastValidRead(uint8_t sensorArray, uint8_t 厘米 ) { 如果 ( 厘米 != 0) { 返回 oldSensorReading[sensorArray] = 厘米 ; } 其他 { 返回 oldSensorReading[sensorArray]; } } //将卡尔曼滤波器应用于传感器读数。 虚空 申请KF() { isObstacleLeft = 障碍物检测(KF_左.updateEstimate(leftSensor)); isObstacleCenter = 障碍物检测(KF_Center.updateEstimate(centerSensor)); isObstacleRight = 障碍物检测(KF_Right.updateEstimate(rightSensor)); } |
第127到131行: 检查传感器的输出,如果该值为0,则返回上一个存储的不同于0的值。上一个不同于0的值存储在数组中。
第136至138行: 应用 卡尔曼滤波器 所有三个传感器。这样,我们就可以消除跳动或不稳定的传感器读数;
1.3安装传感器
我使用的2WD新疆风采机箱的宽度约为16厘米。这意味着传感器应检测到新疆风采前方至少16厘米处的障碍物。为清楚起见,让我们检查一下下面的草图。

传感器检测草图
在新疆风采宽度覆盖的区域内检测障碍物不是最佳方法。我们在底盘左右各增加一厘米来增加关注区域–这意味着新疆风采前方的宽度为18厘米。这意味着每个传感器应在新疆风采前方覆盖至少6厘米的宽度。
几周前,我写了一篇有关 HC-SR04和Arduino。在本教程中,您可以找到HC-SR04的操作检测范围为5到100厘米。在100厘米处,传感器的工作检测范围为8厘米,这比我们在此示例中需要的范围更大。通过做一些数学运算,我们发现最大距离为75厘米是我们检测新疆风采前方所有障碍物所需要的。
我们在新疆风采前面还有一个0到5厘米之间的盲区。新疆风采下部前部的保险杠可能是有助于保护新疆风采的解决方案。但是本部分不是本教程的主题,因此不会涉及。

传感器支架
这是用于HC-SR04超声波传感器的3D打印三重传感器支架。它具有简单的设计,并且组装和拆卸都很实用。传感器非常稳定,不需要任何螺丝或胶水。同样,该支架将保护传感器并为新疆风采提供更好的外观。
传感器支架使用M3螺钉和M3螺母固定在机箱上。
我们完成了检测系统。我们将传感器连接到Arduino,并设计3D打印的三重传感器支架。我们准备好使用传感器来检测和避开障碍物。
第2部分:导航
如果我们的新疆风采可以将障碍物移开,它将非常有用。好吧,因为它’对于小型新疆风采是不可能的,我们必须对新疆风采进行编程以找到无碰撞的路径。
现实世界包含新疆风采应检测并避免的物体,门,家具。控制新疆风采运动的算法应决定要遵循的路线并将其引导到那里。
2.1算法
1. 首先,我们必须定义传感器的最小和最大范围。我们必须编写能够识别障碍物及其在盲区与该项目可接受的最大范围之间的位置的算法。
2. 如果所有传感器均未检测到障碍物,请以最大速度前进。
3. 如果至少一个传感器检测到障碍物,请降低速度。
4. 再次检查传感器是否检测到障碍物。
5. 如果至少一个传感器仍在检测障碍物,请转到传感器’s state.
6. 如果左侧传感器检测到障碍物,请向右移动,直到传感器没有’t检测障碍物。
7. 如果中心传感器检测到障碍物,请向左或向右随机移动,直到中心传感器和左/右传感器没有检测到障碍物。
8. 如果右传感器检测到障碍物,请向左移动,直到传感器没有’t检测障碍。
9. 如果所有传感器都检测到障碍物,请向后移动并向左或向右转,直到检测到自由的障碍物路径。
这种简单的避障算法包括九种状态。该解决方案不需要繁重的计算工作,并且易于实现。
54 55 56 57 58 59 60 61 62 63 64 | 枚举 导航状态 { 选择所有, 最大速度, SPEED_DECREASE, CHECK_OBSTACLE_POSITION, 剩下 , 中央 , 对 , 背部 }; 导航状态 _navState = 选择所有; |
第54至64行: 根据条件定义新疆风采所经过的一组值;
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | 布尔 障碍物检测( 整型 sensorRange) { 如果 ((MIN_RANGE_OBSTACLE <= sensorRange) && (sensorRange <= MAX_RANGE_OBSTACLE)) 返回 真正 ; 其他 返回 假 ; } //避障算法。 虚空 避障() { 开关 (_navState) { 案件 选择所有: { //如果没有障碍物,则以最大速度前进 如果 (isObstacleLeft == 0 && isObstacleCenter == 0 && isObstacleRight == 0) { _navState = 最大速度; } 其他 { startTimerReady(); _navState = SPEED_DECREASE; } } 打破 ; 案件 最大速度: { moveForward(最大速度); _navState = 选择所有; } 打破 ; 案件 SPEED_DECREASE: { moveForward(最小速度); //低速等待更多读数,然后检查障碍物位置 如果 (isTimerReady(DECREESE_SPEED_LOOP)) _navState = CHECK_OBSTACLE_POSITION; } 打破 ; 案件 CHECK_OBSTACLE_POSITION: { //如果路径畅通,请再次转到MAX_SPEED,否则检查障碍物位置 如果 (isObstacleLeft == 0 && isObstacleCenter == 0 && isObstacleRight == 0) { _navState = 最大速度; } 其他 如果 (isObstacleLeft == 1 && isObstacleCenter == 0 && isObstacleRight == 0) { startTimerPosition(); _navState = 剩下 ; } 其他 如果 (isObstacleLeft == 0 && isObstacleCenter == 1 && isObstacleRight == 0) { startTimerPosition(); _navState = 中央 ; } 其他 如果 (isObstacleLeft == 0 && isObstacleCenter == 0 && isObstacleRight == 1) { startTimerPosition(); _navState = 对 ; } 其他 如果 (isObstacleLeft == 1 && isObstacleCenter == 1 && isObstacleRight == 1) { startTimerPosition(); _navState = 背部 ; } } 打破 ; 案件 剩下 : { //向左移动并检查障碍物。如果存在障碍物,请再次向左转到,否则退出 向左移动(最小速度); 如果 (isTimerPosition(MOVE_TO_NEW_POSITION)) { 如果 (isObstacleLeft == 1) _navState = 剩下 ; 其他 _navState = 选择所有; } } 打破 ; 案件 中央 : { //如果存在障碍物,请向左或向右走 如果 ( 随机 Move() == 1) _navState = 剩下 ; 其他 _navState = 对 ; } 打破 ; 案件 对 : { 向右移(最小速度); 如果 (isTimerPosition(MOVE_TO_NEW_POSITION)) { 如果 (isObstacleRight == 1) _navState = 对 ; 其他 _navState = 选择所有; } } 打破 ; 案件 背部 : { 向后移动(最小速度); 如果 (isTimerPosition(MOVE_TO_NEW_POSITION)) { 如果 ( 随机 Move() == 1) _navState = 剩下 ; 其他 _navState = 对 ; } } 打破 ; } } |
143行:定义传感器的最小和最大范围,如果障碍物在范围内,则返回true。
150至157行:在CHECK_ALL情况下,我们检查障碍物是否在传感器范围内。如果没有一个传感器检测到障碍物,则以最大速度前进。如果至少一个传感器检测到障碍物,我们将开始计算用于降低新疆风采速度的毫秒数,然后转到SPEED_DECREASE情况;
160和161行:我们以最快的速度前进,并检查所有传感器是否畅通无阻;
165至167行:新疆风采以较低的速度向前移动一定时间。时间过去后,输入CHECK_OBSTACLE_POSITION。
172至191行:如果路径畅通,则意味着传感器读数错误,我们可以以最大速度返回导航。
如果其中一个传感器仍然检测到障碍物,则我们检查所有传感器以确定障碍物相对于新疆风采的位置。如果来自新疆风采左侧的传感器检测到障碍物,那么我们就是左手情况。如果位于新疆风采中心的传感器正在检测障碍物,则说明我们处于CENTER情况。如果右传感器检测到障碍物,那么我们就处于右案例。如果所有传感器都检测到障碍物,则新疆风采无法前进并进入后退状态。
194至198行:新疆风采以最小速度向左移动特定时间。时间过后,我们将重新检查左传感器。如果传感器返回障碍物,那么我们将留在左箱中,然后再次向左移动。如果传感器没有障碍物,那么我们进入CHECK_ALL阶段。
202线:随机选择新疆风采进入的以下情况之一。它可以是左或右。
206至210行:新疆风采以最小速度向右移动特定时间。时间过后,我们会重新检查正确的传感器。如果传感器返回障碍物,那么我们将停留在RIGHT箱中,然后再次向右移动。如果传感器没有障碍物,那么我们进入CHECK_ALL阶段。
214至217行:所有传感器都返回障碍物。在这种情况下,新疆风采将以较低的速度向后移动一定时间,然后随机向左或向右移动。
第三部分:驱动系统
驱动系统应能够以直流电动机产生的最大功率移动新疆风采。两个直流电动机通常适合于全方位驱动新疆风采。
由于这是2WD平台,因此通过滑行转向转弯比4WD新疆风采容易。使用差速驱动器(两个轮子加上一个脚轮),我们可以对新疆风采进行编程,以使其沿相反的方向向左或向右旋转。
直流电动机具有齿轮机构,可调节电动机的速度,从而使电动机以最大100 rpm的速度旋转车轮。电动机的工作电压范围为3至6V。 6V是直流电动机应能最佳运行的标称电压。
两个轮子的直径为65毫米,并压装到直流电动机的3毫米D轴上。黑色轮胎由软橡胶制成,可增加牵引力。
两个直流电动机由L298N驱动器控制。它是一个双全桥驱动器,可控制直流电动机的速度和方向。电动马达可以同时或一台一台地驱动。我们利用这一优势以最小的驱动力在任何方向上驱动新疆风采。
L298N可以在5至35V的额定电压下驱动直流电动机,峰值电流高达2A。
电机驱动器的输出是PWM信号(脉冲宽度调制),该信号可快速打开和关闭输出功率,以降低提供给电机的平均电压,从而精确控制电机的旋转。
3.1将电机驱动器连接到电机和Arduino
驱动板上有两个用于电动机A和B的螺钉接线端子。我们将使用这两个接线端子来连接直流电动机。另外,我们将使用另一个螺钉接线端子作为接地引脚,并将VMS用作电动机的电源。 GND和VMS端子应连接到6V电池组。
使用母对公跳线将驱动器引脚连接到Arduino引脚。
ENA -> pin 9
IN1 -> pin 8
IN2 -> pin 11
IN3 -> pin 12
IN4 -> pin 13
ENB -> pin 10
Ground screw terminal block -> pin Gnd Arduino的 (we use two power supply sources, and we have to share the ground between them)
3.2操纵新疆风采
将直流电动机连接到电动机驱动器,然后将电动机驱动器连接到Arduino,让我们开始编写草图以控制新疆风采的转向。
根据控制新疆风采的算法,我们需要降低电机速度,向前,向后,向左和向右移动新疆风采。在我们的程序中,是每个动作的函数。
下载源代码
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 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | / * :Version 2.0 :作者:德拉戈斯·卡林 :电子邮件:dragos@intorobotics.com :License: BSD :Date: 20/04/2020 :最新更新:dd / mm / YYYY * / #包括<NewPing.h> #包括<SimpleKalmanFilter.h> #定义SONAR_NUM 3 //传感器的数量。 #定义MAX_DISTANCE 200 //检测障碍物的距离。 #define PING_INTERVAL 33 //在33微秒后循环ping。 整型 循环 = 10; //每10毫秒循环一次。 整型 DECREESE_SPEED_LOOP = 400;//给传感器一些时间以获取更多读数。 整型 MOVE_TO_NEW_POSITION = 500;//等待新职位。 未签名 长 _timerStart = 0; 未签名 长 _timerStartReady = 0; 未签名 长 _timerStartPosition = 0; uint8_t MIN_RANGE_OBSTACLE = 5; //在0到5厘米之间是传感器的盲区。 uint8_t MAX_RANGE_OBSTACLE = 75; //检查障碍物是否存在的最大范围。 uint8_t oldSensorReading[3]; //存储传感器的最后一个有效值。 uint8_t leftSensor; //存储传感器的值。 uint8_t centerSensor; uint8_t rightSensor; 布尔 isObstacleLeft; //是否检测到障碍物。 布尔 isObstacleCenter; 布尔 isObstacleRight; uint8_t 最大速度 = 255; //最大速度的PWM值。 uint8_t 最小速度 = 100; //最小速度的PWM值。 未签名 长 pingTimer[SONAR_NUM]; //保持每个传感器应进行下一次ping的时间。 未签名 整型 厘米 [SONAR_NUM]; //存储ping距离的位置。 uint8_t currentSensor = 0; //跟踪哪个传感器处于活动状态。 新平 声纳 [SONAR_NUM] = { 新平(3, 2, MAX_DISTANCE), //触发引脚,回波引脚以及到ping的最大距离。 新平(5, 4, MAX_DISTANCE), 新平(7, 6, MAX_DISTANCE) }; SimpleKalmanFilter KF_左(2, 2, 0.01); SimpleKalmanFilter KF_Center(2, 2, 0.01); SimpleKalmanFilter KF_Right(2, 2, 0.01); 枚举 导航状态 { 选择所有, 最大速度, SPEED_DECREASE, CHECK_OBSTACLE_POSITION, 剩下 , 中央 , 对 , 背部 }; 导航状态 _navState = 选择所有; // L298N电机驱动器引脚 字节 enA = 9; 字节 in1 = 8; 字节 in2 = 11; 字节 英文 = 10; 字节 in3 = 12; 字节 in4 = 13; 虚空 startTimer() { _timerStart = 毫 (); } 虚空 startTimerReady() { _timerStartReady = 毫 (); } 虚空 startTimerPosition() { _timerStartPosition = 毫 (); } 布尔 isTimeForLoop( 整型 _mSec ) { 返回 ( 毫 () - _timerStart) > _mSec ; } 布尔 isTimerReady( 整型 _mSec ) { 返回 ( 毫 () - _timerStartReady) > _mSec ; } 布尔 isTimerPosition( 整型 _mSec ) { 返回 ( 毫 () - _timerStartPosition) > _mSec ; } //循环传感器 虚空 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(echoCheck); } } } //如果收到ping命令,则将传感器距离设置为array。 虚空 echoCheck() { 如果 ( 声纳 [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() { isObstacleLeft = 障碍物检测(KF_左.updateEstimate(leftSensor)); isObstacleCenter = 障碍物检测(KF_Center.updateEstimate(centerSensor)); isObstacleRight = 障碍物检测(KF_Right.updateEstimate(rightSensor)); } //定义传感器的最小和最大范围,如果障碍物在范围内,则返回true。 布尔 障碍物检测( 整型 sensorRange) { 如果 ((MIN_RANGE_OBSTACLE <= sensorRange) && (sensorRange <= MAX_RANGE_OBSTACLE)) 返回 真正 ; 其他 返回 假 ; } //避障算法。 虚空 避障() { 开关 (_navState) { 案件 选择所有: { //如果没有障碍物,则以最大速度前进 如果 (isObstacleLeft == 0 && isObstacleCenter == 0 && isObstacleRight == 0) { _navState = 最大速度; } 其他 { startTimerReady(); _navState = SPEED_DECREASE; } } 打破 ; 案件 最大速度: { moveForward(最大速度); _navState = 选择所有; } 打破 ; 案件 SPEED_DECREASE: { moveForward(最小速度); //低速等待更多读数,然后检查障碍物位置 如果 (isTimerReady(DECREESE_SPEED_LOOP)) _navState = CHECK_OBSTACLE_POSITION; } 打破 ; 案件 CHECK_OBSTACLE_POSITION: { //如果路径畅通,请再次转到MAX_SPEED,否则检查障碍物位置 如果 (isObstacleLeft == 0 && isObstacleCenter == 0 && isObstacleRight == 0) { _navState = 最大速度; } 其他 如果 (isObstacleLeft == 1 && isObstacleCenter == 0 && isObstacleRight == 0) { startTimerPosition(); _navState = 剩下 ; } 其他 如果 (isObstacleLeft == 0 && isObstacleCenter == 1 && isObstacleRight == 0) { startTimerPosition(); _navState = 中央 ; } 其他 如果 (isObstacleLeft == 0 && isObstacleCenter == 0 && isObstacleRight == 1) { startTimerPosition(); _navState = 对 ; } 其他 如果 (isObstacleLeft == 1 && isObstacleCenter == 1 && isObstacleRight == 1) { startTimerPosition(); _navState = 背部 ; } } 打破 ; 案件 剩下 : { //向左移动并检查障碍物。如果存在障碍物,请再次向左转到,否则退出 向左移动(最小速度); 如果 (isTimerPosition(MOVE_TO_NEW_POSITION)) { 如果 (isObstacleLeft == 1) _navState = 剩下 ; 其他 _navState = 选择所有; } } 打破 ; 案件 中央 : { //如果存在障碍物,请向左或向右走 如果 ( 随机 Move() == 1) _navState = 剩下 ; 其他 _navState = 对 ; } 打破 ; 案件 对 : { 向右移(最小速度); 如果 (isTimerPosition(MOVE_TO_NEW_POSITION)) { 如果 (isObstacleRight == 1) _navState = 对 ; 其他 _navState = 选择所有; } } 打破 ; 案件 背部 : { 向后移动(最小速度); 如果 (isTimerPosition(MOVE_TO_NEW_POSITION)) { 如果 ( 随机 Move() == 1) _navState = 剩下 ; 其他 _navState = 对 ; } } 打破 ; } } // L298N电机驱动器。 虚空 stopMotors() { digitalWrite(in1, 低 ); digitalWrite(in2, 低 ); digitalWrite(in3, 低 ); digitalWrite(in4, 低 ); } 虚空 moveForward(uint8_t pwmValue) { digitalWrite(in1, 高 ); digitalWrite(in2, 低 ); digitalWrite(in3, 高 ); digitalWrite(in4, 低 ); AnalogWrite( enA , pwmValue); AnalogWrite( 英文 , pwmValue); } 虚空 向后移动(uint8_t pwmValue) { digitalWrite(in1, 低 ); digitalWrite(in2, 高 ); digitalWrite(in3, 低 ); digitalWrite(in4, 高 ); AnalogWrite( enA , pwmValue); AnalogWrite( 英文 , pwmValue); } 虚空 向左移动(uint8_t pwmValue) { digitalWrite(in1, 低 ); //向左滚轮。 digitalWrite(in2, 高 ); digitalWrite(in3, 高 );//右轮向前。 digitalWrite(in4, 低 ); AnalogWrite( enA , pwmValue); AnalogWrite( 英文 , pwmValue); } 虚空 向右移(uint8_t pwmValue) { digitalWrite(in1, 高 ); //左轮向前。 digitalWrite(in2, 低 ); digitalWrite(in3, 低 );//右轮后退。 digitalWrite(in4, 高 ); AnalogWrite( enA , pwmValue); AnalogWrite( 英文 , pwmValue); } //从随机数返回1或0。 整型 随机 Move() { uint8_t rnd_number = 随机 (1, 100); 返回 rnd_number % 2; } / * 设定& LOOP*/ 虚空 设定 () { 序列号 . 开始 (115200); pingTimer[0] = 毫 () + 75; 对于 (uint8_t i = 1; i < SONAR_NUM; i ++ ) pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL; pinMode( enA , 输出值 ); pinMode(in1, 输出值 ); pinMode(in2, 输出值 ); pinMode( 英文 , 输出值 ); pinMode(in3, 输出值 ); pinMode(in4, 输出值 ); stopMotors(); } 虚空 循环 () { 如果 (isTimeForLoop(循环)) { sensorCycle(); 申请KF(); 避障(); startTimer(); } } |
概要
我们完成了很长的教程。在本教程中,您学习了如何定义新疆风采的输入和输出,如何编写控制新疆风采的动作和操纵的算法。
在本教程的第一部分中,我们介绍了新疆风采的功能规格。我们定义了新疆风采的两个输入和输出。然后,我们通过安装传感器并将读数转换为厘米来赋予新疆风采传感功能。应用过滤器,我们设法稳定并消除了传感器的跳变或不稳定的读数。
然后我们继续,在第二部分中,我们编写了控制新疆风采如何响应环境中的障碍物的算法。
在第三部分中,我们通过降低电机速度并根据算法的决策在一定方向上移动新疆风采来实现新疆风采的转向。
什么是源代码… robotC or C ++ ?
您好,MasterG,
源代码是Arduino(C ++ )代码。
I’我要先尝试一下,然后用C ++ ,然后我’我会尝试将其翻译成Python。
您好先生..您能为零件的所有连接共享原理图吗?我想在文凭课程中使用我的修订项目