守谷工房の製作品3へ                守谷工房Topへ

Mindstorms NXT挑戦3(2022.10.22)


Lego MindstormsnxtOSEKにより自在かつ高度に制御することを
目標に、開発環境の構築を目指しています。Windows上にUNIX環境を
再現するため、Cygwinに代わりWSL
(Windows Subsystem for
 Linux)を介しUbuntuを組み込むことで、Lego MindstormsNXT上で
簡単なプログラム(helloworld.c)を実行させることに成功しています。
この環境下でnxtOSEKを利用できるか、つまりNXTのアクチュエータや
センサーを制御できるか、チュートリアルに沿って作業を進めます。

 

nxtOSEKのファンクションを呼び出す前に
もう一つ簡単なプログラムを試してみます

 

samples_cフォルダ内にtestフォルダを作成し、Makefile、
test.c、test.oilの3ファイルを以下の通り保存します。
 

  

test.c

  
  

#include "kernel.h"
#include "kernel_id.h"
#include "ecrobot_interface.h"

DeclareTask(Task1);

void ecrobot_device_initialize(){} //OSEK起動時の処理(何もしない)

void ecrobot_device_terminate(){} //OSEK終了時の処理(何もしない)

void user_1ms_isr_type2(void){}

TASK(Task1)
{
while(1){
display_clear(0);
display_goto_xy(5,3);
display_string("TASK1"); /* メッセージを表示する */
display_update();
systick_wait_ms(1000); /* 1秒待つ */

display_clear(0);
display_goto_xy(5,5);
display_string("TASK2"); /* メッセージを表示する */
display_update();
systick_wait_ms(1000); /* 1秒待つ */
}

TerminateTask(); //処理終了
}

  
test.cファイル(テキスト)の内容です。NXTのディスプレイ表示をいったん
消去(display_clear(0);)し、カーソルを(5、3)に移動(display_goto_xy(5,3);)、
"TASK1"と表示(display_string("TASK1");)して1秒間待ちます(systick
_wait_ms(1000);)。再び表示を消してからカーソルを(5、5)に移動させ、
"TASK1"と表示して1秒間待ちます。この処理を繰り返します(while(1){)。

 
  

test.oil

  
  

#include "implementation.oil"

CPU ATMEL_AT91SAM7S256
{
OS LEJOS_OSEK
{
STATUS = EXTENDED;
STARTUPHOOK = FALSE;
SHUTDOWNHOOK = FALSE;
PRETASKHOOK = FALSE;
POSTTASKHOOK = FALSE;
USEGETSERVICEID = FALSE;
USEPARAMETERACCESS = FALSE;
USERESSCHEDULER = FALSE;
};

/* Definition of application mode */
APPMODE appmode1{};

TASK Task1 /* Task1 を定義する */
{
AUTOSTART = TRUE { APPMODE = appmode1; };
PRIORITY = 1;
ACTIVATION = 1;
SCHEDULE = FULL;
STACKSIZE = 512;
};

};

  
oilファイルは、テキストで記述されているオブジェクトの内容により
プログラムの実行の仕方を変えることができるそうです。拡張子の
oilはOSEK Implementation Languageの略です。実行環境が同じ
なので、前回の作業で使用したhelloworld.oilをコピーしファイル
名のみを変更してtest.oilとすることでそのまま利用できます。
 
  

Makefile

  
  

# Target specific macros
TARGET = test

# User application source(ここにソースファイルの名前を指定する)
TARGET_SOURCES = test.c

# 自分のフォルダから見たnxtOSEKフォルダの場所またはそのフルパスを指定する。ここでは次のフルパスを指定する。
NXTOSEK_ROOT = /nxtOSEK

# OSEK OIL file(ここにoilファイルの名前を指定する)
TOPPERS_OSEK_OIL_SOURCE = ./test.oil

# below part should not be modified
O_PATH ?= build
include $(NXTOSEK_ROOT)/ecrobot/ecrobot.mak

  
Makefileも共通して利用できますが、TARGET、TARGET_
SOURCES、TOPPERS_OSEK_OIL_SOURCEの記述を
実行するプログラム名に一致させます。’test’に書き換えます。

 
  

    include $(NXTOSEK_ROOT)/ecrobot/ecrobot.mak
                

    include $../../ecrobot/ecrobot.mak

  
最終行のinclude $(NXTOSEK_ROOT)/ecrobot/ecrobot.mak中で
(NXTOSEK_ROOT)はnxtOSEKがインストールされたルート
ディレクトリを指定しているので、簡単に../..で代用させます。

 

Ubuntuを起動しtestディレクトリに移動します。dirコマンドに
よりフォルダ内のファイルを表示させると、先ほど用意した
Makefile、test.c、test.oilの各ファイルが確認できます

 

make allコマンドによりtest.cをビルド(コンパイル)します。
エラーなく最後に実行ファイルtest.rxeが生成されています。

 

dirコマンドでもう一度フォルダ内のファイルを表示させると、
test.rxeを含む一連のビルドファイルが確認できます。

 

同じくtestフォルダをWindows上で表示させてみます。
もちろんUbuntuによる表示と全く同じファイル構成です。

 

NXTを接続した状態でsh rxeflash.shコマンドを実行し
生成された実行ファイルをNXT内のメモリに転送します。

 

NXT本体との通信にはNeXTToolが呼び出されます。
NeXTTool is terminatedと表示されているので
NXTへtest.rxeの転送は完了しているはずです。

 

NXT側でプログラムが登録
されているか確認します。

 

My Files → Software filesと
辿ると、testが格納されています。

 

testを指定して(それしか指定
できません)、実行(Run)します。



カーソル位置を変えながらTASK1と
TASK2が交互に表示されます。
 

チュートリアルを次の章に進め、モーターを制御してみます。
モーターはNXT本体からポートを介して外部に接続されます。
ディスプレイ表示や操作ボタン入力など標準的なデバイスと
異なり、nxtOSEKに実装されたファンクションがないと制御
できない領域です。nxtOSEKの本領を引き出しにかかります

 

Lego Mindstorms9797に付属する
マニュアルに従い2輪走行車を組み立てます。

 

2個のモーターが左右それぞれのタイヤを
駆動します。後部に補助輪が付きます。

 

NXT本体のポートにモーターの
配線を左右とも接続します。

 

左車輪用モーターはポートCへ、右車輪用
モーターはポートBへ接続されます。

 

同じくsamples_cフォルダ内に
motor1フォルダを作成します

 

Makefile、motor1.c、motor1.oilの
3ファイルを保存し、Makefileを編集します

 
  

motor1.c

  
  

#include "kernel.h"
#include "kernel_id.h"
#include "ecrobot_interface.h"

DeclareTask(Task1); /* Task1を宣言 */

void ecrobot_device_initialize(){ /* OSEK起動時の処理(モータ停止)*/
nxt_motor_set_speed(NXT_PORT_B,0,1);
nxt_motor_set_speed(NXT_PORT_C,0,1);
}

void ecrobot_device_terminate(){ /* OSEK終了時の処理(モータ停止)*/
nxt_motor_set_speed(NXT_PORT_B,0,1);
nxt_motor_set_speed(NXT_PORT_C,0,1);
}

void user_1ms_isr_type2(void){}

TASK(Task1)
{
//2秒前進
nxt_motor_set_speed(NXT_PORT_B,60,1);
nxt_motor_set_speed(NXT_PORT_C,60,1);
systick_wait_ms(2000);

//1秒停止
nxt_motor_set_speed(NXT_PORT_B,0,1);
nxt_motor_set_speed(NXT_PORT_C,0,1);
systick_wait_ms(1000);

//2秒後退
nxt_motor_set_speed(NXT_PORT_B,-60,1);
nxt_motor_set_speed(NXT_PORT_C,-60,1);
systick_wait_ms(2000);

//1秒停止
nxt_motor_set_speed(NXT_PORT_B,0,1);
nxt_motor_set_speed(NXT_PORT_C,0,1);

display_string("THAT'S ALL !"); /* メッセージを表示する */
display_update();
TerminateTask(); /* 処理終了 */
}

  
motor1.cの内容です。左右モーターを同時に一定速度で
2秒間回転させて2輪走行車を前進させます。次に1秒間
モーターを止めて停止させ、続く2秒間でモーターを逆回転し
後退させます。モーターを制御するファンクションを使います。

 

  

nxt_motor_set_speed(NXT_PORT_,,); の説明
:A・B・C
→モーターが接続されているポートをA・B・Cのいずれかから指定する。
:-100~100
→モーターの出力(duty比)を指定する。-値で逆回転する。
:0・1
→0(フロートモード:モーターが空転する)、1(ブレーキモード:モーターが空転しない)を指定する。

systick_wait_ms(); の説明
msec=/1000sec動作を待機する。

  

motor1.cで使用されているファンクションの説明です。
チュートリアルからの抜粋ですが、実際はもう少し詳しく
解説されています。出力はPWM制御されています。
 

Ubuntuを起動しmotor1ディレクトリに移動します。
Makefile、motor1.c、motor1.oilが確認できます

 

make allコマンドによりmotor1.cをビルド(コンパイル)します。
エラーなく最後に実行ファイルmotor1.rxeが生成されています。

 

NXTを接続した状態でsh rxeflash.shコマンドを実行し
生成された実行ファイルをNXT内のメモリに転送します。

 

motor1フォルダをWindows上で表示します。
一連のビルドファイルが生成されています。

 

NXT本体にもmotor1が登録
されていることが確認できます。

 

motor1を指定して実行(Run)します。左右のモーターが音を
たてて回転し、2輪走行車が前進→停止→後退→停止します。
取りあえずnxtOSEKによりLego MindstormsNXTを制御する
基本部分の環境構築に成功したと言えるのではないでしょうか。

 

もう一つ、チュートリアルにあるnxt_motor_set_speed()を
使ったサンプルを試します。motor2フォルダを作成します。
 

Makefile、motor2.c、motor1.oilの
3ファイルを保存し、Makefileを編集します

 
  

motor2.c

  
  

#include "kernel.h"
#include "kernel_id.h"
#include "ecrobot_interface.h"

#define TURN_TIME 220 /* 回転時間を指定するマクロ */
#define MOVE_TIME 750 /* 直進時間を指定するマクロ */
#define STOP_TIME 100

DeclareTask(Task1); /* Task1を宣言 */

void ecrobot_device_initialize(){ /* OSEK起動時の処理(モータ停止)*/
nxt_motor_set_speed(NXT_PORT_B,0,1);
nxt_motor_set_speed(NXT_PORT_C,0,1);
}

void ecrobot_device_terminate(){ /* OSEK終了時の処理(モータ停止)*/
nxt_motor_set_speed(NXT_PORT_B,0,1);
nxt_motor_set_speed(NXT_PORT_C,0,1);
}

void user_1ms_isr_type2(void){}

TASK(Task1)
{
int i;
for(i=0;i<4;i++){
//直進
nxt_motor_set_speed(NXT_PORT_B,60,1);
nxt_motor_set_speed(NXT_PORT_C,60,1);
systick_wait_ms(MOVE_TIME);

//停止
nxt_motor_set_speed(NXT_PORT_B,0,1);
nxt_motor_set_speed(NXT_PORT_C,0,1);
systick_wait_ms(STOP_TIME);

//回転
nxt_motor_set_speed(NXT_PORT_B,-40,1);
nxt_motor_set_speed(NXT_PORT_C,40,1);
systick_wait_ms(TURN_TIME);

//停止
nxt_motor_set_speed(NXT_PORT_B,0,1);
nxt_motor_set_speed(NXT_PORT_C,0,1);
systick_wait_ms(STOP_TIME);
}

nxt_motor_set_speed(NXT_PORT_B,0,1);
nxt_motor_set_speed(NXT_PORT_C,0,1);

display_string("THAT'S ALL !"); /* メッセージを表示する */
display_update();
TerminateTask(); /* 処理終了 */
}

  
前進→停止→回転→停止を4回繰り返し、四角形を描いて元の位置に
戻るプログラムです。回転時にはポートBに-40を指定して右タイヤを
逆回転、ポートCに40を指定して左タイヤを正回転させることで走行車を
右旋回させます。旋回角度を調整しやすくするため、前進・停止・回転の
各動作時間をマクロに定義しています。動作終了後にディスプレイに
゛THAT’S ALL!゛と表示させます。多分うまく動作するでしょう。

 

make allコマンドによりmotor2.cをビルド(コンパイル)します。
エラーなく最後に実行ファイルmotor2.rxeが生成されています。。

 

NXTを接続した状態でsh rxeflash.shコマンドを実行し
生成された実行ファイルをNXT内のメモリに転送します。

 

motor2フォルダをWindows上で表示します。
一連のビルドファイルが生成されています。
 

NXT本体にもmotor2が登録
されていることが確認できます。
 

motor2を指定して実行(Run)します。再び左右のモーターが
回転し、2輪走行車が前進→停止→回転→前進→停止を繰り
返します。残念ながら4回繰り返した結果、元の位置からかなり
ずれています。対処方法は簡単なものでして、motor2.c中に
記述されている゛#define TURN_TIME 220゛の220を変更
させるだけです。右回転が足りないので220よりも大きくします。
Lego MindstormsNXTには、何と加速度センサーやジャイロ
センサーといった高度な制御を実現するセンサーが用意されて
います。実は、これらの環境を利用してどうしても挑戦したい
課題があるのですが、その前にNXTおよびnxtOSEKの扱い
方を十分に習得しておきたいものです。続編にご期待下さい。


 

守谷工房の製作品3へ                守谷工房Topへ