Serial Servo RTCs (C++) for Ubuntu
手軽に利用できるアクチュエータモジュールである、シリアルサーボを動作させるRTCを作成する方法を解説します。
このページでは以下の知識を説明なく使用しますので、各解説ページで使用方法を学んでから読み進めてください。
1. はじめに
今回は、以下のRTCを作成し、シリアルサーボを動作させる方法を学びます。
シリアルサーボには、双葉電子工業製(株)のRSシリーズを用います。
ここでは、1つずつシリアルサーボを動作させるショートパケットに対応します。
作成するRTCは以下のようになります。
-
RSServoManager
RSシリーズのサーボモータを1つずつ動作させます。
-
RSServoMoveConsoleIn
シリアルサーボの角度(位置)と移動時間を指令します。
-
RSServoServoConsoleIn
シリアルサーボの保持トルクのON/OFF状態などを指令します。
-
RSServoSensorConsoleOut
シリアルサーボのセンサ値をコンソール上に出力します。
本解説で想定するシステムは、以下の様になります。
PCからUSB接続の変換器を通して、RSサーボに接続し制御します。
8. おわりに
シリアルサーボを動作させるRTCを作成しました。
専用のデータ型を作成することで、スッキリと通信することが出来ました。
複雑なRTCも専用のConsoleIn/Outを作成してその動作を確認できました。
このように、作成したRTCをテストするために、テスト用RTCを用いるのは面倒ですがとても重要です。
複雑なシステムになればなるほど、この手間は最終的には近道となると思います。
自分のRTCを作るときには、ぜひ応用してみてください。
参考文献
-
「JM Project」<http://linuxjm.sourceforge.jp/index.html>(2014/02/19アクセス)
-
「RS405CB/RS406CB取扱説明書(ver.1.03)」<http://www.futaba.co.jp/robot/command_type_servos/rs405cb>(2014/02/19アクセス)
3. RSServoManager RTC
RSServoManager RTCを作成します。
テンプレートを以下に従って設定てください。
-
モジュール名
RSServoManager
-
ベンダ名
あなたの名前
-
モジュールカテゴリ
Hobby
-
実行周期
1000
-
アクションコールバック
onInitialize
onActivated
onDeactivated
onExecute
-
データポート
・moveポート
ポート名(InPort) move
データ型 RSServo::Move
変数名 move
表示位置 LEFT
・servoポート
ポート名(InPort) servo
データ型 RSServo::Servo
変数名 servo
表示位置 LEFT
・sensorポート
ポート名(OutPort) sensor
データ型 RSServo::Sensor
変数名 sensor
表示位置 RIGHT
-
コンフィギュレーション
・portコンフィギュレーション
名称 port
データ型 string
デフォルト値 COM1
変数名 conf_port
・baudrateコンフィギュレーション
名称 baudrate
データ型 long
デフォルト値 115200
変数名 conf_baudrate
-
言語
C++
プロジェクトの設定が終わったら、RSServoManager.cppに以下のコードを記述します。
以下のコードは抜粋となります。生成したテンプレートに当てはめて下さい。
それではソースコードを解説します。
-
1-3行目
シリアル通信のためにいくつかのヘッダファイルをインクルードします。
-
5行目
シリアル通信用に用いるファイルディスクリプタ(識別子)をグローバルで定義します。
-
7-27行目
シリアルポートをオープンする関数です。
Linuxでのシリアル通信はネット上に多くの情報がありますので、詳しくはそちらをご覧ください[1]。
open_port関数は以下のようになります。
void open_port(ポート名, ボードレート)
-
9-13行目
シリアルポートを開きます。
ポートのオープンには以下の関数を使用します。
ファイルディスクリプタ open(ファイル名, パラメータフラグ)
ファイル名(ポート名)はコンフィグレーションによって与えることを想定しています。
OpenRTM C++版ではstring型のコンフィギュレーションは、std::string型として与えられます。
openのファイル名はchar *型で与える必要があるので、c_str()メソッドでchar *型の変数に変換します。
パラメータフラグにO_RDWRをセットすることで、読み書きモードでファイルをオープンします。
ファイルディスクリプタが負の場合はオープンに失敗しているので、例外をスローします。
-
15-16行目
シリアル通信の設定に使用する構造体を定義し、初期化します。
-
18行目
制御モードを設定します。
それぞれの設定値の意味は以下のようになります。
baudrate :ボーレートをbaudrateに指定された値に設定する
CS8 :文字サイズを8 bitに設定する
CREAD :受信を有効にする
CLOCAL :モデムの制御線を無視する
-
20-21行目
タイムアウトの設定をおこなします。
各設定項目は以下のようになっています。
VTIME :読み込み時のタイムアウト時間 0.1 s *この値は環境によっては調整が必要かもしれません
VMIN :読み込み時の最小文字数
-
23行目
デバイスのパラメータを変更します。
パラメータ変更には以下の関数を使います。ioctlは成功した場合は0、失敗した場合は-1を返します。
int ioctl(ファイルディスクリプタ, コマンド, ...)
コマンドには以下の値を設定します。
TCSETS :現在のシリアルポートの設定を変更します。3番めの引数にtermios構造体を設定します。
-
25行目
入力バッファをクリアします。
-
26行目
出力バッファをクリアします。
-
29-57行目
シリアルサーボに動作指令を与える関数です。
シリアルサーボの角度(位置)と移動時間を与えて、動作させます。
各コマンドやデータの意味は簡単に説明します。
詳しくは、RS405CB/RS406CB取り扱い説明書[2]をご覧ください。
move関数は以下のようになります。
void move(シリアルサーボのID, 角度, 移動時間)
RSシリーズのシリアルサーボには以下のような形式でコマンドを送信します。
[Header] [ID] [Flags] [Address] [Length] [Count] [Data] [Sum]
Header :パケットの先頭を表します。ここでは0xFA、0xAFとなります。
ID :シリアルサーボのIDです。
Flags : リターンパケットの設定やデータ書き込み時の設定を行います。
Address :メモリーマップ上のアドレスを表します。Lengthに指定した長さのデータをメモリーマップに書き込みます。
Length :データの長さ(byte数)を指定します。
Count :サーボの数を表します。今回は1に設定します。
Sum :チェックサムです。IDからDataまでの各バイトの排他的論理和(XOR)を計算した値を設定します。
move関数では、以下のようなバイト列で動作指令を与えます。
目標位置と時間は1 byteを超えるため、上位(H)と下位(L)に分けて設定します。
各| |は1 byte単位となります。
|0xFA|0xAF|ID|0x01|0x1E|0x04|0x01|目標位置L|目標位置H|時間L|時間H|Sum|
-
31行目
コマンドを格納する配列を確保します。
コマンドは1 byteの正数なので、unsigned char型を使用します。
-
31-42行目
配列に先ほど説明したコマンドを格納します。
位置と時間を上位バイトと下位バイトに分けるには、AND演算とビットシフトを用います。
下位バイトは0x00FFと論理的ANDを取ることで、上位ビットは全て0となり、下位ビットは元の値を残せます。
上位バイトは0xFF00と論理的ANDを取り、上位ビットを残した後に1 byteのサイズに収まるよう8 bitシフトしています。
-
44-50行目
チェックサムを計算し、配列に格納します。
-
52行目
この後、コマンドを出力するので、出力バッファをクリアします。
-
54行目
コマンドを出力します。
出力には以下の関数を使用します。
関数が成功すると書き込んだバイト数が返され、失敗した場合は-1が返されます。
書き込んだバイト数 write(ファイルディスクリプタ, データのバッファ, 書き込みバイト数)
-
56行目
シリアルサーボが動作している間スリープします。
*この値は環境によっては調整が必要かもしれません。
スリープには以下の関数を使用します。
関数が成功すると0を返し、エラーの場合は-1が返されます。
int usleep(中断の時間 us)
-
59-81行目
シリアルサーボに保持トルクのON/BRAKE/OFF指令を与える関数です。
保持/非保持/ブレーキモードから選択して動作させます。
コマンドは異なりますが、基本的な操作はmove関数と同様です。
on関数は以下のようになります。
void on(シリアルサーボのID, 保持トルクのモード)
保持トルクのモードは、0x00で非保持、0x01で保持, 0x02でブレーキとなります。
-
83-115行目
シリアルサーボのセンサ値を取得する関数です。
これまでの関数と異なり、シリアルサーボからの返信を受け取ります。
get_sensor関数は以下のようになります。
センサ情報構造体とは、IDLで定義したRSServo::Sensorのことです。
void get_sensor(シリアルサーボのID, センサ情報構造体)
-
85-102行目
コマンドの出力まではこれまでと同様です。
-
104行目
この後、センサ値を読み込むので、入力バッファをクリアします。
-
105-106行目
センサ値を読み込みます。
読み込みには以下の関数を使用します。
関数が成功すると読み込んだバイト数が返され、失敗した場合は-1が返されます。
読み込んだバイト数 read(ファイルディスクリプタ, データのバッファ, 読み込みバイト数)
-
108-114行目
先ほどまで2 byte以上のデータをエンコードしてコマンドを作成していました。
今度はこれと逆のことをして、センサ値をデコードします。
id以外は2 byteのデータなので、2 byteのデータを復元します。
上位バイトと下位バイトを合わせるには、ビットシフトとOR演算を用います。
上位ビットを8 bitずらし、下位ビットと論理的ORを取ります。
デコードした各センサ値をRSServo::Sensor構造体に格納します。
ここからは、上記の関数を使用してRTC本体の挙動をプログラムします。
-
122行目
ポートをオープンします。
引数のポート名とボーレートにはコンフィグレーションを与えます。
このようにすることで、ユーザーの環境に合わせてRTCを外部から操作できます。
このように環境により異なるものにはコンフィグレーションを使用します。
-
130行目
ポートをクローズします。
ポートのクローズには以下の関数を使用します。
関数が成功すると0を返し、失敗した場合は-1が返されます。
int close(ファイルディスクリプタ)
-
138-146行目
サーボ指令がある場合は、シリアルサーボに保持トルクのON/BRAKE/OFF指令を与えます。
-
148-160行目
動作指令がある場合は、シリアルサーボに動作指令を与えます。
その後、センサ値を取得しセンサ値ポートから出力します。
以上で、RSServoManagerのコーディングは終了です。
コードが入力し終わったら、makeを行ってください。
今回はコードが長く、大変でしょうが頑張って最後までコーディングしてみて下さい。
RSシリーズ以外のシリアルサーボでも、同様の構造でRTC化できると思います。
ぜひ、お手元のシリアルサーボでお試し下さい。
7. 動作確認
作成したRTCを実行して下さい。
RSServoManagerのポート名とボーレートのコンフィグレーションは必ず変更し、各環境に合うよう設定してください。
その後、各RTCを接続し、Activateします。
まずは、RSServoServoConsoleInにシリアルサーボの保持トルクをOnにします。
ここでは、id: 1、on:1 と入力します。IDはご使用のサーボに合わせて下さい。
4. RSServoMoveConsoleIn RTC
RSServoMoveConsoleIn RTCを作成します。
テンプレートを以下に従って設定てください。
-
モジュール名
RSServoMoveConsoleIn
-
ベンダ名
あなたの名前
-
モジュールカテゴリ
Hobby
-
実行周期
1000
-
アクションコールバック
onInitialize
onExecute
-
データポート
・moveポート
ポート名(OutPort) move
データ型 RSServo::Move
変数名 move
表示位置 RIGHT
-
言語
C++
プロジェクトの設定が終わったら、RSServoMoveConsoleIn.cppに以下のコードを記述します。
以下のコードは抜粋となります。生成したテンプレートに当てはめて下さい。
コードの解説をします。
-
3-11行目
RSServo::Move構造体のメンバを、順にユーザに入力させます。
-
13行目
動作指令ポートから出力します。
以上で、RSServoMoveConsoleInのコーディングは終了です。
コードが入力し終わったら、makeを行ってください。
シリアルサーボの保持トルクがOnになったのを確認したら、RSServoMoveConsoleInでシリアルサーボを動かします。
ここでは、id: 1、angle: -450、duration: 200と入力します。IDはご使用のサーボに合わせて下さい。

2. Serial Servo RTCの構成
シリアルサーボを1つずつRTC化するのではなく、シリアルラインをRTC化します。
前述したUSB接続の変換器をRTC化するイメージです。
シリアルサーボをRTC化する方が、一見わかりやすい気もします。
しかし、シリアルラインは1つしかないため、システムから見た場合は、シリアルラインをRTC化するほうが素直です。
2.1 Serial Servo RTCのポート構成
Serial Servo RTCは、以下の様なポート構成で作成します。
-
動作指令ポート
シリアルサーボの角度(位置)と移動時間を指令します。
-
サーボ指令ポート
シリアルサーボの保持トルクのON/OFF状態などを指令します。
-
センサ値ポート
シリアルサーボのセンサ値を出力します。

2.2 ポートのデータ型
シリアルサーボ用のデータ型はRTミドルウェアに標準で定義されていないため、独自データ型を定義します。
RSシリーズのシリアルサーボ用に、以下の3つのデータ型を定義します。
-
RSServo::Move型
・tm
タイムスタンプ
・id
シリアルサーボのID
・angle
角度
・duration
移動時間
動作指令ポートに使用します。
-
RSServo::Servo型
・tm
タイムスタンプ
・id
シリアルサーボのID
・on
トルク保持のON/BRAKE/OFF
サーボ指令ポートに使用します。
-
RSServo::Sensor型
・tm
タイムスタンプ
・id
シリアルサーボのID
・angle
現在角度
・time
現在時間
・speed
現在スピード
・load
現在負荷
・temperature
現在温度
・voltage
現在電圧
センサ値ポートに使用します。
上記の定義を以下のようなIDLファイルに記述します。
適当なテキストエディタで以下のコードを入力し、HobbyRobotDataType.idlファイルに保存してください。
*一部の変数の型が雑誌掲載時と異なりますのでご注意下さい。
ここで説明するRTCは以下の様な構成で動作を確認しています。
-
USB-RS485変換器
Futaba製 RSC-U485
-
シリアルサーボ
Futaba製 RS405CB
-
電源スイッチ付きハブ
Futaba製 TB-RV71EH-7.4V/4W
なお、Ubuntu 12.04LTSでRSC-U485を認識させるには、以下のコマンドを入力してください。
5. RSServoServoConsoleIn RTC
RSServoServoConsoleIn RTCを作成します。
テンプレートを以下に従って設定てください。
-
モジュール名
RSServoServoConsoleIn
-
ベンダ名
あなたの名前
-
モジュールカテゴリ
Hobby
-
実行周期
1000
-
アクションコールバック
onInitialize
onExecute
-
データポート
・moveポート
ポート名(OutPort) servo
データ型 RSServo::Servo
変数名 servo
表示位置 RIGHT
-
言語
C++
プロジェクトの設定が終わったら、RSServoServoConsoleIn.cppに以下のコードを記述します。
以下のコードは抜粋となります。生成したテンプレートに当てはめて下さい。
コードの解説をします。
-
3-8行目
RSServo::Servo構造体のメンバを、順にユーザに入力させます。
-
10行目
サーボ指令ポートから出力します。
以上で、RSServoServoConsoleInのコーディングは終了です。
コードが入力し終わったら、makeを行ってください。
6. RSServoSensorConsoleOut RTC
RSServoSensorConsoleOut RTCを作成します。
テンプレートを以下に従って設定てください。
-
モジュール名
RSServoSensorConsoleOut
-
ベンダ名
あなたの名前
-
モジュールカテゴリ
Hobby
-
実行周期
1000
-
アクションコールバック
onInitialize
onExecute
-
データポート
・sensorポート
ポート名(OutPort) sensor
データ型 RSServo::Sensor
変数名 sensor
表示位置 LEFT
-
言語
C++
プロジェクトの設定が終わったら、RSServoServoConsoleOut.cppに以下のコードを記述します。
以下のコードは抜粋となります。生成したテンプレートに当てはめて下さい。
コードの解説をします。
-
3-14行目
センサ値ポートに値を取得した場合、コンソールにRSServo::Sensor構造体のメンバを出力します。
以上で、RSServoSensorConsoleOutのコーディングは終了です。
コードが入力し終わったら、makeを行ってください。

最後に、シリアルサーボが動作したのを確認したら、RSServoSensorConsoleOutでセンサ値を確認します。
ここでは、以下のようになりました。
これで、RTCの動作を確認することができました。
*センサ値が取得できない場合は、VTIMEの変更や読み込み時にusleepを行うなど調整しみてください。


$ sudo modprobe ftdi_sio vendor=0x1115 product=0x0008
なお、RSServoManager RTCの実行時に「Permission denied」と表示された場合はsudoを付けて実行してください。
もしくは、以下のコマンドを入力して、dialoutにユーザーを追加してください。
$ sudo gpasswd–a <ユーザ名> dialout