Udacity机器人软件工程师课程笔记(四)-样本搜索和找回-基于漫游者号模拟器-决策树
7.做出決策
我們已經建立了感知步驟Perception.py,接下來要構建決策函數decision.py 。
我們利用一個基礎的人工智能模型——決策樹模型。其結構如下:
由于我們采用一個非常簡單的模型,所以我們只需要編碼一系列可能的場景與每種場景相關的決策。
我們在這個項目中會接收很多信息,比如漫游者號當前狀態的信息,比如當前位置,速度、方向、轉向角等等。我們只需要給出相應的條件,然后給出如何進行下一步即可。
現在定義一個名為RoverState() 的Python類,它可以跟蹤漫游者號的變化狀態,下面是默認值:
class RoverState():def __init__(self):self.start_time = None # 記錄導航開始的時間self.total_time = None # 記錄導航的總持續時間self.img = None # 當前的相機圖像self.pos = None # 當前的位置 (x, y)self.yaw = None # 當前的偏航角self.pitch = None # 當前的俯仰角self.roll = None # 當前的旋轉角self.vel = None # 當前的速度self.steer = 0 # 當前的轉向角self.throttle = 0 # 當前的油門值self.brake = 0 # 當前的制動值self.nav_angles = None # 可導航地形像素的角度self.nav_dists = None # 可導航地形像素的距離self.ground_truth = ground_truth_3d # 真實的世界地圖self.mode = 'forward' # 當前模式 (可以是前進或者停止)self.throttle_set = 0.2 # 加速時的節流設定self.brake_set = 10 # 剎車時的剎車設定# 下面的stop_forward和go_forward字段表示可導航地形像素的總數。# 這是一種非常粗糙的形式來表示漫游者號當何時可以繼續前進或者何時應該停止。# 可以隨意添加新字段或修改這些字段。self.stop_forward = 50 # T啟動停止時的閾值self.go_forward = 500 # 再次前進的閾值self.max_vel = 2 # 最大速度 (m/s)# 感知步驟的圖像輸入# 更新此圖像以顯示中間分析步驟# 在自主模式下的屏幕上self.vision_image = np.zeros((160, 320, 3), dtype=np.float) # 世界地圖# 使用可導航的位置更新此圖像# 障礙物和巖石樣本self.worldmap = np.zeros((200, 200, 3), dtype=np.float) self.samples_pos = None # 存儲實際樣本的位置self.samples_found = 0 # 計算找到的樣本數self.near_sample = False # 如果在巖石樣本范圍內self.pick_up = False # 設置為True來拾取樣本
然后創建此類的實例:
Rover= RoverState()
我們可以使用Rover對每組新的遙測值進行更新。例如
Rover.vel = new_velocity_from_telemetry
Rover.yaw = new_yaw_from_telemetry
現在我們可以使用條件語句創建一個類似上圖所示的決策樹,以根據當前的遙測來分析決定下一步做什么,例如
if Rover.vel >= Rover.max_vel:Rover.throttle = 0
else:
Rover.throttle = Rover.throttle_set
以下給出可行的漫游者號使用決策樹的決策方案,可將其保存為decision.py
import numpy as np# 命令基于perception_step()函數的輸出
def decision_step(Rover):if Rover.nav_angles is not None:# 檢查 Rover.mode 狀態if Rover.mode == 'forward':# 檢查可導航地形的范圍if len(Rover.nav_angles) >= Rover.stop_forward: # 如果為forward模式,可導航地圖是好的,速度如果低于最大值,則加速if Rover.vel < Rover.max_vel:# 設置油門值Rover.throttle = Rover.throttle_setelse:Rover.throttle = 0Rover.brake = 0# 將轉向設置為平均夾角,范圍為 +/- 15Rover.steer = np.clip(np.mean(Rover.nav_angles * 180/np.pi), -15, 15)# 如果缺少地形圖,則設置為停止模式elif len(Rover.nav_angles) < Rover.stop_forward:# 設置到停止模式并剎車Rover.throttle = 0# 設置制動值Rover.brake = Rover.brake_setRover.steer = 0Rover.mode = 'stop'# 如果我們已經處于“停止”模式,那么做出不同的決定elif Rover.mode == 'stop':# 如果我們處于停止模式但仍然繼續制動if Rover.vel > 0.2:Rover.throttle = 0Rover.brake = Rover.brake_setRover.steer = 0# 如果我們沒有移動(vel <0.2),那就做點別的elif Rover.vel <= 0.2:# 現在為停止狀態,依靠視覺數據,判斷是否有前進的道路if len(Rover.nav_angles) < Rover.go_forward:Rover.throttle = 0# 松開制動器以便轉動Rover.brake = 0# 轉彎范圍為+/- 15度,當停止時,下一條線將引起4輪轉向Rover.steer = -15#如果停下來但看到前面有足夠的可導航地形,那就啟動if len(Rover.nav_angles) >= Rover.go_forward:# 將油門設置回存儲值Rover.throttle = Rover.throttle_setRover.brake = 0# 將轉向設置為平均角度Rover.steer = np.clip(np.mean(Rover.nav_angles * 180/np.pi), -15, 15)Rover.mode = 'forward'else:Rover.throttle = Rover.throttle_setRover.steer = 0Rover.brake = 0# 在可拾取巖石的狀態下發送拾取命if Rover.near_sample and Rover.vel == 0 and not Rover.picking_up:Rover.send_pickup = Truereturn Rover
8.控制漫游者號
我們使用名為send_control() 的函數,來控制漫游者號并將圖像顯示到模擬器屏幕。
def send_control(commands, image_string1, image_string2):# 定義需要發送給漫游者號的命令data={'throttle': commands[0].__str__(),'brake': commands[1].__str__(),'steering_angle': commands[2].__str__(),'inset_image1': image_string1,'inset_image2': image_string2,}# 通過socketIO服務器發送命令sio.emit("data", data, skip_sid=True)
參數commands是一個包含油門、剎車和轉向值的元組,其儲存在Rover.throttle, Rover.brake 和 Rover.steer中
其他參數被稱為image_string1與image_string2,它們包含Rover.vision_image和Rover.worldmap轉換,同時在自主導航模式將base64字符串的圖像呈現在屏幕上。
該send_control() 函數創建一個帶有所有這些值的字典data,然后將該字典傳遞給該 sio.emit() 函數,以將命令和圖像發送到漫游者號。不需要擔心這個被究竟是如何實現的,只是一旦已經更新Rover.throttle,Rover.brake和Rover.steer,commands輸入send_control()將被更新,并在每次更新的時候兩個顯示圖像:Rover.vision_image和Rover.worldmap 將被更新。
總結
以上是生活随笔為你收集整理的Udacity机器人软件工程师课程笔记(四)-样本搜索和找回-基于漫游者号模拟器-决策树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Udacity机器人软件工程师课程笔记(
- 下一篇: Udacity机器人软件工程师课程笔记(