# smach Tutorials Web Site Link --- - [smach Tutorials](http://wiki.ros.org/smach/Tutorials) How to install --- - smachライブラリのインストール $ sudo apt-get install ros-kinetic-executive-smach - smachの可視化ツールのインストール $ sudo apt-get install ros-kinetic-executive-smach-visualization $ sudo add-apt-repository ppa:nilarimogard/webupd8 $ sudo apt-get update $ sudo apt-get install python-wxgtk2.8 Creating a State --- - 基本 - smach.Stateクラスを継承したクラスを作成 - 作成したクラス内にexecuteメソッドを実装 - コード例 ```python= class HotWater(smach.State): def __init__(self, outcomes=['cold', 'with_leaf', 'nothing']): # このstateの初期化処理を書く # 他の処理が割り込んではいけない self.time_passed = false self.add_leaf = false def execute(self, userdate): # このstateで行う処理を書く # 他のstateへ遷移する際に、返り値としてoutcomesを返す。outcomesはこのstateでの処理がどのように終わったかを記述する。 if self.time_passed: return 'cold' elif self.add_leaf: return 'with_leaf' else:    # 何かしらを返さないとNoneが返り値となり、初期化の際にoutcomesにNoneを入れてない場合はエラーが吐かれるので注意。 return 'nothing' ``` Adding states to a state machine and run a state machine --- - コード例 ```python= # このコードの前に前節のようにして、smach.Stateクラスを継承したWaterクラスとHotWaterクラスを作成したものとする。 # state machineの作成。引数としてstate machineの想定される結果を渡す。 sm_drink = smach.StateMachine(outcomes=['tea', 'coke', 'coffee']) # 以下、state machineにそれぞれのstateを追加する。 # 最初に追加したものが状態遷移の最初のstateとなる。 # それぞれのstateは慣例として、全て大文字で記述する。 with sm_drink: smach.StateMachine.add('HOTWATER', HotWater(), transitions={'cold':'WATER', 'with_leaf':'tea', 'nothing':'HOTWATER'}) smach.StateMachine.add('WATER', Water(), transitions={'hot':'HotWater', 'nothing':'WATER'}) # state machineの起動 sm_drink.execute() ``` - 上記のstate machineを可視化したもの ![](https://i.imgur.com/7fUXGXn.png) How to view the running state machine --- ```python= import smach_ros ``` をした上で、可視化したいstate machine(ここではsm)を作成した後、 ```python= sis = smach_ros.IntrospectionServer('server_name', sm, '/SM_ROOT') sis.start() sm.execute() # state machineの起動 rospy.spin() # ctl-cが押されるまで待機 sis.stop() # 可視化終了 ``` と記述すれば、 ``` $ rosrun smach_viewer smach_viewer.py ``` を別ターミナルで実行することでstate machineの様子を可視化できる。 Let a state have userdata --- - それぞれのstateにinputあるいはoutputデータを持たせることができ、それをuserdataと呼ぶ。 - 下記のコード例のように、stateの初期化時にinput_keys, output_keysを引数として渡す。 - input_keysは読み込み専用である点に注意 ```python= class Foo(smach.State): def __init__(self, outcomes=['outcome1', 'outcome2'], input_keys=['foo_input'], output_keys=['foo_output']) def execute(self, userdata): # Do something with userdata if userdata.foo_input == 1: return 'outcome1' else: userdata.foo_output = 3 return 'outcome2' ``` Connecting user data in a state machine --- ```python= # state machineも同様にuserdataを持てる sm_top = smach.StateMachine(outcomes=['outcome4','outcome5'], input_keys=['sm_input'], output_keys=['sm_output']) with sm_top: smach.StateMachine.add('FOO', Foo(), transitions={'outcome1':'BAR', 'outcome2':'outcome4'}, remapping={'foo_input':'sm_input', 'foo_output':'sm_data'}) smach.StateMachine.add('BAR', Bar(), transitions={'outcome2':'FOO'}, remapping={'bar_input':'sm_data', 'bar_output1':'sm_output'}) ``` - state間でデータを受け渡すときの例 ```python= FOO:remapping={'foo_output':'sm_user_data'} BAR:remapping={'bar_input':'sm_user_data'} ``` - sm_user_dataという変数を介してデータを受け渡す - これは他のstateのinput_keys, output_keysに直接アクセスできないため、state machineのuserdataを介して受け渡しを行っている - sm_user_dataは自動的にstate machineのuserdataとなる - state, state machine間でデータを受け渡すときの例 - stateからstate machineへ ```python= BAR:remapping={'bar_output':'sm_output'} ``` - state machineからstateへ ```python= FOO:remapping={'foo_input':'sm_input'} ``` - state間と異なり、state machineのuserdataへのアクセスは直接行える - また、userdataの宣言はstateもしくはstate_machineの初期化時でなくても行うことができる ```python= sm = smach.StateMachine(outcomes=['outcome4']) sm.userdata.sm_counter = 0 ``` Creating a hierarchical State Machine --- - state machineもstateと同じように扱うことができ、下記のように階層的な構造をもつstate machineを作ることも可能である。 ```python= # Create the top level SMACH state machine sm_top = smach.StateMachine(outcomes=['outcome5']) with sm_top: smach.StateMachine.add('BAS', Bas(),   transitions={'outcome3':'SUB'}) # Create the sub state machine sm_sub = smach.StateMachine(outcomes=['outcome4']) with sm_sub: smach.StateMachine.add('FOO', Foo(),   transitions={'outcome1':'BAR', 'outcome2':'outcome4'}) smach.StateMachine.add('BAR', Bar(), transitions={'outcome1':'FOO'}) # Add a state machine to the other state machine like a state smach.StateMachine.add('SUB', sm_sub, transitions={'outcome4':'outcome5'}) ``` ![](https://i.imgur.com/k9xLd2L.png)