それに直面しましょう、ロボットはかっこいいです。彼らはまた、いつか世界を動かし、うまくいけば、その時に彼らは貧しい柔らかな肉質のクリエイター(別名 ロボット工学開発者 )そして私たちがたくさんで満たされたスペースユートピアを構築するのを手伝ってください。もちろん冗談ですが ある種の 。
問題に少し影響を与えたいという私の野心で、私は 自律ロボット制御理論のコース 昨年、Pythonベースのロボットシミュレーターを構築し、シンプルでモバイルなプログラム可能なロボットで制御理論を実践できるようになりました。
この記事では、Pythonロボットフレームワークを使用して制御ソフトウェアを開発する方法を示し、シミュレートされたロボット用に開発した制御スキームについて説明し、ロボットが環境と相互作用して目標を達成する方法を示し、いくつかの途中で遭遇したロボットプログラミングの基本的な課題。
初心者向けのロボットプログラミングに関するこのチュートリアルに従うには、次の2つの基本的な知識が必要です。
ここに示されているコードのスニペットは、クラスとインターフェイスに依存するシミュレーター全体の一部にすぎないため、コードを直接読み取るには、Pythonと オブジェクト指向プログラミング 。
最後に、このチュートリアルをよりよく理解するのに役立つオプションのトピックは、ステートマシンとは何か、および範囲センサーとエンコーダーがどのように機能するかを知ることです。
すべてのロボット工学の基本的な課題はこれです:環境の本当の状態を知ることは不可能です。ロボット制御ソフトウェアは、センサーから返された測定値に基づいて、現実世界の状態を推測することしかできません。制御信号の生成を通じてのみ、現実世界の状態を変更しようとすることができます。
vim vs emacs vs sublime
したがって、制御設計の最初のステップの1つは、現実世界の抽象化を考え出すことです。 モデル 、センサーの読み取り値を解釈して決定を下すために使用します。実世界がモデルの仮定に従って動作する限り、適切な推測を行い、制御を行うことができます。しかし、現実の世界がこれらの仮定から逸脱するとすぐに、私たちはもはや正しい推測をすることができなくなり、制御が失われます。多くの場合、一度制御が失われると、それを取り戻すことはできません。 (何らかの慈悲深い外力がそれを回復しない限り。)
これが、ロボットプログラミングが非常に難しい主な理由の1つです。ラボでは、器用さ、ナビゲーション、またはチームワークの素晴らしい偉業を実行している最新の研究用ロボットのビデオをよく見ます。「なぜこれが現実の世界で使用されないのですか?」と尋ねたくなります。さて、次にそのようなビデオを見るときは、ラボ環境がどれほど高度に制御されているかを見てください。ほとんどの場合、これらのロボットは、環境条件が内部モデルの狭い範囲内にある限り、これらの印象的なタスクを実行することができます。したがって、ロボット工学の進歩の1つの鍵は、より複雑で、柔軟性があり、堅牢なモデルの開発です。この進歩は、利用可能な計算リソースの制限の影響を受けます。
ロボット工学の進歩の鍵の1つは、より複雑で、柔軟性があり、堅牢なモデルの開発です。[補足:哲学者と心理学者は同様に、生き物もまた、感覚が彼らに伝えていることに対する彼ら自身の内部知覚への依存に苦しんでいることに気付くでしょう。ロボット工学の多くの進歩は、生き物を観察し、予期しない刺激にどのように反応するかを見ることから生まれます。考えてみてください。あなたの世界の内部モデルは何ですか?アリや魚とは違うの? (うまくいけば。)しかし、アリや魚のように、それは世界のいくつかの現実を過度に単純化する可能性があります。世界についてのあなたの仮定が正しくないとき、それはあなたに物事のコントロールを失う危険を冒す可能性があります。これを「危険」と呼ぶこともあります。私たちの小さなロボットが未知の宇宙に対して生き残るのに苦労しているのと同じように、私たち全員もそうです。これはロボット工学者にとって強力な洞察です。]
私が作ったシミュレーターは Python 非常に巧妙に吹き替え 土曜日のリミュレーター 。 v1.0.0はGitHubで見つけることができます 。ベルやホイッスルはあまりありませんが、1つのことを非常にうまく行うように構築されています。それは、移動ロボットの正確なシミュレーションを提供し、意欲的なロボット工学者にロボットソフトウェアプログラミングを実践するためのシンプルなフレームワークを提供することです。実際のロボットで遊ぶ方が常に良いのですが、優れたPythonロボットシミュレーターははるかにアクセスしやすく、始めるのに最適な場所です。
実世界のロボットでは、制御信号を生成するソフトウェア(「コントローラー」)が非常に高速で実行され、複雑な計算を行う必要があります。これは、使用するのに最適なロボットプログラミング言語の選択に影響します。通常、これらの種類のシナリオにはC ++が使用されますが、より単純なロボットアプリケーションでは、Pythonは実行速度と開発およびテストの容易さの間の非常に優れた妥協点です。
私が書いたソフトウェアは、と呼ばれる実際の研究ロボットをシミュレートします ケプリ ただし、さまざまな寸法とセンサーを備えたさまざまな移動ロボットに適合させることができます。実際のロボットの機能と可能な限り類似したシミュレータをプログラムしようとしたので、制御ロジックを最小限のリファクタリングで実際のKheperaロボットにロードでき、シミュレートされたロボットと同じように動作します。実装された特定の機能はKheperaIIIを参照していますが、新しいKheperaIVに簡単に適合させることができます。
言い換えれば、シミュレートされたロボットのプログラミングは、実際のロボットのプログラミングに似ています。 これは、シミュレータがさまざまな制御ソフトウェアアプローチの開発と評価に役立つ場合に重要です。
このチュートリアルでは、v1.0.0に付属するロボット制御ソフトウェアアーキテクチャについて説明します。 土曜日のリミュレーター 、Pythonソースからのスニペットを提供します(わかりやすくするために少し変更を加えています)。ただし、ソースに飛び込んで混乱させることをお勧めします。シミュレーターはフォークされており、Roomba2を含むさまざまな移動ロボットを制御するために使用されています。 アイ・ロボット 。同様に、プロジェクトをフォークして改善してください。
ロボットの制御ロジックは、次のPythonクラス/ファイルに制限されています。
models/supervisor.py
—このクラスは、ロボットの周りのシミュレートされた世界とロボット自体の間の相互作用を担当します。ロボットステートマシンを進化させ、目的の動作を計算するためのコントローラーをトリガーします。models/supervisor_state_machine.py
—このクラスは異なるものを表します 州 センサーの解釈に応じて、ロボットが存在する可能性があります。models/controllers
内のファイルディレクトリ-これらのクラスは、環境の既知の状態が与えられた場合のロボットのさまざまな動作を実装します。特に、ステートマシンに応じて特定のコントローラーが選択されます。ロボットは、人と同じように、人生の目的を必要としています。このロボットを制御するソフトウェアの目標は非常に単純です。それは、あらかじめ決められた目標点に到達しようとします。これは通常、自動運転車からロボット掃除機まで、あらゆる移動ロボットが持つべき基本的な機能です。目標の座標は、ロボットがアクティブ化される前に制御ソフトウェアにプログラムされますが、ロボットの動きを監視する追加のPythonアプリケーションから生成することもできます。たとえば、複数のウェイポイントを運転していると考えてください。
しかし、厄介なことに、ロボットの環境には障害物が散らばっている可能性があります。ロボットは、ゴールに向かう途中で障害物と衝突してはなりません。したがって、ロボットが障害物に遭遇した場合、ロボットが目標に向かって進むことができるように、ロボットはその道を見つける必要があります。
すべてのロボットには、さまざまな機能と制御の問題があります。シミュレートされたプログラム可能なロボットに慣れましょう。
最初に注意することは、このガイドでは、私たちのロボットは 自律移動ロボット 。これは、それが宇宙を自由に動き回ること、そしてそれがそれ自身の制御の下でそうすることを意味します。これは、たとえば、リモートコントロールロボット(自律型ではない)または工場のロボットアーム(モバイルではない)とは対照的です。私たちのロボットは、その目標を達成し、その環境で生き残る方法を自分で理解する必要があります。これは、初心者のロボット工学プログラマーにとって驚くほど難しい課題であることがわかります。
ロボットがその環境を監視するために装備することができる多くの異なる方法があります。これらには、近接センサー、光センサー、バンパー、カメラなど、あらゆるものが含まれます。さらに、ロボットは、ロボット自身が直接観察できない情報をロボットに与える外部センサーと通信する場合があります。
私たちの参照ロボットは装備されています 9つの赤外線センサー —新しいモデルには、8つの赤外線および5つの超音波近接センサーがあります—あらゆる方向の「スカート」に配置されています。ロボットは通常、ロボットの後ろよりも前にあるものを知ることが重要であるため、ロボットの後ろよりも前に面しているセンサーの方が多くなります。
近接センサーに加えて、ロボットには ホイールティッカーのペア そのトラックホイールの動き。これらを使用すると、各ホイールが何回転したかを追跡できます。ホイールを1回転させると2,765ティックになります。逆方向にカウントを逆方向に回し、ティックカウントを増やすのではなく減らします。このチュートリアルで作成するソフトウェアはメートルで表された移動距離を使用するため、このチュートリアルでは特定の数値について心配する必要はありません。後で、簡単なPython関数を使用してティックから計算する方法を説明します。
一部のロボットは脚を動かします。ボールのように転がる人もいます。ヘビのようにずるずる人さえいます。
私たちのロボットは ディファレンシャルドライブ ロボット、つまり2つの車輪で転がります。両方の車輪が同じ速度で回転すると、ロボットは直線的に移動します。車輪が異なる速度で動くと、ロボットは回転します。したがって、このロボットの動きを制御することは、これら2つの車輪のそれぞれが回転する速度を適切に制御することになります。
Sobot Rimulatorでは、ロボットの「コンピューター」と(シミュレートされた)物理的な世界の分離は、ファイルrobot_supervisor_interface.py
によって具体化されます。このファイルは、「実際のロボット」のセンサーやモーターと対話するためのAPI全体を定義します。
read_proximity_sensors()
センサーのネイティブ形式で9つの値の配列を返しますread_wheel_encoders()
開始以降の合計ティックを示す2つの値の配列を返しますset_wheel_drive_rates( v_l, v_r )
2つの値(ラジアン/秒)を取り、ホイールの左右の速度をこれらの2つの値に設定しますこのインターフェースは、センサーからのデータとモーターまたはホイールを動かす可能性を提供するロボットオブジェクトを内部的に使用します。別のロボットを作成する場合は、同じインターフェイスで使用できる別のPythonロボットクラスを提供するだけで、残りのコード(コントローラー、スーパーバイザー、シミュレーター)はそのまま使用できます。
関係する物理法則にあまり注意を払わずに現実の世界で実際のロボットを使用するので、ロボットのシミュレーション方法を無視して、コントローラーソフトウェアのプログラミング方法に直接スキップできます。これはほぼ同じです。現実世界とシミュレーションの間。しかし、興味があれば、ここで簡単に紹介します。
ファイルworld.py
は、ロボットと障害物が内部にある、シミュレートされた世界を表すPythonクラスです。このクラス内のstep関数は、次の方法で単純な世界を進化させます。
最終的には、ロボットブレインソフトウェアの実行を担当するロボットスーパーバイザーを呼び出します。
ステップ関数はループで実行されるため、robot.step_motion()
前のシミュレーションステップでスーパーバイザーによって計算されたホイール速度を使用してロボットを移動します。
# step the simulation through one time interval def step( self ): dt = self.dt # step all the robots for robot in self.robots: # step robot motion robot.step_motion( dt ) # apply physics interactions self.physics.apply_physics() # NOTE: The supervisors must run last to ensure they are observing the 'current' world # step all of the supervisors for supervisor in self.supervisors: supervisor.step( dt ) # increment world time self.world_time += dt
apply_physics()
関数は、ロボット近接センサーの値を内部的に更新して、スーパーバイザーが現在のシミュレーションステップで環境を推定できるようにします。同じ概念がエンコーダーにも当てはまります。
まず、私たちのロボットは非常に単純なモデルになります。それは世界について多くの仮定をします。重要なもののいくつかは次のとおりです。
これらの仮定のほとんどは家のような環境の中で合理的ですが、丸い障害物が存在する可能性があります。私たちの障害物回避ソフトウェアは簡単な実装で、障害物を回避するために障害物の境界をたどります。円形の障害物を回避するための追加のチェックを使用して、ロボットの制御フレームワークを改善する方法について読者にヒントを提供します。
次に、制御ソフトウェアのコアに入り、ロボット内でプログラムする動作について説明します。このフレームワークに追加の動作を追加することができます。読み終えたら、独自のアイデアを試す必要があります。 行動ベースのロボット工学 ソフトウェアは20年以上前に提案されましたが、それでもモバイルロボティクスにとって強力なツールです。例として、2007年に 一連の動作 自動運転車の最初のコンテストであるDARPAアーバンチャレンジで使用されました。
ロボットは動的システムです。ロボットの状態、センサーの読み取り値、および制御信号の影響は常に変化しています。イベントの再生方法を制御するには、次の3つの手順が必要です。
これらのステップは、目標を達成するまで何度も繰り返されます。 1秒間にこれを実行できる回数が多いほど、システムをより細かく制御できます。 Sobot Rimulatorロボットは、これらの手順を1秒あたり20回(20 Hz)繰り返しますが、多くのロボットは、適切な制御を行うために、これを1秒あたり数千回または数百万回実行する必要があります。さまざまなロボットシステムと速度要件に対応するさまざまなロボットプログラミング言語についての前回の紹介を思い出してください。
一般に、ロボットがセンサーで測定を行うたびに、ロボットはこれらの測定値を使用して、世界の状態の内部推定値(たとえば、目標からの距離)を更新します。この状態を 参照 それの価値 望む 状態を(距離については、ゼロにする必要があります)、目的の状態と実際の状態の間の誤差を計算します。この情報がわかれば、新しい制御信号の生成を次の問題に減らすことができます。 エラーを最小限に抑える これにより、最終的にロボットが目標に向かって移動します。
プログラムしたいロボットを制御するには、左輪に信号を送信して回転速度を通知し、別の信号を右輪に送信して通知する必要があります。 それ どれだけ速く曲がるか。これらの信号を呼びましょう v L そして v R 。しかし、常に v L そして v R とても面倒です。 「左のホイールをどれだけ速く回転させ、右のホイールをどれだけ速く回転させたいか」と尋ねる代わりに。 「ロボットをどれだけ速く前進させ、どれだけ速く回転させたり、方向を変えたりしたいのか」と尋ねるのがより自然です。これらのパラメータをベロシティと呼びましょう v および角(回転)速度 ω (「オメガ」を読んでください)。モデル全体のベースにできることがわかりました v そして ω の代わりに v L そして v R 、そしてプログラムされたロボットをどのように動かすかを決定したら、これら2つの値を数学的に変換します。 v L そして v R 実際にロボットの車輪を制御する必要があります。これは、 一輪車モデル 制御の。
これは、supervisor.py
で最終的な変換を実装するPythonコードです。次の場合に注意してください ω が0の場合、両方のホイールが同じ速度で回転します。
# generate and send the correct commands to the robot def _send_robot_commands( self ): # ... v_l, v_r = self._uni_to_diff( v, omega ) self.robot.set_wheel_drive_rates( v_l, v_r ) def _uni_to_diff( self, v, omega ): # v = translational velocity (m/s) # omega = angular velocity (rad/s) R = self.robot_wheel_radius L = self.robot_wheel_base_length v_l = ( (2.0 * v) - (omega*L) ) / (2.0 * R) v_r = ( (2.0 * v) + (omega*L) ) / (2.0 * R) return v_l, v_r
ロボットはセンサーを使用して、環境の状態と自身の状態を推定する必要があります。これらの推定値は決して完全ではありませんが、ロボットはこれらの推定値に基づいてすべての決定を行うため、かなり適切である必要があります。近接センサーとホイールティッカーだけを使用して、次のことを推測する必要があります。
最初の2つのプロパティは、近接センサーの読み取り値によって決定され、かなり簡単です。 API関数read_proximity_sensors()
センサーごとに1つずつ、9つの値の配列を返します。たとえば、7番目の読み取り値は、ロボットの右75度を指すセンサーに対応することが事前にわかっています。
したがって、この値が0.1メートルの距離に対応する読み取り値を示している場合、0.1メートル離れた左75度に障害物があることがわかります。障害物がない場合、センサーは最大範囲0.2メートルの読み取り値を返します。したがって、センサー7で0.2メートルを読み取ると、その方向に実際には障害物がないと想定されます。
赤外線センサーの動作方法(赤外線反射の測定)のため、センサーが返す数値は、検出された実際の距離の非線形変換です。したがって、示された距離を決定するためのPython関数は、これらの読み取り値をメートルに変換する必要があります。これはsupervisor.py
で行われます次のように:
# update the distances indicated by the proximity sensors def _update_proximity_sensor_distances( self ): self.proximity_sensor_distances = [ 0.02-( log(readval/3960.0) )/30.0 for readval in self.robot.read_proximity_sensors() ]
繰り返しになりますが、このPythonロボットフレームワークには特定のセンサーモデルがありますが、現実の世界では、センサーには、非線形値からメートルへの同様の変換関数を提供するソフトウェアが付属しています。
ロボットの位置と方向の決定(まとめて、 ポーズ ロボットプログラミング)はやや難しいです。私たちのロボットは オドメトリ そのポーズを推定します。ここでホイールティッカーが登場します。制御ループの最後の反復以降に各ホイールがどれだけ回転したかを測定することで、ロボットのポーズがどのように変化したかを正確に見積もることができます。 変化が小さい場合のみ 。
これが、車輪を動かすモーターが完全ではない可能性がある実際のロボットで制御ループを頻繁に繰り返すことが重要である理由の1つです。ホイールティッカーを測定するのに時間がかかりすぎると、両方のホイールがかなり多くのことを実行できた可能性があり、どこに到達したかを推定することは不可能になります。
現在のソフトウェアシミュレーターを考えると、オドメトリ計算をコントローラーと同じ周波数である20Hzで実行する余裕があります。ただし、ティッカーの小さな動きをキャッチするために、別のPythonスレッドをより高速に実行することをお勧めします。
以下はsupervisor.py
の完全なオドメトリ機能ですロボットの姿勢推定を更新します。ロボットのポーズは座標x
で構成されていることに注意してくださいおよびy
、および見出しtheta
は、正のX軸からラジアンで測定されます。ポジティブx
東にあり、正ですy
北にあります。したがって、0
の見出しロボットが真東を向いていることを示します。ロボットは常に初期ポーズが(0, 0), 0
であると想定します。
# update the estimated position of the robot using it's wheel encoder readings def _update_odometry( self ): R = self.robot_wheel_radius N = float( self.wheel_encoder_ticks_per_revolution ) # read the wheel encoder values ticks_left, ticks_right = self.robot.read_wheel_encoders() # get the difference in ticks since the last iteration d_ticks_left = ticks_left - self.prev_ticks_left d_ticks_right = ticks_right - self.prev_ticks_right # estimate the wheel movements d_left_wheel = 2*pi*R*( d_ticks_left / N ) d_right_wheel = 2*pi*R*( d_ticks_right / N ) d_center = 0.5 * ( d_left_wheel + d_right_wheel ) # calculate the new pose prev_x, prev_y, prev_theta = self.estimated_pose.scalar_unpack() new_x = prev_x + ( d_center * cos( prev_theta ) ) new_y = prev_y + ( d_center * sin( prev_theta ) ) new_theta = prev_theta + ( ( d_right_wheel - d_left_wheel ) / self.robot_wheel_base_length ) # update the pose estimate with the new values self.estimated_pose.scalar_update( new_x, new_y, new_theta ) # save the current tick count for the next iteration self.prev_ticks_left = ticks_left self.prev_ticks_right = ticks_right
ロボットが現実世界の適切な推定値を生成できるようになったので、この情報を使用して目標を達成しましょう。
関連: ビデオゲームの物理チュートリアル-固体オブジェクトの衝突検出このプログラミングチュートリアルでの小さなロボットの存在の最大の目的は、ゴールポイントに到達することです。では、どうやって車輪を回転させてそこに到達させるのでしょうか?まず、世界観を少し単純化して、障害物がないと仮定しましょう。
これは簡単なタスクになり、Pythonで簡単にプログラムできます。目標に向かって前進すれば、そこにたどり着きます。オドメトリのおかげで、現在の座標と方位がわかります。また、事前にプログラムされているため、目標の座標が何であるかがわかります。したがって、小さな線形代数を使用して、go_to_goal_controller.py
のように、位置からゴールまでのベクトルを決定できます。
# return a go-to-goal heading vector in the robot's reference frame def calculate_gtg_heading_vector( self ): # get the inverse of the robot's pose robot_inv_pos, robot_inv_theta = self.supervisor.estimated_pose().inverse().vector_unpack() # calculate the goal vector in the robot's reference frame goal = self.supervisor.goal() goal = linalg.rotate_and_translate_vector( goal, robot_inv_theta, robot_inv_pos ) return goal
ベクトルを目標に到達させていることに注意してください ロボットの参照フレーム内 、および世界座標ではありません。目標がロボットの参照フレームのX軸上にある場合、それはロボットの真正面にあることを意味します。したがって、X軸からのこのベクトルの角度は、見出しと表示したい見出しの差です。言い換えれば、それは エラー 私たちの現在の状態と私たちが現在の状態になりたいものとの間。したがって、私たちはしたい 回転速度を調整する ω ヘディングとゴールの間の角度が0に向かって変化するようにします。 エラーを最小限に抑えたい:
# calculate the error terms theta_d = atan2( self.gtg_heading_vector[1], self.gtg_heading_vector[0] ) # calculate angular velocity omega = self.kP * theta_d
self.kP
上記のコントローラーのスニペットでは、Python実装はコントロールゲインです。これは、ターンインの速さを決定する係数です。 割合 私たちが直面している目標からどれだけ離れているか。見出しの誤差が0
の場合、回転速度も0
です。ファイルgo_to_goal_controller.py
内の実際のPython関数では、を使用したため、より類似したゲインが表示されます。 PIDコントローラー 単純な比例係数の代わりに。
これで角速度が得られました ω 、前進速度をどのように決定するか v ?一般的な経験則としては、おそらく本能的に知っているでしょう。曲がっていない場合は、全速力で前進できます。曲がる速度が速いほど、速度を落とす必要があります。これは通常、システムを安定させ、モデルの範囲内で動作させるのに役立ちます。したがって、 v の機能です ω 。 go_to_goal_controller.py
で方程式は次のとおりです。
cからc ++を学ぶ
# calculate translational velocity # velocity is v_max when omega is 0, # drops rapidly to zero as |omega| rises v = self.supervisor.v_max() / ( abs( omega ) + 1 )**0.5
この公式を詳しく説明するための提案は、ゼロ速度で目標に到達するために、通常、目標に近づくと減速することを考慮することです。この式はどのように変わりますか?どういうわけかv_max()
の置き換えを含める必要があります距離に比例したもので。 OK、ほぼ1つの制御ループが完了しました。あとは、これら2つの一輪車モデルのパラメーターを差動ホイール速度に変換し、信号をホイールに送信するだけです。これは、障害物のない、go-to-goalコントローラーの下でのロボットの軌道の例です。
ご覧のとおり、目標へのベクトルは、制御計算の基礎となる効果的な参照です。これは「行きたい場所」の内部表現です。後で説明するように、go-to-goalと他の動作の唯一の大きな違いは、目標に向かって進むことは悪い考えである場合があるため、別の参照ベクトルを計算する必要があることです。
その方向に障害物があるときにゴールに向かって進むことは、その好例です。私たちのやり方で物事に真っ向からぶつかる代わりに、ロボットにそれらを回避させる制御法則をプログラムしてみましょう。
シナリオを単純化するために、ゴールポイントを完全に忘れて、次のことを目的とします。 目の前に障害物がない場合は、前に進みます。障害物に遭遇したら、それが私たちの前になくなるまで、障害物から離れます。
したがって、目の前に障害物がない場合は、参照ベクトルを単純に前方に向けます。次に ω ゼロになり、 v 最高速度になります。ただし、近接センサーで障害物を検出したらすぐに、参照ベクトルが障害物から離れた方向を指すようにします。これは原因になります ω 私たちを障害物から遠ざけるために撃ち上げ、 v プロセス中に誤って障害物にぶつからないようにドロップします。
目的の参照ベクトルを生成するための適切な方法は、9つの近接測定値をベクトルに変換し、加重和をとることです。障害物が検出されない場合、ベクトルは対称的に合計され、必要に応じて真っ直ぐ前を指す参照ベクトルになります。ただし、たとえば右側のセンサーが障害物を検出すると、合計に与えるベクトルが小さくなり、結果は左にシフトした参照ベクトルになります。
センサーの配置が異なる一般的なロボットの場合、同じアイデアを適用できますが、センサーがロボットの前後で対称である場合、重みの合計がゼロになる可能性があるため、重みの変更や追加の注意が必要になる場合があります。
これをavoid_obstacles_controller.py
で行うコードは次のとおりです。
# sensor gains (weights) self.sensor_gains = [ 1.0+( (0.4*abs(p.theta)) / pi ) for p in supervisor.proximity_sensor_placements() ] # ... # return an obstacle avoidance vector in the robot's reference frame # also returns vectors to detected obstacles in the robot's reference frame def calculate_ao_heading_vector( self ): # initialize vector obstacle_vectors = [ [ 0.0, 0.0 ] ] * len( self.proximity_sensor_placements ) ao_heading_vector = [ 0.0, 0.0 ] # get the distances indicated by the robot's sensor readings sensor_distances = self.supervisor.proximity_sensor_distances() # calculate the position of detected obstacles and find an avoidance vector robot_pos, robot_theta = self.supervisor.estimated_pose().vector_unpack() for i in range( len( sensor_distances ) ): # calculate the position of the obstacle sensor_pos, sensor_theta = self.proximity_sensor_placements[i].vector_unpack() vector = [ sensor_distances[i], 0.0 ] vector = linalg.rotate_and_translate_vector( vector, sensor_theta, sensor_pos ) obstacle_vectors[i] = vector # store the obstacle vectors in the robot's reference frame # accumulate the heading vector within the robot's reference frame ao_heading_vector = linalg.add( ao_heading_vector, linalg.scale( vector, self.sensor_gains[i] ) ) return ao_heading_vector, obstacle_vectors
結果のao_heading_vector
を使用するロボットが一致を試みるための参照として、これは、ゴールポイントを完全に無視して、障害物回避コントローラーのみを使用してシミュレーションでロボットソフトウェアを実行した結果です。ロボットはぶらぶらと跳ね返りますが、障害物と衝突することはなく、非常に狭いスペースをナビゲートすることさえできます。
これまで、2つの動作(目標達成と障害物回避)を個別に説明してきました。どちらも見事に機能しますが、障害物に満ちた環境で目標を達成するには、それらを組み合わせる必要があります。
私たちが開発するソリューションは、最高にクールなサウンドの指定を持つマシンのクラスにあります ハイブリッドオートマトン 。ハイブリッドオートマトンは、いくつかの異なる動作またはモード、および監視ステートマシンでプログラムされています。監視ステートマシンは、個別の時間(目標が達成されたとき、または環境が突然変化しすぎたとき)にあるモードから別のモードに切り替わりますが、各動作はセンサーとホイールを使用して環境の変化に継続的に反応します。解決策は呼ばれました ハイブリッド それは離散的かつ継続的に進化するからです。
Pythonロボットフレームワークは、ファイルsupervisor_state_machine.py
にステートマシンを実装します。
2つの便利な動作を備えた、単純なロジックはそれ自体を示唆しています。 障害物が検出されない場合は、go-to-goal動作を使用します。障害物が検出されたら、障害物が検出されなくなるまで、障害物回避動作に切り替えます。
しかし、結局のところ、このロジックは多くの問題を引き起こします。このシステムが障害物に遭遇したときに行う傾向があるのは、障害物から離れる方向に向きを変え、離れるとすぐに右に向きを変えて再びぶつかることです。その結果、ロボットを役に立たなくする高速スイッチングの無限ループが発生します。最悪の場合、ロボットは次の動作を切り替える可能性があります すべての反復 制御ループの状態-として知られている状態 ゼノン 調子 。
この問題には複数の解決策があり、より深い知識を探している読者は、たとえば、 DAMNソフトウェアアーキテクチャ 。
単純なシミュレートされたロボットに必要なのは、より簡単なソリューションです。取得するタスクに特化したもう1つの動作です。 周り 障害物と反対側に到達します。
アイデアは次のとおりです。障害物に遭遇したら、障害物に最も近い2つのセンサーの読み取り値を取得し、それらを使用して障害物の表面を推定します。次に、参照ベクトルをこのサーフェスに平行になるように設定するだけです。 A)障害物が私たちとゴールの間になくなり、B)開始時よりもゴールに近づくまで、この壁をたどり続けます。そうすれば、障害物を適切にナビゲートしたことを確認できます。
情報が限られているため、障害物を左に回るのが速いのか、右に回るのが速いのかは定かではありません。決心するために、私たちはすぐに目標に近づく方向を選択します。つまり、どちらの方法であるかを理解するには、ゴールへの移動動作と障害物回避動作の参照ベクトル、および可能なフォローウォール参照ベクトルの両方を知る必要があります。これは、最終決定がどのように行われるかを示しています(この場合、ロボットは左に移動することを選択します)。
フォローウォール参照ベクトルの決定は、障害物回避または目標達成参照ベクトルよりも少し複雑であることがわかります。 follow_wall_controller.py
のPythonコードを見てくださいそれがどのように行われるかを確認します。
最終的な制御設計では、障害物とのほとんどすべての遭遇に対してフォローウォール動作を使用します。ただし、ロボットが狭い場所にいて、危険なほど衝突の近くにいる場合は、より安全な距離になるまで純粋な障害物回避モードに切り替わり、その後、フォローウォールに戻ります。障害物の交渉が成功すると、ロボットはゴールに切り替わります。これが最終的な状態図で、supervisor_state_machine.py
内にプログラムされています。
これは、この制御スキームを使用して混雑した環境をうまくナビゲートするロボットです。
実装を試みることができるステートマシンの追加機能は、障害物の境界を最後までたどる代わりに、できるだけ早くゴールに切り替えることによって円形の障害物を回避する方法です(円形のオブジェクトには存在しません! )
SobotRimulatorに付属する制御スキームは非常に細かく調整されています。ここで1つの小さな変数と、そこにある別の方程式を微調整して、満足のいく方法で機能させるのに何時間もかかりました。ロボット工学のプログラミングには、多くの場合、昔ながらの試行錯誤が伴います。ロボットは非常に複雑であり、ロボットシミュレーター環境でロボットを最適に動作させるための近道はほとんどありません。少なくとも、完全な機械学習が不足しているわけではありませんが、それは他のすべてのワームの可能性です。
ロボット工学は、多くの場合、昔ながらの試行錯誤を伴います。Sobot Rimulatorの制御変数を試して、結果を観察して解釈することをお勧めします。以下の変更はすべて、シミュレートされたロボットの動作に大きな影響を及ぼします。
kP
各コントローラーでsupervisor_state_machine.py
で使用される切り替え条件この点に到達するために多くの作業を行いましたが、このロボットはかなり賢いようです。それでも、いくつかのランダム化されたマップを介してSobot Rimulatorを実行する場合、このロボットが処理できないマップを見つけるまでにそう長くはかかりません。時々それはタイトなコーナーに直接自分自身を運転し、衝突します。時々それは障害物の反対側で際限なく前後に振動します。時折、それは合法的に投獄され、ゴールへの道はあり得ません。すべてのテストと調整を行った後、使用しているモデルが適切ではないという結論に達する必要があり、設計を変更するか、機能を追加する必要があります。
移動ロボットの世界では、私たちの小さなロボットの「頭脳」は、スペクトルのより単純な端にあります。発生する障害ケースの多くは、より高度なソフトウェアをミックスに追加することで克服できます。より高度なロボットは、次のような技術を利用します マッピング 、それがどこにあったかを覚えて、同じことを何度も試みるのを避けるため。 経験則 、完全な決定が見つからない場合に受け入れ可能な決定を生成するため。そして 機械学習 、ロボットの動作を制御するさまざまな制御パラメータをより完全に調整します。
ロボットはすでに私たちのために多くのことを行っており、将来的にはさらに多くのことを行う予定です。基本的なロボットプログラミングでさえ、忍耐力を必要とする難しい研究分野ですが、魅力的で非常にやりがいのある分野でもあります。
このチュートリアルでは、高級プログラミング言語Pythonを使用してロボット用のリアクティブ制御ソフトウェアを開発する方法を学びました。ただし、ここでプロトタイプを作成したものと同様のPythonロボットフレームワークを使用して、すばやく学習およびテストできる、より高度な概念が多数あります。検討していただければ幸いです 参加する 来るものの形で!
了承: 感謝したい 博士Magnus Egerstedt そして ジャン=ピエール・ド・ラ・クロワ ジョージア工科大学のこれらすべてを教えてくれたこと、そしてSobotRimulatorでの私の仕事に対する彼らの熱意に感謝します。
関連: OpenCVチュートリアル:iOSでMSERを使用したリアルタイムのオブジェクト検出ロボットは、電子ボードまたはCPUに接続され、それらによって制御されるセンサーと機械部品を備えた機械です。彼らは情報を処理し、物理的な世界に変更を適用します。ロボットはほとんど自律的であり、日常生活から非常に危険な作業まで、あらゆる面で人間に取って代わったり、人間を助けたりします。
ロボットは、工場や農場で重い作業や反復的な作業を行うために使用されます。惑星や海を探索したり、家を掃除したり、高齢者を助けたりするために使用されます。研究者やエンジニアは、災害状況、医療分析、および手術でロボットを使用しようとしています。自動運転車もロボットです!
ロボットの作成には、部品の機械的なレイアウト、センサーとドライバーの設計、ロボットのソフトウェアの開発など、複数のステップが必要です。通常、未加工のボディは工場に組み込まれ、ソフトウェアは作業中のプロトタイプの最初のバッチで開発およびテストされます。
関係する3つのステップがあります。まず、既製のドライバーを使用してモーターとセンサーを実行します。次に、ロボットを動かしてセンサーを読み取ることができるように、基本的な構成要素を開発します。最後に、それを使用して、スマートで複雑なソフトウェアルーチンを開発し、目的の動作を作成します。
ロボット工学で使用する場合は、C ++とPythonの2つの主要なプログラミング言語が最適です。それぞれに長所と短所があるため、一緒に使用されることがよくあります。 C ++は、制御ループ、画像処理、および低レベルハードウェアのインターフェイスに使用されます。 Pythonは、高レベルの動作を処理し、テストまたは概念実証を迅速に開発するために使用されます。
ロボットでJava仮想マシンを実行できると仮定すると、ソケットまたはRPCを使用して、Javaコードをモーターおよびセンサードライバーとインターフェイスさせることができます。 Javaでデバイスドライバーを直接作成することは、C ++などの他の言語よりも難しい場合があるため、高レベルの動作の開発に集中することをお勧めします。
ロボット工学は、ロボットシステム全体の設計と統合に焦点を当てた幅広い工学分野です。したがって、特定のロボットの要件と目標を達成するために、各分野に特化したエンジニアと対話し、機械、電子、ソフトウェア、および制御システムの知識が必要です。
どちらの分野も、人間を支援または置き換えるためのソフトウェアを開発していますが、RPAは、電子メールの送信、領収書の提出、Webサイトの閲覧など、通常はコンピューターの前で人間が行うタスクを対象としています。代わりに、ロボット工学は、清掃、運転、建築、製造などの実世界でのタスクを実行します。
最初の移動ロボットは、1966年にチャールズローゼンとニルスニルソンが率いるチームによってスタンフォード研究所で作成されました。 24ビットCPUと196KBのRAMのみを使用して、障害物を回避しながらオフィス内を自律的に移動することができました。動いている間に揺れたので、彼らの作成者はそれをShakeyと呼びました。