ROSを使用したCRANE+の動かし方 その7

こんにちは!長谷川です。
前回はCRANE+の全ての関節を同時に、かつ自動で動かす方法について説明しましたが、今回はその時出てきたソースコードの解説を通して、ROSのプログラムの書き方について説明したいと思います。

プログラムについてのチュートリアル

ここにC++でのプログラムの書き方が載っていまして、ここ
に実行の仕方が載っています。以上二つに基づいて解説を進めていきます。

ROSで使えるプログラミング言語

ROSでは、PythonとC++の二種類の言語を使うことができます。これは便利なことに思えますが、実はいろいろとめんどくさいです。例えば、C++で書かれたノードがトピックを介してPythonで書かれたノードにデータを送るとしましょう。もしトピックのデータ型を、ノードを起動するプログラム内でfloatとして定義できるとしたら、そのデータ型をPythonにそのまま引き継げるでしょうか?言語が違えばデータ型の定義も違うので、難しいことになります。そこで、トピックのデータ型などは言語によらず共通に定義されています。今の例でいえば、トピックのデータ型をstd_msgs::Float64と定義します。std_msgs::Float64はROS内でPythonでも使えるデータ型になっているので、データを正確に受け渡しできるというわけです。

プログラムの解読

それでは、前回のプログラムを解読していきましょう。
[cpp firstline=”1″]#include "ros/ros.h"[/cpp]
お馴染みのヘッダーのインクルードですが、ros/ros.hをインクルードすると、ROS のシステムでよく用いる部分を使うのに必要なヘッダーをすべてインクルードできます。
[cpp firstline=”6″]#include "std_msgs/Float64.h"[/cpp]
このヘッダーのインクルードにより、先ほど出てきたデータ型、std_msgs::Float64が使えるようになります。今回、CRANE+を動かすために用意したトピックのデータ型はすべてこれなので、インクルードが必要です。
[cpp firstline=”8″]#include <sstream>[/cpp]
文字列ストリームを使うためのヘッダーです。今回は使わないのでいらないのですが、チュートリアル見ながらプログラムを作っていたときに入れてしまいました。
[cpp firstline=”13″]ros::init(argc, argv, "turtlebot_arm");[/cpp]
ROSの初期化をして、このプログラムで起動するノードの名前を指定します。今回は「turtlebot_arm」です。名前には、/を含んではいけないみたいです。
[cpp firstline=”15″]ros::NodeHandle n;[/cpp]
ノードへのハンドラなるものを作成します。ここではnという名前で作成しました。ハンドラとは名前空間を管理するものです。ちなみに、ここでノードの初期化が行われ、最後のハンドラが破棄されるとノードの終了処理に入ります。
[cpp firstline=”18″]
ros::Publisher joint1_pub = n.advertise<std_msgs::Float64>("/tilt1_controller/command", 1000);
[/cpp]
ここで、std_msgs::Float64型のトピック/tilt1_controller/commandに、データの配信を行うことを宣言します。テンプレートを使った宣言です。1000というのは、蓄えることのできるデータの最大数です。トピックにデータが配信されると、そのトピックが購読されるまでデータが保持されなければなりませんが、トピックが購読される前に次の配信が行われてしまう可能性があります。この時、前のデータがすぐ消えないように、キューで値を保持します。このキューの個数が1000個ということです。joint1_pubというros::Publisher型インスタンス(メモリを確保したクラス)が定義されていますが、これは後ですぐに使います。
[cpp firstline=”23″]std_msgs::Float64 pos1;[/cpp]
std_msgs::Float64型のインスタンスpos1を宣言します。これを経由してデータの配信を行います。
[cpp firstline=”29″]pos1.data = 0.0;[/cpp]
pos1のメンバ変数dataに、0.0という値を代入します。
[cpp firstline=”34″]joint1_pub.publish(pos1);[/cpp]
18行目で宣言したjoint1_pubのpublishメソッドを用いることで、トピックへのデータの配信が行えます。この場合は、引数をpos1に設定しているので、pos1がトピックへ配信されます。実質的には、トピック/tilt1_controller/commandに、0.0という値を配信しているようなものです。この値がID1のサーボモータの回転角になることは前回述べた通りなので、サーボモータに回転角を指示していることになります。
[cpp firstline=”40″]ros::Rate loop_rate(0.5);[/cpp]
これで、ループ頻度を設定することができます。この場合は、0.5Hzで駆動するということです。具体的には、loop_rate.sleep()を呼び出してからどれだけ時間が経過したかを常に管理し、次にloop_rate.sleep()が呼び出された際、前回のスリープが終わってから2秒たつまでスリープします。
[cpp firstline=”42″]while (ros::ok())[/cpp]
ros::ok()というのは、以下のような場合にfalseを返す関数です。
・Ctrl-Cが押され、SIGINTシグナルを受け取った時。
・同じ名前のノードができたために,ネットワークから外された時。
・アプリケーションの他の部分でros::shutdown()が呼ばれた時。
・全ての ros::NodeHandles が破棄された時。
以上の場合、falseが返されてwhile文から抜けるため、プログラムが終了します。
[cpp firstline=”184″]ros::spinOnce();[/cpp]
トピックを購読する場合は必須の処理です。これがないとコールバックが呼ばれず、トピックを購読することができません。トピックを購読しようと思っている場所では、必ず繰り返し呼び出すようにしてください。

以上で、ROSのプログラムの書き方の基本は説明できたと思います。次回は、CRANE+のURDFモデルの作り方について説明したいと思います。

ROSを使用したCRANE+の動かし方 その6

こんにちは!長谷川です。
前回はCRANE+を動かすための環境の構築について説明しましたが、今回はCRANE+の全ての関節を同時に、かつ自動で動かす方法について説明したいと思います。

ROSのノードとトピックについて

CRANE+を動かす前に、ROSのシステムの一つ、ノードとトピックについて勉強しなければなりません。
ノードとは、ROSパッケージ内の実行ファイルです。ROSでは多くの場合、複数のノードが起動していて、それぞれの処理のために情報をやりとりしています。例えば、あるノードが常にロボットの位置を計測していて、そのノードからロボットの位置情報を受け取った別のノードが、目的の位置にロボットを動かす、といった具合です。このノード間の情報のやりとりに使われるのがトピックです。各ノードは、やりとりする情報をメッセージとしてトピックに配信し、配信されたメッセージをトピックを購読することで受け取ることができます。上の例で言えば、ロボットの位置情報についてのトピックがあって、位置計測を行うノードはそのトピックに位置情報を配信し、ロボットを動かすノードはそのトピックを購読して位置情報を受け取る、というわけです。
ROS_CRANE_6_1
前回の最後に、
[php]rostopic pub -1 /tilt_controller/command std_msgs/Float64 — 1.5[/php]
というコマンドをご紹介しましたが、このコマンドは、「/tilt_controller/commandというトピックに、std_msgs/Float64というデータ型で1.5という値を配信する」という意味です。/tilt_controller/commandというトピックは、モーターを動かすノードに購読されていまして、そのノードがモーターに設定されている中心位置からこのトピックに入った値(単位はラジアン)だけずれた位置を目標にしてサーボを動かします。3.1415…ラジアン=180度です。
つまり、上のコマンドで、tilt.yamlに記述されたIDのサーボモーターが基準位置から1.5ラジアンだけずれた位置まで動くように指令を送ったというわけです。なので、最後の数字を-1.5とした命令を入力すると、モーターは左右対称な位置まで動きます。

環境の構築

前回は、tilt.yamlなるファイルを作りましたが、今回はこのようなyamlファイルを各モーターに1個ずつ、計5個作ることになります。ID1~5のモーターに、tilt1.yaml~tilt5.yamlをそれぞれ対応させます。まずは、tilt1.yamlを作りましょう。端末に
[php]
$ roscd my_dynamixel_tutorial
$ vi tilt1.yaml
[/php]
と入力してviを起動します。編集モードに入り、以下の内容を貼り付けます。
[php]
tilt1_controller:
controller:
package: dynamixel_controllers
module: joint_position_controller
type: JointPositionController
joint_name: tilt_joint
joint_speed: 1.17
motor:
id: 1
init: 512
min: 0
max: 1023
[/php]
貼り付けたらEscapeを押してコマンドモードに戻り、「:wq」と打ち込んで、tilt1.yamlを保存してviを終了します。同様に、tilt2.yaml~tilt5.yamlを作ります。一行目のtilt1_controllerの1の代わりに各モーターのIDを書き、9行目の「id:」の右側に各モーターのIDを書いてください。

次に、チュートリアルで作ったstart_tilt_controller.launchを、5個のモーターを動かせるように書き換えます。新しいファイルを作ってもいいですが、その場合は、以降の「start_tilt_controller.launch」を自分の設定したファイル名に読み替えてください。端末に[php]vi start_tilt_controller.launch[/php]と入力し、viを起動します。前回書いたものは邪魔になるので、コマンドモードのままddを押していき、何もなくなった所でiを押して編集モードに入ります。以下を貼り付けます。
[php]
<launch>
<!– Start tilt joint controller –>
<rosparam file="$(find my_dynamixel_tutorial)/tilt1.yaml" command="load"/>
<node name="tilt1_controller_spawner" pkg="dynamixel_controllers" type="controller_spawner.py"
args="–manager=dxl_manager
–port pan_tilt_port
tilt1_controller"
output="screen"/>

<!– Start tilt joint controller –>
<rosparam file="$(find my_dynamixel_tutorial)/tilt2.yaml" command="load"/>
<node name="tilt2_controller_spawner" pkg="dynamixel_controllers" type="controller_spawner.py"
args="–manager=dxl_manager
–port pan_tilt_port
tilt2_controller"
output="screen"/>

<!– Start tilt joint controller –>
<rosparam file="$(find my_dynamixel_tutorial)/tilt3.yaml" command="load"/>
<node name="tilt3_controller_spawner" pkg="dynamixel_controllers" type="controller_spawner.py"
args="–manager=dxl_manager
–port pan_tilt_port
tilt3_controller"
output="screen"/>

<!– Start tilt joint controller –>
<rosparam file="$(find my_dynamixel_tutorial)/tilt4.yaml" command="load"/>
<node name="tilt4_controller_spawner" pkg="dynamixel_controllers" type="controller_spawner.py"
args="–manager=dxl_manager
–port pan_tilt_port
tilt4_controller"
output="screen"/>

<!– Start tilt joint controller –>
<rosparam file="$(find my_dynamixel_tutorial)/tilt5.yaml" command="load"/>
<node name="tilt5_controller_spawner" pkg="dynamixel_controllers" type="controller_spawner.py"
args="–manager=dxl_manager
–port pan_tilt_port
tilt5_controller"
output="screen"/>
</launch>
[/php]
貼り付けたらEscapeを押してコマンドモードに戻り、「:wq」と打ち込んで、start_tilt_controller.launchを保存してviを終了します。
これで、チュートリアルと同じように「roslaunch my_dynamixel_tutorial start_tilt_controller.launch」まで入力し、「rostopic pub -1 /tilt(動かしたいモーターのID)_controller/command std_msgs/Float64 — 1.5」と入力すると、該当するモーターが動きます。例えば、[php]rostopic pub -1 /tilt1_controller/command std_msgs/Float64 — 1.5[/php]と入力すると、根元のモーターが動きます。これで、コマンドを手打ちすることによりCRANE+を動かすことができるようになりました。

プログラムによる自動駆動

次は、プログラムにより、あらかじめ決めておいた動きを自動でCRANE+にさせてみましょう。少し長くなるので、CRANE+との接続は一旦切っておいた方がいいと思います。まず、端末に
[php]
$ cd ~/catkin_ws/src
$ catkin_create_pkg turtlebot_arm std_msgs rospy roscpp
[/php]
と入力して、catkin_wsのソースディレクトリに移動してからturtlebot_armパッケージを作成します。(この作業は、ここの「4. catkin形式のパッケージを作る」に基づいています。)そして、
[php]
$ cd turtlebot_arm/src
$ vi turtlebot_arm.cpp
[/php]
と入力してviを起動します。編集モードに入り、以下を貼り付けます。
[cpp]
#include "ros/ros.h"
/**
* turtlebot_arm.cpp – move turtlebot arm according to predefined gestures
*/

#include "std_msgs/Float64.h"

#include <sstream>

int main(int argc, char **argv)
{

ros::init(argc, argv, "turtlebot_arm");

ros::NodeHandle n;

//publish command message to joints/servos of arm
ros::Publisher joint1_pub = n.advertise<std_msgs::Float64>("/tilt1_controller/command", 1000);
ros::Publisher joint2_pub = n.advertise<std_msgs::Float64>("/tilt2_controller/command", 1000);
ros::Publisher joint3_pub = n.advertise<std_msgs::Float64>("/tilt3_controller/command", 1000);
ros::Publisher joint4_pub = n.advertise<std_msgs::Float64>("/tilt4_controller/command", 1000);
ros::Publisher joint5_pub = n.advertise<std_msgs::Float64>("/tilt5_controller/command", 1000);
std_msgs::Float64 pos1;
std_msgs::Float64 pos2;
std_msgs::Float64 pos3;
std_msgs::Float64 pos4;
std_msgs::Float64 pos5;
//Initial gesture of robot arm
pos1.data = 0.0;
pos2.data = 0.0;
pos3.data = 0.0;
pos4.data = 0.0;
pos5.data = -0.3;
joint1_pub.publish(pos1);
joint2_pub.publish(pos2);
joint3_pub.publish(pos3);
joint4_pub.publish(pos4);
joint5_pub.publish(pos5);

ros::Rate loop_rate(0.5);

while (ros::ok())
{
//gesture 1
pos1.data = -0.9;
pos2.data = 0.0;
pos3.data = 0.0;
pos4.data = 0.0;
pos5.data = -0.3;
joint1_pub.publish(pos1);
joint2_pub.publish(pos2);
joint3_pub.publish(pos3);
joint4_pub.publish(pos4);
joint5_pub.publish(pos5);

loop_rate.sleep();

//gesture 2
pos1.data = -0.9;
pos2.data = 0.9;
pos3.data = 1.8;
pos4.data = 1.0;
pos5.data = -0.3;
joint1_pub.publish(pos1);
joint2_pub.publish(pos2);
joint3_pub.publish(pos3);
joint4_pub.publish(pos4);
joint5_pub.publish(pos5);

loop_rate.sleep();

//gesture 3
pos1.data = -0.9;
pos2.data = 0.9;
pos3.data = 1.8;
pos4.data = 1.0;
pos5.data = 0.3;
joint1_pub.publish(pos1);
joint2_pub.publish(pos2);
joint3_pub.publish(pos3);
joint4_pub.publish(pos4);
joint5_pub.publish(pos5);

loop_rate.sleep();

//gesture 4
pos1.data = -0.9;
pos2.data = 0.0;
pos3.data = 0.0;
pos4.data = 0.0;
pos5.data = 0.3;
joint1_pub.publish(pos1);
joint2_pub.publish(pos2);
joint3_pub.publish(pos3);
joint4_pub.publish(pos4);
joint5_pub.publish(pos5);

loop_rate.sleep();

//gesture 5
pos1.data = 0.95;
pos2.data = 0.0;
pos3.data = 0.0;
pos4.data = 0.0;
pos5.data = 0.3;
joint1_pub.publish(pos1);
joint2_pub.publish(pos2);
joint3_pub.publish(pos3);
joint4_pub.publish(pos4);
joint5_pub.publish(pos5);

loop_rate.sleep();

//gesture 6
pos1.data = 0.95;
pos2.data = 0.3;
pos3.data = 2.0;
pos4.data = -0.2;
pos5.data = 0.3;
joint1_pub.publish(pos1);
joint2_pub.publish(pos2);
joint3_pub.publish(pos3);
joint4_pub.publish(pos4);
joint5_pub.publish(pos5);

loop_rate.sleep();

//gesture 7
pos1.data = 0.95;
pos2.data = 0.3;
pos3.data = 2.0;
pos4.data = -0.2;
pos5.data = -0.3;
joint1_pub.publish(pos1);
joint2_pub.publish(pos2);
joint3_pub.publish(pos3);
joint4_pub.publish(pos4);
joint5_pub.publish(pos5);

loop_rate.sleep();

//gesture 8
pos1.data = 0.95;
pos2.data = 0.4;
pos3.data = 0.0;
pos4.data = -0.2;
pos5.data = -0.3;
joint1_pub.publish(pos1);
joint2_pub.publish(pos2);
joint3_pub.publish(pos3);
joint4_pub.publish(pos4);
joint5_pub.publish(pos5);

loop_rate.sleep();

//gesture 9
pos1.data = 0.95;
pos2.data = 0.0;
pos3.data = 0.0;
pos4.data = 0.0;
pos5.data = -0.3;
joint1_pub.publish(pos1);
joint2_pub.publish(pos2);
joint3_pub.publish(pos3);
joint4_pub.publish(pos4);
joint5_pub.publish(pos5);

loop_rate.sleep();

//Initial gesture of robot arm
pos1.data = 0.0;
pos2.data = 0.0;
pos3.data = 0.0;
pos4.data = 0.0;
pos5.data = -0.3;
joint1_pub.publish(pos1);
joint2_pub.publish(pos2);
joint3_pub.publish(pos3);
joint4_pub.publish(pos4);
joint5_pub.publish(pos5);

loop_rate.sleep();

ros::spinOnce();
}

return 0;
}
[/cpp]
これがC++言語で書かれたソースコードになります。このソースコードについての解説は、次回行いたいと思います。貼り付けたらEscapeを押してコマンドモードに戻り、「:wq」と打ち込んで、turtlebot_arm.cppを保存してviを終了します。その後、[php]chmod +x turtlebot_arm.cpp[/php]と入力して、ファイルを実行可能にしておきましょう。

次に、
[php]
$ roscd turtlebot_arm
$ vi CMakeLists.txt
[/php]
と入力します。色々出てきますが、末尾に以下の3文を貼り付けます。
[php]
add_executable(turtlebot_arm src/turtlebot_arm.cpp)
target_link_libraries(turtlebot_arm ${catkin_LIBRARIES})
add_dependencies(turtlebot_arm turtlebot_arm_generate_messages_cpp)
[/php]
これで保存してviを終了してください。
次に、このturtlebot_armパッケージをビルドしましょう。
[php]
$ cd ~/catkin_ws/
$ catkin_make
[/php]
と入力します。「Linking ~」と書かれた一文の後に、「「100%」 Built target turtlebot_arm」と出てきていたら、ビルドが成功していると思います。

ここまで実行したら、CRANE+とPCを接続し、チュートリアルと同じ手順で「roslaunch my_dynamixel_tutorial start_tilt_controller.launch」まで入力してください。端末に
[php]
rosrun turtlebot_arm turtlebot_arm
[/php]
と入力すると、CRANE+が自動で動きだすと思います。天板上で動くので、天板にPC等を置くのは危険です。物をつかんで運ぶ動きをすると思うので、ペットボトルをつかませて遊んでみましょう。

以上、CRANE+の全ての関節を同時に、かつ自動で動かす方法について説明しました。
次回は、今回出てきたソースコードの解説を通して、ROSのプログラムの書き方について説明したいと思います。

ROSを使用したCRANE+の動かし方 その5

こんにちは!長谷川です。
前回はROSのパッケージの作成とビルドについて説明しましたが、今回はCRANE+を動かすための環境の構築について説明したいと思います。

CRANE+を動かすためのチュートリアル

ここを見ていただくとわかりますが、「CRANE+」はROBOTIS社製のサーボモーターDynamixelシリーズの一つ、AX-12Aを使用しております。ROSには、このDynamixelシリーズを動かすパッケージがすでに用意されていまして、ここにインストールの方法が書かれています。また、ここにチュートリアルがあるので、基本的にはこれに従えばCRANE+のモーターを動かすことができます。チュートリアルは、Connecting to Dynamixel busCreating a joint controllerの順になります。

通信環境の構築

まず、パッケージをインストールしましょう。端末(Terminal)を開き、
[php]sudo apt-get install ros-indigo-dynamixel-motor[/php]
と入力します。
パスワードを要求された場合は入力します。これで、必要なパッケージはインストールされました。

次に、チュートリアルに従って作業していきましょう。最初に、今回使用するパッケージを作成しなければならないのですが、ROS_PACKAGE_PATHに登録されたディレクトリに作らないとroscdとかが使えなくなっちゃいます。
試しに、ROS_PACKAGE_PATHに登録されているディレクトリを表示してみましょう。
端末に
[php]echo $ROS_PACKAGE_PATH[/php]
と入力します。すると、この連載の通りにインストールを行っていた場合は、3個のディレクトリが:で区切られて表示されると思います。このうち、/opt/ros/indigo/shareと/opt/ros/indigo/stacksはroot権限でしかアクセスできないので、ここに作ってしまうと後々困ったことになります。そして、(ホーム・ディレクトリ)/catkin_ws/srcは、catkin workspace内なので、ここに作るとビルドに巻き込まれる可能性があり、めんどくさいところです。
そこで今回は、新たなディレクトリを作って、そのディレクトリをROS_PACKAGE_PATHに登録しましょう。ディレクトリ名は、(ホーム・ディレクトリ)/ros_craneにします。私の環境でのホーム・ディレクトリは/home/turtlebotなので、/home/turtlebot/ros_craneになりますね。
ご自分のディレクトリにしたい場合は、そのディレクトリ名に読み替えてやっていただいて構いませんが、root権限のディレクトリにしてしまうと不具合が起きるので、気を付けてください。

それでは、実際に作業していきましょう。
[php]mkdir /home/turtlebot/ros_crane[/php]
と入力して、/home/turtlebot/ros_craneを作ります。
次に、ROS_PACKAGE_PATHに登録します。恒久的に登録しておいたままにするために、~/.bashrcに設定を追記しておきましょう。
[php]vi ~/.bashrc[/php]
と入力し、エディタviで~/.bashrcを開くなどして、次の2行を最終行に追加して保存します。
[php]
PATH=$PATH:/home/turtlebot/ros_crane
ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:/home/turtlebot/ros_crane
[/php]
端末でのエディタviの使い方については、ここでは省略させていただきます。慣れていないと混乱するので、必ず調べてください。
その後、端末に、
[php]source ~/.bashrc[/php]
と入力します。
これで~/.bashrcに書いた環境が設定されます。

次に、今回使用するパッケージを作成しましょう。
[php]cd /home/turtlebot/ros_crane[/php]
と入力してディレクトリを移動します。
その後、
[php]
$ catkin_create_pkg my_dynamixel_tutorial dynamixel_controllers
$ roscd my_dynamixel_tutorial
[/php]
と入力してパッケージを作成し、そのパッケージに移動します。なお、チュートリアルではroscreate-pkgを使っていますが、これはcatkin導入以前のパッケージ作成命令なので、catkin_create_pkgを使うべきだと思われます。

さて、次に実行ファイルを作成していくわけなのですが、そのファイル上ではCRANE+がパソコンのどのUSBポートに刺さっているのかが重要になります。それを調べましょう。
まず、CRANE+のアームから出ている信号線が電源供給用の基板(SMPS2DYNAMIXEL)につながっていることと、そこから出た信号線がUSBコネクタのついたデバイス(USB2DYNAMIXEL)につながっていることをご確認ください。
ROS_CRANE_5_1
次に、SMPS2DYNAMIXELから出た電源ケーブルが、kobukiの「12V 5A」と書かれたコネクタに接続されていることをご確認ください。
ROS_CRANE_5_2
以上が確認できれば、CRANE+を動かすためのハードウェアの準備は整っています。次に、USB2DYNAMIXELの側面にあるスイッチをTTLモードに切り替えます。
ROS_CRANE_5_3
これを忘れると、全く接続できないので、ご注意ください。最後に、USB2DYNAMIXELをパソコンに接続します。これで接続は完了です。
パソコンにつながっているUSBデバイスをUSB2DYNAMIXELだけにしてから、新しい端末を開き、そこに[php]ls /dev/ttyUSB*[/php]と入力します。すると、「/dev/ttyUSB0」とか「/dev/ttyUSB1」などと表示されます。これが、CRANE+が接続されているUSBポート名になります。
私の場合は、/dev/ttyUSB0と表示されたので、これを前提に以下の操作を進めます。ここで一旦USB2DYNAMIXELをパソコンから抜くと、ポート名が変わる恐れがあります。多くの場合では接続した順番でttyUSB0、ttyUSB1、・・・と命名されていくと思われますが、USB2DYNAMIXELを抜く場合は、再接続の際にポート名を再確認するなどした方が無難です。

ポートの情報が確認できたので、これをもとに実行ファイルを作成していきましょう。前に使っていた端末に[php]vi controller_manager.launch[/php]と入力し、エディタviを起動します。なぜ前に使っていた端末に入力するのかというと、controller_manager.launch ファイルはmy_dynamixel_tutorialの中に作らなければならないからです。viの画面が開いたら、iを押して編集モードに入ってから、以下の内容を貼り付けます。
[php]
<!– -*- mode: XML -*- –>

<launch>
<node name="dynamixel_manager" pkg="dynamixel_controllers" type="controller_manager.py" required="true" output="screen">
<rosparam>
namespace: dxl_manager
serial_ports:
pan_tilt_port:
port_name: "/dev/ttyUSB0"
baud_rate: 1000000
min_motor_id: 1
max_motor_id: 25
update_rate: 20
</rosparam>
</node>
</launch>
[/php]
なお、「port_name:」の右側には、CRANE+がつながっているUSBポート名を入力してください。また、チュートリアルにはbaud rate(ボーレート)をきちんと気にしろみたいなことが書いてありますが、ここをご覧になるとわかります通り、AX-12Aの通信速度の初期設定は1Mbps、つまり1000000bpsなので、上に書いてあるbaud rateのままで大丈夫です。
貼り付けたらEscapeを押してコマンドモードに戻り、「:wq」と打ち込んで、controller_manager.launchを保存してviを終了します。

チュートリアルでは、次に、[php]roslaunch my_dynamixel_tutorial controller_manager.launch[/php]と入力するように指示されています。モーターとの通信を開始する命令のようなので、Turtlebotの電源を入れ、USB2DYNAMIXELをパソコンに接続してから新しい方の端末に入力してみると、エラーが出てきてしまいます。
ROS_CRANE_5_4
エラー文の赤文字の少し上に、「could not open port /dev/ttyUSB0: [Errno 13] Permission denied: ‘/dev/ttyUSB0’」と書かれていました。つまり、USBポートに接続できないみたいです。これは、ユーザーがUSBポートを読み書きできる権限を持たないというLinuxの初期設定によるもののようです。これを解決するため、全てのユーザーに/dev/ttyUSB0の読み書きを認めてしまうことにします。端末に[php]sudo chmod 6666 /dev/ttyUSB0[/php]と入力し、パスワードを求められた場合は入力します。これで、全てのユーザーに/dev/ttyUSB0の読み書きが認められました。この状態で[php]roslaunch my_dynamixel_tutorial controller_manager.launch[/php]と入力してみます。
すると、何やら処理が行われました。
ROS_CRANE_5_5
「pan_tilt_port: Found 5 motors」と端末に出力されたので、CRANE+を構成する5つのモーターをきちんと認識したことがわかります。これで接続は成功です。なお、USB2DYNAMIXELをパソコンから抜くと、USBポートのアクセス権限も初期値にリセットされてしまうので、USB2DYNAMIXELをパソコンにさすたびに全てのユーザーに/dev/ttyUSB0の読み書きを認めなくてはなりません。

さて、次はモーターからの信号を見てみましょう。新しい端末を開いて[php]rostopic list[/php]と入力すると、存在しているトピックが表示されます。トピックとは何かについてまだ何も解説していませんが、今回の記事でCRANE+を動かすところまで行きたいので、説明は次回に回します。今はデータのようなものだと思っておいてください。存在しているトピックのうち、「/motor_states/pan_tilt_port」がモーターの状態についてのトピックです。これの内容を、[php]rostopic echo /motor_states/pan_tilt_port[/php]と入力して、見てみましょう。
ROS_CRANE_5_6
この画面には、IDが4と5のモーターの状態が表示されているようです。CRANE+のモーターのIDは、Turtlebotに一番近い根元のサーボモーターから順に1,2,3,4,5と設定されているので、4と5にあたるモーターを手で動かしてみると、errorやpositionなどが変化することが分かります。

モーターの駆動

ここまででCRANE+とパソコンとの通信はできるようになったので、次はモーターを実際に動かしてみましょう。USB2DYNAMIXELを一旦抜く場合は、その前に処理中の2つの端末それぞれでCtrlを押しながらcを押し、処理を終わらせて下さい。
最初に開いた端末に
[php]vi tilt.yaml[/php]
と入力します。最初に開いた端末を閉じてしまっていた場合は、新しい端末を開いて[php]roscd my_dynamixel_tutorial[/php]と入力し、my_dynamixel_tutorialに移動してからviを起動してください。
編集モードに入り、以下の内容を貼り付けます。
[php]
tilt_controller:
controller:
package: dynamixel_controllers
module: joint_position_controller
type: JointPositionController
joint_name: tilt_joint
joint_speed: 1.17
motor:
id: 4
init: 512
min: 0
max: 1023
[/php]
なお、「id:」の右側には、今回操作するモーターのIDを入力します。貼り付けたらEscapeを押してコマンドモードに戻り、「:wq」と打ち込んで、tilt.yamlを保存してviを終了します。
次に、同じ端末に[php]vi start_tilt_controller.launch[/php]と入力し、viを起動します。編集モードに入り、以下の内容を貼り付けます。
[php]
<launch>
<!– Start tilt joint controller –>
<rosparam file="$(find my_dynamixel_tutorial)/tilt.yaml" command="load"/>
<node name="tilt_controller_spawner" pkg="dynamixel_controllers" type="controller_spawner.py"
args="–manager=dxl_manager
–port pan_tilt_port
tilt_controller"
output="screen"/>
</launch>
[/php]
貼り付けたらEscapeを押してコマンドモードに戻り、「:wq」と打ち込んで、start_tilt_controller.launchを保存してviを終了します。
そこまでできたら、CRANE+とパソコンを接続し、USBポートのアクセス権限を変更し、[php]roslaunch my_dynamixel_tutorial controller_manager.launch[/php]を入力する、という先ほどやったのと同じ操作を行います。先ほどUSB2DYNAMIXELを抜かず、処理も終了していなかった場合は、やらなくても大丈夫です。その後、新しい端末が必要な場合は開いて、[php]roslaunch my_dynamixel_tutorial start_tilt_controller.launch[/php]と入力します。すると、以下のように表示されるはずです。
ROS_CRANE_5_7
「Controller tilt_controller successfully started」と表示されているので、大丈夫でしょう。
最後に、[php]rostopic pub -1 /tilt_controller/command std_msgs/Float64 — 1.5[/php]と入力すると、IDが4のサーボモーターが一定の位置に固定されるはずです。モーターが動けば当然アームが動くので、アーム可動範囲にモノを置かないようにして行ってください。
動くサーボモーターはtilt.yamlに記述するIDを変更することで変えられます。このコマンド自体の意味は、次回で解説したいと思います。

以上、CRANE+を動かすための環境の構築について説明しました。
次回は、CRANE+の全ての関節を同時に、かつ自動で動かす方法について説明したいと思います。

※(2015/3/26追記)
上では、デバイスをUSBポートに接続し直すたびに、
[php]sudo chmod 6666 /dev/ttyUSB0[/php]
と書いて権限付与を行っていますが、これをいちいち書かなくてもよくなる方法があるそうです。以下でその方法を述べますが、当方では動作確認をしておりませんので、実行は自己責任でお願いします。
/dev/ttyUSB0などはdialoutグループだそうです。そして、グループ内からはポートを読み書きできる権限があります。つまり、ユーザをdialoutに追加してやれば、ポートを読み書きできるようになるということだそうです。例えば、turtlebotというユーザをdialoutグループに追加したい場合は、
[php]sudo usermod -a -G dialout turtlebot[/php]
と入力します。ここで、-aを忘れてしまうと、既に設定されていた他のグループの設定が全て飛んでしまい、sudoが効かなくなるなど大変なことになるので注意してください。リカバリーモードに頼らなければいけなくなってしまいます。
ともかく、これが成功すれば、いちいち権限付与しなくても接続できるようになります。

ROSを使用したCRANE+の動かし方 その4

こんにちは!長谷川です。
前回はROSの環境のセットアップとROSのファイルシステムについて説明しましたが、今回はROSのパッケージの作成とビルドについて説明したいと思います。
今回も前回同様、主に英語版Wikiのチュートリアルに従って進みます。日本語版Wikiのチュートリアルは情報が古いですが、英語版がわかりにくい場合、適宜参照すると理解の助けになると思います。

パッケージの作成

前回、パッケージとは何かをお話しましたが、パッケージはpackage.xmlとCMakeLists.txtを含んでいる必要があります。逆に言えば、最低限これらを含んでいれば、パッケージとして認められます。パッケージ作成においては、これらのひな形を自動で生成させ、それらを後から編集します。また、前回作ったようなcatkin workspaceを利用しながらパッケージを編集するのが推奨みたいですが、パッケージを単独でビルドすることも可能らしいです。以下では、チュートリアル通り、catkin workspaceを利用してパッケージを作成、ビルドします。

まず、端末(Terminal)を開き、
[php]
$ cd ~/catkin_ws/src
$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
[/php]
と入力します。
ROS_CRANE_4_1
何か表示されましたね。どうやら、~/catkin_ws/srcの中に、beginner_tutorialsというパッケージが作成されたようです。
この場合、すでに一部のパッケージの依存関係が定められています。なぜかというと、「catkin_create_pkg」という命令は、[php]catkin_create_pkg <package_name> [depend1] [depend2] [depend3][/php]のように使用した場合、パッケージ[depend1],[depend2],[depend3]に依存するようなパッケージを作るからです。このことを、前回紹介したrospackを用いて確かめてみましょう。前回はrospackにfindというオプションをつけて使いましたが、今回はdepends1というオプションをつけます。これで依存関係を確認できるというわけです。[php]rospack depends1 beginner_tutorials[/php]と入力すると、roscpp,rospy,std_msgsが表示されました。これは、先にcatkin_create_pkgで指定した依存関係と同じですね。
さて、上の依存関係は当然package.xmlに記録されているはずです。確認してみましょう。
[php]
$ roscd beginner_tutorials
$ cat package.xml
[/php]
と入力します。
ROS_CRANE_4_2
[php]<build_depend>[/php]の後ろと、[php]<run_depend>[/php]の後ろに、roscpp,rospy,std_msgsが確認できますね。

次に、beginner_tutorialsが依存しているパッケージの依存関係(間接的な依存関係)を調べてみましょう。例えばrospyについては、先ほどと同じように
[php]rospack depends1 rospy[/php]
と入力するとわかります。
このような間接的な依存関係も含めて、指定したパッケージが依存するパッケージを全て列挙するのが、rospackにdependsというオプションをつけたものです。
[php]rospack depends beginner_tutorials[/php]
と入力すると、以下のようになります。
ROS_CRANE_4_3
要は、依存関係というのはかなり複雑だ、ということですね・・・。

次に、package.xmlを編集してみましょう。例として、
[php]
$ cd ~/catkin_ws/src/beginner_tutorials
$ vi package.xml
[/php]
と入力して、エディタviでpackage.xmlを開きます。
ROS_CRANE_4_4
チュートリアルによると、色々変えなきゃならないところがあるようですが、とりあえず例として、ライセンス部分を変えてみたいと思います。
[php]<license>[/php]
の後に書かれているTODOを、BSDと書き換えます。
ROS_CRANE_4_5
このようなライセンスの明記や、チュートリアルで指示される作成者の名前、連絡先のタグへの記入は、作成したパッケージが他の人に共有される際の障害を取り払うためのものです。それゆえ、作成したパッケージをアップロードする場合には必ず記入しておきましょう。

パッケージのビルド

次に、自分の作ったパッケージをビルドしてみましょう。ビルドというのは、ソースコードファイルを実行ファイルに変換することです。
[php]
$ cd ~/catkin_ws
$ ls src
[/php]
と入力して、CMakeLists.txt beginner_tutorialsが出てきたら、今までの作業がうまくいっているようです。
[php]catkin_make[/php]と入力します。すると、色々表示されて、ビルドが進行します。終わったら、[php]$ ls[/php]と入力してみます。
ROS_CRANE_4_6
buildとdevel、srcというフォルダがあることがわかります。これでビルドができていることが確認できました。

以上、ROSのパッケージの作成とビルドについて説明しました。
次回は、CRANE+を動かすための環境の構築について説明したいと思います。