NHK2018Bチームの手動ロボットのプログラムです。(製作中)

Dependencies:   HCSR04 PID PS3viaSBDBT QEI mbed

main.cpp

Committer:
tektomo
Date:
2018-10-10
Revision:
7:9837f47a2f55
Parent:
6:eaeaaf374263

File content as of revision 7:9837f47a2f55:

/* ------------------------------------------------------------------- */
/* NHKロボコン2018-Bチーム手動ロボット(設計者: 4S 関) */
/* ------------------------------------------------------------------- */
/* このプログラムは上記のロボット専用の制御プログラムである。 */
/* ------------------------------------------------------------------- */
/* 対応機種: NUCLEO-F446RE */
/* ------------------------------------------------------------------- */
/* 製作者: 1-3 武井 智大, mail: taobmcoe@outlook.com */
/* ------------------------------------------------------------------- */
/* 使用センサ:ロータリーエンコーダ: 2個, 超音波センサ: 1個*/
/* ------------------------------------------------------------------- */
#include "mbed.h"
#include "PS3_S.h"
#include "hcsr04.h"
#include "QEI.h"
#include "PID.h"

#define ps3data ps3s.condata
#define PI 3.14159265359
#define roller_Kp 2.5
#define froller_Ki 1.0
#define broller_Ki 0.8
#define roller_Kd 0.0

//定義

/*I2C定義
    0前輪左:0x10
    1前輪右:0x12
    2後輪左:0x14
    3後輪右:0x16
    4投射前:0x18
    5投射後ろ:0x20
    6エアシリンダー:0x40
    正転:0x84~0xFF
    逆転:0x00~0x7C
    ショートブレーキ:0x7D~0x83
*/
I2C i2c(PB_9, PB_8);
//PS3コン定義
PS3s ps3s(PC_10, PC_11);
//PC定義
Serial pc(USBTX,USBRX);
//ロリコン定義
QEI front_roller_wheel(PC_8, PC_6, NC, 624);
QEI back_roller_wheel(PC_5, PA_12, NC, 624);
//PID定義
PID front_roller(roller_Kp, froller_Ki, roller_Kd, 0.001);
PID back_roller(roller_Kp, broller_Ki, roller_Kd, 0.001);
//超音波センサ定義
HCSR04 topsonic(PB_2,PB_1);
//HCSR04 undersonic(PB_15,PB_14);
//LED定義
DigitalOut Power(PC_12);//Green
DigitalOut i2ccheck(PB_7);//Blue
DigitalOut sncled(PC_2);//Yellow
DigitalOut Powemer(PC_3);//Red
DigitalOut myled(LED1);
//緊急停止定義
DigitalOut emersig(PC_0);
//タイマー定義
Ticker get_rps;//ロリコンからRPMの読み取り
Timer shooot;

//変数定義
//データ配列
char send_data[4][1];//足回り用データ配列
char send_data2[1];//エアシリンダー用データ配列
int address[4] = {0x10, 0x12, 0x14, 0x16};//i2cアドレス
int err[4] = {1, 1, 1, 1};//I2Cリザルト

int front_roller_rpm;//RPM変数
int back_roller_rpm;
int front_roller_pulse[10];//ロリコンパルスバッファ
int back_roller_pulse[10];
int sum_front_roller_pulse;//ロリコンパルス
int sum_back_roller_pulse;
int ave_front_roller_pulse;//ロリコンパルス平均
int ave_back_roller_pulse;
char front_roller_data[1];
char back_roller_data[1];
static int j = 0;
int sonicval;
int mode = true;
int table[3];
int times = 0;
int letshoot = 0;
int endshoot = 0;

//プロトタイプ宣言
//メイン制御関数
void ctrl();
void semiauto();
//移動関数
void amove_R();
void amave_L();
void dmove();
//void shortb(int i);
void backfif();
void sendi2c();
//回転数取得関数
void flip();
//ローラーPID
int roller_PID(int front, int back);
//発射関数
void shoot();
//その他諸関数
void changemode();
void printdata();
void outemergency();
void emergency();

//実装部

//メイン関数
int main()
{
    Power = 1;
    emersig = 0;
    i2ccheck = 0;
    pc.baud(460800);
    get_rps.attach_us(&flip, 40000);
    pc.printf("\x1b[0m");

    send_data2[0] = 0x80;
    i2c.write(0x10, send_data2, 1);
    i2c.write(0x12, send_data2, 1);
    i2c.write(0x14, send_data2, 1);
    i2c.write(0x16, send_data2, 1);
    i2c.write(0x18, send_data2, 1);
    i2c.write(0x20, send_data2, 1);
    i2c.write(0x40, send_data2, 1);

    while(true) {
        topsonic.start();
        sonicval = topsonic.get_dist_cm();
        ps3s.getdata();
        ps3s.checkdata();
        ctrl();
        sendi2c();
    }
}

//メイン制御関数
void ctrl()
{
    bool dmove_val = false;
    front_roller_data[0] = 0x80;
    back_roller_data[0] = 0x80;
    send_data2[0] = 0x80;
    i2c.write(0x18, front_roller_data, 1, false);
    i2c.write(0x20, back_roller_data, 1, false);
    i2c.write(0x40, send_data2, 1, false);
    for(int i = 0; i < 4; i++) {
        send_data[i][0] = 0x80;//ショートブレーキ
    }

    if(ps3data[12]==1) {//Select
        emergency();//緊急停止
    } else if(ps3data[13]==1) {//Start
        outemergency();//緊急停止解除
    }

    if(ps3data[6] == 1) { //まる
        shoot();
    } else if(ps3data[4]==1) { //さんかく
        //semiauto();
    } else if(ps3data[5]==1) { //ばつ
        //changemode();
    } else if(ps3data[7]==1){//しかく
        endshoot = 0;
        shooot.reset();
        times = 0;
    }
    if(emersig == 0) {

        if(ps3data[0]==1) {
            dmove_val = true;//上
        } else if(ps3data[1]==1) {
            dmove_val = true;//下
        } else if(ps3data[2]==1) {
            dmove_val = true;//右
        } else if(ps3data[3]==1) {
            dmove_val = true;//左
        } else if(ps3data[8]==1) {//L1
            dmove_val = true;//左回転
        } else if(ps3data[10]==1) {//R1
            dmove_val = true;//右回転
        }
        if (dmove_val) {
            dmove();//方向キー+L1R1キー
        }

        if(((ps3data[16] <= 51) || (ps3data[16] >= 77)) || ((ps3data[17] <= 51) || (ps3data[17] >= 77))) {
            amove_R();//アナログパッド
        }
    }
}

//緊急停止
void emergency()
{
    emersig = 1;
    Powemer = 1;
}

//緊急停止解除
void outemergency()
{
    emersig = 0;
    Powemer = 0;
}

//右アナログパッド
void amove_R()
{
    int RXdata = ps3data[16];
    int RYdata = ps3data[17];

    if(RXdata == 64 && RYdata < 64) {
        //垂直上
        send_data[0][0] = abs(RYdata - 53) + 202 - RYdata - 8;
        send_data[1][0] = abs(RYdata - 53) + 202 - RYdata;
        send_data[2][0] = abs(RYdata - 53) + 202 - RYdata - 8;
        send_data[3][0] = abs(RYdata - 53) + 202 - RYdata;

    } else if(RXdata == 64 && RYdata > 64) {
        //垂直下
        send_data[0][0] = abs(RYdata - 127) * 2;
        send_data[1][0] = abs(RYdata - 127) * 2 + 8;
        send_data[2][0] = abs(RYdata - 127) * 2;
        send_data[3][0] = abs(RYdata - 127) * 2 + 8;

    } else if(RXdata > 64 && RYdata == 64) {
        //垂直右
        send_data[0][0] = (RXdata - 75) + 203 - abs(RXdata - 127) - 8;
        send_data[3][0] = (RXdata - 75) + 203 - abs(RXdata - 127) - 8;
        send_data[1][0] = abs(RXdata - 127) * 2;
        send_data[2][0] = abs(RXdata - 127) * 2;

    } else if(RXdata < 64 && RYdata == 64) {
        //垂直左
        send_data[0][0] = RXdata * 2;
        send_data[3][0] = RXdata * 2;
        send_data[1][0] = abs(RXdata - 53) + 202 - RXdata - 8;
        send_data[2][0] = abs(RXdata - 53) + 202 - RXdata - 8;

    } else if (RXdata > 64 && RYdata < 64) {
        //右上
        send_data[0][0] = (RXdata - 74) + 202 - abs(RXdata - 127);
        send_data[3][0] = (RXdata - 74) + 202 - abs(RXdata - 127);
    } else if(RXdata < 64 && RYdata < 64) {
        //左上
        send_data[1][0] = abs(RXdata - 54) + 201 - RXdata;
        send_data[2][0] = abs(RXdata - 54) + 201 - RXdata;
    } else if(RXdata < 64 && RYdata > 64) {
        //左下
        send_data[0][0] = RXdata * 2;
        send_data[3][0] = RXdata * 2;
    } else if(RXdata > 64 && RYdata > 64) {
        //右下
        send_data[1][0] = abs(RXdata - 127) * 2;
        send_data[2][0] = abs(RXdata - 127) * 2;
    }
}

void dmove()
{

    if(ps3data[0] == 1) {
        send_data[0][0] = 0xF7;
        send_data[1][0] = 0xFF;
        send_data[2][0] = 0xF7;
        send_data[3][0] = 0xFF;
    } else if(ps3data[1] == 1) {
        send_data[0][0] = 0x00;
        send_data[1][0] = 0x0A;
        send_data[2][0] = 0x00;
        send_data[3][0] = 0x0A;
    } else if(ps3data[2] == 1) {
        send_data[0][0] = 0xF5;
        send_data[3][0] = 0xFF;
        send_data[1][0] = 0x09;
        send_data[2][0] = 0x00;
    } else if(ps3data[3] == 1) {
        send_data[0][0] = 0x00;
        send_data[3][0] = 0x09;
        send_data[1][0] = 0xFF;
        send_data[2][0] = 0xF5;
    } else if(ps3data[10] == 1) {
        send_data[1][0] = 0x00;
        send_data[3][0] = 0x00;
        send_data[0][0] = 0xFF;
        send_data[2][0] = 0xFF;
    } else if(ps3data[8] == 1) {
        send_data[0][0] = 0x00;
        send_data[2][0] = 0x00;
        send_data[1][0] = 0xFF;
        send_data[3][0] = 0xFF;
    }

}

//ショートブレーキ
void shortb(int i)
{
    i2ccheck = 0;
    send_data[i][0] = 0x80;
}


//I2C送信
void sendi2c()
{
    if(send_data[0][0] < 0x80) {
        send_data[0][0] += 50;
    } else if(send_data[0][0] > 0x80) {
        send_data[0][0] -= 50;
    }
    if(send_data[1][0] < 0x80) {
        send_data[1][0] += 50;
    } else if(send_data[1][0] > 0x80) {
        send_data[1][0] -= 50;
    }
    if(send_data[2][0] < 0x80) {
        send_data[2][0] += 50;
    } else if(send_data[2][0] > 0x80) {
        send_data[2][0] -= 50;
    }
    if(send_data[3][0] < 0x80) {
        send_data[3][0] += 50;
    } else if(send_data[3][0] > 0x80) {
        send_data[3][0] -= 50;
    }
    err[0] = i2c.write(address[0], send_data[0], 1);
    err[1] = i2c.write(address[1], send_data[1], 1);
    err[2] = i2c.write(address[2], send_data[2], 1);
    err[3] = i2c.write(address[3], send_data[3], 1);
    if (err[0]!=0 || err[1]!=0 || err[2]!=0 || err[3]!=0) {
        i2ccheck = 0;
    } else {
        i2ccheck = 1;
    }
}

//移動平均をPID
void flip()
{
    //前回のi番目のデータを消して新たにそこにデータを書き込む(キューのような考え?)
    sum_front_roller_pulse -= front_roller_pulse[j];
    sum_back_roller_pulse  -= back_roller_pulse[j];

    //配列のi番目の箱に取得パルスを代入
    front_roller_pulse[j] = front_roller_wheel.getPulses();
    back_roller_pulse[j]  = back_roller_wheel.getPulses();

    front_roller_wheel.reset();
    back_roller_wheel.reset();

    //i[0]~i[9]までの合計値を代入
    sum_front_roller_pulse += front_roller_pulse[j];
    sum_back_roller_pulse  += back_roller_pulse[j];

    //インクリメント
    j++;
    //iが最大値(9)になったらリセット
    if(j > 9) {
        j = 0;
    }
    //10回分の合計値を10で割り、取得パルスの平均を出す
    ave_front_roller_pulse = sum_front_roller_pulse / 10;
    ave_back_roller_pulse  = sum_back_roller_pulse  / 10;

    //平均値をRPMへ変換
    front_roller_rpm = ave_front_roller_pulse * 25 * 60 / 1200;
    back_roller_rpm  = ave_back_roller_pulse  * 25 * 60 / 1200;
    pc.printf("%3d,%3d,%d,%d\n\r",abs(front_roller_rpm), abs(back_roller_rpm),sonicval,times);
}

//ローラー
int roller_PID(int front, int back)
{
    front_roller.setInputLimits(-2000, 2000);
    back_roller.setInputLimits(-2000, 2000);

    front_roller.setOutputLimits(0x84, 0xFF);
    back_roller.setOutputLimits(0x84, 0xFF);

    front_roller.setMode(AUTO_MODE);
    back_roller.setMode(AUTO_MODE);

    front_roller.setSetPoint(front);
    back_roller.setSetPoint(back);

    front_roller.setProcessValue(abs(front_roller_rpm));
    back_roller.setProcessValue(abs(back_roller_rpm));

    front_roller_data[0] = front_roller.compute();
    back_roller_data[0]  = back_roller.compute();

    return 0;
}

//投擲動作
void shoot()
{
    letshoot = 0;
    int front = 1650;
    int back = 600;
    while(endshoot == 0 || times < 2) {
        roller_PID(front, back);
        i2c.write(0x18, front_roller_data, 1, false);
        i2c.write(0x20, back_roller_data, 1, false);
        if( ( ( abs(front_roller_rpm) >= (front - 5)) && ( abs(front_roller_rpm) <= front + 5) ) && ( (abs(back_roller_rpm) >= back - 5) && (abs(back_roller_rpm) <= back + 5) ) ) {
            letshoot++;
        } else {
            letshoot = 0;
        }
        if(letshoot == 30 && endshoot == 0) {
            send_data2[0] = 0x0F;
            i2c.write(0x40, send_data2, 1, false);
            endshoot = 1;
            shooot.start();
        }
        if(endshoot == 1){
            times = shooot.read();
        }
    }
    shooot.stop();
}

//セミオートプレイテスト

void semiauto()
{
    while(true) {//一回目低固定
        if(mode) {
            send_data[0][0] = 0xE1;
            send_data[3][0] = 0xEC;
            send_data[1][0] = 0x1D;
            send_data[2][0] = 0x14;
        } else if(!mode) {
            send_data[0][0] = 0x00;
            send_data[3][0] = 0x09;
            send_data[1][0] = 0xFF;
            send_data[2][0] = 0xF5;
        }
        topsonic.start();
        sonicval = topsonic.get_dist_cm();
        if(sonicval < 100) {
            send_data[0][0] = 0xF7;
            send_data[1][0] = 0xFF;
            send_data[2][0] = 0xF7;
            send_data[3][0] = 0xFF;
            if(sonicval <= 74) {
                send_data[0][0] = 0x80;
                send_data[1][0] = 0x80;
                send_data[2][0] = 0x80;
                send_data[3][0] = 0x80;
            }
        }
        sendi2c();
        if(sonicval <= 74) {
            shoot();
            for(int i = 0; i < 100; i++) {
                pc.printf("Press Box button if pet stood");
                ps3s.getdata();
                ps3s.checkdata();
                if(ps3data[7] == 1) {
                    table[0] = true;
                }
            }
        }
        if(table[0]) {
            break;
        }
    }

    while(true) { //高固定
        if(mode) {
            send_data[0][0] = 0xE1;
            send_data[3][0] = 0xEC;
            send_data[1][0] = 0x1D;
            send_data[2][0] = 0x14;
        } else if(!mode) {
            send_data[0][0] = 0x00;
            send_data[3][0] = 0x09;
            send_data[1][0] = 0xFF;
            send_data[2][0] = 0xF5;
        }
        topsonic.start();
        sonicval = topsonic.get_dist_cm();
        if(sonicval < 150) {
            send_data[0][0] = 0xF7;
            send_data[1][0] = 0xFF;
            send_data[2][0] = 0xF7;
            send_data[3][0] = 0xFF;
            if(sonicval <= 124) {
                send_data[0][0] = 0x80;
                send_data[1][0] = 0x80;
                send_data[2][0] = 0x80;
                send_data[3][0] = 0x80;
            }
        }
        sendi2c();
        if(sonicval <= 124) {
            shoot();
            for(int i = 0; i < 100; i++) {
                pc.printf("Press Box button if pet stood");

                ps3s.getdata();
                ps3s.checkdata();
                if(ps3data[7] == 1) {
                    table[1] = true;
                }
            }
        }
        if(table[1]) {
            break;
        }
    }
}


void changemode()
{
    mode = !mode;
    if(mode) {
        pc.printf("\x1b[41m");
    } else {
        pc.printf("\x1b[44m");
    }
}


//デバック用データ出力
void printdata()
{
    //for (int i = 0; i < 7; i++) {
    //    pc.printf("%d,",ps3s.Rdata[i]);
    //}
    //pc.printf("%d\n\r",ps3s.Rdata[7]);
    pc.printf("%d,",int(send_data[0][0]));
    pc.printf("%d,",int(send_data[0][1]));
    pc.printf("%d.",int(send_data[0][2]));
    pc.printf("%d\n\r",int(send_data[0][3]));
}