なお、このプログラム trace_pid.c を使用する前に「1.ライントレース(2値化制御走行)のlight.c を実行して、ラインの黒値と背景の白値を計測して、プログラム中の BLACK と WHITE の値を書き換える必要があります。
積分動作を入れた場合の制御入力 u(k) は
のように表され、この u(k) がライントレースプログラムでは旋回値(turn値)となります。
#include "kernel.h"
#include "kernel_id.h"
#include "ecrobot_interface.h"
#define PORT_LIGHT NXT_PORT_S3 /* 入出力ポートの定義 */
#define PORT_TOUCH NXT_PORT_S2
#define L_MOTOR NXT_PORT_B
#define R_MOTOR NXT_PORT_C
#define BLACK 700
#define WHITE 500
#define BT_PASS_KEY "1234" /* bluetoothパスキー */
DeclareTask(Task1); /* Task1を宣言 */
void ecrobot_device_initialize(){ /* OSEK起動時の処理 */
nxt_motor_set_speed(L_MOTOR,0,1);
nxt_motor_set_speed(R_MOTOR,0,1);
ecrobot_set_light_sensor_active(PORT_LIGHT);
}
void ecrobot_device_terminate(){ /* OSEK終了時の処理 */
nxt_motor_set_speed(L_MOTOR,0,1);
nxt_motor_set_speed(R_MOTOR,0,1);
ecrobot_set_light_sensor_inactive(PORT_LIGHT);
}
void user_1ms_isr_type2(void){}
void sound_beep(){ /* ビープ音を鳴らすユーザ関数 */
ecrobot_sound_tone(600, 2, 50);
systick_wait_ms(20);
ecrobot_sound_tone(500, 5, 50);
systick_wait_ms(50);
}
TASK(Task1)
{
int speed=70;
float dt = 0.01; // 制御周期(秒):10msec
float Kp, Ki, Kd;
int black,white,gray,light,light_tmp; /* 一つ前の明るさを格納する"light_tmp"変数を定義 */
int err, err_prev, err_sum ;
float turn;
float turn_p, turn_d, turn_i;
float Kc, Tc;
int dtm;
dtm = (int)(dt * 1000);
//限界感度法によるPIDゲイン
Kc = 0.25; // 限界感度のKp
Tc = 0.42 ; //振動周期(秒)
Kp = Kc * 0.6;
Ki = Kp / ( 0.5 * Tc) * dt;
Kd = Kp * ( 0.125 * Tc ) /dt;
//Ki = 0; //PD制御
//Kd = 0; //PI制御
black = BLACK;
white = WHITE;
gray = (black + white) / 2;
//Kp,Ki,Kd の表示
display_clear(0);
display_goto_xy(0, 1);
display_string("KP =");
display_int( (int)(Kp*1000),0);
display_goto_xy(0, 2);
display_string("KI =");
display_int( (int)(Ki*1000),0);
display_goto_xy(0, 3);
display_string("KD =");
display_int( (int)(Kd*1000),0);
display_goto_xy(0, 5);
display_string("PUSH START");
display_update();
while(1){
while(ecrobot_get_touch_sensor(PORT_TOUCH) == 0){ /* TSが押されたらスタート */
systick_wait_ms(10);
}
systick_wait_ms(500); /* 500msec待つ */
err_prev = ecrobot_get_light_sensor(PORT_LIGHT) - gray;
err_sum = 0;
while(ecrobot_get_touch_sensor(PORT_TOUCH) == 0){ // タッチセンサが押されたらストップ
light = ecrobot_get_light_sensor(PORT_LIGHT);
err = light - gray;
err_sum += err;
turn_p = Kp * err ;
turn_d = Kd * (err - err_prev);
turn_i = Ki * err_sum;
turn = turn_p + turn_d + turn_i;
err_prev = err;
light_tmp=light; /* 一つ前の明るさを格納 */
nxt_motor_set_speed( L_MOTOR,speed-turn, 1 );
nxt_motor_set_speed( R_MOTOR,speed+turn, 1 );
systick_wait_ms(dtm); /* dtm[msec]待つ */
}
nxt_motor_set_speed(L_MOTOR,0,1);
nxt_motor_set_speed(R_MOTOR,0,1);
systick_wait_ms(1000); /* 1秒待つ */
}
TerminateTask(); /* 処理終了 */
}
|