玩轉JetBot自動駕駛 (四)開動你的JetBot

本篇詳細講解,如何使用jupyter lab在瀏覽器上控制你的JetBot,如何通過python進行對JetBot的編程。

我的自動駕駛文章首發在:https://robocarstore.cn/

購買整車套件:https://item.taobao.com/item.htm?spm=a2oq0.12575281.0.0.50111deb1H9qSk&ft=t&id=601511987683

 

認識Jupyter Lab的界面

我們在上一篇已經通過瀏覽器接觸過jupyter lab並使用了一些功能,接下來我們會一直使用這個工具,所有我們有必要了解一下jupyter lab的界面,對不同區域的名稱有個印象,將會讓你在之後的操作更得心應手。

 

大概說明一下:

  • 頂部菜單:包含了jupyter lab的所有操作,例如新建,保存,關閉運行中的內核等等
  • 控制檯:是一些快捷方式,在這裏可以快速新建一個notebook,打開一個Terminal(終端,或者叫命令行)等等。
  • 快捷工具欄:是一些快捷方式,從左到右,分別表示「新建一個控制檯」、「創建文件夾」、「上傳文件」、「刷新」
  • 側邊選項卡:可以分別點開「文件瀏覽器」、「運行中的核心列表」、「命令列表」、「窗口列表」

接下來,會解讀notebook裏面python的語句什麼意思,有什麼用。

完整的notebook,請在這裏瀏覽,樣式更好看:

https://github.com/ling3ye/jetbot/blob/master/notebooks/basic_motion/basic_motion.ipynb

也可以下載此notebook,覆蓋你的原有基礎移動notebook。

基本移動

歡迎來到基於jupyter lab的Jetbot編程界面。
這種類型文檔我們稱爲“jupyter Notebook”,是一種集合文本,代碼和圖形顯示於一身的文檔。比起只有代碼然後註釋的方式更整齊簡單明瞭, 如果你不熟悉‘Jupyter’ ,我建議你點擊頂部菜單欄的「help」的下拉菜單,這有很多關於Jupyter lab的使用參考。

而在這個notebook,將會介紹JetBot的基礎編程知識,以及如何使用python對你的JetBot進行編程。

加載Robot類

準備開始JetBot爲編程前,我們需要導入“Robot”類。這個類允許我們輕鬆控制JetBot的電機! 這包含在“jetbot”的package中。

如果你是一名Python新手,一個package就是一個包含代碼文件的文件夾。
這些代碼文件稱爲modules(模型)

要加載Robot類,請高亮顯示下面的單元格,並按下ctrl + enter或上面的play圖標。 這操作將執行單元格中所包含的代碼

from jetbot import Robot

現在已經加載Robot類,我們可以用一下語句初始化這個instance(實例)

robot = Robot()

 通過編程控制機器人(JetBot)

現在我們已經創建了一個名爲“Robot”的Robot實例,我們可以使用這個實例去控制我們的機器人(JetBot),執行下面的命令可使JetBot按最大速度的30%逆時針轉動。

注意:這個命令將會使機器人發生移動,請保證有足夠的平面給機器人移動,避免跌落損壞,或者乾脆就放在地上

robot.left(speed=0.3)

 

很好,你現在應該見到JetBot在逆時針轉動了!

如果你的機器人沒有向左轉,這意味着其中一個或者兩個電機接線出現問題。嘗試關閉電源。找出不正確轉動的電機,交換其正負極的接線。

提醒:請務必仔細檢查接線,線的拔插也需要在切斷電源的狀態下進行。

現在,執行以下stop方法,就可以使機器人停止。

robot.stop()

 有時可能我們只想在一段時間內移動機器人,爲此,我們可以使用Python的time package。執行以下代碼,加載time

import time

 

這個package定義了sleep函數,它導致代碼執行時停止指定的秒數再運行下一個命令。 嘗試以下命令的組合,使機器人僅向左轉半秒鐘。

robot.left(0.3)
ime.sleep(0.5)
robot.stop()

 非常好。你應該見到JetBot左轉了一會兒,然後停了下來。

這個robot類也有rightforwardbackwards方法。 嘗試創建自己的單元格,參考之前的代碼,讓機器人以50%的速度向前移動一秒鐘。

通過鼠標點擊側邊的高亮條並按下“b”或按notebook上方的工具欄“+”圖標來創建一個新單元格。 完成後,嘗試輸入您認爲會使機器人以50%的速度向前移動一秒鐘的代碼,再執行驗證所輸入的代碼是否正確。

單獨控制電機

上面我們看到了如何使用leftright等命令控制JetBot。但是如果我們想要單獨設置每個電機速度怎麼辦?其實,有兩種方法可以做到這一點。

第一種方法是調用set_motors方法。 例如,左轉一秒,我們可以將左電機速度設置爲30%,將右電機設置爲60%,這將實現不同弧度的轉向方式,如下所示。

robot.set_motors(0.3, 0.6)
time.sleep(1.0)
robot.stop()

 非常好!你應該見到JetBot向左轉。但實際上我們可以使用另一種方式來完成同樣的事情。

Robot類中還有兩個名爲left_motorright_motor的屬性,分別表示左電機和右電機的速度值。 這些屬性是Motor類實例中的,每一個實例都包含一個value值。當這個value發生了變化就會觸發events,重新分配電機的速度值。

所以在這個電機類中,我們附加的一個函數,只要值發生變化就會更新電機命令。因此,爲了完成我們上面所做的完全相同的事情,我們可以執行以下操作

robot.left_motor.value = 0.3
robot.right_motor.value = 0.6
time.sleep(1.0)
robot.left_motor.value = 0.0
robot.right_motor.value = 0.0

 

您應該看到JetBot以相同的方式移動!

使用traitlets庫連接到HTML控件操作電機

接下來介紹一個非常酷的功能,就是在Jupyter Notbooks中可以讓我們在這個頁面上製作一些圖形小按鈕(控件),而使用traitlets可以連接這些小部件進行控制操作。這樣,我們就可以通過網頁的按鈕,去控制我們的小車,這將會變得非常方便好玩。

爲了說明如何編寫程序,我們先創建並顯示兩個用於控制電機的滑塊。

import ipywidgets.widgets as widgets
from IPython.display import display

# create two sliders with range [-1.0, 1.0]
left_slider = widgets.FloatSlider(description='left', min=-1.0, max=1.0, step=0.01, orientation='vertical')
right_slider = widgets.FloatSlider(description='right', min=-1.0, max=1.0, step=0.01, orientation='vertical')

# create a horizontal box container to place the sliders next to eachother
slider_container = widgets.HBox([left_slider, right_slider])

# display the container in this cell's output
display(slider_container)

 

你應該看見兩個垂直的滑塊顯示在上面。

技巧提示:在Jupyter Lab,其實你可以把單元格彈出到其他窗口,例如這兩個滑塊。雖然不在同一窗口,但它仍然連接着這個notebook。具體操作是,鼠標移動到單元格(例如:滑塊)上右鍵,選擇「Creat new view for output」(爲輸出創建新窗口),然後拖動窗口到你滿意的地方即可。

嘗試單擊並上下拖動滑塊,會見到數值的變化。 請注意,當前我們移動滑塊時JetBot的電機是沒有任何反應的,那是因爲我們還沒有將它們連接到電機上! 下面我們將通過使用traitlets包中的link函數來實現。

import traitlets

left_link = traitlets.link((left_slider, 'value'), (robot.left_motor, 'value'))
right_link = traitlets.link((right_slider, 'value'), (robot.right_motor, 'value'))

 

現在嘗試拖動滑塊(要先慢慢地拖動,以免你的JetBot突然衝出邊界造成損壞),您應該看到相應的電機在轉動!

我們上面創建的link函數實際上創建了一個雙向鏈接! 那意味着, 如果我們在其他地方設置電機值,滑塊將會跟着更新! 嘗試執行下面的代碼塊:

robot.forward(0.3)
time.sleep(2.0)
robot.stop()

 

執行上面代碼你應該看見滑塊也發生了改變,響應了電機的速度值。如果我們要斷開此連接,我們可以調用unlink方法逐一斷開連接。

left_link.unlink()
right_link.unlink()

但是如果我們不想要一個雙向的連接,比如說我們只想用滑塊來顯示電機的速度值,而不想用來控制,那麼要實現這種功能,我們就可以使用dlink函數,左邊是來源,右邊是目標,(數據來源於電機,然後要顯示在目標上)。  

left_link = traitlets.dlink((robot.left_motor, 'value'), (left_slider, 'value'))
right_link = traitlets.dlink((robot.right_motor, 'value'), (right_slider, 'value'))

 現在你可以上下移動滑塊,你應該看到機器人的電機是沒有一點反應。但當我們設置電機的速度值並執行的時候,滑塊將會作出響應的數值更新。

將函數添加到事件

另一種使用traitlets的方法是把函數附加到事件中(例如 forward) 。只要對對象發生改變,就會調用函數,並將傳遞改變了的一些信息,例如old 值和new值。

先讓我們創建一些用來控制機器人的按鈕顯示在notebook上。

# create buttons
button_layout = widgets.Layout(width='100px', height='80px', align_self='center')
stop_button = widgets.Button(description='stop', button_style='danger', layout=button_layout)
forward_button = widgets.Button(description='forward',
layout=button_layout)

backward_button = widgets.Button(description='backward', layout=button_layout)
left_button = widgets.Button(description='left', layout=button_layout)
right_button = widgets.Button(description='right', layout=button_layout)

# display buttons
middle_box = widgets.HBox([left_button, stop_button, right_button],
layout=widgets.Layout(align_self='center'))
controls_box = widgets.VBox([forward_button, middle_box, backward_button])
display(controls_box)

 

你應該看到上面顯示的一組機器人控制按鈕,但現在你點擊按鈕並不會做任何事。要做到控制,我們需要創建一些函數附加到按鈕on_click事件的中。

def stop(change):
    robot.stop()

def step_forward(change):
    robot.forward(0.4)
    time.sleep(0.5)
    robot.stop()
    
def step_backward(change):
    robot.backward(0.4)
    time.sleep(0.5)
    robot.stop()

def step_left(change):
    robot.left(0.3)
    time.sleep(0.5)
    robot.stop()

def step_right(change):
    robot.right(0.3)
    time.sleep(0.5)
    robot.stop()

現在我們已經定義了那些函數,讓我們把這些函數附加到每一個按鈕的on_click事件

# link buttons to actions
stop_button.on_click(stop)
forward_button.on_click(step_forward) backward_button.on_click(step_backward) left_button.on_click(step_left)
right_button.on_click(step_right)

執行以上代碼,現在當你點擊每一個按鈕時,你應該看到JetBot都會對應作出移動。

心跳開關

這裏我們顯示怎麼去使用’heartbeat’ package 來停止JetBot的的移動。這是檢測JetBot與瀏覽器的連接是否還存在的簡單方法。可以通過下面顯示的滑塊調整心跳週期(以秒爲單位),如果兩次心跳之內不能在瀏覽器之間往返通信的,那麼心跳的’status‘ (狀態)屬性值將會設置爲dead,一旦連接恢復連接,status屬性將設置爲alive

from jetbot import Heartbeat
heartbeat = Heartbeat()

# this function will be called when heartbeat 'alive' status changes
def handle_heartbeat_status(change):
    if change['new'] == Heartbeat.Status.dead:
        robot.stop()

heartbeat.observe(handle_heartbeat_status, names='status')

period_slider = widgets.FloatSlider(description='period', min=0.001, max=0.5, step=0.01, value=0.5)
traitlets.dlink((period_slider, 'value'), (heartbeat, 'period'))
display(period_slider, heartbeat.pulseout)

嘗試執行以下這段代碼去啓動電機,然後降低滑塊去看看發生了什麼情況。你也可以嘗試關閉你的機器人或者電腦。

robot.left(0.2)

 

總結

這是一個簡單的notebook例子,希望能對你的JetBot編程建立信心。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章