ロボカップJrのブロック大会2015で使用したプログラム

Dependencies:   BurstSPI LSM9DS0 PID PWMMotorDriver SDFileSystem mbed

main.cpp

Committer:
denden
Date:
2016-05-11
Revision:
0:ab144c574081

File content as of revision 0:ab144c574081:

/*------------------------

* XBee1
    ID : 5102

    DH : 0013A200
    DL : 407ABE67

* XBee2
    ID : 5102

    DH : 0013A200
    DL : 407C04BD

------------------------*/

/*------------------------
mv /Users/muramatsunaoya/Downloads/RoboCup_2015_LPC1768.bin /Volumes/MBED/ && diskutil unmount /Volumes/MBED/
------------------------*/



#include "mbed.h"
// ライブラリ
#include "MotorDriver.h"
#include "PID.h"
// 自作のクラス
#include "xbeeAPI.h"


/*--- 定義 ---*/
#define PI 3.1415926
#define Deg2Rad (3.1415926/180)
#define Byte2Rad (3.1415926/255/2)

#define mC 261.626
#define mD 293.665
#define mE 329.628
#define mF 349.228
#define mG 391.995
#define mA 440.000
#define mB 493.883

// PIDに関する部分
#define IndividualValueL 0.4
#define IndividualValueR 0.4
#define IndividualValueB 0.4

// 0.4 300.0 0.00001
#define PID_Kc 0.6
#define PID_Ti 0.0  // <- 0.0でもいいかも?
#define PID_Td 0.03
#define RATE   0.00006

#define PID_Kp 0.2
#define PID_Ki 0.0
#define PID_Kd 0.0




// csピン <-> mbedピン の対応
    #define cs01 p23
    #define cs02 p22
    #define cs03 p15
    #define cs04 p14
    #define cs05 p16
    #define cs06 p17
    #define cs07 p18
    #define cs08 p19
    #define cs09 p20
    #define cs10 p30
    #define cs11 p29
    #define cs12 p26
    #define cs13 p25

// デバッグ用の定義_
    // #define PING_RLB_  // 超音波(左,右,後)
    #define MOTOR_     // モータドライバ
    // #define KICK_DIV_  // キッカー, ドリブラー
    // #define IR_FR_     // IRボール距離(右前)
    // #define IR_BR_     // IRボール距離(右後)
    // #define IR_BL_     // IRボール距離(左前)
    // #define IR_FL_     // IRボール距離(左後)
    #define IR__       // IRボール方向
    // #define SDCARD_    // SDカード
    #define PING_F_    // 超音波(前,斜め)
    #define IMU_       // IMU(LSM9DS0)
    #define DEBUG_     // デバッグ
// #define MESSAGE
// #define PROG_TIME

// SPI通信に関するパラメータ
#define SPI_WAIT_US 2   // SPI通信の待ち時間(us)
#define t_SS_SCLK 0.002 // SSを指定してから、通信開始までの待ち時間(us)

// IRに関するマスク用数値
    #define DEG045 0x80
    #define DEG090 0x40
    #define DEG135 0x20
    #define DEG180 0x10
    #define DEG225 0x08
    #define DEG270 0x04
    #define DEG315 0x02
    #define DEG000 0x01



/*--- ピンの設定 ---*/
// LEDの設定
DigitalOut led_Motor(LED1, 0);
DigitalOut led_IR(LED2, 0);
DigitalOut led_IMU(LED3, 0);
DigitalOut led4(LED4, 0);
// SW
DigitalIn SW(p24);  // OFF then 1, ON then 0
// ラインセンサの許可信号
DigitalOut linePermission(p5, 1);
// ラインセンサのinputピン
DigitalIn lineLeft(p6);
DigitalIn lineRight(p7);
// Kickerのピン設定
DigitalIn kickerInput(cs03);
DigitalOut kickerOuput(p8, 1);
// SPI通信用のピン設定
    SPI spi(p11, p12, p13); // mosi, miso, clk
    DigitalOut cs_PingRLB(cs01, 1);         // 超音波(左,右,後)
    DigitalOut cs_Motor(cs02, 1);           // モータドライバ
    // DigitalOut cs_KickerDribbler(cs03, 1);  // キッカー, ドリブラー
    DigitalOut cs_Speed(cs04, 1);           // マウスセンサ(ADNS9800)
    DigitalOut cs_IRFrDistance(cs05, 1);    // IRボール距離(右前)
    DigitalOut cs_IRBrDistance(cs06, 1);    // IRボール距離(右後)
    DigitalOut cs_IRBlDistance(cs07, 1);    // IRボール距離(左前)
    DigitalOut cs_IRFlDistance(cs08, 1);    // IRボール距離(左後)
    DigitalOut cs_IR(cs09, 1);              // IRボール方向
    DigitalOut cs_SDcard(cs10, 1);          // SDカード
    DigitalOut cs_PingF(cs11, 1);           // 超音波(前,斜め)
    DigitalOut cs_IMU(cs12, 1);             // IMU(LSM9DS0)
    DigitalOut cs_Debug(cs13, 1);           // デバッグ
Ticker pidupdata;
// デバッグ用のSerial通信用のピン設定
PwmOut sound(p21);
#if 0
Serial pc(p9, p10);   // tx, rx
#else
Serial pc(USBTX, USBRX);   // tx, rx
#endif

// #define XBEE
#ifdef XBEE
Serial xbee(p9, p10);
#endif



/*--- グローバル変数 ---*/
int LoopCount = 0;
PID pidController(PID_Kc, PID_Ti, PID_Td, RATE);    // Kp, Ki, Kd, RATE
float moveDirection = 0.0;  // ロボットの進む方向
// PINGに関する変数
uint8_t pingFF, pingFR, pingFL;
uint8_t pingBR, pingBL, pingR, pingL;
// ロボットの行動に関する変数
int Integral=0;
int Direction = 0;
int8_t Angle=0, ex_Angle=0;
int dx=0, ex_dx=0, ex2_dx=0;
float R = 2.3;
float Omega = 0.0;
float Theta = 0.0;

// デバッグに関する変数
Timer t;
uint8_t MyRemoteAddress[] = {0x00,0x13,0xa2,0x00,0x40,0x7c,0x04,0xbd};    // コントローラのアドレス


// プロトタイプ宣言
    inline int bitCount(uint8_t bits);
    inline void lineMove();
    inline void lineCheck();
    inline bool SWcheck();
    void PingRead();
    inline int IRRead();
    void ImuRead();
    void PwmLRB1(float* pPwmL, float* pPwmR, float* pPwmB, float vx, float vy, float speed);
    void PwmLRB2(float* pPwmL, float* pPwmR, float* pPwmB, float vx, float vy, float speed);
    void PwmLRB3(float* pPwmL, float* pPwmR, float* pPwmB, float vx, float vy, float speed);
    void RegulationHeading(float* pPwmL, float* pPwmR, float* pPwmB);
    inline void Motor(float direction, float speed);
    inline float MoveDirection(int iBallDirection);
    bool spiChecking();
    inline void ControlCommand(uint8_t command);
    inline void serialChecking();




/*--- メッセージ表示用関数 ---*/
void msgD(int iTab, char *cMsg, int iValue, bool bNew=true)
{
    #ifdef MESSAGE
    for (int i=0; i<iTab; i++) pc.printf(" ");
    pc.printf("%s : %d", cMsg, iValue);
    if (bNew) pc.printf("\n");
    else pc.printf("   ");
    return;
    #endif
}
void msgF(int iTab, char *cMsg, float fValue, bool bNew=true)
{
    #ifdef MESSAGE
    for (int i=0; i<iTab; i++) pc.printf(" ");
    pc.printf("%s : %7.4f", cMsg, fValue);
    if (bNew) pc.printf("\n");
    else pc.printf("   ");
    return;
    #endif
}
void msgX(int iTab, char *cMsg, uint8_t ucValue, bool bNew=true)
{
    #ifdef MESSAGE
    for (int i=0; i<iTab; i++) pc.printf(" ");
    pc.printf("%s : %02x", cMsg, ucValue);
    if (bNew) pc.printf("\n");
    else pc.printf("   ");
    return;
    #endif
}
/*--- エラー表示用関数 ---*/
void errorMsgHex(int iTab, char *cMsg, uint8_t ucValue, bool bNew=true) // tab, message, value, new line
{
    #ifdef MESSAGE
    for (int i=0; i<iTab; i++) pc.printf(" ");
    pc.printf("error: %s   rx_data: %02x", cMsg, ucValue);
    if (bNew) pc.printf("\n");
    else pc.printf("   ");
    return;
    #endif
}
/*--- BitCount関数 ---*/
inline int bitCount(uint8_t bits)
{
    bits = (bits & 0x55) + (bits >> 1 & 0x55);
    bits = (bits & 0x33) + (bits >> 2 & 0x33);
    bits = (bits & 0x0f) + (bits >> 4 & 0x0f);
    bits = (bits & 0xff) + (bits >> 8 & 0xff);
    return (bits & 0xff) + (bits >>16 & 0xff);
}

inline void lineMove()
{
#if 1
    /*--- 反対方向に進む ---*/
    // if (Direction == 1000.0)
    //  return;
    // else if (Direction > 0.0)
    //  Motor(Direction-180.0, 1.0);
    // else
    //  Motor(Direction+180.0, 1.0);
    // wait(0.4);
    int stopDirecetion = 0;
    if (Direction > 0.0)
        stopDirecetion = Direction-180.0;
    else
        stopDirecetion = Direction+180.0;
    for (int i=0; i<700; i++) {
        ImuRead();
        pidController.setProcessValue(Angle);
        Omega = pidController.compute();
        Motor(1000.0, 0.0);
    }
    Motor(stopDirecetion, 0.4);
    wait(0.3);
#endif

#if 0
    /*--- 中央に戻ろうとする ---*/
    if (Direction == 1000.0)
        return;
    else if (lineLeft == 1 && lineRight == 0) {
        Motor(-90.0, 0.5);
    }
    else if (lineLeft == 0 && lineRight == 1) {
        Motor(90.0, 0.5);
    }
    else if (lineLeft == 1 && lineRight == 1) {
        if (Direction > 0.0)
            Motor(Direction-180.0, 1.0);
        else
            Motor(Direction+180.0, 1.0);
    }
    else return;
#endif

#if 0
    /*--- IRsensorの状況を見て行動 ---*/
    while (IRRead() != 1000.0) {
        ImuRead();
        pidController.setProcessValue(Angle);
        Omega = pidController.compute();
        Motor(moveDirection, 0.5);
        Direction = moveDirection;
    }
#endif
}


inline void lineCheck()
{
    // ラインセンサの状態をチェック
    if (lineLeft || lineRight) {
        lineMove();
    }
}

inline bool SWcheck()
{
    /*---
    ボタンが押されているかをチェック
    - ON-> '1'
    - OFF-> '0'
    ---*/
    if (!SW) {
        wait(0.3);
        if (SW) {
            wait(0.2);
            return 1;
        }
    }
    return 0;
}

/*--- 超音波による距離の測定 ---*/
void PingRead()
{
    cs_PingF = 0;
    pingFF = spi.write(0x01);  // 開始信号
    cs_PingF = 1;
    cs_PingF = 0;
    pingFF = spi.write(0x02);  // 正面
    cs_PingF = 1;
    cs_PingF = 0;
    pingFR = spi.write(0x03);  // 右前
    cs_PingF = 1;
    cs_PingF = 0;
    pingFL = spi.write(0x04);  // 左前
    cs_PingF = 1;

    #if 0
    cs_PingRLB = 0;
    pingL = spi.write(0x01);    // 開始信号
    cs_PingRLB = 1;
    cs_PingRLB = 0;
    pingL = spi.write(0x02);    // 左
    cs_PingRLB = 1;
    cs_PingRLB = 0;
    pingR = spi.write(0x03);    // 右
    cs_PingRLB = 1;
    cs_PingRLB = 0;
    pingBL = spi.write(0x04);   // 左後ろ
    cs_PingRLB = 1;
    cs_PingRLB = 0;
    pingBR = spi.write(0x05);   // 右後ろ
    cs_PingRLB = 1;
    #endif
}

/*--- ロボットから見たボールの方向を返す ---*/
inline int IRRead()
{
    /*---

    - IRのnearとfarのデータを取得
    - ボールのある方向を返す

    ---*/

    uint8_t near, far;
    // データを取得する
    cs_IR = 0;  wait_us(t_SS_SCLK); far = spi.write(0x00);  cs_IR = 1;
    wait_us(SPI_WAIT_US);
    cs_IR = 0;  wait_us(t_SS_SCLK); near = ~spi.write(0xFF);    cs_IR = 1;
    wait_us(SPI_WAIT_US);
    // データを解析して、進行方向を決定
    int iDirection = 0;
    int directionNear = 0;
    int directionFar  = 0;
    // int bitCountNear = bitCount(near);
    // int bitCountFar  = bitCount(far);

    // directionNear = ( ((DEG045 & near)?1:0) *  45
    //              + ((DEG090 & near)?1:0) *  90
    //              + ((DEG135 & near)?1:0) * 135
    //              + ((DEG180 & near)?1:0) * 180
    //              + ((DEG225 & near)?1:0) * 225
    //              + ((DEG270 & near)?1:0) * 270
    //              + ((DEG315 & near)?1:0) * 315
    //              + ((DEG000 & near)?1:0) * 000)
    //              / bitCountNear;
    // directionFar  = ( ((DEG045 & far)?1:0) *  45
    //              + ((DEG090 & far)?1:0) *  90
    //              + ((DEG135 & far)?1:0) * 135
    //              + ((DEG180 & far)?1:0) * 180
    //              + ((DEG225 & far)?1:0) * 225
    //              + ((DEG270 & far)?1:0) * 270
    //              + ((DEG315 & far)?1:0) * 315
    //              + ((DEG000 & far)?1:0) * 000)
    //              / bitCountFar;


    int iBitCountNear = 0;
    bool bBitFlag = false;
    int aiAngleData[] = {0, -45, -90, -135, 180, 135, 90, 45};
    int iAngleSum = 0;
    int iBaseAngle = 0;
    for (int i=0, j=0; i<8; i++) {
        if (near & 0x01) {
            iBitCountNear++;
            if (bBitFlag) {
                iAngleSum += aiAngleData[i-j];
            }
            else {
                bBitFlag = true;
                iBaseAngle = aiAngleData[i];
                j = i;
            }
        }
        near >>= 1;
    }
    iAngleSum /= iBitCountNear;
    directionNear = iBaseAngle + iAngleSum;

    if (iBitCountNear > 0) {
        iDirection = directionNear;
    }
    // else if (bitCountFar > 0) {
    //  iDirection = directionFar;
    // }
    else {
        iDirection = 1000.0;
    }

    // 角度を -180~+180 に修正
    if (iDirection > 180.0 && iDirection != 1000.0){
        iDirection -= 360.0;
    }
    else if (iDirection < -180.0 && iDirection != 1000.0){
        iDirection += 360.0;
    }

    msgD(0, "Direction", iDirection);

    return iDirection;
}

/*--- Union ---*/
union uni_8bits {
    uint8_t uint8;
    int8_t  int8;
};
/*--- IMUのデータを取得、Angleに代入 ---*/
void ImuRead()
{
    // 変数宣言
    int count = 5;
    uni_8bits data = {0};
    // データを受信
    do {
        cs_IMU = 0;
        data.uint8 = spi.write(0x50);
        cs_IMU = 1;
        count--;
        wait_us(SPI_WAIT_US);
    } while ((data.uint8==0xFF || data.uint8==0x00) && count);
    // 0~255 -> -128~127
    Angle = data.int8;
    msgD(0, "IMU", Angle);
}
/*--- 偏差から操作量Omegaを求める関数 ---*/
#if 0
void GetOmega() {
    // 偏差の差を求める
    if (-3<=Angle && Angle<=3) Angle=0;

    dx = Angle - ex_Angle;

    if (-3<=dx && dx<=3) {
        dx = 0;
        Angle = ex_Angle = (Angle+ex_Angle) / 2;
    }
    Integral /= 10;
    Integral += (Angle + ex_Angle) / 2;

    #if 1
    // 操作量Omegaを求める(PID制御)
    Omega = - (PID_Kp * (float)(Angle / 127.0))
            - (PID_Ki * (float)(Integral / 127.0))
            - (PID_Kd * (float)(dx / 127.0));
    #else
    // webページものも
    Omega+=  PID_Kp * (float)(dx)
            +PID_Ki * (float)(Angle)
            +PID_Kd * (float)((dx - ex_dx));
    #endif

    if (Omega < -1.0) {
        Omega = -1.0;
    }
    else if (Omega > 1.0) {
        Omega = 1.0;
    }

    msgF(0, "Omega", Omega);

    // データをずらす
    ex_dx = dx;
    ex_Angle = Angle;
}
#endif

/*--- pwmLRBを求める関数 ---*/
void PwmLRB1(float* pPwmL, float* pPwmR, float* pPwmB, float vx, float vy, float speed)
{
    /*---

    このサイトに載っている公式を使用 (http://wiki.tokor.org/index.php?%A5%AA%A5%E0%A5%CB%A5%DB%A5%A4%A1%BC%A5%EB%A4%CB%A4%E8%A4%EB%C1%B4%CA%FD%B8%FE%B0%DC%C6%B0%BC%D6%A4%CE%C0%A9%B8%E6%A1%A1-%A1%A1%B5%A1%B3%A3%C0%A9%B8%E6)

    ---*/
    float pwmL =  vx * cos(Theta+PI*5/6)+ vy * sin(Theta+PI*5/6) - R*Omega;
    float pwmR =  vx * cos(Theta+PI/6)  + vy * sin(Theta+PI/6)   - R*Omega;
    float pwmB =  vx * cos(Theta-PI/2)  + vy * sin(Theta-PI/2)   - R*Omega;
    /*--- 最大値を求める ---*/
    float pwmMAX = fabs(pwmL);
    float aPwmR = fabs(pwmR);
    float aPwmB = fabs(pwmB);
    pwmMAX = (pwmMAX > aPwmR) ? pwmMAX : aPwmR;
    pwmMAX = (pwmMAX > aPwmB) ? pwmMAX : aPwmB;
    /*--- 求めた最大値で正規化 ---*/
    pwmL = pwmL / pwmMAX * speed * IndividualValueL;
    pwmR = pwmR / pwmMAX * speed * IndividualValueR;
    pwmB = pwmB / pwmMAX * speed * IndividualValueB;

    /*--- 値を反映 ---*/
    *pPwmL = pwmL;
    *pPwmR = pwmR;
    *pPwmB = pwmB;
}
void PwmLRB2(float* pPwmL, float* pPwmR, float* pPwmB, float vx, float vy, float speed)
{
    float pwmL =  vx * cos(Theta+PI*5/6)+ vy * sin(Theta+PI*5/6);
    float pwmR =  vx * cos(Theta+PI/6)  + vy * sin(Theta+PI/6)  ;
    float pwmB =  vx * cos(Theta-PI/2)  + vy * sin(Theta-PI/2)  ;
    /*--- 最大値を求める ---*/
    float pwmMAX = fabs(pwmL);
    float aPwmR = fabs(pwmR);
    float aPwmB = fabs(pwmB);
    pwmMAX = (pwmMAX > aPwmR) ? pwmMAX : aPwmR;
    pwmMAX = (pwmMAX > aPwmB) ? pwmMAX : aPwmB;
    /*--- 求めた最大値で正規化 ---*/
    pwmL = pwmL / pwmMAX * speed * IndividualValueL * 0.7 - 0.3*Omega;
    pwmR = pwmR / pwmMAX * speed * IndividualValueR * 0.7 - 0.3*Omega;
    pwmB = pwmB / pwmMAX * speed * IndividualValueB * 0.7 - 0.3*Omega;

    /*--- 値を反映 ---*/
    *pPwmL = pwmL;
    *pPwmR = pwmR;
    *pPwmB = pwmB;
}
void PwmLRB3(float* pPwmL, float* pPwmR, float* pPwmB, float vx, float vy, float speed)
{
    /*---

    このサイトに載っていた方法の応用を使う (http://yukispanicworld.tumblr.com/post/106053191409)
    - 旋回は、求めた値の割合の変化分を足し合わせることによって行う

    ---*/
    float pwmL =  vx * cos(Theta+PI*5/6)+ vy * sin(Theta+PI*5/6);
    float pwmR =  vx * cos(Theta+PI/6)  + vy * sin(Theta+PI/6)  ;
    float pwmB =  vx * cos(Theta-PI/2)  + vy * sin(Theta-PI/2)  ;
    /*--- 最大値を求める ---*/
    float pwmMAX = fabs(pwmL);
    float aPwmR = fabs(pwmR);
    float aPwmB = fabs(pwmB);
    pwmMAX = (pwmMAX > aPwmR) ? pwmMAX : aPwmR;
    pwmMAX = (pwmMAX > aPwmB) ? pwmMAX : aPwmB;
    /*--- 求めた最大値で正規化 ---*/
    pwmL = pwmL / pwmMAX * speed;
    pwmR = pwmR / pwmMAX * speed;
    pwmB = pwmB / pwmMAX * speed;
    /*--- 旋回を考慮する ---*/
    float k = 0.07;
    pwmL += pwmL * k*Omega;
    pwmR += pwmR * k*Omega;
    pwmB += pwmB * k*Omega;
    /*--- 値を反映 ---*/
    *pPwmL = pwmL;
    *pPwmR = pwmR;
    *pPwmB = pwmB;
}
void RegulationHeading(float* pPwmL, float* pPwmR, float* pPwmB)
{
    float k = 1.0;  // 調節用の係数
    float pwmL =  - Omega * k * IndividualValueL;
    float pwmR =  - Omega * k * IndividualValueR;
    float pwmB =  - Omega * k * IndividualValueB;

    /*--- 値を反映 ---*/
    *pPwmL = pwmL;
    *pPwmR = pwmR;
    *pPwmB = pwmB;
}
/*--- モータの計算と通信 ---*/
inline void Motor(float direction, float speed)
{
    uint8_t rx_data;

    /*--- 計算に必要となる値 ---
    * 方向 ... direction (deg)
    * 速度 ... speed (m/s)
    * 機体の回転数 ... Omega (rad/s)
    * 機体の半径 ... R (m)
    * 機体の基準に対する傾き ... Theta (rad)
    * pwmL(左), pwmB(後), pwmR(右)
    --*/

    // 変数宣言
    float pwmL, pwmB, pwmR;



    // 停止コマンドのときの処理
    if (direction == 1000.0) {
        RegulationHeading(&pwmL, &pwmR, &pwmB);
    }
    // 普通のときの処理
    else {
        // Theta = Angle * Byte2Rad;
        direction *= Deg2Rad;
        float vx = cos(direction);
        float vy = sin(direction);

        PwmLRB1(&pwmL, &pwmR, &pwmB, vx, vy, speed);
        // PwmLRB2(&pwmL, &pwmR, &pwmB, vx, vy, speed);
        // PwmLRB3(&pwmL, &pwmR, &pwmB, vx, vy, speed);
    }

    msgF(0, "pwmL", pwmL, false);
    msgF(0, "pwmR", pwmR, false);
    msgF(0, "pwmB", pwmB, false);

    // 回転方向を決定 と マイナスだったらプラスに変える
    uint8_t data0 = 0x3F;   // 0011 1111
    if (pwmL!=0.0 && pwmR!=0.0 && pwmB!=0.0) {
        // 左モータ
        if (pwmL>0) {
            data0 &= 0x37;  // 0011 0111
        }
        else {
            data0 &= 0x3B;  // 0011 1011
            pwmL *= -1.0;
        }
        if (pwmL>1.0) pwmL=1.0;

        // 右モータ
        if (pwmR>0) {
            data0 &= 0x3D;  // 0011 1101
        }
        else {
            data0 &= 0x3E;  // 0011 1110
            pwmR *= -1.0;
        }
        if (pwmR>1.0) pwmR=1.0;

        // 後モータ
        if (pwmB>0) {
            data0 &= 0x1F;  // 0001 1111
        }
        else {
            data0 &= 0x2F;  // 0010 1111
            pwmB *= -1.0;
        }
        if (pwmB>1.0) pwmB=1.0;
    }
    else data0 = 0x00;

    uint8_t dataL = (uint8_t)(pwmL * 255.0);    // 左モータの回転数
    uint8_t dataR = (uint8_t)(pwmR * 255.0);    // 右モータの回転数
    uint8_t dataB = (uint8_t)(pwmB * 255.0);    // 後モータの回転数
    if (dataL == 0x00) {
        data0 &= 0x33;  // 0011 0011
        data0 |= 0x0C;
        dataL++;
    }
    if (dataR == 0x00) {
        data0 &= 0x3C;  // 0011 1100
        data0 |= 0x03;
        dataR++;
    }
    if (dataB == 0x00) {
        data0 &= 0x0F;  // 0000 1111
        data0 |= 0x30;
        dataB++;
    }

    // データ確認用の値を埋め込む
    dataL = dataL & 0xFC | 0x01;
    dataR = dataR & 0xFC | 0x02;
    dataB = dataB & 0xFC | 0x03;

    // デバッグのため、送信データを表示
    // pc.printf("  ");
    msgX(0, "data0", data0, false);
    msgX(0, "dataL", dataL, false);
    msgX(0, "dataR", dataR, false);
    msgX(0, "dataB", dataB, true);

    // データを送信
    int error = 0;
    int count = 0;
    while (1) {
        // 通信開始の合図
            cs_Motor=0; wait_us(t_SS_SCLK);
            rx_data=spi.write((uint8_t)(error%4));  wait_us(t_SS_SCLK);
            cs_Motor=1;
            if (rx_data!=0xAA) {
                errorMsgHex(0, "start", rx_data);
                // errorMsgHex(0, "start_data", (uint8_t)(error%4));
            }
            wait_us(SPI_WAIT_US);
        // 回転方向のデータ
            do {
                cs_Motor=0; wait_us(t_SS_SCLK);
                rx_data=spi.write(data0);   wait_us(t_SS_SCLK);
                cs_Motor=1;
                count++;
            } while(rx_data != 0x00 && count < 5);
            if (rx_data!=0x00) {
                errorMsgHex(0, "data0", rx_data);
                led_Motor = 0;
                error++;
                continue;
            } else led_Motor = 1;
            msgD(0, "count", count);
            count = 0;
            wait_us(SPI_WAIT_US);
        // MotorLのデータ
            do {
                cs_Motor=0; wait_us(t_SS_SCLK);
                rx_data=spi.write(dataL);   wait_us(t_SS_SCLK);
                cs_Motor=1;
                count++;
            } while(rx_data != data0 && count < 5);
            if (rx_data!=data0) {
                errorMsgHex(0, "dataL", rx_data);
                led_Motor = 0;
                error++;
                continue;
            } else led_Motor = 1;
            msgD(0, "count", count);
            count = 0;
            wait_us(SPI_WAIT_US);
        // MotorRのデータ
            do {
                cs_Motor=0; wait_us(t_SS_SCLK);
                rx_data=spi.write(dataR);   wait_us(t_SS_SCLK);
                cs_Motor=1;
                count++;
            } while(rx_data != dataL && count < 5);
            if (rx_data!=dataL) {
                errorMsgHex(0, "dataR", rx_data);
                led_Motor = 0;
                error++;
                continue;
            } else led_Motor = 1;
            msgD(0, "count", count);
            count = 0;
            wait_us(SPI_WAIT_US);
        // MotorBのデータ
            do {
                cs_Motor=0; wait_us(t_SS_SCLK);
                rx_data=spi.write(dataB);   wait_us(t_SS_SCLK);
                cs_Motor=1;
                count++;
            } while(rx_data != dataR && count < 5);
            if (rx_data!=dataR) {
                errorMsgHex(0, "dataB", rx_data);
                led_Motor = 0;
                error++;
                continue;
            } else led_Motor = 1;
            msgD(0, "count", count);
            count = 0;
            wait_us(SPI_WAIT_US);

        break;
    }

    return;
}

/*--- ボールの方向から、ロボットの進行方向を決める関数 ---*/
inline float MoveDirection(int iBallDirection)
{
    /*---

    - ボールの方向から、ロボットの進行方向を求める関数
    - -180 < iBallDirection < +180

    ---*/

    if (iBallDirection == 1000.0) return 1000.0;

    float fMoveDirection = 0.0;
    if (-30<iBallDirection && iBallDirection<30)    fMoveDirection = 0.0;
    else if (iBallDirection > 0)                    fMoveDirection = iBallDirection+60.0;
    else if (iBallDirection < 0)                    fMoveDirection = iBallDirection-60.0;
    else                                            fMoveDirection = 180.0;

    // 角度を -180~+180 に修正
    if (fMoveDirection > 180.0){
        return fMoveDirection - 360.0;
    }
    if (fMoveDirection < -180.0){
        return fMoveDirection + 360.0;
    }

    return fMoveDirection;
}


/*--- SPI通信確認 ---*/
bool spiChecking()
{
    int spicheck = 0;
    uint8_t data = 0;
    uint8_t missData1 = 0;
    uint8_t missData2 = 0;
    uint8_t missData3 = 0;
    uint8_t missData4 = 0;
    pc.printf("\nChecking SPI...\n");

    #ifdef PING_RLB_
        cs_PingRLB        = 0;  missData1 = spi.write(0x50);    cs_PingRLB        = 1;  wait_us(SPI_WAIT_US);
        cs_PingRLB        = 0;  missData2 = spi.write(0x50);    cs_PingRLB        = 1;  wait_us(SPI_WAIT_US);
        cs_PingRLB        = 0;  data = spi.write(0x50);         cs_PingRLB        = 1;
        if (data != 0xAA) {
            pc.printf("##Bad##  mbed <-> LPC1114 <-> Ping(RLB)\n");
            pc.printf("    MissData1 = %x\n    MissData2 = %x\n    MissData3 = %x\n", missData1, missData2, data);
            spicheck++;
        }
    #endif

    #ifdef MOTOR_
        led_Motor = 0;
        // ちゃんと値が入っているかをチェック
        cs_Motor          = 0;  missData1 = spi.write(0x51);    cs_Motor          = 1;  wait_us(SPI_WAIT_US);
        cs_Motor          = 0;  missData2 = spi.write(0x51);    cs_Motor          = 1;  wait_us(SPI_WAIT_US);
        cs_Motor          = 0;  missData3 = spi.write(0x51);    cs_Motor          = 1;  wait_us(SPI_WAIT_US);
        cs_Motor          = 0;  missData4 = spi.write(0x51);    cs_Motor          = 1;  wait_us(SPI_WAIT_US);
        cs_Motor          = 0;  data = spi.write(0x01);         cs_Motor          = 1;
        pc.printf("    ReturnValue1 = %x\n    ReturnValue2 = %x\n    ReturnValue3 = %x\n    ReturnValue4 = %x\n    ReturnValue5 = %x\n", missData1, missData2, missData3, missData4, data);
        // SPI通信のチェック
        cs_Motor          = 0;  missData1 = spi.write(0x50);    cs_Motor          = 1;  wait_us(SPI_WAIT_US);
        cs_Motor          = 0;  missData2 = spi.write(0x50);    cs_Motor          = 1;  wait_us(SPI_WAIT_US);
        cs_Motor          = 0;  data = spi.write(0x01);         cs_Motor          = 1;
        if (data != 0xAA) {
            pc.printf("##Bad##   mbed <-> CY8C29466 <-> Motor\n");
            pc.printf("    MissData1 = %x\n    MissData2 = %x\n    MissData3 = %x\n", missData1, missData2, data);
            spicheck++;
        }
        else led_Motor=1;
    #endif

    #ifdef KICK_DIV_
        cs_KickerDribbler = 0;  missData1 = spi.write(0x50);    cs_KickerDribbler = 1;  wait_us(SPI_WAIT_US);
        cs_KickerDribbler = 0;  missData2 = spi.write(0x50);    cs_KickerDribbler = 1;  wait_us(SPI_WAIT_US);
        cs_KickerDribbler = 0;
        data = spi.write(0x01);
        cs_KickerDribbler = 1;
        if (data != 0xAA) {
            pc.printf("##Bad##   mbed <-> CY8C29466 <-> Kicker&Dribbler\n");
            pc.printf("    MissData1 = %x\n    MissData2 = %x\n    MissData3 = %x\n", missData1, missData2, data);
            spicheck++;
        }
    #endif

    #ifdef IR_FR_
        cs_IRFrDistance   = 0;  missData1 = spi.write(0x50);    cs_IRFrDistance   = 1;  wait_us(SPI_WAIT_US);
        cs_IRFrDistance   = 0;  missData2 = spi.write(0x50);    cs_IRFrDistance   = 1;  wait_us(SPI_WAIT_US);
        cs_IRFrDistance   = 0;  data = spi.write(0x01);         cs_IRFrDistance   = 1;
        if (data != 0xAA) {
            pc.printf("##Bad##   mbed <-> CY8C24123A <-> IR_FR_distance\n");
            pc.printf("    MissData1 = %x\n    MissData2 = %x\n    MissData3 = %x\n", missData1, missData2, data);
            spicheck++;
        }
    #endif

    #ifdef IR_BR_
        cs_IRBrDistance   = 0;  missData1 = spi.write(0x50);    cs_IRBrDistance   = 1;  wait_us(SPI_WAIT_US);
        cs_IRBrDistance   = 0;  missData2 = spi.write(0x50);    cs_IRBrDistance   = 1;  wait_us(SPI_WAIT_US);
        cs_IRBrDistance   = 0;  data = spi.write(0x01);         cs_IRBrDistance   = 1;
        if (data != 0xAA) {
            pc.printf("##Bad##   mbed <-> CY8C24123A <-> IR_BR_distance\n");
            pc.printf("    MissData1 = %x\n    MissData2 = %x\n    MissData3 = %x\n", missData1, missData2, data);
            spicheck++;
        }
    #endif

    #ifdef IR_BL_
        cs_IRBlDistance   = 0;  missData1 = spi.write(0x50);    cs_IRBlDistance   = 1;  wait_us(SPI_WAIT_US);
        cs_IRBlDistance   = 0;  missData2 = spi.write(0x50);    cs_IRBlDistance   = 1;  wait_us(SPI_WAIT_US);
        cs_IRBlDistance   = 0;  data = spi.write(0x01);         cs_IRBlDistance   = 1;
        if (data != 0xAA) {
            pc.printf("##Bad##   mbed  <-> CY8C24123A <-> IR_BL_distance\n");
            pc.printf("    MissData1 = %x\n    MissData2 = %x\n    MissData3 = %x\n", missData1, missData2, data);
            spicheck++;
        }
    #endif

    #ifdef IR_FL_
        cs_IRFlDistance   = 0;  missData1 = spi.write(0x50);    cs_IRFlDistance   = 1;  wait_us(SPI_WAIT_US);
        cs_IRFlDistance   = 0;  missData2 = spi.write(0x50);    cs_IRFlDistance   = 1;  wait_us(SPI_WAIT_US);
        cs_IRFlDistance   = 0;  data = spi.write(0x01);         cs_IRFlDistance   = 1;
        if (data != 0xAA) {
            pc.printf("##Bad##   mbed  <-> CY8C24123A <-> IR_FL_distance\n");
            pc.printf("    MissData1 = %x\n    MissData2 = %x\n    MissData3 = %x\n", missData1, missData2, data);
            spicheck++;
        }
    #endif

    #ifdef IR__
        led_IR = 0;
        cs_IR             = 0;  missData1 = spi.write(0x50);    cs_IR             = 1;  wait_us(SPI_WAIT_US);
        cs_IR             = 0;  missData2 = spi.write(0x50);    cs_IR             = 1;  wait_us(SPI_WAIT_US);
        cs_IR             = 0;  data = spi.write(0x01);         cs_IR             = 1;
        if (data != 0xAA) {
            pc.printf("##Bad##   mbed  <-> CY8C29466 <-> IR_direction\n");
            pc.printf("    MissData1 = %x\n    MissData2 = %x\n    MissData3 = %x\n", missData1, missData2, data);
            spicheck++;
        }
        else led_IR=1;
    #endif

    #ifdef PING_F_
        cs_PingF          = 0;  missData1 = spi.write(0x50);    cs_PingF          = 1;  wait_us(SPI_WAIT_US);
        cs_PingF          = 0;  missData2 = spi.write(0x50);    cs_PingF          = 1;  wait_us(SPI_WAIT_US);
        cs_PingF          = 0;  data = spi.write(0x01);         cs_PingF          = 1;
        if (data != 0xAA) {
            pc.printf("##Bad##   mbed <-> LPC1114 <-> Ping(F)\n");
            pc.printf("    MissData1 = %x\n    MissData2 = %x\n    MissData3 = %x\n", missData1, missData2, data);
            spicheck++;
        }
    #endif

    #ifdef IMU_
        led_IMU = 0;
        int count = 5;
        do {
            cs_IMU            = 0;  data = spi.write(0x50); cs_IMU            = 1;  wait_us(SPI_WAIT_US);
            pc.printf("data : %x\n", data);
            count--;
        } while ((data==0xFF || data==0x00) && count);

        if (count < 1) {
            spicheck++;
            pc.printf("##Bad##   mbed <-> LPC1114 <-> LSM9DS0\n");
        }
        else led_IMU=1;
        pc.printf("    IMU : %d\n", data);
    #endif

    #ifdef DEBUG_
        cs_Debug          = 0;  missData1 = spi.write(0x50);    cs_Debug          = 1;  wait_us(SPI_WAIT_US);
        cs_Debug          = 0;  missData2 = spi.write(0x50);    cs_Debug          = 1;  wait_us(SPI_WAIT_US);
        cs_Debug          = 0;  data = spi.write(0x01);         cs_Debug          = 1;
        if (data != 0xAA) {
            pc.printf("##Bad##   mbed <-> LPC1114_DEBUG\n");
            pc.printf("    MissData1 = %x\n    MissData2 = %x\n    MissData3 = %x\n", missData1, missData2, data);
            spicheck++;
        }
    #endif

    // 最後にメッセージを表示
    if (spicheck) {
        pc.printf("waring : %d\n", spicheck);
        led4 = 0;
        // while (!pc.readable());      // PCから指示があるまで待つ
        // pc.getc();
        return 0;
        wait(2);
    }
    else {
        pc.printf("All SPIdevices complete!!\n");
        led4 = 1;
        return 1;
        wait(1);
    }
    pc.printf("\n");
}


/*--- PCとの通信用関数 ---*/
inline void ControlCommand(uint8_t command)
{
    /*--- コマンド一覧 ---
    * 必要なparameter
    0x01    PID_Kp      PID制御の比例
    0x02    PID_Ki      PID制御の積分
    0x03    PID_Kd      PID制御の微分
    0x04    Robo_R      機体の半径

    * 必要なcommand
    0x10    modeStop        停止コマンド
    0x11    modeBattle1     戦闘モード1
    0x12    modeBattle2     戦闘モード2
    0x13    modeDebug       デバッグモード
    0x21    goFlont         前進
    0x22    goBack          後退
    0x23    goLeft          左
    0x24    goRight         右
    0x25    turnCW          時計回りに一回転
    0x26    turnCCW         反時計回りに一回転
    0x31    checkSensor     センサーチェック
    0x31    checkIMU        IMUからの情報を画面に表示
    0xAA    Reset           リセット(SDカードから、値を再読み込み)
    ---*/
    float wait_time = 1.0;
    switch (command)
    {
        case 0xAA:
            break;
        case 0x13:  // modeDebug
            spiChecking();
            wait(3);
            break;
        case 0x21:  // goFlont
            Motor(0.0, 0.3);
            wait(wait_time);
            break;
        case 0x22:  // goBack
            Motor(180.0, 0.3);
            wait(wait_time);
            break;
        case 0x23:  // goLeft
            Motor(-90.0, 0.3);
            wait(wait_time);
            break;
        case 0x24:  // goRight
            Motor(90.0, 0.3);
            wait(wait_time);
            break;
        default:
            break;
    }
}


#ifdef XBEE
/*--- 送信用関数 ---*/
void xbeeTx(uint8_t *address, uint8_t data) {
    int i=0;

    xbee.putc(0x7E);
    xbee.putc(0x00);    // フレーム長
    xbee.putc(0x0F);
    xbee.putc(0x10);    // フレームタイプ
    xbee.putc(0x01);    // フレームID
    for (int i=0; i<8; i++)
        xbee.putc(address[i]);  // 62bit宛先アドレス
    xbee.putc(0xFF);    // 16bit宛先ネットワークアドレス
    xbee.putc(0xFE);
    xbee.putc(0x00);    // ブロードキャスト半径
    xbee.putc(0x00);    // オプション
    xbee.putc(data);    // RFデータ
    // チェックサムの計算
    uint8_t checksum = 0xFF - (0x10+0x01+0xFF+0xFE+data);
    for (i=0; i<8; i++)  checksum -= address[i];
    xbee.putc(checksum);    // チェックサム

    // 送信ステータスの確認
    if (xbee.readable()) {
        if (xbee.getc() == 0x7E) {
            for (i=0; i<8; i++) xbee.getc();
            if (xbee.getc() == 0x00)
                // pc.printf("Send success!\n");
            else
                // pc.printf("Send missed.\n");
            for (i=9; i<10; i++) xbee.getc();
        }
    }
}
/*--- 受信用関数 ---*/
xbeeAPI xbeeRx() {
    xbeeAPI returnApi;  // 返り値用の変数
    returnApi.reset();
    if (xbee.readable() > 0) {
        // pc.printf("readable\n");
    if (xbee.getc() == 0x7E) {
        // pc.printf("startBit\n");
        int i=0;
        uint8_t buffer[18];

        buffer[0] = 0x7E;
        for (i=1; i<18; i++) {
            buffer[i] = xbee.getc();
        }
        // 送信元アドレスを抽出
        for (i=0; i<8; i++) {
            returnApi.address[i] = buffer[i+4];
        }
        // 受信データを抽出
        returnApi.direction = buffer[15];
        returnApi.turning   = buffer[16];

        // データをPCに表示
        // for (i=0; i<8; i++)  pc.printf("%x", returnApi.address[i]);
        // pc.printf("\n");
        // pc.printf("%x\n", returnApi.direction);
        // pc.printf("%x\n", returnApi.turning);
    }
    }
    return returnApi;
}
#endif

/*--- serialの通信チェック関数 ---*/
inline void serialChecking()
{
    if ( pc.readable() ) {
        uint8_t command = pc.getc();
        printf("command : %x\n", pc.getc());
        ControlCommand(command);
    }
}




int main()
{
    /*--- 変数宣言 ---*/
    int direction = 0;  // ボールのある方向
    float speed = 0.0;  // ロボットの速度

    /*--- 初期処理 ---*/
    // 音
    float mm[]={mC,mD,mE,mF,mG,mA,mB,mC*2}; // ドレミファソラシ
    sound.period(1.0/mm[0]);
    sound = 0.03;
    // Serialの設定
    pc.baud(115200);
    // SPIの初期設定
    spi.format(8, 3); // DataFlameのビット数(4~16)
    spi.frequency(1000000); // クロック周波数(デフォルト:1MHz)
    // ラインセンサに許可信号を
    linePermission=1;
    wait(1);  // 各モジュールのセットアップが完了するまで待つ

    // PIDライブラリの初期設定
    pidController.setInputLimits(-128.0, 127.0);
    pidController.setOutputLimits(-1.0, 1.0);
    pidController.setBias(0.0);
    pidController.setMode(AUTO_MODE);
    pidController.setSetPoint(0.0);
    // pidupdata.attach(&ImuRead, RATE);

    // lineの設定
    // lineLeft.rise(&lineMove);
    // lineRight.rise(&lineMove);

    // SPIの通信確認
    while ( !spiChecking() );


    /*--- スタートの合図を待つ ---*/
    kickerOuput = 1;
    // SWが押されるまで待つ
    sound.period(1.0/mm[1]);
    sound = 0.06;
    while(!SWcheck());
    // 音を止める
    sound = 0.00;


    /*--- メイン処理 ---*/
    while(true) {

        #ifdef PROG_TIME
        t.start();
        #endif

        /*--- pcとの通信があったかをCheck ---*/
        // serialChecking();
        /*--- ストップボタンをCheck ---*/
        if (SWcheck()) {
            Motor(0.0, 0.0);
            sound.period(1.0/mm[1]);
            sound = 0.06;
            while(!SWcheck());
            sound = 0.00;
        }
        lineCheck();

        // PingRead();

        /*--- 現在の方角を確認 ---*/
        // Kicker使用時は、IMUの値は参考にならないので無視する
        // if (kickerInput) {
        //  kickerOuput = 1;
        //  wait(0.8);
        //  kickerOuput = 0;
        // } else {
        //  ImuRead();
        //  pidController.setProcessValue(Angle);
        // }
        ImuRead();
        pidController.setProcessValue(Angle);
        lineCheck();

        /*--- ロボットから見たボールの方向を確認 ---*/
        direction = IRRead();
        lineCheck();

        /*--- ボールの方向の絶対値を算出 ---*/
        if (direction != 1000.0) {
            direction += Angle;
            if (direction > 180.0){
                direction -= 360.0;
            }
            else if (direction < -180.0){
                direction += 360.0;
            }
        }
        lineCheck();

        /*--- ロボットの進行方向を決定 ---*/
        moveDirection = MoveDirection(direction);
        // pc.printf("%f\n", moveDirection);
        lineCheck();

        /*--- 修正のための角速度を算出 ---*/
        // GetOmega();
        Omega = pidController.compute();
        if (-5<Angle && Angle<5) {
            Omega = 0.0;
        }
        lineCheck();

        /*--- 実際にロボットを動かす ---*/
        // moveDirection = 0.0;
        // moveDirection = 1000.0;
        Motor(moveDirection, 0.4);
        lineCheck();

        Direction = moveDirection;


        #ifdef PROG_TIME
        t.stop();
        pc.printf("%f\n", t.read());
        t.reset();
        #endif

        LoopCount++;
    }
}