top of page

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を作るときには、ぜひ応用してみてください。

 

参考文献

  1. 「JM Project」<http://linuxjm.sourceforge.jp/index.html>(2014/02/19アクセス)

  2. 「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

bottom of page