使命服務(Missions service)

前言大綱

Mission Service 是 API 客戶端使用行為樹為 Spot 指定高階自主行為的一種方式。

行為樹Behavior trees

行為樹允許客戶端指定像執行一系列任務一樣簡單的行為以及更複雜的行為,例如在電池電量低時將機器人返回基地。行為樹通常用於 AI 來定義視頻遊戲中非玩家角色的行為。

行為樹由控制樹解析方式的結構節點和執行某些動作的動作節點組成,例如使機器人從一個地方導航到另一個地方或激活外掛載荷。

每個節點可能有零個或多個子節點。每個孩子都可以被認為是一個獨特的行為樹,也稱為子樹。例如,您可以擁有一個行為樹來啟動機器人,然後讓機器人站起來。然後可以將該行為樹作為另一個節點的子節點插入。

行為樹黑板

某些動作節點依賴於可能由樹中的其他節點動態創建的狀態。狀態被寫入黑板和從黑板讀取,這是一種允許節點在行為樹中共享狀態的消息傳遞功能。

例如,BosdynRobotState 動作節點將從機器人中讀取狀態,包括電機電源是否打開,並使用狀態值創建黑板條目。BosdynRobotState 的孩子(及其所有孩子的孩子)可以讀取該信息。黑板中的變量被限定為只有定義變量的節點的子節點才能讀取或寫入該變量。

如果節點A定義了一個變量“MyVariable”並且有一個子節點B,那麼節點B也可以在黑板中定義“MyVariable”。節點 B 及其子節點將只能與節點 B 的“MyVariable”版本進行交互。

行為樹節點類型

行為樹由結構節點和動作節點的層次結構組成。

結構節點控制在任務執行中訪問節點的順序或是否完全訪問節點。

結構節點

節點 描述
Sequence 指定機器人要執行的操作列表。序列可以嵌套或與其他結構節點類型組合。
Selector 選擇器按順序運行它們的子節點,直到其中一個成功。
Repeat 循環子樹一定次數。
Retry 循環子樹直到它成功。
ForDuration 循環子樹直到它失敗。
SimpleParallel 同時執行兩個節點或子樹。

動作節點

動作節點採取一些動作,例如讓機器人做某事或觸發外掛載荷做某事。
節點 描述
Condition 表達一個二元比較運算,如果條件為真則返回真,否則返回假。
BosdynRobotState 查詢機器人服務名稱、主機、子節點、電池、通訊、急停、運動等機器人系統狀態。
BosdynRobotCommand 向機器人發出命令以停止、凍結、自我矯正、坐下、站立、安全關閉電源、前往目的地或以某種速度行走。
BosdynPowerRequest 打開或關閉機器人電源。
BosdynNavigateTo 自主移動機器人。包括用於控制屬性的參數,例如速度。
BosdynGraphNavState 請求任務服務將圖形導航狀態保存到黑板,在那裡它可以被 Condition 節點訪問。
RemoteGrpc 循環子樹一定次數。
Sleep 循環子樹直到它成功。
Prompt 循環子樹直到它失敗。
PTZ 同時執行兩個節點或子樹。
SpotCamStoreMedia 同時執行兩個節點或子樹。
Dock 同時執行兩個節點或子樹。
DefineBlackboard 同時執行兩個節點或子樹。
SetBlackboard 同時執行兩個節點或子樹。
ConstantResult 同時執行兩個節點或子樹。

創建行為樹

以下部分提供了直接使用 Python 編譯的協議緩衝區來構建我們的行為樹表示的 Python 代碼,也稱為“任務”。

上述所有節點類型都有相應的協議緩衝區消息定義。每一個都必須由一個通用的 Node 消息套件。例如,這是一個名為“Just power on”的單節點任務,它將為機器人供電:

...
power_on = nodes_pb2.BosdynPowerRequest(service_name='power',

                                    host='localhost',
                                    request=power_pb2.PowerCommandRequest.REQUEST_ON)

power_on_mission = nodes_pb2.Node(name='Just power on')
power_on_mission.impl.Pack(power_on)
...

簡單序列範例

下面的行為樹圖描繪了一個簡單的線性動作序列。
以下 Python 代碼片段使用 BosdynRobotCommand 操作節點以及之前的“Just power on”任務實現了上面顯示的簡單線性行為樹。
...
request = basic_command_pb2.StandCommand.Request()
mobility_command = mobility_command_pb2.MobilityCommand.Request(stand_request=request)
robot_command = robot_command_pb2.RobotCommand(mobility_command=mobility_command)
stand = nodes_pb2.BosdynRobotCommand(service_name='robot-command',

                                 host='localhost',
                                 command=robot_command)

stand_mission = nodes_pb2.Node(name='Just stand')
stand_mission.impl.Pack(stand)

request = basic_command_pb2.SitCommand.Request() \
mobility_command = mobility_command_pb2.MobilityCommand.Request(sit_request=request) \
robot_command = robot_command_pb2.RobotCommand(mobility_command=mobility_command) \
sit = nodes_pb2.BosdynRobotCommand(service_name='robot-command', \
                               host='localhost', command=robot_command)

sit_mission = nodes_pb2.Node(name='Just sit') \
sit_mission.impl.Pack(sit)

sequence = nodes_pb2.Sequence() \
sequence.children.add().CopyFrom(power_on_mission) \
sequence.children.add().CopyFrom(stand_mission) \
sequence.children.add().CopyFrom(sit_mission)

mission = nodes_pb2.Node(name='Power on then stand then sit') \
mission.impl.Pack(sequence)

...

更複雜的行為樹示例

下面的行為樹圖顯示了一個任務的結構,該任務重複執行任務,直到完成指定的迭代次數或直到機器人電池達到低電量閾值。

在這個例子中,機器人站起來,然後在兩個位置之間進行 10 次行走演示,最終到達標記為“演示結束demo end”的某個位置。 如果在任何時候電池電量低於某個閾值,或者機器人成功進入“演示結束demo end”位置,機器人將前往標記為“家Home”的位置並關閉電源。

樹的根是一個序列,它使機器人站立,然後運行選擇器節點,然後執行“回家並關閉電源go home and power off”序列。

下面的代碼展示瞭如何設置任務,假設“Repeat 10”和“Goto demo end”的內部序列包含在battery_high_mission中,而“Stand”、“Goto Home”和“Power off”的序列是 包含在battery_low_mission 中。

首先我們設置將查詢機器人狀態的節點並將其插入黑板。請注意,state_name 設置為“state”。我們將在 Condition 節點中使用該字符串。
...
robot_state = nodes_pb2.BosdynRobotState(service_name='robot-state',
                                     host='localhost',
                                     state_name='state')

現在我們告訴 Condition 節點從 state 中讀取 power_state.locomotion_charge_percentage.value,看看它是否小於或等於 20。

is_battery_low = nodes_pb2.Condition()
is_battery_low.lhs.var.name = 'state.power_state.locomotion_charge_percentage.value'
is_battery_low.lhs.var.type = util_pb2.VariableDeclaration.TYPE_FLOAT
is_battery_low.operation = nodes_pb2.Condition.COMPARE_LE
is_battery_low.rhs.const.float_value = 20

is_battery_low_mission = nodes_pb2.Node()
is_battery_low_mission.impl.Pack(is_battery_low)

Condition 節點必須是 BosdynRobotState 節點的子節點,才能從黑板上讀取狀態。

robot_state.child.CopyFrom(is_battery_low_mission)

robot_state_mission = nodes_pb2.Node()
robot_state_mission.impl.Pack(robot_state)
Selector 設置為“始終重新啟動always restart”,以便它會在每次 tick 時執行 BosdynRobotState 及其子 "Condition節點"。這意味著行為樹正在從機器人讀取新狀態並根據最新值檢查電池百分比。
selector = nodes_pb2.Selector(always_restart=True)
selector.children.add().CopyFrom(robot_state_mission)
selector.children.add().CopyFrom(battery_high_mission)
selector_mission = nodes_pb2.Node()
selector_mission.impl.Pack(selector)

sequence = nodes_pb2.Sequence()
sequence.children.add().CopyFrom(stand_mission)
sequence.children.add().CopyFrom(selector_mission)
sequence.children.add().CopyFrom(battery_low_mission)

mission = nodes_pb2.Node(name='Do A while battery % > 20, otherwise do B')
mission.impl.Pack(sequence)
...

MissionService RPCs

MissionService 為客戶端提供 RPC 以加載和播放使用 GraphNavRecordingService 記錄的任務。

RPC 描述
LoadMission 加載任務以稍後運行。
PlayMission 開始執行加載或暫停的任務。
PauseMission 暫停任務執行。
RestartMission 從頭開始執行加載的任務。
GetState 獲取任務狀態。
GetInfo 獲取有關任務的靜態信息。
GetMission 下載任務,因為它已上傳到服務。
AnswerQuestion 指定任務提出的問題的答案。

RemoteMissionService RPCs

遠程任務服務RemoteMissionService  RPC 由 MissionService 調用以與機器人外掛載荷進行通信。任務服務使用這些 RPC 與遠程任務服務進行通信。

RPC 描述
EstablishSession 每個節點在任務加載時調用一次。
Tick 每次滴答 RemoteGrpc 節點時調用此方法。
Stop 每次 RemoteGrpc 節點在上一個循環中被滴答,但在本次循環中沒有被滴答時調用此方法。
TeardownSession 告訴服務它可以忘記與給定會話相關的任何數據。

參考資料

特色、摘要,Feature、Summary:

關鍵字、標籤,Keyword、Tag:

留言

這個網誌中的熱門文章

Ubuntu 常用指令、分類與簡介

iptables的觀念與使用

網路設定必要參數IP、netmask(遮罩)、Gateway(閘道)、DNS

了解、分析登錄檔 - log

Python 與SQLite 資料庫

Blogger文章排版範本

Pandas 模組

如何撰寫Shell Script

查詢指令或設定 -Linux 線上手冊 - man

下載網頁使用 requests 模組