初始化文档
|
@ -0,0 +1,3 @@
|
|||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="EMPTY_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/autolabor-m1-doc.iml" filepath="$PROJECT_DIR$/.idea/autolabor-m1-doc.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE categories
|
||||
SYSTEM "https://resources.jetbrains.com/writerside/1.0/categories.dtd">
|
||||
<categories>
|
||||
<category id="wrs" name="Writerside documentation" order="1"/>
|
||||
</categories>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE instance-profile
|
||||
SYSTEM "https://resources.jetbrains.com/writerside/1.0/product-profile.dtd">
|
||||
|
||||
<instance-profile id="hi"
|
||||
name="Help Instance"
|
||||
start-page="Default-topic.md">
|
||||
|
||||
<toc-element topic="Default-topic.md"/>
|
||||
</instance-profile>
|
After Width: | Height: | Size: 125 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 341 KiB |
After Width: | Height: | Size: 119 KiB |
After Width: | Height: | Size: 306 KiB |
After Width: | Height: | Size: 274 KiB |
|
@ -0,0 +1,79 @@
|
|||
# This is the first topic
|
||||
|
||||
<!--Writerside adds this topic when you create a new documentation project.
|
||||
You can use it as a sandbox to play with Writerside features, and remove it from the TOC when you don't need it anymore.
|
||||
If you want to re-add it for your experiments, click + to create a new topic, choose Topic from Template, and select the
|
||||
"Starter" template.-->
|
||||
|
||||
## Add new topics
|
||||
You can create empty topics, or choose a template for different types of content that contains some boilerplate structure to help you get started:
|
||||
|
||||
![Create new topic options](new_topic_options.png){ border-effect="line" thumbnail="true" width="321"}
|
||||
|
||||
## Write content
|
||||
%product% supports two types of markup: Markdown and XML.
|
||||
When you create a new help article, you can choose between two topic types, but this doesn't mean you have to stick to a single format.
|
||||
You can author content in Markdown and extend it with semantic attributes or inject entire XML elements.
|
||||
|
||||
For example, this is how you inject a procedure:
|
||||
|
||||
<procedure title="Inject a procedure" id="inject-a-procedure">
|
||||
<step>
|
||||
<p>Start typing <code>procedure</code> and select a procedure type from the completion suggestions:</p>
|
||||
<img src="completion_procedure.png" alt="completion suggestions for procedure" border-effect="line"/>
|
||||
</step>
|
||||
<step>
|
||||
<p>Press <shortcut>Tab</shortcut> or <shortcut>Enter</shortcut> to insert the markup.</p>
|
||||
</step>
|
||||
</procedure>
|
||||
|
||||
## Add interactive elements
|
||||
|
||||
### Tabs
|
||||
To add switchable content, use tabs (start typing `tabs` on a new line).
|
||||
|
||||
<tabs>
|
||||
<tab title="Markdown">
|
||||
<code-block lang="plain text">![Alt Text](new_topic_options.png){ width=450 }</code-block>
|
||||
</tab>
|
||||
<tab title="Semantic markup">
|
||||
<code-block lang="xml">
|
||||
<![CDATA[<img src="new_topic_options.png" alt="Alt text" width="450px"/>]]></code-block>
|
||||
</tab>
|
||||
</tabs>
|
||||
|
||||
### Collapsible blocks
|
||||
Besides injecting entire XML elements, you can use attributes to configure the behavior of certain elements.
|
||||
For example, you can collapse a chapter that contains non-essential information like this:
|
||||
|
||||
#### Supplementary info {collapsible="true"}
|
||||
Content under such header will be collapsed by default, but you can modify the behavior by adding the following attribute:
|
||||
`default-state="expanded"`
|
||||
|
||||
## Convert selection to XML
|
||||
If you need to extend an element with more functions, you can convert selected content from Markdown to semantic markup.
|
||||
For example, if you want to merge cells in a table, it's much easier to convert it to XML than do this in Markdown.
|
||||
Position the caret anywhere in the table and press <shortcut>Alt+Enter</shortcut>:
|
||||
|
||||
<img src="convert_table_to_xml.png" alt="Convert table to XML" width="706" border-effect="line"/>
|
||||
|
||||
## Feedback and support
|
||||
Please report any issues, usability improvements, or feature requests to our
|
||||
<a href="https://youtrack.jetbrains.com/newIssue?project=WRS">YouTrack project</a>
|
||||
(you will need to register).
|
||||
|
||||
You are welcome to join our
|
||||
<a href="https://jb.gg/WRS_Slack">public Slack workspace</a>.
|
||||
Before you do, please read our [Code of conduct](https://plugins.jetbrains.com/plugin/20158-writerside/docs/writerside-code-of-conduct.html).
|
||||
We assume that you’ve read and acknowledged it before joining.
|
||||
|
||||
You can also always email us at [writerside@jetbrains.com](mailto:writerside@jetbrains.com).
|
||||
|
||||
<seealso>
|
||||
<category ref="wrs">
|
||||
<a href="https://plugins.jetbrains.com/plugin/20158-writerside/docs/markup-reference.html">Markup reference</a>
|
||||
<a href="https://plugins.jetbrains.com/plugin/20158-writerside/docs/manage-table-of-contents.html">Reorder topics in the TOC</a>
|
||||
<a href="https://plugins.jetbrains.com/plugin/20158-writerside/docs/local-build.html">Build and publish</a>
|
||||
<a href="https://plugins.jetbrains.com/plugin/20158-writerside/docs/configure-search.html">Configure Search</a>
|
||||
</category>
|
||||
</seealso>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE vars SYSTEM "https://resources.jetbrains.com/writerside/1.0/vars.dtd">
|
||||
<vars>
|
||||
<var name="product" value="Writerside"/>
|
||||
</vars>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ihp SYSTEM "https://resources.jetbrains.com/writerside/1.0/ihp.dtd">
|
||||
|
||||
<ihp version="2.0">
|
||||
<topics dir="topics" web-path="topics"/>
|
||||
<images dir="images" web-path="images"/>
|
||||
<categories src="c.list"/>
|
||||
<vars src="v.list"/>
|
||||
<instance src="hi.tree"/>
|
||||
</ihp>
|
|
@ -0,0 +1,231 @@
|
|||
### <mark>注意</mark>:
|
||||
* 在使用串口发送指令时,底层超过 **1s** 没有接收到上位机的指令,会向上位机返回错误状态码FF (error状态:连接超时),此时用户如果想要重新控制车辆,需要发送Reset命令
|
||||
* 在调试发送指令时,先发一条Reset命令,然后接着发指令,如:
|
||||
|
||||
0x 55 AA 02 02 05 00 FA
|
||||
0x 55 AA 09 00 01 00 04 00 00 00 00 00 00 F3
|
||||
0x 55 AA 02 02 05 00 FA
|
||||
0x 55 AA 09 00 01 00 04 00 00 00 00 00 00 F3
|
||||
...
|
||||
|
||||
#### 串口测试速度指令样例
|
||||
|
||||
##### 左转
|
||||
|
||||
55 AA 02 02 05 00 FA 55 AA 09 00 01 00 00 00 04 00 00 00 00 F3
|
||||
|
||||
##### 右转
|
||||
|
||||
55 AA 02 02 05 00 FA 55 AA 09 00 01 00 04 00 00 00 00 00 00 F3
|
||||
|
||||
##### 前进
|
||||
|
||||
55 AA 02 02 05 00 FA 55 AA 09 00 01 00 04 00 04 00 00 00 00 F7
|
||||
|
||||
##### 后退
|
||||
|
||||
55 AA 02 02 05 00 FA 55 AA 09 00 01 FF FA FF FA 00 00 00 00 F7
|
||||
|
||||
下面列出几个常用的控制指令示例:
|
||||
|
||||
# 控制车轮速度指令
|
||||
假设请求左车轮速度为0.1m/s,传输数据帧内容为:
|
||||
|
||||
0x 55 AA 09 00 01 00 04 00 00 00 00 00 00 F3
|
||||
<table>
|
||||
<tbody>
|
||||
<tr align="center">
|
||||
<td rowspan="2">Header</td>
|
||||
<td rowspan="2">Length</td>
|
||||
<td rowspan="2">Sequence</td>
|
||||
<td colspan="5">Payload</td>
|
||||
<td rowspan="2">Checksum </td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td width="10%">MsgID</td>
|
||||
<td colspan="4">PARAM</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>55 AA</td>
|
||||
<td>09</td>
|
||||
<td>00</td>
|
||||
<td>01</td>
|
||||
<td>00 04</td>
|
||||
<td>00 00</td>
|
||||
<td>00 00</td>
|
||||
<td>00 00</td>
|
||||
<td>F3</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>起始标志位</td>
|
||||
<td>有效数据的长度为9个字节</td>
|
||||
<td>第一个指令</td>
|
||||
<td>控制车轮速度指令</td>
|
||||
<td>左车轮</td>
|
||||
<td>右车轮</td>
|
||||
<td colspan="2">固定不变为0</td>
|
||||
<td>异或校验码</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
如上文所说,通常我们所说的速度是以m/s为单位的速度,而指令中车轮速度的参数实际上是单位时间内期望编码器的计数,在此需要将指令的速度V(m/s)结合AP1下位机的物理参数进行计算,下面是车轮速度换算方法。
|
||||
|
||||
M1下位机物理参数如下表:
|
||||
|
||||
名称 | 参数 | 说明
|
||||
:-------------: | :-------------: | :-------------
|
||||
wheel_diameter | 0.25 | 车轮直径,单位:米
|
||||
encoder_resolution | 1600 | 编码器转一圈产生的脉冲数
|
||||
PID_RATE | 50 | PID调节PWM值的频率
|
||||
|
||||
假设我们给M1左轮V=0.1m/s的速度(右轮速度的计算指令与此相同),<a name="caculate-method">计算方法</a>如下:
|
||||
|
||||
车轮转动一圈,移动的距离为轮子的周长:
|
||||
|
||||
distance_one_round
|
||||
=wheel_diameter*π
|
||||
=wheel_diameter*3.1415926
|
||||
=0.25*3.1415926
|
||||
|
||||
车轮转动一圈,编码器产生的脉冲数为:
|
||||
|
||||
wheel_encoder_resolution
|
||||
=1*encoder_resolution
|
||||
=1*1600
|
||||
=1600
|
||||
|
||||
注:编码器与车轮连接在一起,车轮转1圈,编码器转1圈;编码器的脉冲数可以理解为编码器计数,编码器自转一圈计数1600,则车轮转一圈编码器计数为1600。
|
||||
|
||||
所以AP1每移动1米产生脉冲数(编码器的计数)为:
|
||||
|
||||
ticks_per_meter
|
||||
=(1/distance_one_round)*wheel_encoder_resolution
|
||||
=1/(0.25*3.1415926)*1600
|
||||
=2037.18
|
||||
|
||||
又因为PID的频率是1秒钟50次,所以指令的参数计算方法为:
|
||||
|
||||
int(V*ticks_per_meter/PID_RATE)
|
||||
=int(0.1*2037.18/50)
|
||||
=4
|
||||
|
||||
|
||||
用户可直接使用0.1m/s速度的计算结果来对应自己期望的速度换算成相应的数值,如0.2m/s为8,1m/s为40等。
|
||||
|
||||
接着将计算出来的4换算为16进制为:
|
||||
|
||||
00 04
|
||||
|
||||
则速度指令的PARAM为
|
||||
|
||||
00 04 00 00 00 00 00 00
|
||||
|
||||
|
||||
注:如果用户发送的速度超过了最大速度,则会按最大速度行进。
|
||||
|
||||
# 获取电池电量指令
|
||||
0x 55 AA 02 01 02 00 FE
|
||||
<table>
|
||||
<tbody>
|
||||
<tr align="center">
|
||||
<td rowspan="2">Header</td>
|
||||
<td rowspan="2">Length</td>
|
||||
<td rowspan="2">Sequence</td>
|
||||
<td colspan="2">Payload</td>
|
||||
<td rowspan="2">Checksum </td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>MsgID</td>
|
||||
<td>PARAM</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>55 AA</td>
|
||||
<td>02</td>
|
||||
<td>01</td>
|
||||
<td>02</td>
|
||||
<td>00</td>
|
||||
<td>FE</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>起始标志位</td>
|
||||
<td>有效数据的长度为2个字节</td>
|
||||
<td>第二个指令</td>
|
||||
<td>小车的电量请求</td>
|
||||
<td>参数为00</td>
|
||||
<td>异或校验码</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
# 重置状态指令
|
||||
当接收到下位机发送的错误状态码FF时,需要将AP1状态重置(Reset),才能重新恢复控制,指令如下:
|
||||
|
||||
0x 55 AA 02 02 05 00 FA
|
||||
<table>
|
||||
<tbody>
|
||||
<tr align="center">
|
||||
<td rowspan="2">Header</td>
|
||||
<td rowspan="2">Length</td>
|
||||
<td rowspan="2">Sequence</td>
|
||||
<td colspan="2">Payload</td>
|
||||
<td rowspan="2">Checksum </td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>MsgID</td>
|
||||
<td>PARAM</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>55 AA</td>
|
||||
<td>02</td>
|
||||
<td>02</td>
|
||||
<td>05</td>
|
||||
<td>00</td>
|
||||
<td>FA</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>起始标志位</td>
|
||||
<td>有效数据的长度为2个字节</td>
|
||||
<td>第三个指令</td>
|
||||
<td>重置状态指令</td>
|
||||
<td>参数为00</td>
|
||||
<td>异或校验码</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
# 清除编码器计数指令
|
||||
|
||||
|
||||
0x 55 AA 02 03 06 00 F8
|
||||
<table>
|
||||
<tbody>
|
||||
<tr align="center">
|
||||
<td rowspan="2">Header</td>
|
||||
<td rowspan="2">Length</td>
|
||||
<td rowspan="2">Sequence</td>
|
||||
<td colspan="2">Payload</td>
|
||||
<td rowspan="2">Checksum </td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>MsgID</td>
|
||||
<td>PARAM</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>55 AA</td>
|
||||
<td>02</td>
|
||||
<td>03</td>
|
||||
<td>06</td>
|
||||
<td>00</td>
|
||||
<td>F8</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>起始标志位</td>
|
||||
<td>有效数据的长度为2个字节</td>
|
||||
<td>第四个指令</td>
|
||||
<td>请求清除编码器计数</td>
|
||||
<td>参数为00</td>
|
||||
<td>异或校验码</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
After Width: | Height: | Size: 14 MiB |
After Width: | Height: | Size: 378 KiB |
After Width: | Height: | Size: 138 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 572 KiB |
After Width: | Height: | Size: 3.5 MiB |
|
@ -0,0 +1,108 @@
|
|||
# 产品参数
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="20%">尺寸</td>
|
||||
<td>726*617*326mm</td>
|
||||
<td>净重</td>
|
||||
<td>40kg</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>负载</td>
|
||||
<td>50kg</td>
|
||||
<td>电池</td>
|
||||
<td>24v 磷酸铁锂电池</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>电池容量</td>
|
||||
<td>20AH</td>
|
||||
<td>续航时间</td>
|
||||
<td>4h</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>辅助电源</td>
|
||||
<td>24v</td>
|
||||
<td>最大速度</td>
|
||||
<td>0.8m/s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>驱动方式</td>
|
||||
<td>四驱</td>
|
||||
<td>转向方式</td>
|
||||
<td>差速转向</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>通信接口</td>
|
||||
<td>RS232串口</br>115200bps</td>
|
||||
<td>编码器精度</td>
|
||||
<td>物理:400线</br>逻辑:1600线(四倍频)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PID控制频率</td>
|
||||
<td>50Hz</td>
|
||||
<td>适用地形</td>
|
||||
<td>全地形</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>垂直越障能力</td>
|
||||
<td>8cm</td>
|
||||
<td>爬坡能力</td>
|
||||
<td>25°</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>支持系统</td>
|
||||
<td>Windows/Linux</td>
|
||||
<td>支持平台</td>
|
||||
<td>x86/arm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>手柄控制</td>
|
||||
<td>20m</td>
|
||||
<td>手柄通讯</td>
|
||||
<td>2.4Ghz</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
# 产品尺寸
|
||||
|
||||
![4.png](imgs/4.png)
|
||||
|
||||
|
||||
|
||||
# 控制手柄参数
|
||||
该手柄有自动休眠功能,长时间不操作,省电模块被激活后自动进入休眠模式,按下START键即可唤醒手柄。
|
||||
|
||||
参数名称 | 参数内容
|
||||
:-------------: | :-------------:
|
||||
电池 | AAA(7号)电池\*2
|
||||
使用时间 | 约10小时
|
||||
无线频率 | 2.4GHz
|
||||
接收范围 | 20m
|
||||
|
||||
* * *
|
||||
|
||||
# 控制面板使用
|
||||
![1.png](imgs/1.png)
|
||||
|
||||
控制面板清单:
|
||||
|
||||
名称 | 个数 | 说明
|
||||
:-------------: | :-------------: | :-------------:
|
||||
紧急停止 | 1 | 在紧急情况下请按下该紧急停止按钮
|
||||
电源 | 1 | 电源开启关闭按钮
|
||||
充电口 | 1 | 为内置电池充电
|
||||
电量显示 | 1 | 以百分比的形式显示M1电池电量
|
||||
遥控/上位机 | 1 | 切换手柄控制与上位机控制按钮
|
||||
RS232 | 1 | 使用串口数据线连接下位机与上位机,进行通信
|
||||
|
||||
* * *
|
||||
|
||||
# 熔断式保险或空气开关
|
||||
|
||||
当M1意外出现短路、过载的情况时,熔断式保险或空气开关会主动切断电池的回路。
|
||||
![2.png](imgs/2.png)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
## 里程计标定
|
||||
|
||||
里程计标定也叫里程计校准,即在当前运行环境下重新计算运动模型,得到里程计的运动模型参数,此教程**只适用于使用ROS控制M1机器人**的用户。
|
||||
|
||||
Autolabor M1 出厂时已做过标定了,在一般运行环境下(地毯、水泥、普通瓷砖等平坦路面)不用重新做标定,但如果您的运行环境是非一般环境,机器人可能就需要重新做标定,比如【经过打磨过的】并且还有【镜面效果】的水泥路面,或摩擦力较大路面,如果您在使用导航套件建图时效果不佳,也可以进行标定。
|
||||
|
||||
对于不太确定产品是否需要标定的用户,可先进行里程计测试,根据测试结果来判断机器人是否需要标定。
|
||||
|
||||
|
||||
|
||||
## 检测机器人是否需要标定
|
||||
|
||||
|
||||
|
||||
### 操作步骤:
|
||||
|
||||
1. 启动键盘控制,使用ROS键盘控制AP1原地转360度
|
||||
2. 打开一个新的terminal,运行
|
||||
```
|
||||
$ rviz
|
||||
```
|
||||
3. rviz窗口打开后,将fixed frame选择为odom
|
||||
4. 关闭其他所有勾选,只保留grid和tf(如没有grid,左下角add新增)
|
||||
5. 打开tf,下拉出来frames的内容,关闭其他所有勾选,保留baselink和odom
|
||||
6. rviz右侧界面可看两个重合的坐标系(baselink和odom)
|
||||
7. 对机器人(实体)的四个轮子做标记,标记此时车的位置
|
||||
8. 键盘控制机器人原地360度转一圈(请必须记住此时旋转的方向,标定会用到),控制机器人回到刚刚标记的位置(重合),保持机器人与标记的初始位置方向一致
|
||||
9. 观察rviz中的2个坐标系是否重合
|
||||
|
||||
如果不重合,表示需要标定。
|
||||
|
||||
如果基本重合,表示不需要标定。
|
||||
|
||||
## 对机器人进行里程计标定
|
||||
|
||||
### 操作步骤:
|
||||
|
||||
1. 打开一个新的terminal
|
||||
2. 运行
|
||||
```
|
||||
$ rosrun tf tf_echo /odom /base_link
|
||||
```
|
||||
3. 在出现的数据中查找in RPY (degree)[0,0,X]
|
||||
4. 查看X值,如果刚刚键盘控制车时是顺时针转,用360-X,如果是逆时针转,用360+X,得到Y
|
||||
5. 计算 model_param*Y/360,得到计算结果
|
||||
6. 打开启动的launch文件,找到Autolabor M1驱动部分(autolabor_pro1_driver),找到model_param参数,将model_param改为上一步得到的结果
|
||||
7. 保存、关闭launch文件
|
||||
8. 关闭terminal中的运行的launch(ctrl+c),如果rviz关闭时弹出窗口,询问是否需要保存,点击【without saving】(不保存)
|
||||
9. 再次重复【检测机器人是否需要标定】的操作
|
||||
|
||||
如果不重合,表示需要标定,如果基本重合,表示不需要标定,重复以上【标定】工作,一次次的进行,直到基本重合。
|
||||
|
||||
注意:除第一次标定时使用的model_param为驱动中的原始值,之后每一次的标定操作中model_param为上一次标定计算的model_param结果(第5步)
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
# 产品概述
|
||||
Autolabor M1机器人移动开发平台是一款集模块化、简洁化、可定制为一身的机器人底盘,适用于机器人教育培训、科学研究和产品开发等。具有通过性强、负载能力大、精度高、动力足、续航长和扩展性高等特点,可跨平台开发,支持多种应用场景。
|
||||
|
||||
* * *
|
||||
|
||||
|
||||
# 主要特性
|
||||
* 可靠耐用,操作简单,无需组装,开机直接使用
|
||||
* 高通过性,爬坡能力十足,续航能力强
|
||||
* 高精度工业级编码器,定位精准
|
||||
* 高负载,负重可达50KG
|
||||
* 适应场景广泛,室内外均可使用
|
||||
* 兼容多个系统,支持多种开发平台、控制方式
|
||||
* 支持ROS开发,提供ROS驱动包与运动模型
|
||||
* 雷达、摄像头、惯导等多种传感器随意组合搭配,拆装方便
|
||||
* 使用文档齐全,配备后续用户支持,并不断更新开发教程
|
||||
|
||||
* * *
|
||||
|
||||
|
||||
# 产品清单
|
||||
|
||||
名称 | 数量 | 备注
|
||||
:---:|:---:|---
|
||||
M1移动平台 | 1辆 |
|
||||
M1充电器 | 1个 |
|
||||
M1控制手柄| 1套 | 含电池
|
||||
串口数据线 | 1根 |
|
||||
配套工具 | 1套 |
|
||||
|
||||
* * *
|
||||
|
||||
# 使用提醒
|
||||
|
||||
* 产品边缘锋利,请小心接触,避免划伤
|
||||
* 产品表面为金属材质,请勿与电路板直接接触
* 操控平台时避免速度过快,引起碰撞
* 搬运时以及设置作业时,请勿落下或倒置
|
||||
* 非专业人员,请不要私自拆卸
* 不使用非原厂标配的电池、电源、充电座
* 运行时请勿用手触碰
|
||||
* 不要在有水的地方,存在腐蚀性、易燃性气体的环境内和靠近可燃性物质的地方使用
* 不要放置在加热器或者大型卷线电阻器等发热体周围
|
||||
* 切勿将电机直接与商用电源连接
|
||||
|
||||
* * *
|
||||
|
||||
# 电池安全
|
||||
* 请在有人看护的状态下充电,若人员离开请拔掉充电插头
|
||||
* 充电器在充电工作时,会向外界散发一定的热量,充电器与产品应放在通风干燥的环境中使用
* 正常充电时,充电指示灯为红色,当转为绿色时为充满
|
||||
* 停止充电时,应先拔下插头,然后取下电池端插头
|
||||
* 产品长期不用,需三个月至半年补充一次电
|
||||
* 产品电池不可将电完全用完,否则会严重受损,容易造成不可修复
|
||||
|
||||
* * *
|
|
@ -0,0 +1,198 @@
|
|||
## 协议概述
|
||||
|
||||
本协议是一种用于M1上位机与下位机之间通信的自定义通信协议,波特率为115200,以16进制格式传输。上位机向下位机发送请求(commands),下位机在收到来自上位机的请求后,作出相应的反应并返回应答(feedback)至上位机,帧结构说明如下。
|
||||
|
||||
## 帧结构说明
|
||||
数据帧分为5个部分:起始标志位/帧头(Header),数据长度(Length),序列号(Sequence),有效载荷数据(Payload),检验码(Checksum)。
|
||||
|
||||
数据帧结构如下表所示:
|
||||
|
||||
<table>
|
||||
<tr align="center">
|
||||
<th style="background-color:#374F7F;color:#fff;">Name</th>
|
||||
<td>Header</td>
|
||||
<td>Length</td>
|
||||
<td>Sequence</td>
|
||||
<td>Payload</td>
|
||||
<td>Checksum</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<th style="background-color:#374F7F;color:#fff;">Size</th>
|
||||
<td>2 Byte</td>
|
||||
<td>1 Byte</td>
|
||||
<td>1 Byte</td>
|
||||
<td>N Bytes</td>
|
||||
<td>1 Byte</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### 起始标志位/帧头(Header)
|
||||
起始标志位,即为我们常说的帧头,以固定不变的“55AA”作为起始标志位,标志着一帧的开始。
|
||||
|
||||
### 数据长度(Length)
|
||||
数据长度,其值表示数据包Payload的长度。
|
||||
|
||||
### 序列号(Sequence)
|
||||
帧的序列号从0开始,范围为0~255,消息的发送端每发送一个帧将该字段的值加1,接收端可以根据该字段是否连续,判断是否有丢包的情况发生。
|
||||
|
||||
### 有效载荷数据(Payload)
|
||||
有效载荷数据,即实际数据内容,考虑到数据传输效率与可扩展性,本协议将Payload的长度设计为非固定长度,可适应不同的消息类型。
|
||||
|
||||
Payload分为两部分:MsgID和PARAM。
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr align="center">
|
||||
<td colspan="2">Payload</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">MsgID</td>
|
||||
<td align="center">PARAM</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>指令的类型</td>
|
||||
<td>指令的内容</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Payload指令如下表所示:
|
||||
<table>
|
||||
<tbody>
|
||||
<tr align="center">
|
||||
<th width="5%">Name</th>
|
||||
<th>Type</th>
|
||||
<th>MsgID</th>
|
||||
<th colspan="4" width="35%">PARAM</th>
|
||||
<th colspan="2">Description</th>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td rowspan="4">车轮速度指令</td>
|
||||
<td rowspan="2">发送</td>
|
||||
<td rowspan="2">01</td>
|
||||
<td width="8%">00 00</td>
|
||||
<td width="8%">00 00</td>
|
||||
<td width="8%">00 00</td>
|
||||
<td width="8%">00 00</td>
|
||||
<td rowspan="2" align="left" colspan="2">
|
||||
|
||||
* M1是2电机4轮驱动模式,左/右两侧的两个轮子各由一个电机驱动。因此左边的两个轮子的速度是相同的,在发送左/右轮速度时,仅需发送一个轮子的速度,每个轮速是2个字节
|
||||
* PARAM中前2个字节设置左轮的速度,接着2个字节设置右轮的速度,后面4个字节全部置0,用于后续拓展四轮控制
|
||||
* 当我们改变车轮的速度的时候,其实是改变车轮编码器的计数,例如给左轮一个0.1m/s前进的速度,即给出的指令是0004,则需要通过计算将车轮速度转化为编码器的计数,后面会讲到如何计算
|
||||
</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>左轮</td>
|
||||
<td>右轮</td>
|
||||
<td colspan="2">空字段,用于后续扩展</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td rowspan="2">接收</td>
|
||||
<td rowspan="2">01</td>
|
||||
<td width="8%">00 04</td>
|
||||
<td width="8%">00 00</td>
|
||||
<td width="8%">00 00</td>
|
||||
<td width="8%">00 00</td>
|
||||
<td align="left" colspan="2" rowspan="2">返回的数据是当前时刻车轮编码器的累计计数</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>左轮</td>
|
||||
<td>右轮</td>
|
||||
<td colspan="2">空字段,用于后续扩展</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td rowspan="2">电池电量指令</td>
|
||||
<td>发送</td>
|
||||
<td>02</td>
|
||||
<td colspan="4">00</td>
|
||||
<td colspan="2" align="left">请求电池电量</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>接收</td>
|
||||
<td>02</td>
|
||||
<td colspan="4">32</td>
|
||||
<td align="left" colspan="2">返回的数据为0~100电量区间的16进制表达,例如电量为50,则返回32</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td rowspan="3">重置状态指令</td>
|
||||
<td>发送</td>
|
||||
<td>05</td>
|
||||
<td colspan="4">00</td>
|
||||
<td align="left" colspan="2">
|
||||
|
||||
**<mark>注:当上位机在发送指令后,接收到错误状态信息FF时,必须发送重置指令,重置后才能恢复对下位机的控制</mark>**
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td rowspan="2">接收</td>
|
||||
<td>05</td>
|
||||
<td colspan="4">01</td>
|
||||
<td align="left" colspan="2">返回操作成功</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>05</td>
|
||||
<td colspan="4">00</td>
|
||||
<td align="left" colspan="2">返回操作失败</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td rowspan="3">清除编码器计数指令</td>
|
||||
<td>发送</td>
|
||||
<td>06</td>
|
||||
<td colspan="4">00</td>
|
||||
<td align="left" colspan="2">对编码器计数清零</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td rowspan="2">接收</td>
|
||||
<td>06</td>
|
||||
<td colspan="4">01</td>
|
||||
<td align="left" colspan="2">返回操作成功</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>06</td>
|
||||
<td colspan="4">00</td>
|
||||
<td align="left" colspan="2">返回操作失败</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td rowspan="4">错误状态指令</td>
|
||||
<td rowspan="4">接收</td>
|
||||
<td>FF</td>
|
||||
<td colspan="4">01</td>
|
||||
<td align="left">电池没电</td>
|
||||
<td rowspan="4" width="20%" align="left" valign="top">当上位机向发送请求,下位机发生错误无法执行指令时,会向上位机返回相应的错误信息</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>FF</td>
|
||||
<td colspan="4">02</td>
|
||||
<td align="left">电流过大</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>FF</td>
|
||||
<td colspan="4">03</td>
|
||||
<td align="left">串口通信故障</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>FF</td>
|
||||
<td colspan="4">04</td>
|
||||
<td align="left">车轮卡死</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
错误状态处理流程图:
|
||||
<div style="width:60%">
|
||||
|
||||
![Flow](imgs/autolaborPro1-flow.jpg)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### 检验码(Checksum)
|
||||
|
||||
为保证上位机与下位机所传输数据的无误性与一致性,本协议采用异或(XOR)校验的方式,根据具体发送的指令生成异或校验码,校验的数据包括帧头55AA,用户可以使用在线的[异或校验计算器](http://www.ip33.com/bcc.html)来计算,如下图所示**计算结果(Hex)**即时我们所需的异或校验码。
|
||||
<div style="width:80%">
|
||||
|
||||
![XOR](imgs/autolaborPro1-xor.png)
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
# ROS驱动包(ROS Driver Package)
|
||||
|
||||
ROS驱动包(ROS Driver Package)是为使用ROS开发的用户,提供上位机与下位机通讯的驱动包([下载](http://www.autolabor.com.cn/download))。
|
||||
### 订阅的话题
|
||||
/cmd\_vel ([geometry_msgs/Twist]( http://download.autolabor.com.cn/ROS/AutolaborPro1_ROS_Driver_Package20190107.zip))
|
||||
控制下位机运动的速度指令
|
||||
|
||||
### 发布的话题
|
||||
/wheel\_odom ([nav_msgs/Odometry](http://docs.ros.org/api/nav_msgs/html/msg/Odometry.html))
|
||||
轮速里程计
|
||||
|
||||
/remaining\_battery ([std_msgs::Int32](http://docs.ros.org/hydro/api/std_msgs/html/msg/Int32.html))
|
||||
剩余电池电量
|
||||
|
||||
/current([std_msgs::Float32](http://docs.ros.org/hydro/api/std_msgs/html/msg/Float32.html))
|
||||
电流信息
|
||||
|
||||
/voltage([std_msgs::Float32](http://docs.ros.org/hydro/api/std_msgs/html/msg/Float32.html))
|
||||
电压信息
|
||||
|
||||
|
||||
### 参数
|
||||
|
||||
| 参数 | 名称 | 备注 |
|
||||
| :------------ | :------------ | :------------ |
|
||||
| ~port_name (str, default: /dev/ttyUSB0) | 串口名称 | |
|
||||
| ~odom_frame (str, default: odom) | odom | |
|
||||
| ~base_frame (str, default: base_link) | base_link | |
|
||||
| ~baud_rate (int, default: 115200) | 波特率 | |
|
||||
| ~control_rate (int, default: 10) | 控制频率 | |
|
||||
| ~sensor_rate (int, default: 5) | 请求电池电量频率 | |
|
||||
| ~reduction_ratio (double, default: 1) | 减速比 | |
|
||||
| ~encoder_resolution (double, default: 1600) | 编码器的编码数 | |
|
||||
| ~wheel_diameter (double, default: 0.25) | 车轮直径 | |
|
||||
| ~model_param_cw (double, default:0.8) | 顺时针旋转运动模型参数 | | ~model_param_acw (double, default:0.8) | 逆时针旋转运动模型参数 | | ~pid_rate (double, default:50.0) | PID控制周期 | |
|
||||
|
||||
### TF转换
|
||||
|
||||
odom → base_link
|
||||
|
||||
### 驱动示例
|
||||
|
||||
|
||||
<launch>
|
||||
<node name="autolabor_driver" pkg="autolabor_pro1_driver" type="autolabor_pro1_driver" output="screen">
|
||||
<param name="port_name" value="/dev/ttyUSB0" />
|
||||
<param name="odom_frame" value="odom" />
|
||||
<param name="base_frame" value="base_link" />
|
||||
|
||||
<param name="baud_rate" value="115200" />
|
||||
<param name="control_rate" value="10" />
|
||||
<param name="sensor_rate" value="5" />
|
||||
|
||||
<param name="reduction_ratio" value="1.0" />
|
||||
<param name="encoder_resolution" value="1600.0" />
|
||||
|
||||
<param name="wheel_diameter" value="0.25" />
|
||||
<param name="model_param_cw" value="0.8" />
|
||||
<param name="model_param_acw" value="0.8" />
|
||||
<param name="pid_rate" value="50.0" />
|
||||
<param name="maximum_encoding" value="32.0" />
|
||||
</node>
|
||||
</launch>
|
||||
|
||||
### 驱动启动方法
|
||||
|
||||
1. 将ROS驱动放入工作空间catkin_ws/src
|
||||
2. 回到catkin_ws根目录下
|
||||
3. 打开terminal
|
||||
3. 执行
|
||||
source /opt/ros/kinetic/setup.bash
|
||||
4. 执行
|
||||
caktin_make
|
||||
5. 执行
|
||||
source devel/setup.bash
|
||||
6. 执行
|
||||
roslaunch autolabor_pro1_driver driver.launch
|
||||
|
||||
驱动启动后,可以给小车发送速度指令。此时须将底盘架起来,车轮悬空。
|
||||
|
||||
### 速度指令发送
|
||||
|
||||
1. 打开一个terminal
|
||||
2. 执行 rostopic list 查看有无/cmd_vel 话题
|
||||
3. 如果有的话,执行:
|
||||
|
||||
rostopic pub -r 10 /cmd_vel geometry_msgs/Twist -- '[0.0,0.0,0.0]' '[0.0,0.0,1]'
|
||||
|
||||
此时车轮会开始转动,如果想要停止的话,必须在执行命令的terminal中执行Ctrl+C,停止发送。
|
||||
|
||||
关于指令参数的详细介绍,请参考ROS官网 [Using rostopic pub](http://wiki.ros.org/ROS/Tutorials/UnderstandingTopics)
|
||||
|
||||
|
||||
|
||||
### 常见问题
|
||||
* 如果启动的时无法找到端口,请使用以下命令,查看是否存在该目录 /dev/ttyUSB0
|
||||
|
||||
ll /dev/ttyUSB0
|
||||
|
||||
* 若不存在,请检查:
|
||||
|
||||
1. 串口线是否插好
|
||||
2. 小车电源是否打开
|
||||
3. 如果上述都没有问题,请查询是否是其他的USB端口,如/dev/ttyUSB1或/dev/ttyUSB2
|
||||
|
||||
* 如果存在目录,但启动显示权限不足,请使用以下命令进行赋权
|
||||
|
||||
sudo chmod 666 /dev/ttyUSB0
|
||||
|
||||
# ROS驱动调试助手
|
||||
|
||||
该驱动还为用户提供了一个调试的节点,可以使用该节点直接向驱动板发送串口指令,进行指令速度与实际运行速度的校准或调整模型等工作。
|
||||
|
||||
|
||||
### 使用步骤
|
||||
1. 创建并启动launch文件,示例如下
|
||||
|
||||
|
||||
<launch>
|
||||
<node name="driver" pkg="autolabor_pro1_driver" type="sim_autolabor_pro1_driver" output="screen">
|
||||
<param name="port_name" value="/dev/ttyUSB0" />
|
||||
<param name="baud_rate" value="115200" />
|
||||
<param name="control_rate" value="10" />
|
||||
<param name="pid_rate" value="50" />
|
||||
</node>
|
||||
</launch>
|
||||
|
||||
2. 打开新终端,输入以下命令,打开操作界面(如下图)
|
||||
|
||||
rosrun rqt_reconfigure rqt_reconfigure
|
||||
|
||||
![](imgs/autolaborPro1-rqt.png)
|
||||
|
||||
3. 调整 left\_wheel 与 right\_wheel的数值,可独立控制左/右轮转速,勾选 run\_flag,即可向小车发送速度指令
|
||||
|
||||
注:调整的数值为一个PID控制周期下,预期编码器的变化数,详细的计算方法可参见控制车轮速度指令中的**[编码器计数计算方法](controlRule#caculate-method)**
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
# 控制方式
|
||||
AP1可以使用手柄控制和上位机控制两种方式来控制,下面将分别概述这两种控制方式。
|
||||
|
||||
## 手柄控制
|
||||
|
||||
### 概述
|
||||
|
||||
我们配送一个控制手柄用于控制M1移动。
|
||||
|
||||
### 使用说明
|
||||
|
||||
M1出厂默认控制模式为手柄控制,在控制面板中可切换控制模式,将M1控制面板中的上位机控制按钮置于“手柄”方向切换到手柄控制模式,即可操作手柄的按键控制移动平台。
|
||||
|
||||
#### 手柄操作步骤
|
||||
|
||||
1. 打开手柄电源,切换至ON模式,手柄顶部POWER指示灯亮起
|
||||
2. 使用MODE键开启控制模式,顶部MODE LED指示灯为红色时,才能使用手柄进行控制
|
||||
3. 先按住手柄顶部两个【1】键,然后按照下文使用说明操作
|
||||
|
||||
![PS2 control](imgs/ps1.jpg)
|
||||
![PS2 control](imgs/ps2.jpg)
|
||||
|
||||
#### 手柄按键说明
|
||||
|
||||
我们对于M1的手柄控制设计有几种速度档位,如下表。
|
||||
|
||||
<table>
|
||||
<tr align="center">
|
||||
<th>档位</th>
|
||||
<td>0档</td>
|
||||
<td>1档</td>
|
||||
<td>2档</td>
|
||||
<td>3档</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<th>速度</th>
|
||||
<td>25%</td>
|
||||
<td>50%</td>
|
||||
<td>75%</td>
|
||||
<td>100%</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>按键</th>
|
||||
<th>功能</th>
|
||||
<th width="50%">备注</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>左区4控制键</td>
|
||||
<td>前/后/左/右控制运动方向</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SELECT/最低速度档</td>
|
||||
<td>设置运动速度为最低档位</td>
|
||||
<td>设置速度档位为0档</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>START/最高速度档</td>
|
||||
<td>设置运动速度为最高档位</td>
|
||||
<td>设置速度档位为3档</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>左侧摇杆键</td>
|
||||
<td>控制M1的运动方向和速度</td>
|
||||
<td>使用摇杆灵活的控制运动角度与速度,不必受限于正前/后/左/右,控制摇杆推动的力度来控制速度档位的调节,将摇杆向前方直接推到低,则直接是3档,向后方直接推到底,则直接设置为0档</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>右侧摇杆键</td>
|
||||
<td>无功能</td>
|
||||
<td>现阶段暂未使用</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>右区控制键-上</td>
|
||||
<td>线速度增加</td>
|
||||
<td>调整速度档位,每按一下,速度提高一档,最高不得高于最高档,如3档</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>右区控制键-下</td>
|
||||
<td>线速度减少</td>
|
||||
<td>每按一下,速度降低一档,最低不得高于最底档,如0档</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>右区控制键-左/右</td>
|
||||
<td>角速度增加/减少</td>
|
||||
<td>同线速度</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>顶部名为“1”的按键</td>
|
||||
<td>运动控制使能</td>
|
||||
<td>在遥控底盘运动、调整线速度、调整角速度的时候,这两个按钮应该处于被按下的状态</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>顶部名为“2”的按键</td>
|
||||
<td>配对测试按键</td>
|
||||
<td>当按下其中任意一个名为“2”的按键后,且配对的机器人为下位机模式,此时机器人会发出蜂鸣音提示</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
## 上位机控制
|
||||
### 概述
|
||||
使用M1配送的串口数据线与上位机相连,按照预定义的**协议规则**,向下位机(底层硬件平台)发送指令,控制移动平台。
|
||||
|
||||
### 使用说明
|
||||
将AP1控制面板中的上位机控制按钮置于开启状态,使用接口线将下位机与上位机连接起来,向下位机发送指令。
|
||||
|
||||
### 指令发送方式
|
||||
用户可按照自己的开发场景,选择不同的方式发送指令:
|
||||
|
||||
* 使用**串口调试助手**直接向下位机发送指令
|
||||
* 基于ROS开发可使用我们提供的**ROS驱动包**与下位机通信发送接收指令
|
||||
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
{
|
||||
"_readme": [
|
||||
"注:uri 必须保障唯一性,若有重复引用,请使用 rewrite 注册新的 uri",
|
||||
"由于设计缺陷,rewrite 时只能自定义最后一级路径",
|
||||
"uri 格式 1 - 相对文档:a/b/c",
|
||||
"uri 格式 2 - 相对站内:/usedoc/ap1/a/b/c",
|
||||
"uri 格式 3 - 绝对地址:https://www.baidu.com",
|
||||
"_readme 本身并没有什么软用"
|
||||
],
|
||||
"index": "navigationKit/receivingGuide/inspection",
|
||||
"rewrite": {
|
||||
},
|
||||
"plugin": {
|
||||
"emoji": false,
|
||||
"taskList": true,
|
||||
"tex": true,
|
||||
"flowChart": true,
|
||||
"sequenceDiagram": true
|
||||
},
|
||||
"menu": {
|
||||
"toc": {
|
||||
"startLevel": "1",
|
||||
"overLevel": "1"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"name": "Autolabor M1",
|
||||
"isOpen": true,
|
||||
"items": [
|
||||
{
|
||||
"name": "收货指南",
|
||||
"items": [
|
||||
{
|
||||
"name": "检查",
|
||||
"uri": "navigationKit/receivingGuide/inspection"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "快速开始",
|
||||
"items": [
|
||||
{
|
||||
"name": "手柄控制",
|
||||
"uri": "navigationKit/quickStart/handle"
|
||||
},
|
||||
{
|
||||
"name": "键盘控制",
|
||||
"uri": "navigationKit/quickStart/keyboard"
|
||||
},
|
||||
{
|
||||
"name": "2DSLAM建图",
|
||||
"uri": "navigationKit/quickStart/2dSlam"
|
||||
},
|
||||
{
|
||||
"name": "3DSLAM建图",
|
||||
"uri": "navigationKit/quickStart/3dSlam"
|
||||
},
|
||||
{
|
||||
"name": "RTK循迹",
|
||||
"items": [
|
||||
{
|
||||
"name": "安装设置",
|
||||
"uri": "navigationKit/quickStart/rtk/install"
|
||||
},
|
||||
{
|
||||
"name": "使用步骤",
|
||||
"uri": "navigationKit/quickStart/rtk/use"
|
||||
},
|
||||
{
|
||||
"name": "工作原理",
|
||||
"uri": "navigationKit/quickStart/rtk/principle"
|
||||
},
|
||||
{
|
||||
"name": "开发引导",
|
||||
"uri": "navigationKit/quickStart/rtk/develop"
|
||||
},
|
||||
{
|
||||
"name": "常见问题",
|
||||
"uri": "navigationKit/quickStart/rtk/faq"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "深度相机",
|
||||
"items": [
|
||||
{
|
||||
"name": "简介",
|
||||
"uri": "navigationKit/quickStart/vzense/intro"
|
||||
},
|
||||
{
|
||||
"name": "使用",
|
||||
"uri": "navigationKit/quickStart/vzense/use"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "远程连接",
|
||||
"items": [
|
||||
{
|
||||
"name": "远程连接",
|
||||
"uri": "navigationKit/quickStart/remote/remoteConnect"
|
||||
},
|
||||
{
|
||||
"name": "远程控制-键盘插件",
|
||||
"uri": "navigationKit/quickStart/remote/keyboardPlugin"
|
||||
},
|
||||
{
|
||||
"name": "常见问题",
|
||||
"uri": "navigationKit/quickStart/remote/qa"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "里程计标定",
|
||||
"uri": "navigationKit/quickStart/robotCalibration"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "二次开发",
|
||||
"items": [
|
||||
{
|
||||
"name": "系统目录",
|
||||
"uri": "navigationKit/development/osIntro"
|
||||
},
|
||||
{
|
||||
"name": "激光SLAM",
|
||||
"uri": "navigationKit/development/slamintro"
|
||||
},
|
||||
{
|
||||
"name": "激光SLAM-多点导航",
|
||||
"uri": "navigationKit/development/multiGoalintro"
|
||||
},
|
||||
{
|
||||
"name": "RTK循迹",
|
||||
"uri": "navigationKit/development/rtkintro"
|
||||
},
|
||||
{
|
||||
"name": "视觉SLAM",
|
||||
"uri": "navigationKit/development/vslamintro"
|
||||
},
|
||||
{
|
||||
"name": "YOLO识别",
|
||||
"uri": "navigationKit/development/yolo"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Autolabor M1底盘",
|
||||
"items": [
|
||||
{
|
||||
"name": "产品概述",
|
||||
"uri": "chassis/overview"
|
||||
},
|
||||
{
|
||||
"name": "产品参数",
|
||||
"uri": "chassis/intro"
|
||||
},
|
||||
{
|
||||
"name": "产品使用",
|
||||
"uri": "chassis/use"
|
||||
},
|
||||
{
|
||||
"name": "串口协议",
|
||||
"uri": "chassis/protocolRule"
|
||||
},
|
||||
{
|
||||
"name": "串口指令",
|
||||
"uri": "chassis/controlRule"
|
||||
},
|
||||
{
|
||||
"name": "ROS驱动",
|
||||
"uri": "chassis/sendCommand"
|
||||
},
|
||||
{
|
||||
"name": "里程计标定",
|
||||
"uri": "chassis/odomCalibration"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
{
|
||||
"_readme": [
|
||||
"注:uri 必须保障唯一性,若有重复引用,请使用 rewrite 注册新的 uri",
|
||||
"由于设计缺陷,rewrite 时只能自定义最后一级路径",
|
||||
"uri 格式 1 - 相对文档:a/b/c",
|
||||
"uri 格式 2 - 相对站内:/usedoc/ap1/a/b/c",
|
||||
"uri 格式 3 - 绝对地址:https://www.baidu.com",
|
||||
"_readme 本身并没有什么软用"
|
||||
],
|
||||
"index": "navigationKit/receivingGuide/inspection",
|
||||
"rewrite": {
|
||||
},
|
||||
"plugin": {
|
||||
"emoji": false,
|
||||
"taskList": true,
|
||||
"tex": true,
|
||||
"flowChart": true,
|
||||
"sequenceDiagram": true
|
||||
},
|
||||
"menu": {
|
||||
"toc": {
|
||||
"startLevel": "1",
|
||||
"overLevel": "1"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"name": "Autolabor M1",
|
||||
"isOpen": true,
|
||||
"items": [
|
||||
{
|
||||
"name": "收货指南",
|
||||
"items": [
|
||||
{
|
||||
"name": "检查",
|
||||
"uri": "navigationKit/receivingGuide/inspection"
|
||||
},
|
||||
{
|
||||
"_remark": "TODO",
|
||||
"name": "清点",
|
||||
"uri": "navigationKit/receivingGuide/inventory"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_remark": "TODO",
|
||||
"name": "组装测试",
|
||||
"items": [
|
||||
{
|
||||
"name": "组装",
|
||||
"uri": "navigationKit/assembly/install"
|
||||
},
|
||||
{
|
||||
"name": "测试",
|
||||
"uri": "navigationKit/assembly/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "快速开始",
|
||||
"items": [
|
||||
{
|
||||
"name": "手柄控制",
|
||||
"uri": "navigationKit/quickStart/handle"
|
||||
},
|
||||
{
|
||||
"name": "键盘控制",
|
||||
"uri": "navigationKit/quickStart/keyboard"
|
||||
},
|
||||
{
|
||||
"name": "2DSLAM建图",
|
||||
"uri": "navigationKit/quickStart/2dSlam"
|
||||
},
|
||||
{
|
||||
"name": "3DSLAM建图",
|
||||
"uri": "navigationKit/quickStart/3dSlam"
|
||||
},
|
||||
{
|
||||
"name": "RTK循迹",
|
||||
"items": [
|
||||
{
|
||||
"name": "安装设置",
|
||||
"uri": "navigationKit/quickStart/rtk/install"
|
||||
},
|
||||
{
|
||||
"name": "使用步骤",
|
||||
"uri": "navigationKit/quickStart/rtk/use"
|
||||
},
|
||||
{
|
||||
"name": "工作原理",
|
||||
"uri": "navigationKit/quickStart/rtk/principle"
|
||||
},
|
||||
{
|
||||
"name": "开发引导",
|
||||
"uri": "navigationKit/quickStart/rtk/develop"
|
||||
},
|
||||
{
|
||||
"name": "常见问题",
|
||||
"uri": "navigationKit/quickStart/rtk/faq"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "深度相机",
|
||||
"items": [
|
||||
{
|
||||
"name": "简介",
|
||||
"uri": "navigationKit/quickStart/vzense/intro"
|
||||
},
|
||||
{
|
||||
"name": "使用",
|
||||
"uri": "navigationKit/quickStart/vzense/use"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "远程连接",
|
||||
"items": [
|
||||
{
|
||||
"name": "远程连接",
|
||||
"uri": "navigationKit/quickStart/remote/remoteConnect"
|
||||
},
|
||||
{
|
||||
"name": "远程控制-键盘插件",
|
||||
"uri": "navigationKit/quickStart/remote/keyboardPlugin"
|
||||
},
|
||||
{
|
||||
"name": "常见问题",
|
||||
"uri": "navigationKit/quickStart/remote/qa"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "里程计标定",
|
||||
"uri": "navigationKit/quickStart/robotCalibration"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "二次开发",
|
||||
"items": [
|
||||
{
|
||||
"name": "系统目录",
|
||||
"uri": "navigationKit/development/osIntro"
|
||||
},
|
||||
{
|
||||
"name": "激光SLAM",
|
||||
"uri": "navigationKit/development/slamintro"
|
||||
},
|
||||
{
|
||||
"name": "激光SLAM-多点导航",
|
||||
"uri": "navigationKit/development/multiGoalintro"
|
||||
},
|
||||
{
|
||||
"name": "RTK循迹",
|
||||
"uri": "navigationKit/development/rtkintro"
|
||||
},
|
||||
{
|
||||
"name": "视觉SLAM",
|
||||
"uri": "navigationKit/development/vslamintro"
|
||||
},
|
||||
{
|
||||
"name": "YOLO识别",
|
||||
"uri": "navigationKit/development/yolo"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_remark": "TODO deviceInfo",
|
||||
"name": "设备资料",
|
||||
"items": [
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Autolabor M1底盘",
|
||||
"items": [
|
||||
{
|
||||
"name": "产品概述",
|
||||
"uri": "chassis/overview"
|
||||
},
|
||||
{
|
||||
"name": "产品参数",
|
||||
"uri": "chassis/intro"
|
||||
},
|
||||
{
|
||||
"name": "产品使用",
|
||||
"uri": "chassis/use"
|
||||
},
|
||||
{
|
||||
"name": "串口协议",
|
||||
"uri": "chassis/protocolRule"
|
||||
},
|
||||
{
|
||||
"name": "串口指令",
|
||||
"uri": "chassis/controlRule"
|
||||
},
|
||||
{
|
||||
"name": "ROS驱动",
|
||||
"uri": "chassis/sendCommand"
|
||||
},
|
||||
{
|
||||
"name": "里程计标定",
|
||||
"uri": "chassis/odomCalibration"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#Autolabor M1(navigationKit)
|
||||
|
||||
|
||||
##收货指南(receivingGuide)
|
||||
###检查(receipt)
|
||||
###清点
|
||||
|
||||
##组装测试
|
||||
###组装
|
||||
###测试
|
||||
|
||||
##快速开始(quickStart)
|
||||
###手柄控制(handle)
|
||||
###键盘控制(keyboard)
|
||||
###2DSLAM建图(2dSlam)
|
||||
###3DSLAM建图(3dSlam)
|
||||
###RTK循迹(rtk)
|
||||
安装设置(install)
|
||||
|
||||
使用步骤(use)
|
||||
|
||||
工作原理(principle)
|
||||
|
||||
开发引导(develop)
|
||||
|
||||
常见问题(faq)
|
||||
|
||||
###深度相机(vzense)
|
||||
简介(intro)
|
||||
|
||||
使用(use)
|
||||
###远程连接(remote)
|
||||
远程连接(remoteConnect)
|
||||
|
||||
远程控制-键盘插件(keyboardPlugin)
|
||||
|
||||
常见问题(qa)
|
||||
###里程计标定(robotCalibration)
|
||||
##二次开发(development)
|
||||
###系统目录(OSintro)
|
||||
###激光SLAM(slamintro)
|
||||
###激光SLAM-多点导航(multiGoalintro)
|
||||
###RTK循迹(rtkintro)
|
||||
###视觉SLAM(vslamintro)
|
||||
###YOLO识别(yolo)
|
||||
##设备资料
|
||||
|
||||
#Autolabor M1底盘(chassis)
|
||||
##产品概述(overview)
|
||||
##产品参数(intro)
|
||||
##产品使用(use)
|
||||
##串口协议(protocolRule)
|
||||
##串口指令(controlRule)
|
||||
##ROS驱动(sendCommand)
|
||||
##里程计标定(odomCalibration)
|
||||
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
.
|
||||
├── script
|
||||
│ ├── 3d_suit
|
||||
│ ├── box_suit
|
||||
│ ├── common
|
||||
│ ├── simulation
|
||||
│ ├── test
|
||||
│ └── track_suit
|
||||
└── src
|
||||
├── autolabor_description
|
||||
│ ├── launch
|
||||
│ ├── meshes
|
||||
│ ├── rviz
|
||||
│ └── urdf
|
||||
├── driver
|
||||
│ ├── car
|
||||
│ │ ├── autolabor_canbus_driver
|
||||
│ │ └── autolabor_pro1_driver
|
||||
│ ├── depth_camera
|
||||
│ │ ├── pico_zense_driver
|
||||
│ │ └── zed_wrapper
|
||||
│ ├── imu
|
||||
│ │ ├── ah100b
|
||||
│ │ ├── ch104m //ch104m IMU 驱动
|
||||
│ │ ├── rviz_imu_plugin
|
||||
│ │ └── tl740d
|
||||
│ ├── lidar
|
||||
│ │ ├── ldlidar_stl_ros
|
||||
│ │ ├── rslidar_sdk
|
||||
│ │ └── wr_fslidar
|
||||
│ └── location
|
||||
│ ├── al_rtk_ros_driver
|
||||
│ └── marvelmind
|
||||
│
|
||||
├── launch
|
||||
│ ├── autolabor_navigation_launch
|
||||
│ │ ├── cmake-build-debug
|
||||
│ │ ├── launch
|
||||
│ │ ├── map
|
||||
│ │ ├── params
|
||||
│ │ └── rviz
|
||||
│ ├── autolabor_test_launch
|
||||
│ │ ├── launch
|
||||
│ │ └── rviz
|
||||
│ └── rtk_tracking
|
||||
│ ├── log
|
||||
│ └── resources
|
||||
├── mapping
|
||||
│ ├── cartographer //cartographer GPU 加速版本
|
||||
│ │ ├── bazel
|
||||
│ │ ├── cartographer
|
||||
│ │ ├── cmake
|
||||
│ │ ├── configuration_files
|
||||
│ │ ├── docs
|
||||
│ │ └── scripts
|
||||
│ └── cartographer_ros
|
||||
│ ├── cartographer_ros
|
||||
│ ├── cartographer_ros_msgs
|
||||
│ ├── cartographer_rviz
|
||||
│ ├── docs
|
||||
│ └── scripts
|
||||
├── navigation
|
||||
│ ├── amcl
|
||||
│ │ ├── cfg
|
||||
│ │ ├── examples
|
||||
│ │ ├── include
|
||||
│ │ ├── src
|
||||
│ │ └── test
|
||||
│ ├── base_local_planner
|
||||
│ │ ├── cfg
|
||||
│ │ ├── include
|
||||
│ │ ├── msg
|
||||
│ │ ├── src
|
||||
│ │ └── test
|
||||
│ ├── carrot_planner
|
||||
│ │ ├── include
|
||||
│ │ └── src
|
||||
│ ├── clear_costmap_recovery
|
||||
│ │ ├── include
|
||||
│ │ ├── src
|
||||
│ │ └── test
|
||||
│ ├── costmap_2d
|
||||
│ │ ├── cfg
|
||||
│ │ ├── include
|
||||
│ │ ├── launch
|
||||
│ │ ├── msg
|
||||
│ │ ├── plugins
|
||||
│ │ ├── src
|
||||
│ │ └── test
|
||||
│ ├── dwa_local_planner
|
||||
│ │ ├── cfg
|
||||
│ │ ├── include
|
||||
│ │ └── src
|
||||
│ ├── fake_localization
|
||||
│ ├── global_planner
|
||||
│ │ ├── cfg
|
||||
│ │ ├── include
|
||||
│ │ └── src
|
||||
│ ├── location_fusion
|
||||
│ │ ├── include
|
||||
│ │ └── src
|
||||
│ ├── loop_path_planner
|
||||
│ │ ├── include
|
||||
│ │ └── src
|
||||
│ ├── map_server
|
||||
│ │ ├── include
|
||||
│ │ ├── scripts
|
||||
│ │ ├── src
|
||||
│ │ └── test
|
||||
│ ├── move_base
|
||||
│ │ ├── cfg
|
||||
│ │ ├── include
|
||||
│ │ └── src
|
||||
│ ├── move_slow_and_clear
|
||||
│ │ ├── include
|
||||
│ │ └── src
|
||||
│ ├── nav_core
|
||||
│ │ └── include
|
||||
│ ├── navfn
|
||||
│ │ ├── include
|
||||
│ │ ├── src
|
||||
│ │ ├── srv
|
||||
│ │ └── test
|
||||
│ ├── navigation
|
||||
│ ├── path_rviz_plugin
|
||||
│ │ ├── include
|
||||
│ │ └── src
|
||||
│ ├── path_server
|
||||
│ │ ├── include
|
||||
│ │ ├── path_data
|
||||
│ │ ├── src
|
||||
│ │ └── srv
|
||||
│ ├── record_path_planner
|
||||
│ │ ├── include
|
||||
│ │ └── src
|
||||
│ ├── rotate_recovery
|
||||
│ │ ├── include
|
||||
│ │ └── src
|
||||
│ ├── teb_local_planner
|
||||
│ │ ├── cfg
|
||||
│ │ ├── cmake_modules
|
||||
│ │ ├── include
|
||||
│ │ ├── launch
|
||||
│ │ ├── msg
|
||||
│ │ ├── scripts
|
||||
│ │ ├── src
|
||||
│ │ └── test
|
||||
│ └── voxel_grid
|
||||
│ ├── include
|
||||
│ ├── src
|
||||
│ └── test
|
||||
├── simulation
|
||||
│ ├── autolabor_simulation_base
|
||||
│ │ ├── include
|
||||
│ │ ├── launch
|
||||
│ │ ├── rviz
|
||||
│ │ ├── script
|
||||
│ │ └── src
|
||||
│ ├── autolabor_simulation_lidar
|
||||
│ │ ├── include
|
||||
│ │ ├── launch
|
||||
│ │ ├── rviz
|
||||
│ │ └── src
|
||||
│ ├── autolabor_simulation_location
|
||||
│ │ ├── include
|
||||
│ │ └── src
|
||||
│ ├── autolabor_simulation_object
|
||||
│ │ ├── include
|
||||
│ │ ├── launch
|
||||
│ │ ├── rviz
|
||||
│ │ └── src
|
||||
│ └── autolabor_simulation_stage
|
||||
│ ├── include
|
||||
│ ├── launch
|
||||
│ ├── map
|
||||
│ ├── src
|
||||
│ └── srv
|
||||
└── tool
|
||||
├── autolabor_keyboard_control
|
||||
│ ├── include
|
||||
│ └── src
|
||||
├── cartographer_initialpose
|
||||
│ ├── include
|
||||
│ └── src
|
||||
├── joy_to_twist
|
||||
│ └── src
|
||||
├── laser_proc
|
||||
│ ├── include
|
||||
│ └── src
|
||||
├── navi_multi_goals_pub_rviz_plugin
|
||||
│ └── src
|
||||
├── rviz_autolabor_calibration
|
||||
│ ├── include
|
||||
│ └── src
|
||||
├── rviz_keyboard_twist
|
||||
│ ├── include
|
||||
│ └── src
|
||||
└── rviz_navigation_tools
|
||||
├── include
|
||||
└── src
|
||||
|
||||
206 directories
|
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 139 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 175 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 303 KiB |
After Width: | Height: | Size: 388 KiB |
After Width: | Height: | Size: 384 KiB |
After Width: | Height: | Size: 295 KiB |
After Width: | Height: | Size: 428 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 97 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 1.7 MiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 1.2 MiB |
|
@ -0,0 +1,602 @@
|
|||
# 激光SLAM-多点导航
|
||||
|
||||
本文介绍SLAM导航中*多点导航功能包*的开发思路。
|
||||
|
||||
|
||||
### 开发背景:
|
||||
|
||||
在使用 ROS Navigation & RViz 进行 2D Nav Goal 导航的时候,我们会遇到这些情况:
|
||||
|
||||
1. 给定导航的目标点只能设置一个,当有多点任务时需要等待一个个任务结束后,再次手动给目标
|
||||
2. 无法暂停或取消任务
|
||||
3. 任务不可循环
|
||||
|
||||
### 开发目的:
|
||||
|
||||
完成多目标点导航,可以对导航环节进行操控,如可循环、取消、重置任务等。
|
||||
|
||||
### 开发思路:
|
||||
|
||||
1. 2D Nav Goal 的单点导航是如何实现的?
|
||||
|
||||
我们可以知道导航目标是通过 RViz 工具栏中 2D Nav Goal发布出去的。
|
||||
|
||||
通过查看 RViz的配置文件或者 Panels->Add New Panel-> Tool Property ,可以了解当使用2D Nav Goal 在地图上拉了一个箭头(给定目标点时),其实是向话题 /move_base_simple/goal 发布了 [geometry_msgs/PoseStamped](http://docs.ros.org/en/api/geometry_msgs/html/msg/PoseStamped.html) 类型的消息,这个是目标点的位姿,包含坐标点与朝向。
|
||||
|
||||
根据 NodeGraph 可以看到话题 /move_base_simple/goal 被导航包的节点 /move_base 订阅了,进而发给 Navigation 中的各个话题,完成导航。
|
||||
|
||||
![](./imgs/multi1.png)
|
||||
|
||||
|
||||
2. 如何基于单点实现多点导航?
|
||||
|
||||
要在单点基础上实现多目标点导航的话,就要设计一个关于多个导航目标点消息geometry_msgs/PoseStamped的数据结构,并对多个目标点进行处理,完成导航。
|
||||
|
||||
实现多点的方法有多种,在不打破 ROS Navigation 包的完整性的前提下,我选择在2D Nav Goal的 RViz节点和 /move_base 节点中间添加了一个话题 /move_base_simple/goal_temp,将原本发送给 /move_base_simple/goal 的消息,转发给/move_base_simple/goal_temp,通过此话题来积攒多个 2D Nav Goal(任务队列),并根据任务完成的状态反馈,按顺序将每个导航目标点消息 geometry_msgs/PoseStamped 再发送给话题/move_base_simple/goal,以完成多任务中的单次目标点的导航(如下图示)。
|
||||
|
||||
![](./imgs/multi2.jpeg)
|
||||
|
||||
|
||||
3. 如何来发布多点任务?
|
||||
|
||||
像 2D Nav Goal 一样,我们也可以在 RViz 中开发可视化的操作栏,这要使用到 RViz plugin , ROS中的可视化工具绝大部分都是基于Qt进行开发的,此前古月居有过详细介绍,可参考[这篇文章](https://zhuanlan.zhihu.com/p/39390512)。
|
||||
|
||||
### 最终效果
|
||||
|
||||
首先,我们来看一下最终的实现效果。
|
||||
|
||||
MultiNaviGoalsPanel是多点SLAM导航任务的可视化操作区,包括任务点列表、循环、重置、取消、开始任务。
|
||||
|
||||
通过 RViz plugin 设计的Mark Display,能够显示的目标点的标号及箭头(朝向)。
|
||||
|
||||
![](./imgs/multi3.png)
|
||||
|
||||
|
||||
#### 代码实现
|
||||
|
||||
#### 1. 头文件 multi_navi_goal_panel.h
|
||||
|
||||
Qt说明:
|
||||
|
||||
* 文字编辑——QLineEdit
|
||||
* 按键——QPushButton
|
||||
* 列表——QTableWidget
|
||||
* 复选框——QCheckBox
|
||||
* 文字显示——QString
|
||||
|
||||
ROS说明:
|
||||
|
||||
Publisher:
|
||||
|
||||
* 发送每个目标点消息给/move_base_simple/goal的goal_pub_
|
||||
* 发送取消指令消息给/move_base/cancel的cancel_pub_
|
||||
* 发送文字和箭头标记的mark_pub_。
|
||||
|
||||
Subsrciber:
|
||||
|
||||
* 订阅来自rviz中2D Nav Goal的导航目标点消息的goal_sub_
|
||||
* 订阅目前导航状态的status_sub_
|
||||
|
||||
|
||||
|
||||
```
|
||||
#ifndef MULTI_NAVI_GOAL_PANEL_H
|
||||
#define MULTI_NAVI_GOAL_PANEL_H
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <ros/ros.h>
|
||||
#include <ros/console.h>
|
||||
#include <tf2_ros/transform_listener.h>
|
||||
#include <tf2_geometry_msgs/tf2_geometry_msgs.h>
|
||||
|
||||
#include <rviz/panel.h>//plugin基类的头文件
|
||||
|
||||
#include <QPushButton>//Qt按钮
|
||||
#include <QTableWidget>//Qt表格
|
||||
#include <QCheckBox>//Qt复选框
|
||||
|
||||
#include <visualization_msgs/Marker.h>
|
||||
#include <geometry_msgs/PoseArray.h>
|
||||
#include <geometry_msgs/Point.h>
|
||||
#include <geometry_msgs/PoseStamped.h>
|
||||
#include <std_msgs/String.h>
|
||||
#include <actionlib_msgs/GoalStatus.h>
|
||||
#include <actionlib_msgs/GoalStatusArray.h>
|
||||
#include <tf/transform_datatypes.h>
|
||||
|
||||
|
||||
namespace navi_multi_goals_pub_rviz_plugin {
|
||||
|
||||
class MultiNaviGoalsPanel : public rviz::Panel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MultiNaviGoalsPanel(QWidget *parent = 0);
|
||||
|
||||
virtual void load(const rviz::Config &config);
|
||||
|
||||
virtual void save(rviz::Config config) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
void setMaxNumGoal(const QString &maxNumGoal);//设置最大可设置的目标点数量
|
||||
void writePose(geometry_msgs::Pose pose);//将目标点位姿写入任务列表
|
||||
void markPose(const geometry_msgs::PoseStamped::ConstPtr &pose);//在地图中标记目标位姿
|
||||
void deleteMark();//删除标记
|
||||
|
||||
protected Q_SLOTS:
|
||||
|
||||
void updateMaxNumGoal(); // 更新最大可设置的目标点数量
|
||||
void initPoseTable(); // 初始化目标点表格
|
||||
|
||||
void updatePoseTable(); // 更新目标点表格
|
||||
void startNavi(); // 开始第一个目标点任务导航
|
||||
void cancelNavi(); // 取消现在进行中的导航
|
||||
void addPose();
|
||||
|
||||
void goalCntCB(const geometry_msgs::PoseStamped::ConstPtr &pose); // 目标数量子回调函数
|
||||
|
||||
void statusCB(const actionlib_msgs::GoalStatusArray::ConstPtr &statuses); // 状态子回调函数
|
||||
|
||||
void checkCycle(); // 确认循环
|
||||
|
||||
void completeNavi(); // 第一个任务到达后,继续进行剩下任务点的导航任务
|
||||
void cycleNavi();
|
||||
|
||||
bool checkGoal(std::vector<actionlib_msgs::GoalStatus> status_list); // 检查是否到达目标点
|
||||
|
||||
static void startSpin(); // 启用ROS订阅
|
||||
protected:
|
||||
QLineEdit *output_maxNumGoal_editor_;
|
||||
QPushButton *output_maxNumGoal_button_, *output_reset_button_, *output_startNavi_button_, *output_cancel_button_, *output_addPoint_button_;
|
||||
QTableWidget *poseArray_table_;
|
||||
QCheckBox *cycle_checkbox_;
|
||||
|
||||
QString output_maxNumGoal_;
|
||||
|
||||
// The ROS node handle.
|
||||
ros::NodeHandle nh_;
|
||||
ros::Publisher goal_pub_, cancel_pub_, marker_pub_, init_goal_pub_;
|
||||
ros::Subscriber goal_sub_, status_sub_;
|
||||
|
||||
tf2_ros::Buffer tfBuffer_;
|
||||
tf2_ros::TransformListener tfListener_;
|
||||
// 多目标点任务栏定义
|
||||
int maxNumGoal_;
|
||||
int curGoalIdx_ = 0, cycleCnt_ = 0;
|
||||
bool permit_ = false, cycle_ = false, arrived_ = false;
|
||||
geometry_msgs::PoseArray pose_array_;
|
||||
|
||||
actionlib_msgs::GoalID cur_goalid_;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // end namespace navi-multi-goals-pub-rviz-plugin
|
||||
|
||||
#endif // MULTI_NAVI_GOAL_PANEL_H
|
||||
|
||||
```
|
||||
|
||||
#### 2. cpp文件 multi_navi_goal_panel.cpp
|
||||
|
||||
```
|
||||
#include <cstdio>
|
||||
|
||||
#include <ros/console.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QLineEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include <QtWidgets/QTableWidget>
|
||||
#include <QtWidgets/qheaderview.h>
|
||||
|
||||
|
||||
#include "multi_navi_goal_panel.h"
|
||||
|
||||
namespace navi_multi_goals_pub_rviz_plugin {
|
||||
|
||||
|
||||
MultiNaviGoalsPanel::MultiNaviGoalsPanel(QWidget *parent)
|
||||
: rviz::Panel(parent), nh_(), maxNumGoal_(1), tfListener_(tfBuffer_) {
|
||||
|
||||
goal_sub_ = nh_.subscribe<geometry_msgs::PoseStamped>("move_base_simple/goal_temp", 100,
|
||||
boost::bind(&MultiNaviGoalsPanel::goalCntCB, this, _1));
|
||||
|
||||
status_sub_ = nh_.subscribe<actionlib_msgs::GoalStatusArray>("move_base/status", 1,
|
||||
boost::bind(&MultiNaviGoalsPanel::statusCB, this,
|
||||
_1));
|
||||
|
||||
goal_pub_ = nh_.advertise<geometry_msgs::PoseStamped>("move_base_simple/goal", 1);
|
||||
|
||||
init_goal_pub_ = nh_.advertise<geometry_msgs::PoseStamped>("move_base_simple/goal_temp", 1);
|
||||
|
||||
cancel_pub_ = nh_.advertise<actionlib_msgs::GoalID>("move_base/cancel", 1);
|
||||
|
||||
marker_pub_ = nh_.advertise<visualization_msgs::Marker>("visualization_marker", 1);
|
||||
|
||||
QVBoxLayout *root_layout = new QVBoxLayout;
|
||||
// create a panel about "maxNumGoal"
|
||||
QHBoxLayout *maxNumGoal_layout = new QHBoxLayout;
|
||||
maxNumGoal_layout->addWidget(new QLabel("目标最大数量"));
|
||||
output_maxNumGoal_editor_ = new QLineEdit;
|
||||
maxNumGoal_layout->addWidget(output_maxNumGoal_editor_);
|
||||
output_maxNumGoal_button_ = new QPushButton("确定");
|
||||
maxNumGoal_layout->addWidget(output_maxNumGoal_button_);
|
||||
root_layout->addLayout(maxNumGoal_layout);
|
||||
|
||||
QHBoxLayout *second_row_layout = new QHBoxLayout;
|
||||
cycle_checkbox_ = new QCheckBox("循环");
|
||||
second_row_layout->addWidget(cycle_checkbox_);
|
||||
output_addPoint_button_ = new QPushButton("添加机器人当前位置");
|
||||
second_row_layout->addWidget(output_addPoint_button_);
|
||||
root_layout->addLayout(second_row_layout);
|
||||
|
||||
// creat a QTable to contain the poseArray
|
||||
poseArray_table_ = new QTableWidget;
|
||||
initPoseTable();
|
||||
root_layout->addWidget(poseArray_table_);
|
||||
//creat a manipulate layout
|
||||
QHBoxLayout *manipulate_layout = new QHBoxLayout;
|
||||
output_reset_button_ = new QPushButton("重置");
|
||||
manipulate_layout->addWidget(output_reset_button_);
|
||||
output_cancel_button_ = new QPushButton("取消");
|
||||
manipulate_layout->addWidget(output_cancel_button_);
|
||||
output_startNavi_button_ = new QPushButton("开始导航!");
|
||||
manipulate_layout->addWidget(output_startNavi_button_);
|
||||
root_layout->addLayout(manipulate_layout);
|
||||
|
||||
setLayout(root_layout);
|
||||
// set a Qtimer to start a spin for subscriptions
|
||||
QTimer *output_timer = new QTimer(this);
|
||||
output_timer->start(200);
|
||||
|
||||
// 设置信号与槽的连接
|
||||
connect(output_maxNumGoal_button_, SIGNAL(clicked()), this,
|
||||
SLOT(updateMaxNumGoal()));
|
||||
connect(output_maxNumGoal_button_, SIGNAL(clicked()), this,
|
||||
SLOT(updatePoseTable()));
|
||||
connect(output_reset_button_, SIGNAL(clicked()), this, SLOT(initPoseTable()));
|
||||
connect(output_cancel_button_, SIGNAL(clicked()), this, SLOT(cancelNavi()));
|
||||
connect(output_startNavi_button_, SIGNAL(clicked()), this, SLOT(startNavi()));
|
||||
connect(output_addPoint_button_, SIGNAL(clicked()), this, SLOT(addPose()));
|
||||
connect(cycle_checkbox_, SIGNAL(clicked(bool)), this, SLOT(checkCycle()));
|
||||
connect(output_timer, SIGNAL(timeout()), this, SLOT(startSpin()));
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 更新maxNumGoal命名
|
||||
void MultiNaviGoalsPanel::updateMaxNumGoal() {
|
||||
setMaxNumGoal(output_maxNumGoal_editor_->text());
|
||||
}
|
||||
|
||||
// set up the maximum number of goals
|
||||
void MultiNaviGoalsPanel::setMaxNumGoal(const QString &new_maxNumGoal) {
|
||||
// 检查maxNumGoal是否发生改变.
|
||||
if (new_maxNumGoal != output_maxNumGoal_) {
|
||||
output_maxNumGoal_ = new_maxNumGoal;
|
||||
|
||||
// 如果命名为空,不发布任何信息
|
||||
if (output_maxNumGoal_ == "") {
|
||||
nh_.setParam("maxNumGoal_", 1);
|
||||
maxNumGoal_ = 1;
|
||||
} else {
|
||||
// velocity_publisher_ = nh_.advertise<geometry_msgs::Twist>(output_maxNumGoal_.toStdString(), 1);
|
||||
nh_.setParam("maxNumGoal_", output_maxNumGoal_.toInt());
|
||||
maxNumGoal_ = output_maxNumGoal_.toInt();
|
||||
}
|
||||
Q_EMIT configChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// initialize the table of pose
|
||||
void MultiNaviGoalsPanel::initPoseTable() {
|
||||
ROS_INFO("Initialize");
|
||||
curGoalIdx_ = 0, cycleCnt_ = 0;
|
||||
permit_ = false, cycle_ = false;
|
||||
poseArray_table_->clear();
|
||||
pose_array_.poses.clear();
|
||||
deleteMark();
|
||||
poseArray_table_->setRowCount(maxNumGoal_);
|
||||
poseArray_table_->setColumnCount(3);
|
||||
poseArray_table_->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
poseArray_table_->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
QStringList pose_header;
|
||||
pose_header << "x" << "y" << "yaw";
|
||||
poseArray_table_->setHorizontalHeaderLabels(pose_header);
|
||||
cycle_checkbox_->setCheckState(Qt::Unchecked);
|
||||
|
||||
}
|
||||
|
||||
// delete marks in the map
|
||||
void MultiNaviGoalsPanel::deleteMark() {
|
||||
visualization_msgs::Marker marker_delete;
|
||||
marker_delete.action = visualization_msgs::Marker::DELETEALL;
|
||||
marker_pub_.publish(marker_delete);
|
||||
}
|
||||
|
||||
//update the table of pose
|
||||
void MultiNaviGoalsPanel::updatePoseTable() {
|
||||
poseArray_table_->setRowCount(maxNumGoal_);
|
||||
// pose_array_.poses.resize(maxNumGoal_);
|
||||
QStringList pose_header;
|
||||
pose_header << "x" << "y" << "yaw";
|
||||
poseArray_table_->setHorizontalHeaderLabels(pose_header);
|
||||
poseArray_table_->show();
|
||||
}
|
||||
|
||||
// call back function for counting goals
|
||||
void MultiNaviGoalsPanel::goalCntCB(const geometry_msgs::PoseStamped::ConstPtr &pose) {
|
||||
if (pose_array_.poses.size() < maxNumGoal_) {
|
||||
pose_array_.poses.push_back(pose->pose);
|
||||
pose_array_.header.frame_id = pose->header.frame_id;
|
||||
writePose(pose->pose);
|
||||
markPose(pose);
|
||||
} else {
|
||||
ROS_ERROR("Beyond the maximum number of goals: %d", maxNumGoal_);
|
||||
}
|
||||
}
|
||||
|
||||
// write the poses into the table
|
||||
void MultiNaviGoalsPanel::writePose(geometry_msgs::Pose pose) {
|
||||
|
||||
poseArray_table_->setItem(pose_array_.poses.size() - 1, 0,
|
||||
new QTableWidgetItem(QString::number(pose.position.x, 'f', 2)));
|
||||
poseArray_table_->setItem(pose_array_.poses.size() - 1, 1,
|
||||
new QTableWidgetItem(QString::number(pose.position.y, 'f', 2)));
|
||||
poseArray_table_->setItem(pose_array_.poses.size() - 1, 2,
|
||||
new QTableWidgetItem(
|
||||
QString::number(tf::getYaw(pose.orientation) * 180.0 / 3.14, 'f', 2)));
|
||||
|
||||
}
|
||||
|
||||
// when setting a Navi Goal, it will set a mark on the map
|
||||
void MultiNaviGoalsPanel::markPose(const geometry_msgs::PoseStamped::ConstPtr &pose) {
|
||||
if (ros::ok()) {
|
||||
visualization_msgs::Marker arrow;
|
||||
visualization_msgs::Marker number;
|
||||
arrow.header.frame_id = number.header.frame_id = pose->header.frame_id;
|
||||
arrow.ns = "navi_point_arrow";
|
||||
number.ns = "navi_point_number";
|
||||
arrow.action = number.action = visualization_msgs::Marker::ADD;
|
||||
arrow.type = visualization_msgs::Marker::ARROW;
|
||||
number.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
|
||||
arrow.pose = number.pose = pose->pose;
|
||||
number.pose.position.z += 1.0;
|
||||
arrow.scale.x = 1.0;
|
||||
arrow.scale.y = 0.2;
|
||||
number.scale.z = 1.0;
|
||||
arrow.color.r = number.color.r = 1.0f;
|
||||
arrow.color.g = number.color.g = 0.98f;
|
||||
arrow.color.b = number.color.b = 0.80f;
|
||||
arrow.color.a = number.color.a = 1.0;
|
||||
arrow.id = number.id = pose_array_.poses.size();
|
||||
number.text = std::to_string(pose_array_.poses.size());
|
||||
marker_pub_.publish(arrow);
|
||||
marker_pub_.publish(number);
|
||||
}
|
||||
}
|
||||
|
||||
// check whether it is in the cycling situation
|
||||
void MultiNaviGoalsPanel::checkCycle() {
|
||||
cycle_ = cycle_checkbox_->isChecked();
|
||||
}
|
||||
|
||||
void MultiNaviGoalsPanel::addPose() {
|
||||
std::string target_frame = "map";
|
||||
std::string child_frame = "base_link";
|
||||
if (tfBuffer_.canTransform(target_frame, child_frame, ros::Time(0), ros::Duration(4.0))) {
|
||||
geometry_msgs::TransformStamped transformStamped = tfBuffer_.lookupTransform(target_frame, child_frame,
|
||||
ros::Time(0),
|
||||
ros::Duration(4.0));
|
||||
geometry_msgs::PoseStamped pose;
|
||||
pose.header.frame_id = target_frame;
|
||||
pose.header.stamp = transformStamped.header.stamp;
|
||||
pose.pose.position.x = transformStamped.transform.translation.x;
|
||||
pose.pose.position.y = transformStamped.transform.translation.y;
|
||||
pose.pose.position.z = transformStamped.transform.translation.z;
|
||||
pose.pose.orientation = transformStamped.transform.rotation;
|
||||
|
||||
init_goal_pub_.publish(pose);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// start to navigate, and only command the first goal
|
||||
void MultiNaviGoalsPanel::startNavi() {
|
||||
curGoalIdx_ = curGoalIdx_ % pose_array_.poses.size();
|
||||
if (!pose_array_.poses.empty() && curGoalIdx_ < maxNumGoal_) {
|
||||
geometry_msgs::PoseStamped goal;
|
||||
goal.header = pose_array_.header;
|
||||
goal.pose = pose_array_.poses.at(curGoalIdx_);
|
||||
goal_pub_.publish(goal);
|
||||
ROS_INFO("Navi to the Goal%d", curGoalIdx_ + 1);
|
||||
poseArray_table_->item(curGoalIdx_, 0)->setBackgroundColor(QColor(255, 69, 0));
|
||||
poseArray_table_->item(curGoalIdx_, 1)->setBackgroundColor(QColor(255, 69, 0));
|
||||
poseArray_table_->item(curGoalIdx_, 2)->setBackgroundColor(QColor(255, 69, 0));
|
||||
curGoalIdx_ += 1;
|
||||
permit_ = true;
|
||||
} else {
|
||||
ROS_ERROR("Something Wrong");
|
||||
}
|
||||
}
|
||||
|
||||
// complete the remaining goals
|
||||
void MultiNaviGoalsPanel::completeNavi() {
|
||||
if (curGoalIdx_ < pose_array_.poses.size()) {
|
||||
geometry_msgs::PoseStamped goal;
|
||||
goal.header = pose_array_.header;
|
||||
goal.pose = pose_array_.poses.at(curGoalIdx_);
|
||||
goal_pub_.publish(goal);
|
||||
ROS_INFO("Navi to the Goal%d", curGoalIdx_ + 1);
|
||||
poseArray_table_->item(curGoalIdx_, 0)->setBackgroundColor(QColor(255, 69, 0));
|
||||
poseArray_table_->item(curGoalIdx_, 1)->setBackgroundColor(QColor(255, 69, 0));
|
||||
poseArray_table_->item(curGoalIdx_, 2)->setBackgroundColor(QColor(255, 69, 0));
|
||||
curGoalIdx_ += 1;
|
||||
permit_ = true;
|
||||
} else {
|
||||
ROS_ERROR("All goals are completed");
|
||||
permit_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
// command the goals cyclically
|
||||
void MultiNaviGoalsPanel::cycleNavi() {
|
||||
if (permit_) {
|
||||
geometry_msgs::PoseStamped goal;
|
||||
goal.header = pose_array_.header;
|
||||
goal.pose = pose_array_.poses.at(curGoalIdx_ % pose_array_.poses.size());
|
||||
goal_pub_.publish(goal);
|
||||
ROS_INFO("Navi to the Goal%lu, in the %dth cycle", curGoalIdx_ % pose_array_.poses.size() + 1,
|
||||
cycleCnt_ + 1);
|
||||
bool even = ((cycleCnt_ + 1) % 2 != 0);
|
||||
QColor color_table;
|
||||
if (even) color_table = QColor(255, 69, 0); else color_table = QColor(100, 149, 237);
|
||||
poseArray_table_->item(curGoalIdx_ % pose_array_.poses.size(), 0)->setBackgroundColor(color_table);
|
||||
poseArray_table_->item(curGoalIdx_ % pose_array_.poses.size(), 1)->setBackgroundColor(color_table);
|
||||
poseArray_table_->item(curGoalIdx_ % pose_array_.poses.size(), 2)->setBackgroundColor(color_table);
|
||||
curGoalIdx_ += 1;
|
||||
cycleCnt_ = curGoalIdx_ / pose_array_.poses.size();
|
||||
}
|
||||
}
|
||||
|
||||
// cancel the current command
|
||||
void MultiNaviGoalsPanel::cancelNavi() {
|
||||
if (!cur_goalid_.id.empty()) {
|
||||
cancel_pub_.publish(cur_goalid_);
|
||||
ROS_ERROR("Navigation have been canceled");
|
||||
}
|
||||
}
|
||||
|
||||
// call back for listening current state
|
||||
void MultiNaviGoalsPanel::statusCB(const actionlib_msgs::GoalStatusArray::ConstPtr &statuses) {
|
||||
bool arrived_pre = arrived_;
|
||||
arrived_ = checkGoal(statuses->status_list);
|
||||
// if (arrived_) { ROS_ERROR("%d,%d", int(arrived_), int(arrived_pre)); }
|
||||
if (arrived_ && arrived_ != arrived_pre && ros::ok() && permit_) {
|
||||
if (cycle_) cycleNavi();
|
||||
else completeNavi();
|
||||
}
|
||||
}
|
||||
|
||||
//check the current state of goal
|
||||
bool MultiNaviGoalsPanel::checkGoal(std::vector<actionlib_msgs::GoalStatus> status_list) {
|
||||
bool done;
|
||||
if (!status_list.empty()) {
|
||||
for (auto &i : status_list) {
|
||||
if (i.status == 3) {
|
||||
done = true;
|
||||
// ROS_INFO("completed Goal%d", curGoalIdx_);
|
||||
} else if (i.status == 4) {
|
||||
// ROS_ERROR("Goal%d is Invalid, Navi to Next Goal%d", curGoalIdx_, curGoalIdx_ + 1);
|
||||
return false;
|
||||
} else if (i.status == 0) {
|
||||
done = true;
|
||||
} else if (i.status == 1) {
|
||||
cur_goalid_ = i.goal_id;
|
||||
done = false;
|
||||
} else done = false;
|
||||
}
|
||||
} else {
|
||||
// ROS_INFO("Please input the Navi Goal");
|
||||
done = false;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
// spin for subscribing
|
||||
void MultiNaviGoalsPanel::startSpin() {
|
||||
if (ros::ok()) {
|
||||
ros::spinOnce();
|
||||
}
|
||||
}
|
||||
//读取目标点
|
||||
void MultiNaviGoalsPanel::load(const rviz::Config &config) {
|
||||
Panel::load(config);
|
||||
QString goal_number;
|
||||
if (config.mapGetString("multi_goal_panel_number", &goal_number)) {
|
||||
output_maxNumGoal_editor_->setText(goal_number);
|
||||
updateMaxNumGoal();
|
||||
updatePoseTable();
|
||||
|
||||
QString goal_var;
|
||||
if (config.mapGetString("multi_goal_panel_data", &goal_var)) {
|
||||
QStringList goal_list = goal_var.split("|");
|
||||
for (int i = 0; i < goal_list.size(); i++) {
|
||||
QStringList goal = goal_list.at(i).split(",");
|
||||
|
||||
geometry_msgs::PoseStamped pose;
|
||||
pose.header.frame_id = "map";
|
||||
pose.header.stamp = ros::Time::now();
|
||||
pose.pose.position.x = goal.at(0).toDouble();
|
||||
pose.pose.position.y = goal.at(1).toDouble();
|
||||
pose.pose.position.z = 0.0;
|
||||
|
||||
pose.pose.orientation = tf::createQuaternionMsgFromYaw(goal.at(2).toDouble() / 180 * 3.14);
|
||||
init_goal_pub_.publish(pose);
|
||||
}
|
||||
}
|
||||
|
||||
bool cycle_flag;
|
||||
if (config.mapGetBool("multi_goal_panel_cycle", &cycle_flag)) {
|
||||
if (cycle_flag) {
|
||||
cycle_checkbox_->setCheckState(Qt::CheckState::Checked);
|
||||
} else {
|
||||
cycle_checkbox_->setCheckState(Qt::CheckState::Unchecked);
|
||||
}
|
||||
checkCycle();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//保存目标点
|
||||
void MultiNaviGoalsPanel::save(rviz::Config config) const {
|
||||
Panel::save(config);
|
||||
config.mapSetValue("multi_goal_panel_cycle", cycle_checkbox_->isChecked());
|
||||
if (!output_maxNumGoal_editor_->text().isEmpty()) {
|
||||
int goal_number = output_maxNumGoal_editor_->text().toInt();
|
||||
if (goal_number > 0) {
|
||||
config.mapSetValue("multi_goal_panel_number", goal_number);
|
||||
|
||||
QString *goal_list = new QString();
|
||||
for (int i = 0; i < pose_array_.poses.size(); i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
goal_list->append(poseArray_table_->item(i, j)->text());
|
||||
if (j != 2) {
|
||||
goal_list->append(",");
|
||||
}
|
||||
}
|
||||
if (i != goal_number - 1) {
|
||||
goal_list->append("|");
|
||||
}
|
||||
}
|
||||
|
||||
if (!goal_list->isEmpty()) {
|
||||
config.mapSetValue("multi_goal_panel_data", *goal_list);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace navi-multi-goals-pub-rviz-plugin
|
||||
|
||||
// 声明此类是一个rviz的插件
|
||||
|
||||
#include <pluginlib/class_list_macros.h>
|
||||
|
||||
PLUGINLIB_EXPORT_CLASS(navi_multi_goals_pub_rviz_plugin::MultiNaviGoalsPanel, rviz::Panel)
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
# Autolabor M1 系统目录
|
||||
|
||||
## 简介
|
||||
|
||||
Autolabor M1 搭载的是 Autolabor 推出的Autolabor OS机器人操作系统,基于 ubuntu20.04 与 ROS Noetic 开发而成,包含 ROS Noetic 、常用
|
||||
ROS包(Cartographer、Gmapping、Navigation ···),机器人底盘与传感器驱动包,机器人仿真应用,以及激光SLAM导航、自动巡迹导航应用等。
|
||||
|
||||
解决了繁琐的 ROS 环境安装问题,节省时间成本,降低技术壁垒。使用该系统学习ROS、开发机器人、实现自己的算法,做一些有趣的事情。
|
||||
|
||||
秉持小而实用的原则,对原生的Ubuntu系统的功能模块进行了精简,在原有的基础上增加了ROS开发中使用到的常见功能包。
|
||||
|
||||
既保证了简洁性,又增加了实用性。按需构建,有非常良好的可扩展性。
|
||||
|
||||
OS在M1上已经实现了机器人自主导航(2D/3D SLAM 单目标/多目标)、RTK自动循迹、远程遥控等功能。
|
||||
|
||||
## 系统目录
|
||||
|
||||
|
||||
```
|
||||
catkin_ws
|
||||
├── script //执行脚本
|
||||
├── src //源码
|
||||
|
||||
catkin_ws/src/driver/
|
||||
├── car
|
||||
│ ├── autolabor_canbus_driver //PM1底盘驱动
|
||||
│ └── autolabor_pro1_driver //AP1/M1底盘驱动
|
||||
├── depth_camera
|
||||
│ ├── zed_wrapper //ZED 相机驱动
|
||||
│ └── pico_zense_driver //Vzense DCAM710 相机驱动
|
||||
├── imu
|
||||
│ ├── ah100b //ah100b,ah200c 惯导驱动
|
||||
│ ├── ch104m //ch104m IMU 驱动
|
||||
│ ├── rviz_imu_plugin //rviz 惯导可视化插件,显示惯导图像
|
||||
│ └── tl740d //tl740d 转角仪驱动
|
||||
├── lidar
|
||||
│ ├── ldlidar_stl_ros //乐动19 雷达驱动
|
||||
│ ├── rslidar //速腾RS16、RS-Helios雷达驱动
|
||||
│ └── wr_fslidar // 砝石FS-D10 雷达驱动
|
||||
└── location
|
||||
└── al_rtk_ros_driver // RTK570 接收机驱动
|
||||
└── marvelmind // marvelmind 定位标签驱动
|
||||
|
||||
catkin_ws/src/launch/
|
||||
├── autolabor_navigation_launch //导航launch
|
||||
│ ├── launch
|
||||
│ │ ├── real_environment //实车launch
|
||||
│ │ │ ├── first_generation_base.launch //单雷达版本-传感器驱动
|
||||
│ │ │ ├── first_generation_mapping.launch //单雷达版本-建图
|
||||
│ │ │ ├── first_generation_navigation.launch //单雷达版本-导航
|
||||
│ │ │ ├── rtk_tracking_basic_base.launch//RTK版本-传感器驱动
|
||||
│ │ │ ├── rtk_tracking.launch //RTK版本-循迹
|
||||
│ │ │ ├── second_generation_advanced_base.launch //双雷达版本-传感器驱动(含定位标签)
|
||||
│ │ │ ├── second_generation_basic_base.launch //双雷达版本-传感器驱动
|
||||
│ │ │ ├── second_generation_mapping.launch //双雷达版本-建图
|
||||
│ │ │ ├── second_generation_multigoal_navigation.launch //双雷达版本-多点导航
|
||||
│ │ │ ├── second_generation_navigation.launch //双雷达版本-导航
|
||||
│ │ │ ├── second_generation_tracking.launch //双雷达版本-循迹
|
||||
│ │ │ ├── third_generation_base.launch //多线雷达版本-传感器驱动
|
||||
│ │ │ ├── third_generation_cartographer_3d.launch //多线雷达版本-建图
|
||||
│ │ │ └── third_generation_navigation_3d.launch //多线雷达版本-导航
|
||||
│ │ └── simulated_environment //模拟器launch
|
||||
│ │ ├── common_stage_simulation.launch //模拟场景地图
|
||||
│ │ ├── first_generation_base_simulation.launch
|
||||
│ │ ├── first_generation_mapping_simulation.launch
|
||||
│ │ ├── first_generation_navigation_simulation.launch
|
||||
│ │ ├── second_generation_advanced_base_simulation.launch
|
||||
│ │ ├── second_generation_basic_base_simulation.launch
|
||||
│ │ ├── second_generation_driver_simulation.launch
|
||||
│ │ ├── second_generation_mapping_simulation.launch
|
||||
│ │ ├── second_generation_multicar_following_simulation.launch //多车跟随
|
||||
│ │ ├── second_generation_multicar_navigation_simulation.launch //多车导航
|
||||
│ │ ├── second_generation_multigoal_navigation_simulation.launch //多目标导航
|
||||
│ │ ├── second_generation_navigation_simulation.launch
|
||||
│ │ └── second_generation_tracking_simulation.launch
|
||||
│ ├── map //建图保存的地图文件
|
||||
│ │ ├── map_3d.pbstream //3d slam 地图文件,用于定位,不可修改(保存地图后生成)
|
||||
│ │ ├── map_3d.pgm //3d slam 地图文件,用于导航,可修改(保存地图后生成)
|
||||
│ │ ├── map_3d.yaml //map_3d.pgm 的解释文件(保存地图后生成)
|
||||
│ │ ├── map.pbstream //2d slam 地图文件,用于定位导航,不可修改
|
||||
│ │ ├── map_simulation.pbstream //模拟器地图文件
|
||||
│ │ ├── simulation_stage.png //模拟器环境地图
|
||||
│ │ └── simulation_stage.yaml //simulation_stage.png 的解释文件
|
||||
│ ├── params //配置文件
|
||||
│ │ ├── cartographer
|
||||
│ │ │ ├── first_generation_location.lua //单雷达版本-定位
|
||||
│ │ │ ├── first_generation_mapping.lua //单雷达版本-建图
|
||||
│ │ │ ├── map_builder.lua //cartographer 配置文件
|
||||
│ │ │ ├── map_builder_server.lua //cartographer 配置文件
|
||||
│ │ │ ├── pose_graph.lua //cartographer 配置文件
|
||||
│ │ │ ├── second_generation_location.lua //双雷达版本-定位
|
||||
│ │ │ ├── second_generation_mapping.lua //双雷达版本-建图
|
||||
│ │ │ ├── second_generation_multicar_location.lua //双雷达版本-多车定位(模拟器)
|
||||
│ │ │ ├── third_generation_location.lua //多线雷达版本-定位
|
||||
│ │ │ ├── third_generation_mapping.lua //多线雷达版本-建图
|
||||
│ │ │ ├── trajectory_builder_2d.lua //cartographer 配置文件
|
||||
│ │ │ ├── trajectory_builder_3d.lua //cartographer 配置文件
|
||||
│ │ │ └── trajectory_builder.lua //cartographer 配置文件
|
||||
│ │ ├── common
|
||||
│ │ │ ├── back_lidar_config.yaml //后雷达过滤配置文件
|
||||
│ │ │ └── front_lidar_config.yaml //前雷达过滤配置文件
|
||||
│ │ └── navigation
|
||||
│ │ ├── costmap //代价地图配置文件
|
||||
│ │ │ ├── 3d_global_costmap_params.yaml //3d slam 全局代价地图
|
||||
│ │ │ ├── 3d_local_costmap_params.yaml //3d slam 局部代价地图
|
||||
│ │ │ ├── one_laser_global_costmap_params.yaml //单雷达版本-全局代价地图
|
||||
│ │ │ ├── one_laser_local_costmap_params.yaml //单雷达版本-局部代价地图
|
||||
│ │ │ ├── two_laser_global_costmap_params_for_tracking.yaml //双雷达版本-循迹-全局代价地图
|
||||
│ │ │ ├── two_laser_global_costmap_params.yaml //双雷达版本-全局代价地图
|
||||
│ │ │ └── two_laser_local_costmap_params.yaml //双雷达版本-局部代价地图
|
||||
│ │ ├── global_planer //全局规划配置文件
|
||||
│ │ │ ├── global_planner_params.yaml //用于导航
|
||||
│ │ │ ├── navfn_params.yaml //用于多车(模拟器)
|
||||
│ │ │ └── tracking_planner_params.yaml //用于循迹
|
||||
│ │ ├── local_planer //局部规划配置文件
|
||||
│ │ │ ├── navigation_teb_local_planner_params.yaml //用于导航
|
||||
│ │ │ └── tracking_teb_local_planner_params.yaml //用于循迹
|
||||
│ │ └── move_base //ROS Navigation 配置文件
|
||||
│ │ ├── navigation_move_base.yaml //用于导航
|
||||
│ │ └── tracking_move_base.yaml //用于循迹
|
||||
│ └── rviz //rviz配置文件
|
||||
│ ├── 3d_mapping.rviz //3d slam-建图
|
||||
│ ├── 3d_navigation.rviz //3d slam-导航
|
||||
│ ├── first_generation_create_map.rviz //单雷达版本-建图
|
||||
│ ├── first_generation_navigation.rviz //单雷达版本-导航
|
||||
│ ├── second_generation_create_map.rviz //双雷达版本-建图
|
||||
│ ├── second_generation_multicar_navigation.rviz //双雷达版本-多车导航(模拟器)
|
||||
│ ├── second_generation_multigoal_navigation.rviz //双雷达版本-多点导航
|
||||
│ ├── second_generation_navigation.rviz //双雷达版本-导航
|
||||
│ └── second_generation_tracking.rviz //双雷达版本-循迹
|
||||
└── autolabor_test_launch //测试
|
||||
├── launch
|
||||
│ ├── car_test.launch //键盘遥控
|
||||
│ ├── 2dlidar_test.launch //单线激光雷达测试
|
||||
│ ├── 3dlidar_test.launch //多线激光雷达测试
|
||||
│ ├── imu_test.launch //惯导测试
|
||||
│ ├── kinect2_test.launch //深度相机测试
|
||||
│ ├── robot_calibration.launch //AP1标定
|
||||
│ └── rtk_test.launch //RTK测试
|
||||
│ └── tag_test.launch //定位标签测试
|
||||
└── rviz //rviz配置文件
|
||||
├── 3dlidar.rviz //多线激光雷达测试
|
||||
├── car.rviz //键盘遥控
|
||||
├── fslidar.rviz //单线雷达测试
|
||||
├── robot_calibration.rviz //AP1标定
|
||||
└── rtk_test.rviz //RTK测试
|
||||
└── tag.rviz //定位标签测试
|
||||
|
||||
|
||||
catkin_ws/src/mapping/ //建图源码
|
||||
├── cartographer //cartographer GPU 加速版本
|
||||
├── cartographer_ros//cartographer算法源码-适配ROS
|
||||
|
||||
|
||||
|
||||
catkin_ws/src/navigation/ //ROS Navigation 源码
|
||||
├── amcl //粒子滤波定位
|
||||
├── base_local_planner //局部规划
|
||||
├── carrot_planner //全局规划
|
||||
├── clear_costmap_recovery //恢复行为
|
||||
├── costmap_2d //障碍物地图
|
||||
├── dwa_local_planner //dwa局部规划
|
||||
├── fake_localization //OS中未使用
|
||||
├── global_planner //全局规划
|
||||
├── location_fusion //定位融合(定位标签/RTK+里程计)
|
||||
├── loop_path_planner //循迹全局规划
|
||||
├── map_server //地图服务
|
||||
├── move_base //movebase
|
||||
├── move_slow_and_clear //恢复行为
|
||||
├── multi_car_goal //多车-前车向后车发目标(模拟器)
|
||||
├── nav_core //导航核心接口
|
||||
├── navfn //全局规划
|
||||
├── navigation //ROS Navigation元
|
||||
├── path_rviz_plugin //循迹rviz插件,功能按钮组
|
||||
├── path_server //用于循迹中录制路线
|
||||
│ ├── path_data
|
||||
│ │ ├── default_path.path //循迹中保存的路径数据
|
||||
├── record_path_planner //循迹全局规划
|
||||
├── rotate_recovery //恢复行为
|
||||
├── teb_local_planner //局部规划
|
||||
└── voxel_grid //用于障碍物地图
|
||||
|
||||
|
||||
catkin_ws/src/simulation/ //模拟器
|
||||
├── autolabor_description //机器人模型
|
||||
│ ├── launch
|
||||
│ │ ├── display_autolabor_mini.launch
|
||||
│ │ └── display_autolabor_pro1.launch
|
||||
│ ├── meshes
|
||||
│ │ ├── autolabor_mini.stl
|
||||
│ │ ├── pro1_body_color.dae //AP1模型文件-主体
|
||||
│ │ └── pro1_wheel_color.dae //AP1模型文件-轮子
|
||||
│ ├── rviz
|
||||
│ │ └── urdf.rviz
|
||||
│ └── urdf
|
||||
│ ├── autolabor_mini.urdf
|
||||
│ ├── second_generation_model.xacro //双雷达版本-机器人描述(类似urdf)
|
||||
│ └── third_generation_model.xacro //多线雷达版本-机器人描述(类似urdf)
|
||||
├── autolabor_simulation_base //机器人底盘模拟
|
||||
├── autolabor_simulation_lidar //雷达模拟
|
||||
├── autolabor_simulation_location //定位标签模拟
|
||||
├── autolabor_simulation_object //运动物体模拟
|
||||
└── autolabor_simulation_stage //场景模拟
|
||||
|
||||
|
||||
catkin_ws/src/tool/
|
||||
├── autolabor_keyboard_control //键盘控制(必须要插实体键盘)
|
||||
├── cartographer_initialpose //cartographer初始化定位
|
||||
├── laser_proc //雷达驱动
|
||||
├── joy_to_twist //手柄转速度驱动包
|
||||
├── navi_multi_goals_pub_rviz_plugin //rviz插件-多点导航
|
||||
├── rviz_autolabor_calibration //rviz插件-AP1标定
|
||||
├── rviz_keyboard_twist //rviz插件-键盘控制
|
||||
└── rviz_navigation_tools //rviz插件-多车导航工具,切换机器人(模拟器)
|
||||
|
||||
|
||||
|
||||
script //执行脚本
|
||||
├── 3d_suit //多线雷达版本
|
||||
│ ├── create_map_start
|
||||
│ ├── create_map_stop
|
||||
│ ├── navigation_start
|
||||
│ └── navigation_stop
|
||||
├── box_suit //单雷达版本
|
||||
│ ├── create_map_start
|
||||
│ ├── create_map_stop
|
||||
│ ├── navigation_start
|
||||
│ └── navigation_stop
|
||||
├── common
|
||||
│ ├── add_keyboard_udev //用于键盘控制,加键盘权限
|
||||
│ └── rebuild //工作空间编译脚本
|
||||
├── simulation //模拟器
|
||||
│ ├── create_map_start
|
||||
│ ├── create_map_stop
|
||||
│ ├── navigation_start
|
||||
│ ├── navigation_stop
|
||||
│ ├── tracking_start
|
||||
│ └── tracking_stop
|
||||
├── test //测试
|
||||
│ ├── car_test
|
||||
│ ├── fslidar_test
|
||||
│ ├── imu_test
|
||||
│ ├── kinect2_test
|
||||
│ ├── pico_test
|
||||
│ ├── robot_calibration
|
||||
│ ├── rplidar_test
|
||||
│ ├── rslidar_test
|
||||
│ └── tag_test
|
||||
└── track_suit //双雷达版本
|
||||
├── create_map_start
|
||||
├── create_map_stop
|
||||
├── navigation_start
|
||||
├── navigation_stop
|
||||
├── tracking_start //开始循迹
|
||||
└── tracking_stop //停止循迹
|
||||
```
|
|
@ -0,0 +1,100 @@
|
|||
# RTK循迹
|
||||
|
||||
## 目录
|
||||
|
||||
* 功能介绍
|
||||
* 传感器介绍
|
||||
* 实现原理
|
||||
|
||||
## 功能介绍
|
||||
|
||||
RTK循迹是机器人循着用户提前录好的轨迹自主行走,行走过程中机器人能够自动躲避障碍物,自动规划路线,达到目标点。
|
||||
|
||||
RTK循迹要求配置好RTK接收机,然后控制车端完成循迹。
|
||||
|
||||
RTK接收机的数据与里程计的数据融合定位,得到M1在环境中的坐标点,控制M1运动,边走边记录当前坐标点的位置,将这些坐标点记录为文件保存下来,得到路径文件。
|
||||
|
||||
在开始循迹的时候,程序加载路径文件,RTK接收机定位数据与里程计融合定位匹配路径数据,机器人按照指定路径行走。
|
||||
|
||||
## 传感器介绍
|
||||
|
||||
RTK循迹 用到的传感器有:
|
||||
|
||||
|
||||
* 单线激光雷达x2,安装在M1车内前后底部
|
||||
* RTK接收机,安装在M1套件内
|
||||
* 编码器/轮速里程计x2,安装在车体内部前侧
|
||||
* 电机x2,安装在车体内部中间位置
|
||||
|
||||
![](imgs/rtk_intro_1.png)
|
||||
|
||||
|
||||
## 实现原理
|
||||
|
||||
|
||||
|
||||
![](imgs/rtk_intro_2.png)
|
||||
|
||||
| 步骤 | 输入数据 | 操作 | 输出数据 | 使用ROS包 |
|
||||
|-----|------------------|--------------------------------------------|----------------|-------------------------------------------------------------------------------------------------------|
|
||||
| 1 | | RTK接收机 | 定位数据 | marvelmind驱动包(catkin_ws\src\driver\location\al_rtk_ros_driver) |
|
||||
| 2 | 里程计数据 定位数据 | 定位融合 | 当前机器人在环境中的位姿 | location_fusion(catkin_ws\src\navigation\location_fusion) |
|
||||
| 3 | 当前机器人位姿 | 控制机器人运动,录制路径 | 路径数据 | path_server(catkin_ws\src\navigation\path_server) |
|
||||
| 4 | 路径数据 | 读取录制的路径数据,执行循迹操作 | 目标机器人位姿 | path_server(catkin_ws\src\navigation\path_server) [move_base](http://wiki.ros.org/move_base/) |
|
||||
| 5 | 当前机器人位姿 目标机器人位姿 | 根据机器人当前位姿,进行全局规划路线 | 路径数据(初步预估导航路线) | [global_planner(dijkstra) ](http://wiki.ros.org/global_planner) |
|
||||
| 6 | 路径数据 前雷达数据 后雷达数据 | 根据规划路径开始导航,进行过程中随着实际环境、障碍物变化,进行局部路径规划,实时避障 | 局部路径规划 避障 | [costmap_2d ](http://wiki.ros.org/cost_map)[teb_local_planner](http://wiki.ros.org/teb_local_planner) |
|
||||
| 7 | 速度信息 /cmd_vel | 向底层发送速度命令 | | [move_base](http://wiki.ros.org/move_base/) |
|
||||
|
||||
定位循迹 launch配置示例
|
||||
|
||||
```
|
||||
<!-- RTK定位驱动 -->
|
||||
<node pkg="al_rtk_ros_driver" type="al_rtk_ros_driver" name="al_ros_driver">
|
||||
<remap from="/al_ros_driver/location_pos" to="location_pos"/>
|
||||
<param name="map_frame" value="map"/>
|
||||
<param name="serial_device" value="/dev/box_3"/>
|
||||
<param name="badurate" value="115200"/>
|
||||
<param name="domain" value="rtk.ntrip.qxwz.com"/>
|
||||
<param name="account" value="qxnsv0012"/>
|
||||
<param name="password" value="7fd7069"/>
|
||||
<param name="publish_pos_fix_only" value="true"/>
|
||||
<param name="auto_use_first_fix_as_enu_origin" value="true" />
|
||||
<param name="origin_config_file" value="$(find autolabor_navigation_launch)/params/rtk_tracking_enu_origin.json"/>
|
||||
</node>
|
||||
|
||||
<!-- 定位与里程计定位融合 -->
|
||||
<node name="location_fusion" pkg="location_fusion" type="simple_fusion">
|
||||
<param name="map_frame" value="map"/>
|
||||
<param name="odom_frame" value="odom"/>
|
||||
<param name="buffer_size" value="50"/>
|
||||
<param name="tag_frame" value="lidar_front" />
|
||||
<param name="distance_interval" value="0.1"/>
|
||||
<param name="rate" value="200"/>
|
||||
|
||||
</node>
|
||||
|
||||
<!-- 录制路径 -->
|
||||
<node name="path_saver" pkg="path_server" type="record_path_node">
|
||||
<param name="map_frame" value="map"/>
|
||||
<param name="base_link_frame" value="base_link"/>
|
||||
<param name="odom_topic" value="odom"/>
|
||||
<param name="distance_interval" value="0.2"/>
|
||||
</node>
|
||||
|
||||
<!-- 加载路径 -->
|
||||
<node name="path_loader" pkg="path_server" type="load_path_node">
|
||||
<param name="map_frame" value="map"/>
|
||||
<param name="path_file" value="default_path"/>
|
||||
</node>
|
||||
|
||||
<!-- 导航模块 -->
|
||||
<node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/move_base/rtk_tracking_move_base.yaml" command="load" />
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/costmap/two_laser_global_costmap_params_for_tracking.yaml" command="load" ns="global_costmap"/>
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/costmap/two_laser_local_costmap_params.yaml" command="load" ns="local_costmap"/>
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/global_planer/tracking_planner_params.yaml" command="load" ns="LoopPathPlanner"/>
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/local_planer/tracking_teb_local_planner_params.yaml" command="load" ns="TebLocalPlannerROS"/>
|
||||
</node>
|
||||
|
||||
|
||||
```
|
|
@ -0,0 +1,246 @@
|
|||
# 激光SLAM
|
||||
|
||||
## 目录
|
||||
|
||||
* SLAM介绍
|
||||
* 基于激光SLAM的机器人自主导航
|
||||
* Autolabor M1 SLAM 导航功能详解
|
||||
* 2D SLAM 实现原理
|
||||
* 3D SLAM 实现原理
|
||||
|
||||
|
||||
## SLAM介绍
|
||||
|
||||
**SLAM**,全称是 Simultaneous Localization and Mapping,同时定位与地图构建。
|
||||
|
||||
SLAM 技术解决的是,我在哪里?(**定位**Localization )我周围是什么样?(**建图**Mapping)这两个问题。
|
||||
|
||||
移动设备从未知环境中的某一点开始运动,根据传感器获取到的数据,即时计算获取传感器的位置并绘制周围的环境。
|
||||
|
||||
![](imgs/slamintro1.jpg)
|
||||
|
||||
SLAM 的应用很广泛,有扫地机器人、无人驾驶汽车、无人机,三维场景重建等。
|
||||
|
||||
根据使用传感器不同,SLAM的可分为激光SLAM和视觉SLAM(VSLAM),本文介绍的是激光SLAM,对视觉SLAM相关知识感兴趣的可以[看这里](/usedoc/navigationKit2/version_two/development/vslamintro)。
|
||||
|
||||
|
||||
## 基于激光SLAM的机器人自主导航
|
||||
|
||||
激光SLAM导航,指的是使用激光雷达采集的数据进行建图与定位(SLAM),并在构建的环境地图中自动导航(规划+控制)。
|
||||
|
||||
![](imgs/slamintro2.png)
|
||||
|
||||
地图构建完成后,给出目标点,根据当前位置信息与已知环境地图规划出可行走路径,控制机器人运动,最终达到目标点。
|
||||
|
||||
![](imgs/slamintro3.png)
|
||||
|
||||
以上只是简单概述了机器人导航的流程,但 SLAM 与 路径规划/Planning 都是很复杂的内容,在此不做过多的探讨。
|
||||
|
||||
|
||||
## Autolabor M1 SLAM 导航功能详解
|
||||
|
||||
Autolabor SLAM 导航使用的是谷歌开源的 [Cartographer](https://github.com/googlecartographer/cartographer_ros),支持多平台和传感器配置,提供2D和3D实时同步定位与建图,使用回环检测消除建图产生的累积误差,建图效果更好,在国内外众多机器人应用上得到了广泛使用。
|
||||
|
||||
> Cartographer is a system that provides real-time simultaneous localization and mapping (SLAM) in 2D and 3D across multiple platforms and sensor configurations.
|
||||
|
||||
|
||||
![](imgs/slamintro4.gif)
|
||||
|
||||
|
||||
|
||||
### 2D SLAM 实现原理
|
||||
|
||||
|
||||
#### 传感器介绍
|
||||
|
||||
2D SLAM 用到的传感器有:
|
||||
|
||||
|
||||
* 单线激光雷达x2,安装在M1内部前后位置
|
||||
* 编码器/轮速里程计x2,安装在车体内部前侧
|
||||
|
||||
|
||||
![](imgs/software_intro_6.png)
|
||||
|
||||
#### 2D SLAM 建图
|
||||
|
||||
![](imgs/software_intro_1.jpg)
|
||||
|
||||
| 步骤 | 输入数据 | 操作 | 输出数据 | 使用ROS包 |
|
||||
|-----|------------------|--------------------------------------------|----------------|-------------------------------------------------------------------------------------------------------|
|
||||
|1 | 左编码器数据 右编码器数据 | 使用运动模型计算编码器数据,得到符合ROS标准的里程计数据| 里程计数据| [autolabor_pro_driver](http://www.autolabor.com.cn/usedoc/ap1/sendCommand)|
|
||||
|2 | 前雷达数据 后雷达数据 | 过滤并融合前后激光雷达采集的数据,得到机器人周围环境点云数据| 雷达点云数据 | [cartographer_ros](https://google-cartographer-ros.readthedocs.io/en/latest/) [laser_filters](http://wiki.ros.org/laser_filters) |
|
||||
|3 | 里程计数据 点云数据 | 点云匹配| 相对位姿数据 子地图数据 | [cartographer_ros](https://google-cartographer-ros.readthedocs.io/en/latest/)|
|
||||
|4 | 相对位姿数据 子地图数据 | 回环检测,得到子地图拼接的全地图数据 | 地图数据 | [cartographer_ros](https://google-cartographer-ros.readthedocs.io/en/latest/)|
|
||||
|
||||
|
||||
Cartographer 2D 建图 launch配置示例
|
||||
|
||||
```
|
||||
|
||||
<!-- 建图节点 -->
|
||||
<node name="cartographer_node" pkg="cartographer_ros"
|
||||
type="cartographer_node" args="
|
||||
-configuration_directory $(find autolabor_navigation_launch)/params/cartographer
|
||||
-configuration_basename second_generation_mapping.lua"
|
||||
output="screen">
|
||||
</node>
|
||||
|
||||
<node name="cartographer_occupancy_grid_node" pkg="cartographer_ros" type="cartographer_occupancy_grid_node" args="-resolution 0.05" />
|
||||
|
||||
|
||||
```
|
||||
|
||||
#### 2D SLAM 导航
|
||||
|
||||
![](imgs/software_intro_2.jpg)
|
||||
|
||||
| 步骤 | 输入数据 | 操作 | 输出数据 | 使用ROS包 |
|
||||
|-----|------------------|--------------------------------------------|----------------|-------------------------------------------------------------------------------------------------------|
|
||||
|1 | 左编码器数据 右编码器数据 | 使用运动模型计算编码器数据,得到符合ROS标准的里程计数据| 里程计数据| [autolabor_pro_driver](http://www.autolabor.com.cn/usedoc/ap1/sendCommand)|
|
||||
|2|前雷达数据 后雷达数据 里程计数据 地图数据|将机器人的实时数据与已构建的地图进行匹配|当前机器人在环境中的位姿| [cartographer_ros](https://google-cartographer-ros.readthedocs.io/en/latest/)|
|
||||
|3| 目标机器人位姿| 给机器人制定一个目标点| |[move_base](http://wiki.ros.org/move_base/)|
|
||||
|4| 当前机器人位姿 地图数据 目标机器人位姿| 根据机器人当前位姿与地图数据,进行全局规划路线| 路径数据(初步预估导航路线) |[global_planner(dijkstra) ](http://wiki.ros.org/global_planner)|
|
||||
|5| 路径数据 地图数据 前雷达数据 后雷达数据 | 根据规划路径开始导航,进行过程中随着实际环境、障碍物变化,进行局部路径规划,实时避障| 局部路径规划 避障 |[costmap_2d ](http://wiki.ros.org/cost_map)[teb_local_planner](http://wiki.ros.org/teb_local_planner)|
|
||||
|6| 速度信息 /cmd_vel | 向底层发送速度命令 | |[move_base](http://wiki.ros.org/move_base/)|
|
||||
|
||||
说明:
|
||||
|
||||
1. move_base, global_planner(dijkstra), costmap_2d 这些功能包(package)都从属于
|
||||
Navigation 导航这个大的功能包集,teb_local_planner 是navigation包的一个插件。
|
||||
2. 机器人导航过程中,会按照周围环境、实时障碍物做调整不断规划调整路径,向底层发布指令,步骤五和六是一个多次的过程,并非一次就结束了。
|
||||
|
||||
Cartographer 2D 导航 launch配置示例
|
||||
|
||||
```
|
||||
<!-- 定位模块 -->
|
||||
<node name="cartographer_node" pkg="cartographer_ros"
|
||||
type="cartographer_node" args="
|
||||
-configuration_directory $(find autolabor_navigation_launch)/params/cartographer
|
||||
-configuration_basename second_generation_location.lua
|
||||
-load_state_filename $(find autolabor_navigation_launch)/map/map.pbstream"
|
||||
output="screen">
|
||||
</node>
|
||||
|
||||
<node name="cartographer_occupancy_grid_node" pkg="cartographer_ros"
|
||||
type="cartographer_occupancy_grid_node" args="
|
||||
-resolution 0.05
|
||||
--noinclude_unfrozen_submaps"
|
||||
output="screen">
|
||||
</node>
|
||||
|
||||
<node pkg="cartographer_initialpose" type="cartographer_initialpose" name="cartographer_initialpose" >
|
||||
<param name="configuration_directory" value="$(find autolabor_navigation_launch)/params/cartographer" />
|
||||
<param name="configuration_basename" value="second_generation_location.lua" />
|
||||
</node>
|
||||
|
||||
<!-- 导航模块 -->
|
||||
<node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/move_base/navigation_move_base.yaml" command="load" />
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/costmap/two_laser_global_costmap_params.yaml" command="load" ns="global_costmap"/>
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/costmap/two_laser_local_costmap_params.yaml" command="load" ns="local_costmap"/>
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/global_planer/global_planner_params.yaml" command="load" ns="GlobalPlanner"/>
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/local_planer/navigation_teb_local_planner_params.yaml" command="load" ns="TebLocalPlannerROS"/>
|
||||
</node>
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 3D SLAM 实现原理
|
||||
|
||||
|
||||
#### 传感器介绍
|
||||
|
||||
3D SLAM 用到的传感器有:
|
||||
|
||||
* 多线激光雷达,安装在M1套件内
|
||||
* 单线激光雷达x2,安装在M1内部前后位置
|
||||
* 编码器/轮速里程计x2,安装在车体内部前侧
|
||||
* 惯导,安装在M1套件内
|
||||
|
||||
|
||||
|
||||
![](imgs/software_intro_7.png)
|
||||
|
||||
#### 3D SLAM 建图
|
||||
|
||||
![](imgs/software_intro_4.jpg)
|
||||
|
||||
| 步骤 | 输入数据 | 操作 | 输出数据 | 使用ROS包 |
|
||||
|-----|------------------|--------------------------------------------|----------------|-------------------------------------------------------------------------------------------------------|
|
||||
|1 | 左编码器数据 右编码器数据 | 使用运动模型计算编码器数据,得到符合ROS标准的里程计数据| 里程计数据| [autolabor_pro_driver](http://www.autolabor.com.cn/usedoc/ap1/sendCommand)|
|
||||
|2 | 多线雷达数据 惯导数据 里程计数据 | 点云匹配| 相对位姿数据 子地图数据 | [cartographer_ros](https://google-cartographer-ros.readthedocs.io/en/latest/)|
|
||||
|3 | 相对位姿数据 子地图数据 | 回环检测,得到子地图拼接的全地图数据 | 地图数据 | [cartographer_ros](https://google-cartographer-ros.readthedocs.io/en/latest/)|
|
||||
|
||||
|
||||
|
||||
Cartographer 3D 建图 launch配置示例
|
||||
|
||||
```
|
||||
<!-- 建图节点 -->
|
||||
<node name="cartographer_node" pkg="cartographer_ros"
|
||||
type="cartographer_node" args="
|
||||
-configuration_directory $(find autolabor_navigation_launch)/params/cartographer
|
||||
-configuration_basename third_generation_mapping.lua"
|
||||
output="screen">
|
||||
<remap from="points2" to="rslidar_points" />
|
||||
</node>
|
||||
|
||||
<node name="cartographer_occupancy_grid_node" pkg="cartographer_ros" type="cartographer_occupancy_grid_node" args="-resolution 0.05" />
|
||||
|
||||
<node name="rviz" pkg="rviz" type="rviz" args="-d $(find autolabor_navigation_launch)/rviz/3d_mapping.rviz" />
|
||||
```
|
||||
|
||||
#### 3D SLAM 导航
|
||||
|
||||
![](imgs/software_intro_5.jpg)
|
||||
|
||||
| 步骤 | 输入数据 | 操作 | 输出数据 | 使用ROS包 |
|
||||
|-----|------------------|--------------------------------------------|----------------|-------------------------------------------------------------------------------------------------------|
|
||||
|1 | 左编码器数据 右编码器数据 | 使用运动模型计算编码器数据,得到符合ROS标准的里程计数据| 里程计数据| [autolabor_pro_driver](http://www.autolabor.com.cn/usedoc/ap1/sendCommand)|
|
||||
|2|多线雷达数据 惯导数据 里程计数据 地图数据|将机器人的实时数据与已构建的地图进行匹配|当前机器人在环境中的位姿| [cartographer_ros](https://google-cartographer-ros.readthedocs.io/en/latest/)|
|
||||
|3| 目标机器人位姿| 给机器人制定一个目标点| |[move_base](http://wiki.ros.org/move_base/)|
|
||||
|4| 当前机器人位姿 地图数据 目标机器人位姿| 根据机器人当前位姿与地图数据,进行全局规划路线| 路径数据(初步预估导航路线) |[global_planner(dijkstra) ](http://wiki.ros.org/global_planner)|
|
||||
|5| 路径数据 地图数据 前雷达数据 后雷达数据 多线雷达数据 | 根据规划路径开始导航,进行过程中随着实际环境、障碍物变化,进行局部路径规划,实时避障| 局部路径规划 避障 |[costmap_2d ](http://wiki.ros.org/cost_map)[teb_local_planner](http://wiki.ros.org/teb_local_planner)|
|
||||
|6| 速度信息 /cmd_vel | 向底层发送速度命令 | |[move_base](http://wiki.ros.org/move_base/)|
|
||||
|
||||
说明:
|
||||
|
||||
1. move_base, global_planner(dijkstra), costmap_2d 这些功能包(package)都从属于
|
||||
Navigation 导航这个大的功能包集,teb_local_planner 是navigation包的一个插件。
|
||||
2. 机器人导航过程中,会按照周围环境、实时障碍物做调整不断规划调整路径,向底层发布指令,步骤五和六是一个多次的过程,并非一次就结束了。
|
||||
|
||||
|
||||
Cartographer 3D 导航 launch配置示例
|
||||
|
||||
```
|
||||
<!-- 定位模块 -->
|
||||
<node name="cartographer_node" pkg="cartographer_ros"
|
||||
type="cartographer_node" args="
|
||||
-configuration_directory $(find autolabor_navigation_launch)/params/cartographer
|
||||
-configuration_basename third_generation_location.lua
|
||||
-load_state_filename $(find autolabor_navigation_launch)/map/map_3d.pbstream"
|
||||
output="screen">
|
||||
<remap from="points2" to="rslidar_points" />
|
||||
</node>
|
||||
|
||||
<node pkg="map_server" type="map_server" name="map_server" args="$(find autolabor_navigation_launch)/map/map_3d.yaml" />
|
||||
|
||||
<node pkg="cartographer_initialpose" type="cartographer_initialpose" name="cartographer_initialpose" >
|
||||
<param name="configuration_directory" value="$(find autolabor_navigation_launch)/params/cartographer" />
|
||||
<param name="configuration_basename" value="third_generation_location.lua" />
|
||||
</node>
|
||||
|
||||
<!-- 导航模块 -->
|
||||
<node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/move_base/navigation_move_base.yaml" command="load" />
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/costmap/3d_global_costmap_params.yaml" command="load" ns="global_costmap"/>
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/costmap/3d_local_costmap_params.yaml" command="load" ns="local_costmap"/>
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/global_planer/global_planner_params.yaml" command="load" ns="GlobalPlanner"/>
|
||||
<rosparam file="$(find autolabor_navigation_launch)/params/navigation/local_planer/navigation_teb_local_planner_params.yaml" command="load" ns="TebLocalPlannerROS"/>
|
||||
<param name="TebLocalPlannerROS/xy_goal_tolerance" value="0.2" />
|
||||
<param name="TebLocalPlannerROS/yaw_goal_tolerance" value="0.5" />
|
||||
</node>
|
||||
|
||||
```
|
|
@ -0,0 +1,106 @@
|
|||
# 视觉SLAM
|
||||
|
||||
>本文主要对SLAM技术进行介绍,叙述了VSLAM的框架及关键技术和方法,并总结了目前已有的VSLAM系统和相关资料。
|
||||
|
||||
## 目录
|
||||
|
||||
1. SLAM技术介绍
|
||||
2. VSLAM系统及相关资料介绍
|
||||
3. SLAM框架
|
||||
1. SLAM的基本过程
|
||||
2. VSLAM的主要模块
|
||||
|
||||
|
||||
## 1.SLAM技术介绍
|
||||
|
||||
**SLAM**,全称是Simultaneous Localization and Mapping,即**同时定位与建图**,指机器人在自身位置不确定的条件下,在完全未知环境中创建地图,同时利用地图进行自主定位和导航。因此可知SLAM的主要工作是**定位**以及**建图**。
|
||||
|
||||
|
||||
![](./imgs/slamintro1.jpg)
|
||||
|
||||
目前SLAM有很多实现方法,根据使用传感器不同,主要分为:
|
||||
|
||||
**(1)激光雷达传感器;**
|
||||
**(2)视觉传感器;**
|
||||
|
||||
**视觉SLAM**(Visual SLAM 简称VSLAM)包括使用**单目SLAM**、**双目SLAM**和以**Kinect**为代表的深度摄像头的**RGB-D SLAM**。相比使用激光雷达传感器,视觉传感器的成本更低,因此也越来越受青睐。
|
||||
|
||||
目前SLAM被广泛应用于无人驾驶汽车、无人机、VR和AR等领域。
|
||||
|
||||
下面是宾大的教授kumar做的特别有名的一个demo,是在无人机上利用二维激光雷达做的SLAM。
|
||||
|
||||
![](./imgs/vslam1.gif)
|
||||
|
||||
## 2.VSLAM系统及相关资料介绍
|
||||
|
||||
目前在VSLAM领域实现较好的SLAM系统有:
|
||||
|
||||
- 单目、双目SLAM:
|
||||
|
||||
(1).**PTAM**(Parallel Tracking And Mapping):2007年很流行的SLAM项目,是**第一个**使用BA完成**实时SLAM**的系统。但其缺乏**回环检测和重定位等功能**,只能作用于小规模的场景,且稳定性也不是很高。(http://www.robots.ox.ac.uk/~gk/PTAM/)
|
||||
|
||||
(2).**DTAM**(Dense tracking and mapping in real-time):2011年,Direct SLAM方法的**鼻祖**;
|
||||
|
||||
(3).**LSD-SLAM**(Large-Scale Direct Monocular SLAM):2014年一个半稠密SLAM系统。(http://vision.in.tum.de/research/vslam/lsdslam)
|
||||
|
||||
(4).**ORB-SLAM**:2015年一个比较完整的基于特征点的SLAM系统。
|
||||
(http://webdiis.unizar.es/~raulmur/orbslam/)
|
||||
|
||||
- RGB-D SLAM:
|
||||
|
||||
(1).**KinectFusion** 2011
|
||||
(http://www.microsoft.com/en-us/research/project/kinectfusion-project-page/)
|
||||
|
||||
(2).**RGBD-SLAM2** 2014 (http://felixendres.github.io/rgbdslam_v2/)
|
||||
|
||||
(3).**ElasticFusion** 2015 (http://www.imperial.ac.uk/dyson-robotics-lab/downloads/elastic-fusion/)
|
||||
|
||||
当然除了上述项目的学习外,对于slam的学习入门,有一些经典教材如:
|
||||
**Multiple View Geometry in Computer Vision (Second Edition)**
|
||||
(http://www.robots.ox.ac.uk/~vgg/hzbook/)也有中文版为《计算机视觉中的多视图几何》。
|
||||
|
||||
**Robotics Vision and Control**(http://www.petercorke.com/RVC/) 本书是面向实践的,详细介绍了机器人和机器视觉。也有了中文版,叫做《机器人学、机器视觉与控制》。
|
||||
此外,对于slam入门学习推荐高博的**一起做RGB-D SLAM**其博客为半闲居士(http://www.cnblogs.com/gaoxiang12/p/4633316.html)
|
||||
|
||||
## 3.SLAM框架
|
||||
|
||||
### 3.1 SLAM的基本过程
|
||||
|
||||
描述为:机器人在未知环境中从一个未知位置开始移动,在移动过程中根据位置估计和传感器数据进行自身定位,同时建造增量式地图。
|
||||
|
||||
(1)**定位(localization)**:机器人必须知道自己在环境中位置。
|
||||
|
||||
(2)**建图(mapping)**:机器人必须记录环境中特征的位置(如果知道自己的位置)
|
||||
|
||||
(3)**SLAM**:机器人在定位的同时建立环境地图。其基本原理是运过概率统计的方法,通过多特征匹配来达到定位和减少定位误差的。
|
||||
|
||||
![](./imgs/vslam2.png)
|
||||
|
||||
### 3.2 VSLAM的主要模块
|
||||
|
||||
视觉SLAM主要分为几个模块:**数据采集、视觉里程计(Visual Odometry)、后端优化、建图(Mapping)、闭环检测(Loop closure detection)**。如下图所示:
|
||||
|
||||
![](./imgs/vslam3.png)
|
||||
|
||||
#### 3.2.1 视觉里程计
|
||||
|
||||
视觉里程计是利用一个图像序列或者一个视频流,计算摄像机的方向和位置的过程。一般包括图像获取后、畸变校正、特征检测匹配或者直接匹配对应像素、通过对极几何原理估计相机的旋转矩阵和平移向量。
|
||||
|
||||
|
||||
![](./imgs/vslam4.jpg)
|
||||
|
||||
#### 3.2.2 后端优化
|
||||
|
||||
理论上来说,如果视觉里程计模块估计的相机的旋转矩阵R和平移向量t都正确,就能得到完美的定位和建图了。但实际试验中,我们得到的数据往往有很多噪声,且由于传感器的精度、错误的匹配等,都对造成结果有误差。并且由于我们是只把新的一帧与前一个关键帧进行比较,当某一帧的结果有误差时,就会对后面的结果产生**累计误差**,导致误差越来越大。**为了解决这个问题,引入后端优化**。
|
||||
|
||||
后端优化一般采用捆集调整(BA)、卡尔曼滤波(EKF)、图优化等方式来解决。其中**基于图优化的后端优化**,效果最好。Graph-based SLAM一般使用g2o求解器,进行图优化计算。
|
||||
|
||||
![](./imgs/vslam5.jpg)
|
||||
|
||||
#### 3.2.3 闭环检测
|
||||
|
||||
后端优化可能得到一个比较优的解,但当运动回到某一个之前去过的地方,如果能认出这个地方,找到并与当时的关键帧进行比较,就可以得到比单用后端优化更准确更高效的结果。闭环检测就是要解决这个问题。
|
||||
|
||||
闭环检测有两种方式,一是根据估计出来的相机的位置,看是否与之前否个位置邻近;**另外一种是根据图像,自动识别出来这个场景之前到过,并找到当时的关键帧**。目前常用的后一种方法,其实是一个非监督的模式识别问题。比较常用的方法是采用Bag-of-Words(BOW),**ORB-SLAM**就是使用这个方法来进行**闭环检测**。
|
||||
|
||||
![](./imgs/vslam6.jpg)
|
|
@ -0,0 +1,45 @@
|
|||
## YOLO V5
|
||||
## 简介
|
||||
YOLOv5 是革命性的“You Only Look Once”物体检测模型的第五次迭代,旨在实时提供高速、高精度的结果。
|
||||
|
||||
这个强大的深度学习框架基于 PyTorch 构建,因其多功能性、易用性和高性能而广受欢迎。我们的文档将指导您完成安装过程,解释模型的架构细微差别,展示各种用例,并提供一系列详细的教程。这些资源将帮助您在计算机视觉项目中充分发挥 YOLOv5 的潜力。让我们开始吧!
|
||||
|
||||
![](imgs/yolo.jpeg)
|
||||
|
||||
## 教程
|
||||
|
||||
这是综合教程的汇编,将指导您了解 YOLOv5 的不同方面。
|
||||
|
||||
[快速入门](https://docs.ultralytics.com/yolov5/quickstart_tutorial/)
|
||||
|
||||
[训练自定义数据](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/) 推荐:了解如何在自定义数据集上训练 YOLOv5 模型。
|
||||
|
||||
[获得最佳训练结果的技巧](https://docs.ultralytics.com/yolov5/tutorials/tips_for_best_training_results/):发现优化模型训练过程的实用技巧。
|
||||
|
||||
[多 GPU 训练](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/):了解如何利用多个 GPU 来加快训练速度。
|
||||
|
||||
[PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/):学习通过 PyTorch Hub 加载预训练模型。
|
||||
|
||||
[TFLite、ONNX、CoreML、TensorRT 导出](https://docs.ultralytics.com/yolov5/tutorials/model_export/):了解如何将模型导出为不同的格式。
|
||||
|
||||
[NVIDIA Jetson 平台部署](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano/):了解如何在 NVIDIA Jetson 平台上部署 YOLOv5 模型。
|
||||
|
||||
[测试时间增强 (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/):探索如何使用 TTA 来提高模型的预测准确性。
|
||||
|
||||
[模型集成](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling/):学习组合多个模型以提高性能的策略。
|
||||
|
||||
[模型剪枝/稀疏性](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity/):了解剪枝和稀疏性概念,以及如何创建更有效的模型。
|
||||
|
||||
[超参数演化](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution/):探索自动超参数调整的过程,以获得更好的模型性能。
|
||||
|
||||
[使用冻结层进行迁移学习](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers/):了解如何通过冻结 YOLOv5 中的层来实现迁移学习。
|
||||
|
||||
[架构总结](https://docs.ultralytics.com/yolov5/tutorials/architecture_description/) 深入研究 YOLOv5 模型的结构细节。
|
||||
|
||||
[Roboflow数据集](https://docs.ultralytics.com/yolov5/tutorials/roboflow_datasets_integration/):了解如何利用 Roboflow 进行数据集管理、标记和主动学习。
|
||||
|
||||
[ClearML 日志记录](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration/) :了解如何集成 ClearML 以在模型训练期间进行高效日志记录。
|
||||
|
||||
[YOLOv5 与 Neural Magic](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization/):了解如何使用 Neural Magic 的 Deepsparse 来修剪和量化您的 YOLOv5 模型。
|
||||
|
||||
[Comet 日志记录](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration/) 新功能:探索如何利用 Comet 改进模型训练日志记录。
|
|
@ -0,0 +1,119 @@
|
|||
# 规格参数
|
||||
|
||||
## 上位机(Orin NX)
|
||||
| 项目 | 规格 |
|
||||
|-----|-----------|
|
||||
|算力 | 100TOPS |
|
||||
|GPU | 32个Tensor核心1024核 |
|
||||
|CPU|8核Arm Cortex-A78 2GHz|
|
||||
|内存|16GB 128位LPDDR5 102.4GB/s|
|
||||
|存储|128GB|
|
||||
|视频编解码|H.265|
|
||||
|PCIe|1X4+3X1 PCIe4.0|
|
||||
|显示接口|HDMI2. 1 1x8K30DP|
|
||||
|网卡|内置|
|
||||
|I/O|USB3.0/SCI/I2C/CAN/DMIC/ DSPK/I2S/GPIOs|
|
||||
|
||||
|
||||
## 显示器
|
||||
|
||||
| 项目 | 规格 |
|
||||
|-----|-----------|
|
||||
| 尺寸 | 13.3 英寸 |
|
||||
| 比例 | 16: 9 |
|
||||
| 分辨率 | 1920*1080 |
|
||||
| 亮度 | 300 cd/m² |
|
||||
| 对比度 | 800: 1 |
|
||||
| 触摸 | 否 |
|
||||
|
||||
##多线激光雷达(RS-Helios-16p)
|
||||
|
||||
| 项目 | 规格 |
|
||||
|----------|--------------------------|
|
||||
| 线数 | 16 |
|
||||
| 激光波长 | 905nm |
|
||||
| 激光安全等级 | Class 1 人眼安全 |
|
||||
| 测距能力 | 150m(90m@10% NIST) |
|
||||
| 盲区 | ≤0.2m |
|
||||
| 精度(典型值) | ±2cm(1m to 100m)<br>±3cm(0.1m to 1m)<br>±3cm(100m to 150m) |
|
||||
| 水平视场角 | 360° |
|
||||
| 垂直视场角 | 30°(-15°~+15°) |
|
||||
| 水平角分辨率 | 0.2°/0.4° |
|
||||
| 垂直角分辨率 | 均匀 2° |
|
||||
| 帧率 | 10Hz/20 Hz |
|
||||
| 转速 | 600/1200rpm (10/20Hz) |
|
||||
| 出点数 | ~288,000pts/s(单回波)<br> ~576,000pts/s(双回波) |
|
||||
| UDP数据包内容 | 三维空间坐标<br>反射强度<br>时间戳等 |
|
||||
| 输出数据协议 | UDP packets over Ethernet |
|
||||
| 时间同步 | ≈ GPRMC with 1PPS,PTP&gPTP |
|
||||
|
||||
##卫星接收机(RTK580)
|
||||
|
||||
| 项目 | 规格 |
|
||||
|----------|--------------------------|
|
||||
| 通道 | 1408 通道 |
|
||||
| 频点 | 5星多频<br>BDS、GPS、QZSS、GLONASS、Galileo |
|
||||
| 单点定位 (RMS) | 平面 1.5m 高程 2.5m |
|
||||
| RTK(RMS) |平面 0.8cm+1ppm ;高程 1.5cm+1ppm |
|
||||
| 冷启动 |<30s |
|
||||
| RTK 初始化时间 | <5s( 典型值 ) |
|
||||
| 初始化可靠性 | >99.9% |
|
||||
|差分通讯方式| 免DTU模块|
|
||||
| 差分数据 | RTCM 3.X |
|
||||
| 数据格式 | NMEA 0183 Unicore |
|
||||
| 定位测向数据更新率 | 20Hz |
|
||||
| 原始观测量数据更新率 | 20Hz |
|
||||
| 定向精度 (RMS) | 0.1° /1m 基线 |
|
||||
| 时间精度 (RMS) |20ns |
|
||||
| 速度精度 (RMS) | 0.03m/s |
|
||||
| 双天线接口 | SMA公头外螺内孔 * 2 |
|
||||
| 通讯接口 | USB-Type-C |
|
||||
| 供电接口 | USB-Type-C/XT-30 |
|
||||
| 供电电压 | 5-15V |
|
||||
| 功耗 |2.4W |
|
||||
| 尺寸 | 93mmx69mmx37mm |
|
||||
| 重量 | 153g |
|
||||
|
||||
##惯导(CH104M)
|
||||
| 项目 | 规格 |
|
||||
|----------|--------------------------|
|
||||
|姿态角 | 横滚/俯仰:0.2°<br>偏航(静态):0.2°°<br>偏航(动态):3° |
|
||||
|陀螺仪 |测量范围:±2000°/s <br>分辨率:0.01°/s<br>零偏稳定性:1.76°/hr |
|
||||
|加速度计|测量范围:±8G <br>分辨率:1uG<br>零偏稳定性:30uG |
|
||||
|磁传感器|测量范围:±8G(Gauss)<br>非线性度:±0.1%<br>分辨率:0.25mG|
|
||||
|
||||
## 激光雷达(LD19)
|
||||
|
||||
|
||||
| 参数名称 | 单位 | 最小值 | 典型值 | 最大值 | 备注 |
|
||||
|:------|:-----|:------|:-----|:----|:-----------------------------------------|
|
||||
| 测距范围 | m | 0.02 | - | 12 | 70%目标反射率 |
|
||||
| 扫描频率 | Hz | 5 | 10 | 13 | 外部提供PWM 控速 |
|
||||
| 测距频率 | Hz | - | 4500 | - | 固定频率 |
|
||||
| 测距精度 | mm | - | - | - | 测距小于0.3m时,有数据输出。</br>测距数据变化趋势与实际距离变化趋势一致 |
|
||||
| 测距精度 | m | -45 | - | 45 | 测距范围在300mm到12000mm时,测量100次的平均值(70%漫反射面) |
|
||||
| 测距标准差 | mm | - | 10 | - | 测距范围在300mm到12000mm时 |
|
||||
| 测量分辨率 | mm | - | 15 | - | |
|
||||
| 角度误差 | ° | - | - | 2 | |
|
||||
| 角度分辨率 | ° | - | 1 | - | |
|
||||
| 抗环境光 | KLux | - | - | 30 | |
|
||||
| 整机寿命 | h | 10000 | - | - | |
|
||||
|
||||
|
||||
|
||||
## 深度相机(Vzense DCAM710)
|
||||
|
||||
| 项目 | 规格 |
|
||||
|----------|--------------------------|
|
||||
| 尺寸 | 103mmx33mmx22mm |
|
||||
| 传感器 | ToF CCD+RGB |
|
||||
| 激光发射器 | 940nm VCSEL |
|
||||
| ToF分辨率帧率 | 640X480, Max.30fps |
|
||||
| RGB分辨率帧率 | 1920X1080, 30fps |
|
||||
| ToF FOV | 69°(H) × 51°(V) |
|
||||
| RGB FOV | 73°(H)X42°(V) |
|
||||
| 输出格式 | RAW12(深度,IR), MJPEG(RGB) |
|
||||
| 检测距离 | 0.35m~4.4m |
|
||||
| 工作温度 | -10℃~50℃ |
|
||||
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
# 建图导航
|
||||
|
||||
|
||||
|
||||
## 操作步骤
|
||||
|
||||
### 一、连接键鼠
|
||||
鼠标键盘建议使用普通成套的无线键鼠,避免使用机械键盘、游戏鼠标,请不要同时使用有线、无线鼠标或键盘。
|
||||
|
||||
### 二、启动系统
|
||||
打开电源,打开工控机,等待 Autolabor OS 系统启动,输入密码 autolabor,字母全部是小写,回车。
|
||||
|
||||
![](imgs/login.png)
|
||||
|
||||
### 三、建图导航
|
||||
|
||||
|
||||
#### 准备工作:
|
||||
1. 将 M1 控制模式切换到上位机控制,右转打开急停开关,确保急停开关没有被按下
|
||||
2. 禁用工控机无线功能
|
||||
在建图过程中,如果工控机连接了无线网络,当M1走出无线网络的覆盖区域后,网络连接会自动断开,这将导致M1控制失控,所以在开始建图之前,为了避免失控,需要将工控机的无线网络连接关闭。
|
||||
3. 进入桌面 SLAM建图导航 - > 2d 文件夹,首次使用时文件如下图,双击打开后点击 trust and launch,程序第一次打开后会重命名。
|
||||
|
||||
![](imgs/slam-8.png)
|
||||
|
||||
![](imgs/slam-9.png)
|
||||
|
||||
|
||||
#### 1. 点击【开始建图】
|
||||
|
||||
|
||||
RVIZ工具打开,能够看到地图中的 M1。
|
||||
|
||||
使用键盘的上下左右控制 M1 行走,边走边建图,可以看到环境地图随着 M1 的行走不断被构建更新。
|
||||
|
||||
地图中,红色是前置激光雷达实时数据,黄色是后置激光雷达实时数据,颜色从白至黑为障碍物的几率是0%~100%。
|
||||
|
||||
![](imgs/slam-3.png)
|
||||
|
||||
|
||||
##### 键盘控制说明
|
||||
|
||||
键盘控制功能在系统中已经安装好,无需安装可直接使用。
|
||||
|
||||
有2种键盘控制的方式:
|
||||
|
||||
一、直接在电脑上插上键鼠,直接控制机器人(默认模式)
|
||||
|
||||
数字键【1/2】线速度增加/减少,数字键【3/4】角速度增加/减少,数字键【9】启用,数字键【0】禁用。
|
||||
|
||||
二、使用键盘插件,用另一台电脑远程控制机器人
|
||||
|
||||
![](imgs/key_control.png)
|
||||
|
||||
如使用该插件,则需将机器人上的键鼠拔掉,否则远程给出的速度指令会被机器人上的键鼠指令覆盖,如插上了不使用键鼠控制,程序默认向底盘发送速度指令为0,机器人会停止不动。
|
||||
|
||||
如想远程操控机器人,请查看[这里](/usedoc/navigationKit2/version_two/network/setting)。
|
||||
|
||||
|
||||
#### 2. 建图完毕,点击【保存并停止建图】
|
||||
|
||||
|
||||
最终建图结果示意:
|
||||
|
||||
<img style="width:37%;" src="imgs/slam-4.png"/>
|
||||
|
||||
完成建图后,一定要点击【保存并停止建图】关闭窗口,不能直接关闭RVIZ窗口或者关闭终端,否则地图文件无法正确保存,导航时会报错。
|
||||
|
||||
地图文件存储路径为catkin_ws\src\launch\autolabor_navigation_launch\map
|
||||
|
||||
2D SLAM 地图文件:
|
||||
|
||||
```
|
||||
map.pbstream: 地图文件,用于定位导航,不可修改
|
||||
```
|
||||
|
||||
如有多个环境,想保存不同的地图,在不同的环境使用:
|
||||
1. 最后一次成功保存的地图会自动存储为以上的名称,而过去建好的地图会用时间戳重命名,备份在同一路径下,地图的名称可以自定义。
|
||||
2. 如果要切换地图,可以将现有地图重命名,将要替换的地图文件分别修改为以上文件的名称,之后需要再次切换的时候,依然更换地图名称即可。
|
||||
|
||||
注:如修改文件名,请务必保证名称正确无误。
|
||||
|
||||
#### 3. 点击【开始导航】
|
||||
RVIZ工具打开,建好的地图会自动加载。
|
||||
|
||||
<img style="width:50%;" src="imgs/slam-5.png"/>
|
||||
|
||||
|
||||
##### 初始化定位
|
||||
|
||||
导航之前,要对机器人做初始化定位,设置方式有两种:
|
||||
|
||||
一、使用键盘控制机器人走到初始建图位置,注意车头、车尾方向与之前基本保持一致;
|
||||
|
||||
二、使用2D Pose Estimate,点击 2D Pose Estimate(2D nav goal左边),根据机器人现在的所在位置,对比地图,找到机器人在地图中大概的位置,根据真实车头的朝向,方向指向车头朝向的方向,拉动鼠标。
|
||||
|
||||
设置后控制机器人行走一段距离,当激光雷达的数据与实时的环境匹配成功时,即为机器人找到在地图中的初始定位。
|
||||
|
||||
<img style="width:50%;" src="imgs/slam-6.gif"/>
|
||||
|
||||
如上图所示,进行初始化定位操作后,机器人突然跳到了一个新地点,并且地图中的地点与真实环境中机器人位置一致,即为初始化成功,可进行下一步操作。
|
||||
|
||||
##### 关闭键盘控制
|
||||
|
||||
<b style="color:red;">点击数字键【0】关闭键盘控制功能</b>(非小键盘0),控制方式将切换至导航程序控制,如不切换机器人接收到目标点命令后将不会自动导航行走。
|
||||
|
||||
##### 给定目标点
|
||||
|
||||
点击 2D Nav Goal,指定目标位置,拉动鼠标,箭头方向是最终车辆运行至目标的车头朝向,鼠标松开,这样就完成了目标点的指定。
|
||||
|
||||
目标点给定后在地图中我们能看到一条线,这是规划好的路径。根据这个规划好的路径,M1 向目标点行走。
|
||||
|
||||
当M1已经到达目标点后,再一次使 2D Nav Goal 设置目标位置,M1将去到下一个目标点。
|
||||
|
||||
<img style="width:50%;" src="imgs/slam-7.gif"/>
|
||||
|
||||
|
||||
|
||||
### 四、点击【终止导航】,停止导航功能,导航结束。
|
||||
|
||||
之后在同一环境中需要再次使用导航功能时,无须重复建图,点击【开始导航】即可。
|
||||
|
||||
|
||||
[>>常见问题](/usedoc/navigationKit2/common/q_a/doc2)
|
||||
|
||||
## 附录 - 软件功能图
|
||||
|
||||
|
||||
![](imgs/software_intro_1.jpg)
|
||||
|
||||
![](imgs/software_intro_2.jpg)
|
|
@ -0,0 +1,150 @@
|
|||
# 建图导航
|
||||
|
||||
|
||||
## 操作步骤
|
||||
|
||||
### 一、连接键鼠
|
||||
鼠标键盘建议使用普通成套的无线键鼠,避免使用机械键盘、游戏鼠标,请不要同时使用有线、无线鼠标或键盘。
|
||||
|
||||
### 二、启动系统
|
||||
打开电源,打开工控机,等待 Autolabor OS 系统启动,输入密码 autolabor,字母全部是小写,回车。
|
||||
|
||||
![](imgs/login.png)
|
||||
|
||||
### 三、建图导航
|
||||
|
||||
|
||||
#### 准备工作:
|
||||
1. 将 M1 控制模式切换到上位机控制,右转打开急停开关,确保急停开关没有被按下
|
||||
2. 禁用工控机无线功能
|
||||
在建图过程中,如果工控机连接了无线网络,当M1走出无线网络的覆盖区域后,网络连接会自动断开,这将导致M1控制失控,所以在开始建图之前,为了避免失控,需要将工控机的无线网络连接关闭。
|
||||
3. 进入桌面 SLAM建图导航 - > 3d 文件夹,首次使用时文件如下图,双击打开后点击 trust and launch,程序第一次打开后会重命名。
|
||||
|
||||
![](imgs/slam-8.png)
|
||||
|
||||
![](imgs/slam-9.png)
|
||||
|
||||
|
||||
#### 1. 点击【开始建图】
|
||||
|
||||
|
||||
RVIZ工具打开,能够看到地图中的 M1。
|
||||
|
||||
使用键盘的上下左右控制 M1 行走,边走边建图,可以看到环境地图随着 AP1 的行走不断被构建更新。
|
||||
|
||||
地图中,黑色是障碍物,白色是可行走区域,彩色的激光点是激光雷达实时数据,颜色从白至黑为障碍物的几率是0%~100%。
|
||||
|
||||
![](imgs/3d_slam1.png)
|
||||
|
||||
|
||||
##### 键盘控制说明
|
||||
|
||||
键盘控制功能在系统中已经安装好,无需安装可直接使用。
|
||||
|
||||
有2种键盘控制的方式:
|
||||
|
||||
一、直接在电脑上插上键鼠,直接控制机器人(默认模式)
|
||||
|
||||
数字键【1/2】线速度增加/减少,数字键【3/4】角速度增加/减少,数字键【9】启用,数字键【0】禁用。
|
||||
|
||||
二、使用键盘插件,用另一台电脑远程控制机器人
|
||||
|
||||
![](imgs/key_control.png)
|
||||
|
||||
如使用该插件,则需将机器人上的键鼠拔掉,否则远程给出的速度指令会被机器人上的键鼠指令覆盖,如插上了不使用键鼠控制,程序默认向底盘发送速度指令为0,机器人会停止不动。
|
||||
|
||||
如想远程操控机器人,请查看[这里](/usedoc/navigationKit2/version_two/network/setting)。
|
||||
|
||||
|
||||
#### 2. 建图完毕,点击【保存并停止建图】
|
||||
|
||||
最终建图结果示意:
|
||||
|
||||
|
||||
![](imgs/3d_slam3.png)
|
||||
|
||||
完成建图后,一定要点击【保存并停止建图】关闭窗口,不能直接关闭RVIZ窗口或者关闭终端,否则地图文件无法正确保存,导航时会报错。
|
||||
|
||||
地图文件存储路径为catkin_ws\src\launch\autolabor_navigation_launch\map
|
||||
|
||||
3D SLAM 地图文件:
|
||||
|
||||
```
|
||||
map_3d.pbstream: 地图文件,用于定位,不可修改
|
||||
map_3d.pgm:地图文件,用于导航,可修改
|
||||
map_3d.yaml : pgm 文件的解释文件
|
||||
```
|
||||
|
||||
如有多个环境,想保存不同的地图,在不同的环境使用:
|
||||
1. 最后一次成功保存的地图会自动存储为以上的名称,而过去建好的地图会用时间戳重命名,备份在同一路径下,地图的名称可以自定义。
|
||||
2. 如果要切换地图,可以将现有地图重命名,将要替换的地图文件分别修改为以上文件的名称,之后需要再次切换的时候,依然更换地图名称即可。
|
||||
|
||||
注:如修改文件名,请务必保证名称正确无误。
|
||||
|
||||
#### 3. 修地图
|
||||
|
||||
|
||||
注:此步骤非必须操作,如建图结果与真实环境基本一致,可跳至下一步。
|
||||
|
||||
建图完成后,对照真实的建图环境,对地图进行修改,涂抹掉临时障碍物,增加真实环境中实际存在的障碍物,也可以自定义机器人的行走区域。
|
||||
|
||||
为避免修改错误无法返回,建议在修改前对要文件做一个备份。
|
||||
|
||||
右键点击map_3d.pgm,选择Krita软件打开,选择画笔工具,白色涂掉障碍物,黑色新增障碍物。
|
||||
|
||||
![](imgs/3d_slam4.png)
|
||||
![](imgs/3d_slam5.png)
|
||||
![](imgs/3d_slam6.png)
|
||||
|
||||
地图修改完毕后,保存关闭。
|
||||
|
||||
|
||||
#### 4. 点击【开始导航】
|
||||
RVIZ工具打开,建好的地图会自动加载。
|
||||
|
||||
![](imgs/3d_slam7.png)
|
||||
|
||||
|
||||
|
||||
##### 初始化定位
|
||||
|
||||
导航之前,要对机器人做初始化定位,设置方式有两种:
|
||||
|
||||
一、使用键盘控制机器人走到初始建图位置,注意车头、车尾方向与之前基本保持一致;
|
||||
|
||||
二、使用2D Pose Estimate,点击 2D Pose Estimate(2D nav goal左边),根据机器人现在的所在位置,对比地图,找到机器人在地图中大概的位置,根据真实车头的朝向,方向指向车头朝向的方向,拉动鼠标。
|
||||
|
||||
设置后控制机器人行走一段距离,当激光雷达的数据与实时的环境匹配成功时,即为机器人找到在地图中的初始定位。
|
||||
|
||||
![](imgs/3d_slam8.gif)
|
||||
|
||||
如上图所示,进行初始化定位操作后,机器人突然跳到了一个新地点,并且地图中的地点与真实环境中机器人位置一致,即为初始化成功,可进行下一步操作。
|
||||
|
||||
##### 关闭键盘控制
|
||||
|
||||
<b style="color:red;">点击数字键【0】关闭键盘控制功能</b>(非小键盘0),或取消键盘插件的【激活键盘控制】,关闭后控制方式将切换至导航程序,如不切换机器人接收到目标点命令后将不会自动导航行走。
|
||||
|
||||
##### 给定目标点
|
||||
|
||||
点击 2D Nav Goal,指定目标位置,拉动鼠标,箭头方向是最终车辆运行至目标的车头朝向,鼠标松开,这样就完成了目标点的指定。
|
||||
|
||||
目标点给定后在地图中我们能看到一条线,这是规划好的路径。根据这个规划好的路径,M1向目标点行走。
|
||||
|
||||
当M1已经到达目标点后,再一次使 2D Nav Goal 设置目标位置,M1将去到下一个目标点。
|
||||
|
||||
|
||||
|
||||
### 四、点击【终止导航】,停止导航功能,导航结束。
|
||||
|
||||
之后在同一环境中需要再次使用导航功能时,无须重复建图,点击【开始导航】即可。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 附录 - 软件功能图
|
||||
|
||||
|
||||
![](imgs/software_intro_4.jpg)
|
||||
|
||||
![](imgs/software_intro_5.jpg)
|
|
@ -0,0 +1,101 @@
|
|||
## 手柄控制
|
||||
|
||||
### 概述
|
||||
|
||||
我们配送一个控制手柄用于控制M1移动。
|
||||
|
||||
### 使用说明
|
||||
|
||||
M1出厂默认控制模式为手柄控制,在控制面板中可切换控制模式,将M1控制面板中的上位机控制按钮置于“手柄”方向切换到手柄控制模式,即可操作手柄的按键控制移动平台。
|
||||
|
||||
#### 手柄操作步骤
|
||||
|
||||
1. 打开手柄电源,切换至ON模式,手柄顶部POWER指示灯亮起
|
||||
2. 使用MODE键开启控制模式,顶部MODE LED指示灯为红色时,才能使用手柄进行控制
|
||||
3. 先按住手柄顶部两个【1】键,然后按照下文使用说明操作
|
||||
|
||||
![PS2 control](imgs/ps1.jpg)
|
||||
![PS2 control](imgs/ps2.jpg)
|
||||
|
||||
#### 手柄按键说明
|
||||
|
||||
我们对于M1的手柄控制设计有几种速度档位,如下表。
|
||||
|
||||
<table>
|
||||
<tr align="center">
|
||||
<th>档位</th>
|
||||
<td>0档</td>
|
||||
<td>1档</td>
|
||||
<td>2档</td>
|
||||
<td>3档</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<th>速度</th>
|
||||
<td>25%</td>
|
||||
<td>50%</td>
|
||||
<td>75%</td>
|
||||
<td>100%</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>按键</th>
|
||||
<th>功能</th>
|
||||
<th width="50%">备注</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>左区4控制键</td>
|
||||
<td>前/后/左/右控制运动方向</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SELECT/最低速度档</td>
|
||||
<td>设置运动速度为最低档位</td>
|
||||
<td>设置速度档位为0档</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>START/最高速度档</td>
|
||||
<td>设置运动速度为最高档位</td>
|
||||
<td>设置速度档位为3档</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>左侧摇杆键</td>
|
||||
<td>控制M1的运动方向和速度</td>
|
||||
<td>使用摇杆灵活的控制运动角度与速度,不必受限于正前/后/左/右,控制摇杆推动的力度来控制速度档位的调节,将摇杆向前方直接推到低,则直接是3档,向后方直接推到底,则直接设置为0档</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>右侧摇杆键</td>
|
||||
<td>无功能</td>
|
||||
<td>现阶段暂未使用</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>右区控制键-上</td>
|
||||
<td>线速度增加</td>
|
||||
<td>调整速度档位,每按一下,速度提高一档,最高不得高于最高档,如3档</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>右区控制键-下</td>
|
||||
<td>线速度减少</td>
|
||||
<td>每按一下,速度降低一档,最低不得高于最底档,如0档</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>右区控制键-左/右</td>
|
||||
<td>角速度增加/减少</td>
|
||||
<td>同线速度</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>顶部名为“1”的按键</td>
|
||||
<td>运动控制使能</td>
|
||||
<td>在遥控底盘运动、调整线速度、调整角速度的时候,这两个按钮应该处于被按下的状态</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>顶部名为“2”的按键</td>
|
||||
<td>配对测试按键</td>
|
||||
<td>当按下其中任意一个名为“2”的按键后,且配对的机器人为下位机模式,此时机器人会发出蜂鸣音提示</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 272 KiB |
After Width: | Height: | Size: 322 KiB |
After Width: | Height: | Size: 260 KiB |
After Width: | Height: | Size: 175 KiB |
After Width: | Height: | Size: 177 KiB |
After Width: | Height: | Size: 254 KiB |
After Width: | Height: | Size: 262 KiB |
After Width: | Height: | Size: 773 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 164 KiB |
After Width: | Height: | Size: 235 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 461 KiB |
After Width: | Height: | Size: 688 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 695 KiB |
After Width: | Height: | Size: 1007 KiB |
After Width: | Height: | Size: 867 KiB |
After Width: | Height: | Size: 815 KiB |
After Width: | Height: | Size: 832 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 237 KiB |
After Width: | Height: | Size: 624 KiB |
After Width: | Height: | Size: 140 KiB |
After Width: | Height: | Size: 215 KiB |
After Width: | Height: | Size: 95 KiB |
After Width: | Height: | Size: 222 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 432 KiB |
After Width: | Height: | Size: 97 KiB |
After Width: | Height: | Size: 572 KiB |
After Width: | Height: | Size: 3.5 MiB |