GifuRobo B term

Dependencies:   FastPWM cal_PID mbed omuni

Fork of omuni_speed_pid by shinji sawai

main.cpp

Committer:
Akito914
Date:
2017-09-11
Revision:
4:5591d3c8a761
Parent:
3:6223efea43fe
Child:
5:12be2ac0f395

File content as of revision 4:5591d3c8a761:

#include "mbed.h"
#include "omuni.hpp"
#include "cal_PID.hpp"
#include "timeBaseTrapezoidalMotionCal.h"
#include "FastPWM.h"
#include "soundData.h"

const int comTimeout_ms = 200;
const float omuni_speed[4] = {0, 1.0, 2.0, 3.0};
const float omega_max = 0.7 * 2 * 3.14159265f;
const float wrap_radius = 1.0f;
const float wrap_speed = 1.8f;
const int8_t armDuty[] = {-50, -50};
const signed int spearDuty = 127;
const int32_t lift_preset_min = 135;
const int32_t lift_preset_max = 450;
const int32_t lift_preset[4] = {
    lift_preset_min,
    (lift_preset_max - lift_preset_min) / 3.0 + lift_preset_min,
    (lift_preset_max - lift_preset_min) * 2.0 / 3.0 + lift_preset_min,
    lift_preset_max,
    }; // 12bit 0 ~ 4095
const int32_t lift_max = lift_preset_max;
const int32_t lift_min = lift_preset_min;
const int32_t lift_up_speed = 5;
const int32_t lift_down_speed = 5;


const int omuniAddr[] = {0x10, 0x12, 0x14}; // 0000 , 1000 , 0100
const int armAddr[] = {0x16, 0x18};    // 1100 , 0010
const int spearAddr = 0x1a;            // 1010
const int liftAddr = 0x1c;             // 0110
const int EMO_Addr = 0x1e;             // 1110

int comTimeout_count = 0;

int drive_motor(int address,signed int duty);
void emergencyStop();

bool ems = false;

bool arm = false;
bool spear = false;

int lift_targ = lift_preset[0];
int lift_stepTarg;
bool lift_stepMoving = false;
bool first_receive = true;
int past_lift_gray = 0b00;
int lift_inc = 0;

const float soundGain = 1.0;
int soundDataCount = 0;
bool soundEnd = false;

//DigitalIn button(USER_BUTTON);
DigitalOut led(LED1);

Serial pc(USBTX, USBRX);
Serial com(PA_11, PA_12);
I2C i2cMaster(D14, D15);
omuni omuni(&i2cMaster, TIM1, TIM2, TIM3, 533, 2.0f, omuniAddr, 0.4704f, 0.1f);
AnalogIn lift_meter(PC_0);
DigitalIn spear_sensor(PC_3);
Timer mesPeriod;
cal_pid lift_pid;
Ticker comTimeout;

FastPWM soundOut(PB_6);
Ticker soundRenew;

float speed_x, speed_y, omega;
bool f;

typedef union{
    struct{
        unsigned angle   :4;
        unsigned speed   :2;
        unsigned byteNum0:2;
    };
    struct{
        unsigned wrap_R   :1;
        unsigned wrap_L   :1;
        unsigned coorSys  :1;
        unsigned omega    :2;
        unsigned dir      :1;
        unsigned byteNum1 :2;
    };
    struct{
        unsigned lift_down  :1;
        unsigned lift_up    :1;
        unsigned lift_gray  :2;
        unsigned spear      :1;
        unsigned arm        :1;
        unsigned byteNum2   :2;
    };
    struct{
        unsigned reserved2 :1;
        unsigned emo       :1;
        unsigned reserved3 :4;
        unsigned byteNum3  :2;
    };
    struct{
        unsigned control :6;
        unsigned byteNum :2;
    };
    struct{
        unsigned bit0:1;
        unsigned bit1:1;
        unsigned bit2:1;
        unsigned bit3:1;
        unsigned bit4:1;
        unsigned bit5:1;
        unsigned bit6:1;
        unsigned bit7:1;
    };
    int8_t data;
}comData_t;


comData_t RCData[4] = {0};

int grayDiffer2bit(int gray, int origin){
    
    switch(origin){
        case 0b00:
            switch(gray){
                case 0b01: return 1;
                case 0b10: return -1;
                default  : return 0;
            }
        case 0b01:
            switch(gray){
                case 0b11: return 1;
                case 0b00: return -1;
                default  : return 0;
            }
        case 0b11:
            switch(gray){
                case 0b10: return 1;
                case 0b01: return -1;
                default  : return 0;
            }
        case 0b10:
            switch(gray){
                case 0b00: return 1;
                case 0b11: return -1;
                default  : return 0;
            }
    }
    return 0;
}


void com_rx()
{
    char temp = com.getc();
    comData_t rcTemp;
    rcTemp.data = temp;
    float rad, speed;
    int lift_nearest_num = 0;
    
    
    RCData[rcTemp.byteNum] = rcTemp;
    
    /*
    pc.printf("%d",rcTemp.bit7);
    pc.printf("%d",rcTemp.bit6);
    pc.printf("%d",rcTemp.bit5);
    pc.printf("%d",rcTemp.bit4);
    pc.printf("%d",rcTemp.bit3);
    pc.printf("%d",rcTemp.bit2);
    pc.printf("%d",rcTemp.bit1);
    pc.printf("%d",rcTemp.bit0);
    pc.printf("\n");
    */
    //pc.printf("%d\n", rcTemp.byteNum);
    //pc.printf("speed = %d, angle = %d\n",rcTemp.speed, rcTemp.angle);
    
    switch(temp >> 6){
        case 0:
            //pc.printf("speed = %d, angle = %d\n",rcTemp.speed, rcTemp.angle);
            break;
        case 1:
            //pc.printf("dir = %d, omega = %d, coorSys = %d\n", rcTemp.dir, rcTemp.omega, rcTemp.coorSys);
            break;
        case 2:
            //pc.printf("arm = %d, spear = %d, lift_gray = %d, lift_up = %d, lift_down = %d\n",rcTemp.arm, rcTemp.spear, rcTemp.lift_gray, rcTemp.lift_up, rcTemp.lift_down);
            break;
        case 3:
        
            
            break;
    }
    
    if(rcTemp.byteNum == 3){ // データは揃った
        
        led = !led;
        comTimeout_count = 0;
        
        ems = RCData[3].emo != 0;
        
        rad = RCData[0].angle * 3.141592 / 8.0;
        speed = omuni_speed[RCData[0].speed];
        if(RCData[0].speed == 0)speed = 0;
        speed_x = speed * cos(rad) * -1;
        speed_y = speed * sin(rad) * -1;
        
        f = RCData[1].coorSys;
        omega = RCData[1].omega * omega_max / 3.0f;
        omega *= RCData[1].dir ? 1 : -1;
        
        
        if(RCData[1].wrap_R || RCData[1].wrap_L){
            speed_x = wrap_speed;
            speed_y = 0;
            f = 0;
            omega = wrap_speed / wrap_radius;
            speed_x *= RCData[1].wrap_L ? 1 : -1;
            omega *= RCData[1].wrap_L ? 1 : -1;
        }
        
        
        arm = RCData[2].arm != 0;
        
        spear = RCData[2].spear != 0;      
        
        if(first_receive){
            past_lift_gray = RCData[2].lift_gray;
            first_receive = false;
        }
        if(RCData[2].lift_gray != past_lift_gray){ // 段階移動
            int lift_currentTarg;
            int lift_diff = 0;
            int lift_nearest = 10000;
            int lift_nextTarg;
            
            lift_currentTarg = lift_targ;
            if(lift_stepMoving){
                lift_nextTarg = lift_stepTarg;
            }
            else{
                lift_nextTarg = lift_currentTarg;
            }
            
            lift_diff = grayDiffer2bit(RCData[2].lift_gray, past_lift_gray);
            for(int num = 0; num < 4; num++){ // 最寄りの段階
                if(lift_nearest > abs(lift_preset[num] - lift_currentTarg)){
                    lift_nearest_num = num;
                    lift_nearest = abs(lift_preset[num] - lift_currentTarg);
                }
            }
            if(lift_diff != 0){
                if(lift_diff == 1){
                    if(lift_preset[lift_nearest_num] >= lift_currentTarg){
                        if(lift_nearest_num < 3)lift_nextTarg = lift_preset[lift_nearest_num + 1];
                    }
                    else{
                        lift_nextTarg = lift_preset[lift_nearest_num];
                    }
                }
                else if(lift_diff == -1){
                    if(lift_preset[lift_nearest_num] <= lift_currentTarg){
                        if(lift_nearest_num > 0)lift_nextTarg = lift_preset[lift_nearest_num - 1];
                    }
                    else{
                        lift_nextTarg = lift_preset[lift_nearest_num];
                    }
                }
                
                lift_stepTarg = lift_nextTarg;
                lift_stepMoving = true;
                                
            }
            
        }
        past_lift_gray = RCData[2].lift_gray;
        
        if(RCData[2].lift_down != 0)lift_inc = -1;
        else if(RCData[2].lift_up != 0)lift_inc = 1;
        else lift_inc = 0;
        
    } // すっきりした // してない
    
}


void soundRenew_intr(){
    
    if(soundDataCount < soundData_size - 1000){
        
        soundOut.write((soundData[soundDataCount] * soundGain / 256.0) + 0.5);
        
        soundDataCount++;
        
    }
    else{
        soundEnd = true;
    }
    
}


void comTimeout_intr(){
    
    if(comTimeout_count >= comTimeout_ms){
        speed_x = 0;
        speed_y = 0;
        omega = 0;
        arm = 0;
        spear = 0;
        lift_inc = 0;
    }
    else{
        comTimeout_count += 1;
    }
    
}


void arm_control(){
    char armData[2] = {0};
    
    armData[0] = arm? armDuty[0] : 0 ;
    armData[1] = arm? armDuty[1] : 0 ;
    
    i2cMaster.write(armAddr[0], &armData[0], 1);
    i2cMaster.write(armAddr[1], &armData[1], 1);
    
}

void lift_control(){
    int32_t meter = 0;
    signed int duty = 0;
    int32_t error = 0;
    
    error = lift_stepTarg - lift_targ;
    if(lift_stepMoving){
        if(error > lift_up_speed){
            lift_targ += lift_up_speed; 
        }
        else if(error < lift_down_speed * -1){
            lift_targ -= lift_down_speed;
        }
        else{
            lift_targ = lift_stepTarg;
            lift_stepMoving = false;
        }
    }
    else{
        if(lift_inc < 0){
            if(lift_min < lift_targ + lift_inc)lift_targ += lift_inc;
        }
        else if(lift_inc > 0){
            if(lift_max > lift_targ + lift_inc)lift_targ += lift_inc;
        }
    }
    
    meter = lift_meter.read_u16() >> 6;
    duty = lift_pid.get_pid(meter, lift_targ, -1);
    drive_motor(liftAddr, duty);
    
}

void spear_control(){
    const int spear_timeout_short = 100;
    const int spear_timeout_long = 500;
    static int spear_state = 0;
    static int spear_timeout_count = 0;
    signed int duty = 0;
    int sensor = spear_sensor;  // リミット時に1
    
    switch(spear_state){
        case 0 : // 待ち
            if(spear){
                spear_state = 1;
            }
            else{
                if(sensor == 0){
                    duty = spearDuty * -1;
                }
            }
            break;
        case 1 : // 初期位置から抜け出す
            duty = spearDuty;
            if(sensor != 0){
                if(spear_timeout_count < spear_timeout_short){
                    spear_timeout_count += 1;
                }
                else{
                    spear_timeout_count = 0;
                    spear_state = 0;
                }
            }
            else{
                spear_timeout_count = 0;
                spear_state = 2;
            }
            break;
        case 2 : // 到達位置まで動かす
            if(sensor == 0){
                duty = spearDuty;
                if(spear_timeout_count < spear_timeout_long){
                    spear_timeout_count += 1;
                }
                else{
                    spear_timeout_count = 0;
                    spear_state = 3;
                }
            }
            else{
                spear_timeout_count = 0;
                spear_state = 3;
            }
            break;
        case 3 : // 到達位置から抜け出す
            duty = spearDuty * -1;
            if(sensor == 0){
                spear_state = 4;
            }
            break;
        case 4 : // 初期位置まで戻る
            if(sensor == 0){
                duty = spearDuty * -1;
            }
            else{
                spear_state = 0;
            }
            break;
        default :
            break;
    }
    drive_motor(spearAddr, duty);
} 


void control(){
    
    arm_control();
    lift_control();
    spear_control();
    
}

int main()
{
    int period_us = 0;
    int count = 0;
    
    pc.baud(115200);
    com.baud(9600);
    pc.printf("Hello!\n");
    com.attach(com_rx, Serial::RxIrq);
    
    i2cMaster.frequency(400000);
    
    omuni.set_speed(0.0f, 0.0f);
    omuni.set_pid(0, 3.0f, 0.07f, 0.05f);
    //omuni.set_pid(0, 6.0f, 0.14f, 0.10f);
    omuni.set_pid(1, 3.0f, 0.07f, 0.05f);
    omuni.set_pid(2, 3.0f, 0.07f, 0.05f);
    
    lift_pid.param(1.5, 0.0, 0.0);
    lift_pid.period(0.001);
    lift_pid.output(-127, 127);
    
    comTimeout.attach_us(comTimeout_intr, 1000);
    
    led = 0;
    
    /*
    soundOut.period_us(10);
    for(count = 0; count < 500; count++){
        wait_ms(1);
        soundOut.write(count / 100.0);
    }
    soundRenew.attach_us(soundRenew_intr, 63);
    
    while(soundEnd == false);
    */
    
    while(1)
    {
        wait(0.001);
        omuni.set_speed(speed_x, speed_y, omega, f);
        omuni.drive();
        control();
        
        drive_motor(EMO_Addr, 1);
        
        if(ems){
            emergencyStop();
        }
    }
}

int drive_motor(int address,signed int duty){ /* アドレスを指定してモータを駆動 */
    char send_data;
    int ack;
    if((duty>127)||(duty<-128))return -1; /* 範囲外なら送信しない */
    send_data=duty;
    ack=i2cMaster.write(address,&send_data,1);
    return ack;
}

void emergencyStop(){
    drive_motor(omuniAddr[0], 0);
    drive_motor(omuniAddr[1], 0);
    drive_motor(omuniAddr[2], 0);
    drive_motor(armAddr[0], 0);
    drive_motor(armAddr[1], 0);
    drive_motor(liftAddr, 0);
    drive_motor(spearAddr, 0);
    
    drive_motor(EMO_Addr, 0);
    
    while(1);
}