Basic_motion程序 NVIDIA 官方提供了一个驱动电机的脚本,我们可以直接运行来测试电机安装是否正确,以及电机工作是否正常。我们以摄像头的方向为向前方向,OLED屏幕的方向为向后方向。 运行程序 左边导航打开Notebooks/basic_motion目录,然后双击basic_motion.ipynb文件打开。你可以看到例程中已经有了大量备注。同时程序分成了多个单元(后面我们讲到代码就以单元的说法来说每个代码块)。当你想要运行某个单元的时候,你可以点击该条语句,然后按下ctrl+enter按键,就可以运行该条语句了。 比如,第一条语句是调用封装好的jetbot库,我们鼠标点击该单元,会有蓝色高亮显示。 然后键盘按下Ctrl+Enter语句就会运行了。 可以看到,当程序在运行的时候,单元前的括号中显示星号,表示代码正在执行。你也可以观察右上角的python3图标,后面如果是实心圆就说明kernel正忙,如果是空心圆,说明kernel空闲,可以运行下一单元了。 运行结束之后,如果没有报错的话,星号会变成序号,表示这是第几个被执行的单元。如果你重复运行统一单元的话,序号也会不断增加。 引用函数库 我们在写程序的时候,很多时候需要引用一些已经封装好的函数库,可以大大节省我们的精力。同样的,这里开头直接引用JetBot库。JetBot主要封装好了操作Jetbot小车的一些基本函数。小车运动函数,摄像头操作函数等。 题外话 由于本章节我们只需要驱动点击,所以这里只应用了Jetbot函数库里面的robot类。这个类包含了小车运动的控制函数。你如果想要了解函数的话,可以查看jetbot/jetbot路径下的robot.py文件。 可以看到这里包含了forward()向前, backward()后退,left()左转,right()右转和stop()停止等函数。 基本运动 单元3操作让小车左转,速度设置为0.3;你可以修改speed的值,来修改小车的转动速度。 单元4操作让小车停止。 注意:这里运行单元的时候,确保你的小车是放置在可以自由活动的地方。不要放在桌上或者有充电线连在,避免出现摔落或者扯掉线材。另外,有一些用户在测试的时候是跳着运行单元的,然后发现小车动不了。这里要特别说明一下,开头倒入库和相关类是必须先运行的,否则后面的单元无法正常运行。所以,请按顺序一步一步来。 单元5和单元6:导入Python的time函数库,通过添加时间函数,来让小车的动作保持一段时间。这里就相当于我们一般说的添加延迟。 这里运行单元的话。可以看到,小车先左转大约0.5s,然后停止。细心的用户会发现,这里的左转语句和单元3不同,这里并没有加入speed=的参数名,而是直接把速度值写进去。这个就是Python的特点,你既可以把参数名写上,也可以不加参数名,直接填写参数值,这两种方法都可以。 如果说你想要自己写一点东西,试试自己对前面的代码的理解是不是对的。你可以点击标签栏的+号来添加新的单元。然后写入你的控制程序。例如,我们添加新单元,让小车向前运行一段时间然后停止。写好之后你就额可以按下Ctrl+Enter让程序运行。试试吧。 OK,让我们接着往下走。实际上让小车运动的是底部的两个电机。小车运行就是通过控制电机的状态来完成的。前面我们调用的都是小车的形态语句,比如左转,右转,向前,停止。这里我们也可以直接控制电机来达到相同的目的。 单元8,我们设置两个电机的转动速度分别为0.3 和 0.6。我们都知道,如果小车的两个车轮转动速度不一样,即便他们的转动方向是一样的,也会让小车发生转向。这里如果你运行语句的话就会发现小车向左转了。 有人会问,那单元9跟单元8的区别是什么?好像运行之后效果是一样的。没有错,他们的效果是一样的。单元9是直接设置电机的值,而单元8就是调用函数,然后把值传进去。如果你看了前面的robot.py就会发现,实际上set_motor函数里面的操作也是去设置电机的值的。这就是为什么函数库存在的意义,它帮我们把一些功能封装成函数,我们使用的时候直接调用就行了,不用一条一条去设置。简单易操作。 控制运动 这里我们可以在web端创建一下小工具,然后通过web端的widgets来创建图形工具控制小车。这里就需要用到widgets和traitlets. 关于widgets. 可以了解: https://github.com/jupyter-widgets/ipywidgets 关于traitlets.可以了解: https://github.com/ipython/traitlets (没有错,都是英文的。^_^) 这里我们开头先引用widgets函数库,以及调用Ipython中的display类。display类是为了可以把我们创建的工具显示在页面上 这里我们创建两条滑动条,分别命名为left和right, 滑动调的数值范围为-1到1。 方向为竖直。 然后创建一个小窗口来显示这两个滑动条。 最后将两条滑动条显示在页面。运行之后,你就可以看到两个滑动条出现在单元下方。 引用traitlets库。 然后创建两条链接。分别是将left滑动条的值,链接到左电机的值。就是滑动条的值多少,电机的值就相应的设置为多少。通过这种方式。我们就可以通过滑动条来控制电机的值,从而控制小车的运动。第二个设置right滑动条也是如此。现在,你可以试着调一下上面单元的滑动条,看一下小车的反应了。 调用traitlets创建的链接其实是一个双向的链接的,也就是说我们可以通过滑动条来控制电机的状态,同样的,如果我们直接设置电机的状态,也会影响到滑动条的状态。你运行下一个单元设置小车向前运行然后停止的时候,会发现上面的滑条的状态会跟着这单元的运行同步。 题外话 题外话总是来得猝不及防^_^。 我们一个页面有时候只能显示几个单元。我们前面运行的时候你应该也发现了,前面运行的语句其实也是一直在产生影响的,不是说运行完了就跟它没关系的。所以就会像刚刚那样,我们在运行到后面的语句的时候,还需要查看滑条的状况,但是我们的页面又不够大,没办法同时放下那么多单元。这时候,我们就可以把某个单元的显示界面单独显示。 右键该单元,然后选择Create New View for Outputs. 滑条就会以单窗口的方式显示在浏览器下方。你可以拖动窗口修改窗口的位置。 这里再特别说明一下,本文说到的第几单元并不是实际上的顺序,而是笔者在演示的时候运行语句对应的顺序。因为可能会重复运行某些单元,会出现序号增加。所以跟着教程做的时候请以截图为准。 控制运动2 前面我们创建了滑条和电机的一个链接,这里我们可以通过unlink语句来断开两者之间的链接。 我们说到,前面创建的链接是一个双向的链接,滑条可以控制小车,同时小车的状态也会显示到滑条上去。有时候我们并不想要控制小车,只是想要让小车的运行状态可视化。这里我们可以dlink来创建一个单向的链接。 这时候你再去调节滑条,就会发现小车并不会有任何反应了,但是如果你重新运行单元13,你就会发现,滑条的状态会跟着小车的状态发生变化。 控制运动3 这里我们通过事件触发的方式来控制小车。首先使用widgets创建控制按键。 首先设置每个按键的布局,宽100px,长80px,居中放置。 然后创建5个按键,分别命名为stop_button等。调用刚刚创建的布局 创建一个水平窗口放置left, stop right,并居中放置 再创建一个窗口把forward,前面的水平窗口和backward 竖直放置。(可以看到这里是通过嵌套窗口的放置来布局的) 最后让窗口显示在页面上。 然后设置每个事件发生时候对应的处理函数。比如,如果向前的按键发生变化的时候,就让小车向前运行0.5秒然后停止 将按键跟对应的事件处理函数链接起来。比如,如果forward_button(我们在单元17中创建的一个按钮), on_click被点击的时候,就运行函数step_forward. 运行之后,你可以试着点击单元17的按键,看看小车对应有什么操作。 控制运动4 这里我们通过“心跳”来控制小车。调用jetbot库中封装好的hearbeat类。将心跳的周期和心跳数以滑条和数值的方式显示出来。周期就是心跳值增加1的所需要花的时间,周期时间越长,心跳跳动越慢,周期越短,跳动越慢。同时创建一个触发函数,当心跳alive状态发生变化的时候,如果检测到新的心跳状态为dead的时候,就让小车停止。 运行单元21,然后试着滑动滑条看一下现象。你也可以试着断开小车或者电脑的网络连接看一下效果。 |