本文为 2019 秋季学期《计算机导论》的课程作业之一。
经 czy 带佬发布,由俺整理而成。
实验要求
- 避障实验:设计障碍环境,实现小车自动避障功能。
- 追踪实验:选择追踪目标,实现小车追踪目标功能。
实验过程
0x00 硬件组装
参照官网教程完成
我们小组拿到的小车焊接工作已经完成,只需进行零件的拆装即可。其中尤应注意数据线的连接。
0x01 软件配置
-
使用 i2c-tools 调试 i2c 总线
-
检测有几组 i2c 总线在系统上 i2cdetect-l
-
检测挂载在 i2c-1 上的设备 i2cdetect-r-y1
- 查看设备(地址为 0x20)上所有寄存器的值 i2cdump -f -y 1 0x20
- 对单个寄存器进行读写:
i2cset-f-y10x200x770x3f
(设置 i2c-1 上 0x20 器件的 0x77 寄存器值为 0x3f)i2cget-f-y10x200x77
(读取 i2c-1 上 0x20 器件的 0x77 寄存器值)
得知 jetson-nano 开发板提供了 6 条 I2C 主线,以及其他丰富的接口.
-
-
软件连接:ssh 远程桌面
我们小组使用网线把小车和电脑连接起来组成局域网,通过 ssh 进入系统。
- 发现 ip:在插入网线前后执行两次 arp-a,多出的动态地址即为小车的内网 IP(小车的 LED 屏也会显示其 ip,故此可以直接从浏览器访问该 ip 的 8888 端口并运行 jupyter)
- 配置无线网络:将电脑 wifi 连接设为对以太网可共享,扫描并使用官方教程的账户密码连接:sshjetbot@192.168.x.x
- 安装并配置远程桌面
-
配置之后跟随教程运行 demo,遇到第一个问题。
0x02 demo1_自动避障
下载 AlexNet 并训练模型,运行 demo 实现自动避障。
- 在环境中拍很多张照片进行标记(通路与死路),尽量分布于各个位置与各个方向,作为模型的数据集。
- 然后运行代码,第一次运行会下载 244M 左右的文件即 AlexNet。(存放于
/home/jetbot/.torch/model
目录下) - 继续运行程序,完整的输出结果有三十行,每行后面的小数代表当前模型的准确度,程序最后会从这 30 个模型中选取准确度最高的作为最终模型。
- 引入我们训练出的模型,模型输入为经过处理的摄像头的图形信号,输出一个 0~1 的数,越接近 1 越意味着模型认为小车即将撞墙。由代码来看当大于 0.5 的时候就会触发转向,实现自动避障。
0x03 demo2_追踪目标
基于上一个 demo,我们还要下载一个模型 coco 数据集神经网络 用以检测 90 种不同的物体。
按教程把.engine 文件下载到指定位置,引入模型。
程序首先用字符串打印识别的物体,在数据集里搜索 label 的编号就能知道其代表的物体。如:
若有数据集里的物品,从输出里能看到蓝框标出,小车会自动转向物体,同时还保留了自动避障的程序。(label 62 代表椅子)
我们小组遇到第二个问题:摄像头调用无法更新。
按理说执行 observe 函数即可让摄像头更新,但执行该步无反应,小车只能依据单张画面判断物品。且拖动图像旁边的窗口组建,也并不能操纵小车的速度。
问题及其解决方案
第一个问题
问题
我们小组配置好小车后运行 demo ,始终指向同一个错误:OSError:[Errno121]RemoteI/Oerror
解决方案
沿着 jupyter notebook 的报错提示一直到最底层,得到 remoteIOerror
, 看起来像是硬件的问题,则一步一步排查。
- 怀疑跳线错误
- 更换跳线——无果
- 用万用表测量线两端的信号——正常,排除连接问题
- 时钟线及数据线保持 3.3v 间断跳到 2.2v 又回来,结合 i2c 原理分析应为正常现象。
- 使用软件方法检验设备连接性
- 用 i2ctools 可以检测到设备,拔下 4 根接线,在 0x60,0x70 处的设备消失,推测一个是 i2c 线,一个是逻辑供电。
- 然而在通电状态下将连线重新插拔,i2c 又能检测到设备,demo 正常运行
原因
开机时机器并没能正确载入设备,反倒是重新连接后能识别了。
第二个问题
问题
摄像头只要调用过一次,后面就无法在其他地方再次调用。
尝试解决
- 直接在 jupyter 上关闭输出并没有作用。只能在同一个 notebook 里反复调用,且没有报错信息。程序一直处在 busy 状态。
- 在寻找后发现源码
jetbot/jetbot/camera.py
,但是 demo 中调用摄像头均使用Camera.instance()
,而它处于traitlets
库中,于是搜寻官方文档找到 instance 的定义。 其功能为返回现有的类,如果没有就新建一个。后面将摄像头信号转换到屏幕图像也靠的是这个库。 -
则尝试从 camera.py 里调用原始 api。得到报错:
EachobjectmustbeHasTraits,not <class'NoneType'>
,即必须为对象指定类型。 -
再次梳理调用摄像头的流程:
-
引入模型:
model.load_state_dict(torch.load('best_model.pth'))
-
连接摄像头
-
模型执行:
def update(): ...#此处为模型执行函数,将输入图像预处理后,执行模型,每0.01秒更新 update({'new':camera.value}) #初始化该函数 camera.observe(update,names='value') #将update函数设为camera.value的observer,即摄像头图像改变时调用update函数
研究一下 observe 用法:让对象发生变化时调用函数。
https://traitlets.readthedocs.io/en/stable/using_traitlets.html#validation
······
-
由于拿到小车的时间有限,我们小组最后没有来得及自己编程调试问题,摄像头的问题暂待考究。
但我们掌握了小车的操作方法和 AI 程序的基本原理,受益匪浅。
心得体会
本次研究耗时两周,经过我们小组的通力协作,最终实现了小车自动避障的功能。并在理论上弄清了 AI 程序的基本原理,明晓了实现小车自动避障与追踪目标功能的过程细节。
我们小组通过查找国内外资料、付诸于实践、不断地修正过程中遇到的错误的方式,实现了从零到一的突破。我们成功地将无形的网络与可见的实体联系起来,以 jetbot 小车为载体实现了机器学习领域的尝鲜,也对机器学习和物联网的应用加深了理解。
同时,在研究的过程中,我们小组学会了如何更好的搜寻、整理资料,提升了阅读英文文档、团队协作、动手操作的能力,同时掌握了寻找过程中错误并分步调试的方法。
总之,本次 jetbot 小车实验带给我们小组所有人的,不止是实践能力的熟练,更是思想境界的提升。