ステップ12 リモコン操作を実装する

ステップ12 リモコン操作を実装する
ステップ12 リモコン操作を実装する
ロボットの倒立が出来るようになると、リモコン操作で操縦してみたくなります。今
回のロボットには、赤外線センサを実装してあるので、TV のリモコンを使って操縦が
出来るようにします。赤外線リモコン信号の受信処理は、マイコンプログラミング2で
作ったので、これをポートの設定を今回のハードウェアに合わせて変更し、ほぼそのま
ま再利用します。
12.1 ロボットの動かし方
ロボットを倒立させたまま、前後の移動や回転をさせるにはどのようにすれば良いで
しょうか。モータへは、既に倒立制御から倒立するのに必要な制御がされているので、
この動きとは別に、人が好きな方向へ動かすことは一見難しそうに思えますが、このス
テッピングモータを使ったロボットでは、非常に簡単に出来てしまいます。そのやり方
は、下記の実際のコードを見てもらえば分かりますが、倒立制御からモータに指示され
るスピード値にロボットを動かしたい方向のスピード値を足して、モータを動かせば良
いだけです。このやり方は、倒立制御からみると、リモコン操作で加えられた動き(加
速、減速)は、外乱として処理して、後追いで倒立制御を続ける動きとなります。
mv_m_r = mv_m + (int)op_mv_r;
mv_m_l = mv_m + (int)op_mv_l;
if(mv_m_r >
MAXSPEED) mv_m_r =
MAXSPEED;
if(mv_m_r < -1*MAXSPEED) mv_m_r = -1*MAXSPEED;
if(mv_m_l >
MAXSPEED) mv_m_l =
MAXSPEED;
if(mv_m_l < -1*MAXSPEED) mv_m_l = -1*MAXSPEED;
set_speed(-1*mv_m_r, mv_m_l);
mv_m が倒立制御から指示されたスピード値で、これに赤外線リモコンからの
op_mv_r または、op_mv_l を足して、set_speed()でそれぞれのモータのスピードを
指示します。op_mv_r,l に正のスピードを加えれば前進、負のスピードを加えれば後進
します。左右のモータに正と負のスピードを指示をすれば、その場で回転するようにな
ります。左右のモータにスピード差を付ければ、その差に応じた曲率で曲がることがで
きます。
1
ステップ12 リモコン操作を実装する
ここで、注意しなければいけないのが、倒立制御が動く余裕をみたスピードを指示す
ること、急激なスピード変化を与えないことです。例えば、いきなりスピード値100
のような指示をした場合、ステッピングモータは直ぐにそのスピードで回るため、ロボ
ットは、いきなり突き飛ばされたように倒れてしまいます。停止の場合も同様です。
以下のソースが実際のものですが、モータ制御の時間間隔と同じ 5ms 毎にスピード
を目的のスピードまで徐々に変化させるようにしています。
/* 加速・減速*/
void move(char target_r, char target_l)
{
if(op_mv_r > target_r){
op_mv_r--;
}
if(op_mv_l > target_l){
op_mv_l--;
}
if(op_mv_r < target_r){
op_mv_r++;
}
if(op_mv_l < target_l){
op_mv_l++;
}
return;
}
12.2 赤外線リモコン処理
赤外線リモコンのボタンに下記のようにロボット操作を割り付けます。
モータ停止
左折
直進
左回転
後左折
右折
Power
右回転
後進
後右折
ゼロスタート
RESET
使用した赤外線リモコンは、NEC フォーマットのものなので、ボタンを押し続ける
とリピートコードが送信されます。このリピートコードが出ている間は、上記ボタンに
書かれた動作を行い、ボタンを放すと停止するようにします。
2
ステップ12 リモコン操作を実装する
リモコンの押されたボタンリモコンから送信されるコードを調べて操作との対応付
けを行います。例えば、前進なら左右モータのスピードを100、100するとか、右
折なら右を50、左を100するなどの設定を行います。
/* ラジコン操作*/
#define LEFT 0x1
#define FORWARD 0xb
#define RIGHT 0x1b
#define LEFTTURN 0x05
#define RIGHTTURN 0x15
#define LEFTBACK 0x06
#define BACK 0x0a
#define RIGHTBACK 0x12
#define POWER 0x1e
#define RESET 0x1d
#define RELE 0x00
#define HIGH 100
#define LOW 50
#define TURN 70
/* ラジコン操作*/
void radio_control(void)
{
switch(data[2]) {
case RELE:
move(ZERO, ZERO); break;
case LEFT:
move(HIGH, LOW); break;
case FORWARD:
move(HIGH, HIGH); break;
case RIGHT:
move(LOW, HIGH); break;
case LEFTTURN:
move(TURN, -1*TURN); break;
case RIGHTTURN:
move(-1*TURN, TURN); break;
case LEFTBACK:
move(-1*HIGH, -1*LOW); break;
case BACK:
move(-1*HIGH, -1*HIGH); break;
case RIGHTBACK:
move(-1*LOW, -1*HIGH); break;
case POWER:
motor_stop = 1; break;
case RESET:
reset = 1; break;
}
}
3
//停止
//左折
//直進
//右折
//左回転
//右回転
//後左折
//後進
//後右折
//モータ停止(転倒)
//倒立用変数初期化
ステップ12 リモコン操作を実装する
マイコンプログラミング2で作った赤外線リモコンの受信処理に、リモコンからのコ
ードが、一定時間(約 0.3 秒)来なかったときに受信したコードをゼロにする処理を
加え、ボタンが離されたことを検出しロボットが停止するようにします。
// 赤外線受信処理
// 0.17ms 毎に赤外線センサーの状態をチェックし、受信処理を実行
// 赤外線処理パラメータ
#define RELEASE 2000
static int release_count = 0;
switch(state)
{
case WAITON:
if(release_count > RELEASE){
data[2] = 0;
}
else{
release_count++;
}
if((PORTA & IRD_IN) != 0) {
break;
}
state = CHECKON;
// ONになるまで待つ
count = 0;
12.3 割込みの2レベル化
赤外線リモコンの受信処理は、インターバル割込みの間隔を基準に信号の解析を行う
作りとなっているので、割込み時間がある程度正確でないと正しく処理が出来ません。
PIC18F2550 は、78K0 とは異なり割込みの種類毎に割込みベクタが分かれていな
いため、全ての割込み共通の割込みベクタで受けて、ソフトウェアでハードウェアの割
込み要因フラグを見て処理を分けるようにしています。この赤外線リモコンの受信処理
も、最初は受信処理に使った 170μs毎の割込みを他の割込み同じ割込みベクタで処
理するようにしていましたが、ジャイロのオフセット補正処理や USB 処理などの比較
的重い処理のため偶に誤動作することがありました。
そこで、この PIC18 から拡張された2つの割込みレベルを使って見ることにしまし
た。2 レベル割込みと言っても特に難しことは無く(78K0 から考えると寧ろこの方
が普通)High と Low の2つの割込みベクタを使うだけです。ただし、UBW のソフト
ウェアローダの関係や C18 でも2つの割込みの書き方がありますので、その部分の
KnowHow が少しあります。
4
ステップ12 リモコン操作を実装する
■UBW 関係
UBW のブートローダを使うために、ユーザソフトウェアは 1000 番地以降にロー
ドするので、新たに増えた割込みベクタも 1000 番地以降に設定を追加します。
#pragma code RESET_ADDRESS = 0
void START_ADDRESS (void)
{
_asm
GOTO 0x800
_endasm
}
#pragma code
#pragma code HIGH_VECTOR = 0x08
void HIGH_INTERRUPT (void)
{
_asm
GOTO 0x808
_endasm
}
#pragma code
#pragma code LOW_VECTOR = 0x18
void LOW_INTERRUPT (void)
{
_asm
GOTO 0x818
_endasm
}
RESET ベクタへのリンク
High レベル割込みベクタへのリンク
Low レベル割込みベクタへのリンク
#pragma code
■C18 での2レベルの割込みハンドラの書き方
#pragma interrupt interrupt_isr_high
#pragma code high_vector=0x808
void high_interrupt (void)
{
_asm
GOTO interrupt_isr_high
_endasm
}
#pragma code
#pragma interruptlow interrupt_isr_low
#pragma code low_vector=0x818
void low_interrupt (void)
{
_asm
GOTO interrupt_isr_low
_endasm
}
High レベル割込みハンドラの指定
Low レベル割込みハンドラの指定
#pragma code
上記、赤字にした pragma の指定で2つのレベルの割込ハンドラを定義します。
後は、タイマ等のハードウェアでどちらの割込みレベルを使うのか指定します。
因みにこのロボットでは、赤外線リモコン受信とモータ制御を High、それ以外に
Low レベルを使いました。
5