iXs Research製のラジコン用サーボモータコントローラ iMCs04の制御用RTコンポーネントを作りました.
これを使えばかなり簡単にラジコン用サーボモータを扱えます.
iMCs04とは,最大4台のラジコン用サーボモータを制御できる,モータコントローラです.
すばらしいのはなんといってもそのサイズ.4.5cm×3cm×0.5cm!名刺の半分くらいのサイズでしょうか.
今回はアナログ4系統の入力についても扱えるように作りました.
ラジコン用サーボモータについて説明します.
ラジコン用サーボモータは,もともとラジコンカーやラジコンヘリの操舵を行うために販売されているモータで,簡単に角度制御ができ,小型でトルクが大きいのが特徴です.
また近年はロボット用途として,サーボゲイン調整機能や,現在角度のフィードバック機能がついたラジコンサーボが販売されています.
iMCs04は,2008年3月現在の仕様では,角度指定機能しかありませんが,これでも十分に遊べます.
ラジコン用サーボモータとコントローラは,基本的に3本の線で通信します.とはいえ1本目は電源,2本目はGNDですから,実質1本の信号線のみで角度を指定します.角度の指定方法はアナログではなく,0-5[V]のデジタル信号で,具体的にはパルスの幅で指定されます.
パルス幅は通常1500[us]を中心として1000[us]〜2000[us]程度.パルスの周期は22[ms]程度です.このパルスの幅に比例して,サーボモータが舵を切るわけです.
しかし近年ではいろいろなモデルが出ているので,モーターに付属しているマニュアルか,メーカーの公式ウェブサイトの情報を参照して下さい.
iMCs04を簡単に使用できるRTコンポーネントを作ります.あくまで簡単に,というのが目的なので,機能はできるだけ削いで,モータの角度指令とアナログ値の取得にとどめました.
モータ,アナログ入力,ともに4系統ですので,4つの入力ポート,4つの出力ポートを持つプログラムになっています.
まずiMCs04を簡単に扱うことができるクラスライブラリ(iMCs04.h iMCs04.cpp)を作りました.この後にこれをコンポーネントに実装します.
#pragma once
/**
* iMCs04.h
* author: ysuga (ysuga.net)
* Copyright: ysuga.net 2008
**/
/// 最大のパルス幅値
#define MAX_DUTY 5600
/// 最小のパルス幅値
#define MIN_DUTY 1800
/// ニュートラル時のパルス幅
#define NEUTRAL_DUTY 3150
/**
* CiMCs04
* iMCs04をかんたんに使うためのライブラリ
*
**/
class CiMCs04
{
private:
// 制御用ハンドル
void* m_husb;
HANDLE m_hContinous, m_hCounter, m_hDesire;
// 制御用バッファ
struct urcout m_cmd;
struct urcin m_AD_VAL;
// USBの最大パケットサイズ
DWORD m_MaxPacketSize;
public:
// コンストラクタ
// この時点でiMCs04をオープンします.
// 失敗した場合は文字列へのポインタをthrowします.
// try-catch節を用いて,失敗の原因文字列を取得してください.
CiMCs04(void);
// デストラクタ
~CiMCs04(void);
private:
// 内部処理.USBのパケットデータの最大サイズを取得
USHORT GetMaxPacket(HUSB husb, DWORD if_num, DWORD pipe_num);
public:
// 初期化
void Init(void);
// 目標位置を取得
// channel:チャンネル(0−3)
// duty:パルス幅
void SetTargetDuty(int channel, USHORT duty);
// アナログ電圧取得
// channel:チャンネル(0−3)
// 返り値:アナログ電圧値をデジタル化した値(0−1024)
USHORT GetAdValue(int channel);
public:
// データをUSBデバイスから読み込む
// GetAdValudeでアナログ電圧を取得する前に呼ぶこと.
void Read(void);
// データをUSBデバイスに書き込む
// SetTargetDutyを呼び,パルス幅を設定した後に呼ぶこと.
void Write(void);
// サーボをオフにします.
// KONDO科学製 KRS-4014HVで動作確認済み
void ServoOff(void);
};
関数の実装については,iMCs04.cppファイルを参照してください.
コンポーネント側には,入力ポート4つと出力ポート4つを実装しますが,ソースコードを見ると配列で宣言していることがわかると思います.後々の処理に関して考えても,同様のポートを配列で宣言しておくのは有効です.これは適当に入力・出力ポートをRTCTemplateで宣言しておいて,手作業で配列化しました.
// iMCs04Component.hより
TimedFloat m_VoltagePort[4];
OutPort<TimedFloat> *m_pVoltagePortOut[4];
こうやって配列で宣言したときは,コンストラクタでポートをRTMに登録するときに,ちょっとした手作業が必要ですが,簡単ですよ.
次はiMCs04Componentのコンストラクタ内でポートの登録をします.registerOutPort,registerInPort関数を呼び出します.これも配列を使えばスッキリ♪
char stringBuffer[256];
for(int i = 0;i < 4;i++) {
//入力ポートであるTargetDegreePort0〜3を登録します.
sprintf(stringBuffer, "TargetDegreePort%d", i); //名前の文字列を作って…
m_pTargetDegreePortIn[i] = new RTC::InPort<TimedLong>(stringBuffer, m_TargetDegreePort[i]); // ポートのインスタンスを作成して…
registerInPort(stringBuffer, *m_pTargetDegreePortIn[i]); // 名前の文字列とポートのインスタンスを登録する
//出力ポートであるVoltagePort0〜3を登録します.
// やってることは入力ポートと一緒です.
sprintf(stringBuffer, "VoltagePort%d", i);
m_pVoltagePortOut[i] = new RTC::OutPort<TimedFloat>(stringBuffer, m_VoltagePort[i]);
registerOutPort(stringBuffer, *m_pVoltagePortOut[i]);
}
そのほか,onActivateではファイルを開く作業です.USBを開くことが出来なかった場合(たとえばiMCs04の認識が失敗しているとかが原因)は,RTC_ERRORという値を返します.すると,コンポーネントはERROR状態に遷移します.状態遷移図を参考にして下さい.
これまでと同様でかまいません.周期をゆっくりめに設定してもいいかな.
corba.nameservers:localhost:2809
naming.formats: %n.rtc
logger.log_level: TRACE
とにかく使ってほしいRTCの第1弾.非常にシンプルに動作します.不具合を見つけてくれた方は連絡をください.
ダウンロードはこちら→iMCs04Component.zip (ver. 0.4.1)
iMCs04Component042.zip (ver. 0.4.2)