2014 sift / Mbed 2 deprecated TVDctrller2017_brdRev1_PandA

Dependencies:   mbed

Fork of TVDctrller2017_brdRev1_ver6 by 2014 sift

TVDCTRL.cpp

Committer:
sift
Date:
2016-08-06
Revision:
10:87ad65eef0e9
Parent:
9:220e4e77e056
Child:
11:88701a5e7eae

File content as of revision 10:87ad65eef0e9:

#include "TVDCTRL.h"
#include "MCP4922.h"
#include "Steering.h"

extern AnalogIn apsP;
extern AnalogIn apsS;
extern AnalogIn brake;
extern DigitalOut LED[];
extern InterruptIn rightMotorPulse;
extern InterruptIn leftMotorPulse;
extern DigitalOut MotorPulse[];
extern MCP4922 mcp;
extern Serial pc;

Timer RightPulseTimer;
Timer LeftPulseTimer;
Ticker ticker1;
Ticker ticker2;
Ticker ticker3;

#define apsPVol() (apsP.read() * 3.3)
#define apsSVol() (apsS.read() * 3.3)

struct {
    unsigned int valA:12;
    unsigned int valB:12;
} McpData;

//各変数が一定値を超えた時点でエラー検出とする
//2つのAPSの区別はつけないことにする
volatile struct errCounter_t errCounter= {0,0,0,0,0,0,0};

volatile int gApsP=0, gApsS=0, gBrake=0;        //現在のセンサ値
volatile int rawApsP=0, rawApsS=0, rawBrake=0;  //現在の補正無しのセンサ値

void getCurrentErrCount(struct errCounter_t *ptr)
{
    ptr->apsUnderVolt = errCounter.apsUnderVolt;
    ptr->apsExceedVolt = errCounter.apsExceedVolt;
    ptr->apsErrorTolerance = errCounter.apsErrorTolerance;
    ptr->apsStick = errCounter.apsStick;
    ptr->brakeUnderVolt = errCounter.brakeUnderVolt;
    ptr->brakeExceedVolt = errCounter.brakeExceedVolt;
    ptr->brakeFuzzyVolt = errCounter.brakeFuzzyVolt;
    ptr->brakeOverRide = errCounter.brakeOverRide;
}

int getCurrentSensor(int sensor)
{
    switch (sensor) {
        case APS_PRIMARY:
            return gApsP;
        case APS_SECONDARY:
            return gApsS;
        case BRAKE:
            return gBrake;
        default:
            return -1;
    }
}

int getRawSensor(int sensor)
{
    switch (sensor) {
        case APS_PRIMARY:
            return rawApsP;
        case APS_SECONDARY:
            return rawApsS;
        case BRAKE:
            return rawBrake;
        default:
            return -1;
    }
}

int myAbs(int x)
{
    return (x<0)?-x:x;
}

bool loadSensorFlag = false;

//タイマー割り込みでコールされる
void loadSensorsISR(void)
{
    loadSensorFlag = true;
}

//関数内処理時間より短い時間のタイマーのセットは禁止
void loadSensors(void)
{
    if(true == loadSensorFlag) {
        loadSensorFlag = false;
        static int preApsP=0, preApsS=0;            //過去のセンサ値
        static int preBrake=0;
        int tmpApsP=0, tmpApsS=0, tmpBrake=0;       //補正後のセンサ値
        int tmpApsErrCountU=0, tmpApsErrCountE=0;   //APSの一時的なエラーカウンタ

        //Low Pass Filter
        tmpApsP = (int)(apsP.read_u16()*ratioLPF + preApsP*(1.0f-ratioLPF));
        tmpApsS = (int)(apsS.read_u16()*ratioLPF + preApsS*(1.0f-ratioLPF));
        tmpBrake = (int)(brake.read_u16()*ratioLPF + preBrake*(1.0f-ratioLPF));

        //生のセンサ値取得
        rawApsP = tmpApsP;
        rawApsS = tmpApsS;
        rawBrake = tmpBrake;

        //センサーチェック
        //APS上限値チェック
        if(tmpApsP > APS_MAX_POSITION + ERROR_TOLERANCE) {
            tmpApsP = APS_MAX_POSITION;         //異常時,上限値にクリップ
            tmpApsErrCountE++;
        }
        if(tmpApsS > APS_MAX_POSITION + ERROR_TOLERANCE) {
            tmpApsS = APS_MAX_POSITION;         //異常時,上限値にクリップ
            tmpApsErrCountE++;
        }
        if(0 == tmpApsErrCountE)
            errCounter.apsExceedVolt = 0;       //どちらも正常時エラーカウンタクリア
        else
            errCounter.apsExceedVolt += tmpApsErrCountE;

        //APS下限値チェック
        if(tmpApsP < APS_MIN_POSITION - ERROR_TOLERANCE) {
            tmpApsP = APS_MIN_POSITION;         //下限値にクリップ
            tmpApsErrCountU++;
        }
        if(tmpApsS < APS_MIN_POSITION - ERROR_TOLERANCE) {
            tmpApsS = APS_MIN_POSITION;         //下限値にクリップ
            tmpApsErrCountU++;
        }
        if(0 == tmpApsErrCountU)
            errCounter.apsUnderVolt = 0;        //どちらも正常時エラーカウンタクリア
        else
            errCounter.apsUnderVolt += tmpApsErrCountU;

        //センサー偏差チェック
        if(myAbs(tmpApsP - tmpApsS) > APS_DEVIATION_TOLERANCE) {    //偏差チェックには補正後の値(tmp)を使用
            errCounter.apsErrorTolerance++;
        } else {
            errCounter.apsErrorTolerance = 0;
        }

        //小さい方にクリップ
        //APS値は好きな方を使いな
        if(tmpApsP > tmpApsS) {
            tmpApsP = tmpApsS;
        } else {
            tmpApsS = tmpApsP;
        }

        //Brake上限値チェック
        if(tmpBrake > BRK_OFF_VOLTAGE + ERROR_TOLERANCE) {
            errCounter.brakeExceedVolt++;
            tmpBrake = BRK_OFF_VOLTAGE;
        } else {
            errCounter.brakeExceedVolt = 0;
        }

        //Brake下限値チェック
        if(tmpBrake < BRK_ON_VOLTAGE - ERROR_TOLERANCE) {
            errCounter.brakeUnderVolt++;
            tmpBrake = BRK_ON_VOLTAGE;
        } else {
            errCounter.brakeUnderVolt = 0;
        }

        //brake範囲外電圧チェック
        if((tmpBrake < BRK_OFF_VOLTAGE - ERROR_TOLERANCE) && (tmpBrake > BRK_ON_VOLTAGE + ERROR_TOLERANCE)) {
            errCounter.brakeFuzzyVolt++;
            tmpBrake = BRK_OFF_VOLTAGE;
        } else {
            errCounter.brakeFuzzyVolt=0;
        }

        //APS固着チェック
        if((preApsP == tmpApsP) && (tmpApsP == APS_MAX_POSITION))
            errCounter.apsStick++;
        else
            errCounter.apsStick=0;

        //ブレーキオーバーライドチェック
        if((tmpApsP >= APS_OVERRIDE+APS_MIN_POSITION) && (tmpBrake > BRK_ON_VOLTAGE)) {
            errCounter.brakeOverRide++;
        } else {
            errCounter.brakeOverRide=0;
        }

        //センサ値取得
        gApsP = tmpApsP;
        gApsS = tmpApsS;
        gBrake = tmpBrake;

        //未来の自分に期待
        preApsP = rawApsP;
        preApsS = rawApsS;
        preBrake = rawBrake;
    }
}

volatile int gRightPulseTime=100000, gLeftPulseTime=100000;
volatile bool pulseTimeISRFlag = false;

void countRightPulseISR(void)
{
    //Do not use "printf" in interrupt!!!
    static int preTime=0;
    int currentTime = RightPulseTimer.read_us();

    gRightPulseTime = currentTime - preTime;

    if(gRightPulseTime < MAX_PULSE_TIME)  //12000rpm上限より早い場合
        gRightPulseTime = MAX_PULSE_TIME;

    if(currentTime < 1800000000) {
        preTime = currentTime;
    } else {    //30分経過後
        RightPulseTimer.reset();
        preTime = 0;
    }
}

void countLeftPulseISR(void)
{
    //Do not use "printf" in interrupt!!!
    static int preTime=0;
    int currentTime = LeftPulseTimer.read_us();

    gLeftPulseTime = currentTime - preTime;

    if(gLeftPulseTime < MAX_PULSE_TIME)  //12000rpm上限より早い場合
        gLeftPulseTime = MAX_PULSE_TIME;

    if(currentTime < 1800000000) {
        preTime = currentTime;
    } else {    //30分経過後
        LeftPulseTimer.reset();
        preTime = 0;
    }
}

void getPulseTimeISR(void)
{
    pulseTimeISRFlag = true;
}

int getPulseTime(SelectMotor rl)
{
    static int preRightPulse, preLeftPulse;

    if(pulseTimeISRFlag == true) {
        pulseTimeISRFlag = false;

        if(gRightPulseTime > 100000)
            gRightPulseTime = 100000;
        if(gLeftPulseTime > 100000)
            gLeftPulseTime = 100000;

        preRightPulse = (int)(gRightPulseTime*ratioLPF_V + preRightPulse*(1.0f-ratioLPF_V));
        preLeftPulse = (int)(gLeftPulseTime*ratioLPF_V + preLeftPulse*(1.0f-ratioLPF_V));
    }

    if(rl == RIGHT_MOTOR)
        return preRightPulse;
    else
        return preLeftPulse;
}

float getVelocity(void)
{
    int rightPulse=0, leftPulse=0;
    int avePulseTime;

    rightPulse = getPulseTime(RIGHT_MOTOR);
    leftPulse = getPulseTime(LEFT_MOTOR);

    avePulseTime = (int)((rightPulse+leftPulse)/2.0);

    if(avePulseTime < MAX_PULSE_TIME)    //最低パルス時間にクリップ
        avePulseTime = MAX_PULSE_TIME;

    return (M_PI*TIRE_DIAMETER / ((avePulseTime/1000000.0)*TVD_GEAR_RATIO));
}

void generatePulse(void)
{
    static bool flag = false;
    flag = !flag;
    MotorPulse[0] = MotorPulse[1] = LED[0] = flag;
}

int distributeTorque(float velocity, float steering)
{
    int disTrq = 0;
    double sqrtVelocity = (double)velocity*velocity;
    double Gy=0;

    Gy = (sqrtVelocity*steering) / ((1.0+STABIRITY_FACTOR*sqrtVelocity)*WHEEL_BASE);

    if(Gy > 9.8)
        Gy = 9.8;

    if(Gy < 0.98) {
        disTrq = 0;
    } else if(Gy < 4.9) {
        disTrq = (int)(MAX_DISTRIBUTION_TORQUE / (4.9-0.98) * (Gy-0.98));
    } else {    //0.5G以上は配分一定
        disTrq = MAX_DISTRIBUTION_TORQUE;
    }

    return disTrq;
}

//トルク値線形補間関数
inline int interpolateLinear(int torque, int currentMaxTorque)
{
    return (int)(((double)(DACOUTPUT_MAX-LINEAR_REGION_VOLTAGE)/(currentMaxTorque-LINEAR_REGION_TORQUE)) * (torque-LINEAR_REGION_TORQUE)) + LINEAR_REGION_VOLTAGE-DACOUTPUT_MIN;
}

unsigned int calcTorqueToVoltage(int torque, SelectMotor rl)
{
    int outputVoltage=0;
    int rpm=0;
    int currentMaxTorque=0;

    if(torque <= LINEAR_REGION_TORQUE) {         //要求トルク<=2.5Nmの時
        outputVoltage = (int)((double)(LINEAR_REGION_VOLTAGE-DACOUTPUT_MIN)/LINEAR_REGION_TORQUE * torque);
    } else {
        rpm = (int)(1.0/getPulseTime(rl)*1000000.0 * 60.0);  //pulseTime:[us]

        //rpm = 12000;

        if(rpm < 3000) {        //3000rpm未満は回転数による出力制限がないフラットな領域
            outputVoltage = interpolateLinear(torque, MAX_MOTOR_TORQUE);
        } else {
            if(rpm <= 11000) {
                int index = (int)((rpm - 3000)/10.0);    //マップは10rpm刻みに作成
                currentMaxTorque = calcMaxTorque[index];
            } else {
                currentMaxTorque = MAX_REVOLUTION_TORQUE;      //回転数上限時の最大トルク
            }

            if(currentMaxTorque < torque) {     //要求トルクが現在の回転数での最大値を超えている時
                outputVoltage = DACOUTPUT_VALID_RANGE;  //現在の回転数での最大トルクにクリップ
            } else {
                outputVoltage = interpolateLinear(torque, currentMaxTorque);
            }
        }
    }

    outputVoltage += DACOUTPUT_MIN;   //最低入力電圧でかさ上げ

    return (unsigned int)(0xFFF*((double)outputVoltage/0xFFFF));  //DACの分解能に適応(16bit->12bit)
}

int calcRequestTorque(void)
{
    int currentAPS;
    int requestTorque;

    currentAPS = ((gApsP>gApsS) ? gApsS : gApsP);   //センサ値は小さい方を採用
    if(currentAPS < APS_MIN_POSITION)
        currentAPS = 0;
    else
        currentAPS -= APS_MIN_POSITION;     //オフセット修正

    if(currentAPS < APS_DEADBAND)   //デッドバンド内であれば要求トルク->0
        requestTorque = 0;
    else
        requestTorque = (int)(((double)MAX_OUTPUT_TORQUE / APS_VALID_RANGE) * (currentAPS - APS_DEADBAND));

    if(requestTorque > MAX_OUTPUT_TORQUE)
        requestTorque = MAX_OUTPUT_TORQUE;
    else if(requestTorque < 0)
        requestTorque = 0;

    return requestTorque;
}

void driveTVD(void)
{
    int requestTorque=0;    //ドライバー要求トルク
    int distributionTrq=0;  //分配トルク
    int torqueHigh, torqueLow;    //トルクの大きい方小さい方

    loadSensors();      //APS,BRAKE更新
    loadSteerAngle();   //舵角更新
    //getPulseTime(RIGHT_MOTOR);  //車速更新(更新時は片方指定コールでOK)

    requestTorque=calcRequestTorque();  //ドライバー要求トルク取得

    distributionTrq = distributeTorque(getVelocity(), MAX_STEER_ANGLE / M_PI * getSteerAngle());  //トルク分配量計算
    //distributionTrq = distributeTorque(50.0f, MAX_STEER_ANGLE / M_PI * getSteerAngle());  //トルク分配量計算
    distributionTrq /= 2.0;
    
    //デバッグ中
    distributionTrq = 0;

    if(requestTorque + distributionTrq > MAX_OUTPUT_TORQUE)  //片モーター上限時最大値にクリップ
        torqueHigh = MAX_OUTPUT_TORQUE;
    else
        torqueHigh = requestTorque + distributionTrq;

    if(requestTorque - distributionTrq < 0) {
        torqueLow = 0;
        torqueHigh = (int)(requestTorque*2.0);   //片モーター下限値時,反対のモーターも出力クリップ
    } else
        torqueLow = requestTorque - distributionTrq;

    if(getSteerDirection()) {
        //steer left
        McpData.valA = calcTorqueToVoltage(torqueHigh, RIGHT_MOTOR);
        McpData.valB = calcTorqueToVoltage(torqueLow, LEFT_MOTOR);
    } else {
        //steer right
        McpData.valA = calcTorqueToVoltage(torqueLow, RIGHT_MOTOR);
        McpData.valB = calcTorqueToVoltage(torqueHigh, LEFT_MOTOR);
    }

    mcp.writeA(McpData.valA);   //右モーター
    mcp.writeB(McpData.valB);   //左モーター
}

void initTVD(void)
{
    rightMotorPulse.mode(PullUp);
    leftMotorPulse.mode(PullUp);
    rightMotorPulse.fall(&countRightPulseISR);
    leftMotorPulse.fall(&countLeftPulseISR);

    RightPulseTimer.reset();
    LeftPulseTimer.reset();
    RightPulseTimer.start();
    LeftPulseTimer.start();

    ticker1.attach(&loadSensorsISR, 0.01f);    //サンプリング周期10msec
    //ticker2.attach(&generatePulse, 0.03f);
    ticker3.attach(&getPulseTimeISR, 0.01f);

    mcp.writeA(0);   //右モーター
    mcp.writeB(0);   //左モーター

}