大会本番用

Dependencies:   mbed SpeedController hcsr04 Encoder CruizCore_R1370P

main.cpp

Committer:
maxnagazumi
Date:
2020-03-27
Revision:
2:0be4cfbdf408
Parent:
1:a692014d8e41

File content as of revision 2:0be4cfbdf408:

#include "mbed.h"
#include "EC.h"
#include "SpeedController.h"
#include "math.h"
#include "R1370P.h"
#include"hcsr04.h"
#define RESOLUTION 500

CAN can1(PB_5,PB_13);
/*
0 start/stop
1 to 4 , 6 to 9
5 stop
10 clock move
11 not clock move
12 speed change
*/
Ec2multi ec[]= {
    Ec2multi(PC_5,PB_2,RESOLUTION),
    Ec2multi(PA_11,PB_1,RESOLUTION),
    Ec2multi(PB_12,PB_15,RESOLUTION),
    Ec2multi(PC_4,PB_14,RESOLUTION)
};  //2逓倍用class

Ec2multi ecXY[]= {
    Ec2multi(PC_6,PB_8,RESOLUTION),
    Ec2multi(PC_8,PB_9,RESOLUTION)
};

SpeedControl motor[]= {
    SpeedControl(PA_5,PC_7,50,ec[0]),
    SpeedControl(PC_9,PA_1,50,ec[1]),
    SpeedControl(PA_10,PB_4,50,ec[2]),
    SpeedControl(PA_9,PA_7,50,ec[3])
};

DigitalIn button(USER_BUTTON);
Serial pc(USBTX, USBRX); // tx, rx
R1370P gyro(PC_10,PC_11);   // tx, rx

/*HCSR04 echo[]= {
    HCSR04(PC_0,PC_12)//A
    ,HCSR04(PA_15,PB_7)//A
    ,HCSR04(PH_1,PB_0)// B
    ,HCSR04(PC_3,PB_10)//B
};*/

//自己位置取得
double theta;
double angle;

class Location
{
public:
    Location():x_(0),y_(0)
    {
        for(int i =0; i<2; i++) {
            old_count[i]=0;
        }
    }
    void calXY()
    {
        double ec_count[2]= {};
        double ax,ay,bx,by;
        double atheta,btheta;
        atheta = (45+theta)/180*3.14;
        btheta = (135+theta)/180*3.14;

        ec_count[0]=ecXY[0].getCount();
        ec_count[1]=ecXY[1].getCount();
        ax = (ec_count[0]-old_count[0])*cos(atheta);
        ay = (ec_count[0]-old_count[0])*sin(atheta);
        bx = (ec_count[1]-old_count[1])*cos(btheta);
        by = (ec_count[1]-old_count[1])*sin(btheta);
        x_=x_+ax + bx;
        y_=y_+ay + by;
        old_count[0]=ec_count[0];
        old_count[1]=ec_count[1];
    }
    double getX()
    {
        return x_;
    }
    double getY()
    {
        return y_;
    }

private:
    double x_;
    double y_;
    double old_count[2];
};



//目的地決定
int plot[][2]= {
    {0,0}
    ,{2000,16000}
    ,{8000,16000}
    ,{4000,0}
    ,{0,0}
    ,{0,4000}
    ,{4000,4000}
    ,{4000,0}
    ,{0,0}
};

double aimTheta[]= {//目標角度を指定
    0,0,0,0,0,0,0,0,0,0,0,0
};

double zMin[]= { //速度の最少を指定
    0,0,0,0,0,0,0,0,0,0,0,0
};

//出力を計算
int x,y;

class WheelOmega
{
public:
    WheelOmega(): max_(0),vx_(0),vy_(0),theta_(0)
    {
        for(int i=0; i<4; i++) {
            omega[i]=0;
        }
    }
    void setOmega(double max,double k)
    {
        max_=max;
        k_=k;

    }
    void setVxy(double vx,double vy,double aimtheta_)
    {
        vx_=vx;
        vy_=vy;
        theta_=aimtheta_ - theta;
        if(theta_>30) {//目標角度まで30度以上空いていたら補正、係数調整のため30は適当
            theta_=30;
        }
        if(theta_<-30) {
            theta_=-30;
        }
    }
    void calOmega()
    {
        double theta_rad=45/180*3.14;
        omega[0]=max_*vx_*cos(theta_rad)-max_*vy_*cos(theta_rad) + theta_*k_;
        omega[1]=-max_*vx_*cos(theta_rad)-max_*vy_*cos(theta_rad)+theta_*k_;
        omega[2]=-max_*vx_*cos(theta_rad)+max_*vy_*cos(theta_rad)+theta_*k_;
        omega[3]=max_*vx_*cos(theta_rad)+max_*vy_*cos(theta_rad)+theta_*k_;
    };
    double getOmega(int i)
    {
        return omega[i];
    }
private:
    double max_,vx_,vy_,theta_,k_;
    double omega[4];
};

WheelOmega omega;
//パラメタ処理
double pControl(double distance_,double zMin,double newtime)
{
    double z,zMax,olddistance,oldtime;
    double diftime_;
    diftime_ = newtime - oldtime;
    oldtime= newtime;
    z=0.004*distance_ - 0.1*(olddistance-distance_)/diftime_;
    zMax=2;
    if(z>zMax) {
        z=zMax;
    }
    if(z<zMin) {
        z=zMin;
    }
    if(newtime<1) {
        z=z*newtime;
    }
    olddistance = distance_;
    return z;
}

//超音波
/*class Sonic
{
public:
    Sonic()
    {
        for(int i=0; i<4; i++) {
            sonic_cm[i]=0;
        }
    }

    void cal_sonic()
    {
        for(int i=0; i<4; i++) {
            echo[i].start();
        }
        for(int i=0; i<4; i++) {
            sonic_cm[i] =echo[i].get_dist_cm();
        }
    }
    double get_sonic(int i)
    {
        return sonic_cm[i];
    }

private:
    double sonic_cm[4];
};

*/
class CAN_ticker
{
public:
    CAN_ticker():x(0)
    {
        data[0]=0;
    }
    void canmsg_read()
    {
        CANMessage msg;
        if(can1.read(msg)) {
            if(msg.id == 1) {
                x=(short)(msg.data[0]);
            }
        }
    }
    int get_xCAN()
    {
        return x;
    }
private:
    char data[0];
    int x;
};
//手動出力
double canOmega[4]= {
    0,0,0,0
};
void calOmega_CAN(int canx)
{
    static double a=0.1;
    static int count=0;
    switch(canx) {
        case 1:
            canOmega[0]=0;
            canOmega[1]=a;
            canOmega[2]=0;
            canOmega[3]=-a;
            printf("   1");
            break;
        case 2:
            canOmega[0]=a*1.4;
            canOmega[1]=a*1.4;
            canOmega[2]=-a*1.4;
            canOmega[3]=-a*1.4;
            printf("   2");
            break;
        case 3:
            canOmega[0]=a;
            canOmega[1]=0;
            canOmega[2]=-a;
            canOmega[3]=0;
            printf("   3");
            break;
        case 4:
            canOmega[0]=-a*1.4;
            canOmega[1]=a*1.4;
            canOmega[2]=a*1.4;
            canOmega[3]=-a*1.4;
            printf("   4");
            break;
        case 5:
            for(int i=0; i<4; i++) {
                canOmega[i]=0;
            }
            printf("   5");
            break;
        case 6:
            canOmega[0]=a*1.4;
            canOmega[1]=-a*1.4;
            canOmega[2]=-a*1.4;
            canOmega[3]=a*1.4;
            printf("   6");
            break;
        case 7:
            canOmega[0]=0;
            canOmega[1]=-a;
            canOmega[2]=0;
            canOmega[3]=a;
            printf("   7");
            break;
        case 8:
            canOmega[0]=-a*1.4;
            canOmega[1]=-a*1.4;
            canOmega[2]=a*1.4;
            canOmega[3]=a*1.4;
            printf("   8");
            break;
        case 9:
            canOmega[0]=-a;
            canOmega[1]=0;
            canOmega[2]=a;
            canOmega[3]=0;
            printf("   9");
            break;
        case 10:
            for(int i=0; i<4; i++) {
                canOmega[i]=a;
            }
            printf("   10");
            break;
        case 11:
            for(int i=0; i<4; i++) {
                canOmega[i]=-a;
            }
            printf("   11");
            break;
        case 12:
            wait(0.2);
            if(count==1) {
                a=0.1;
                count=0;
            } else {
                a=0.05;
                count=1;
            }
            printf("   12 Speed change");
            break;

    }
    printf(" %f\r\n",a);
    int i=0;
    while(i<4) {
        motor[i].turn(canOmega[i]);
        i++;
    }
}

//ticker に入れる関数
Ticker ticker;
Ticker canTicker;
Ticker locTicker;

//出力
void motorOut()
{
    for(int i=0; i<4; i++) {
        motor[i].Sc(omega.getOmega(i));
    }
}
CAN_ticker canx;
void ticker_CanRead()
{
    canx.canmsg_read();
    /*for(int i=0; i<4; i++) {
       motor[i].Sc(canOmega[i]);
    }*/
}

Location location;
void calLoc()
{
    theta=gyro.getAngle()-angle;    //角度受け取り
    location.calXY();
}
int main()
{
    can1.frequency(1000000);
    gyro.initialize();    //main関数の最初に一度だけ実行
    gyro.acc_offset();
    angle=gyro.getAngle();//角度初期化
    double z;
    printf("start\r\n");
    motor[0].setEquation(0.008031,-0.022300,-0.008839,-0.016290);
    motor[1].setEquation(0.008878,-0.016622,-0.009702,-0.015806);
    motor[2].setEquation(0.008637,-0.016537,-0.009397,-0.012159);
    motor[3].setEquation(0.008096,-0.014822,-0.008801,-0.016645);

    motor[0].setDutyLimit(0.4);
    motor[1].setDutyLimit(0.4);
    motor[2].setDutyLimit(0.4);
    motor[3].setDutyLimit(0.4);

    motor[0].setPDparam( 0.01790, 0.00560);
    motor[1].setPDparam( 0.01705, 0.00620);
    motor[2].setPDparam( 0.01790, 0.00620);
    motor[3].setPDparam( 0.01680, 0.00560);

    int first=0;
    while(first==0) {
        printf("waiting\r\n");
        if(button==0) {
            wait(1);
            ticker.attach(&motorOut,0.05);
            first++;
            break;
        }
    }

    int canX=20;//can変数
    int n=1,dx,dy,aimX,aimY;
    double vx_,vy_,vx,vy,newtime,distance;
    Timer time;
    time.start();
    locTicker.attach(&calLoc,0.05);
    canTicker.attach(&ticker_CanRead,0.1);//can読み込み
    while(1) {
        canX=canx.get_xCAN();//0で手\動化
        if(canX==13) {//手動化
            wait(0.2);
            printf("change1\r\n");
            ticker.detach();
            while(1) {
                canX=canx.get_xCAN();
                calOmega_CAN(canX);
                //自己位置取得
                x=location.getX();
                y=location.getY();
                printf("X=%06d ,Y=%06d",x,y);
                //目的地決定(syuusoku check)
                aimX = plot[n][0];
                aimY = plot[n][1];
                dx=aimX-x;
                dy=aimY-y;
                distance = sqrt((float)dx*dx+dy*dy);
                if(distance<1000) {
                    n++;
                    printf("reach%d\r\n",n);
                    time.reset();
                }
                if(canX==13) {//自動化
                    canX=20;
                    for(int i=0; i<4; i++) {
                        canOmega[i]=0;
                    }
                    ticker.attach(&motorOut,0.05);
                    printf("change2\r\n");
                    wait(0.1);
                    break;
                }
            }
        }
        //自己位置取得
        x=location.getX();
        y=location.getY();
        int i=0;
        if(i==10) {
            printf("X=%d,Y=%d,theta=%5.3f ,angle=%5.3f z=%5.3f  n=%d\r\n",x,y,theta,angle,z,n);
            for(int j=0; j<4; j++) {
                printf("%d : %d,",j,ec[j].getCount());
            }
            printf("\r\n");
            i=10;
        } else {
            i++;
        }
        //目的地決定(syuusoku check)
        aimX = plot[n][0];
        aimY = plot[n][1];
        //出力を計算(kitai xy);
        dx=aimX-x;
        dy=aimY-y;
        vx_=dx/sqrt((double)dx*dx+dy*dy);
        vy_=dy/sqrt((double)dx*dx+dy*dy);
        vx=vx_*cos(theta/180*3.14)+vy_*sin(theta/180*3.14);
        vy=-vx_*sin(theta/180*3.14)+vy_*cos(theta/180*3.14);
        //四輪の出力計算
        newtime=time.read();
        distance = sqrt((float)dx*dx+dy*dy);
        z=pControl(distance,zMin[n],newtime);
        omega.setOmega(z,0.05);
        omega.setVxy(vx,vy,aimTheta[n]);
        omega.calOmega();
        //ゴール判定
        if(distance<800) {
            n++;
            printf("reach%d\r\n",n);
            time.reset();
        }

        if(n>=8) {
            for(int j=0; j<4; j++) {
                motor[j].stop();
            }
            printf("fin\r\n");
            ticker.detach();
        }
    }
}