Antenna rotator for Nano Ground Station

Dependencies:   mbed ServoMotor Suteppa

main.cpp

Committer:
j_rocket_boy
Date:
2020-03-08
Revision:
1:656a0c325626
Parent:
0:022e5e32d580

File content as of revision 1:656a0c325626:

#include "mbed.h"                           //mbed関数
#include "Suteppa.h"                        //ステッピングモータ関数
#include "ServoMotor.h"                     //駆動速度を設定可能なサーボモータ関数
#include "Serial.h"                         //シリアル通信関数

//マイクロステップ駆動段階(ステッピングモータの1ステップをさらにいくつで分割するか)
#define MICRO_STEP  128     
 
Serial usbSerial(USBTX, USBRX);             //PCとの接続用
DigitalIn LimitSW(D2);                      //方位角0セット用リミットスイッチ
SERVO_MOTOR Elv(D10, 90, 590, 0, 1490);     //仰角用サーボモータ(使用ピン,角度1,パルス幅1,角度2,パルス幅2)
Suteppa Azm;                                //方位角用ステッピングモータ

//方位角ステッピングモータ マイクロステップ駆動用PWMピン
PwmOut AIN1(D7);
PwmOut AIN2(D6);
PwmOut BIN1(D5);
PwmOut BIN2(D4);


//方位角ゼロ点設定
void Azm_home(bool init = true){
    //10ステップを加減速に使い, 開始速度は10000us
    Azm.beginSmooth(10*MICRO_STEP, 10000);
    //最終速度は1000us
    Azm.setSpeed(1000);

    if(init == false){
        Azm.rotate(Suteppa::ABSOLUTE, 0*MICRO_STEP);
        wait(0.5);
    }
    
    //リミットスイッチが反応している間は時計回りに回す。
    Azm.rotate(Suteppa::RELATIVE, 100*MICRO_STEP,false);
    while(LimitSW == 0 && Azm.tick());

    //リミットスイッチが反応するまで反時計回りに回す。
    Azm.rotate(Suteppa::RELATIVE, -100*MICRO_STEP,false);
    while(LimitSW == 1 && Azm.tick());

    //少し時計回りに回す。
    Azm.rotate(Suteppa::RELATIVE, 1*MICRO_STEP,true);

    //リミットスイッチが反応するまで反時計回りに回す。
    Azm.rotate(Suteppa::RELATIVE, -100*MICRO_STEP,false);
    while(LimitSW == 1 && Azm.tick());

    //ゼロ点セット
    Azm.setHome();
    Azm.rotate(Suteppa::RELATIVE, 0,true);
}

//d(= -1 or +1 )ステップ変える関数
void step(int d){

    static int i = 0;   //現在ステップ数記憶用
    double x,y;         //マイクロステップ用電圧値計算用
    i -= d;             //1ステップ増やす or 戻す

    //ステップ数を0~MICRO_STEPの間に収める
    while(i >= MICRO_STEP){
        i -= MICRO_STEP;
    }
    while(i < 0){
        i+= MICRO_STEP;
    }

    //マイクロステップ駆動のための電圧値計算    
    x = cos(2.0 * M_PI * i / MICRO_STEP);
    y = sin(2.0 * M_PI * i / MICRO_STEP);
    
    //ステッピングモータA相に電圧印加
    if(x > 0){
        AIN1 =  1-x;
        AIN2 =  1;
    }else{
        AIN1 =  1;
        AIN2 =  1+x;
    }
    
    //ステッピングモータB相に電圧印加
    if(y > 0){
        BIN1 =  1-y;
        BIN2 =  1;
    }else{
        BIN1 =  1;
        BIN2 =  1+y;
    }    
    
}

//方位角と仰角を設定して向ける
void Antenna(double Azm_angle, double Elv_angle, bool sync = false){
    Azm.rotate(Suteppa::ABSOLUTE,100 * MICRO_STEP * Azm_angle / 360.0,sync);
    Elv.move(Elv_angle,sync);
}

//現在の方位角を取得する
double get_Azm(void){
    return 360.0 * Azm.getStep() / 100 / MICRO_STEP;
}

//現在の仰角を取得する
double get_Elv(void){
    return Elv.get_angle();
}

//ステッピングモータの処理を進める。
bool tick(void){
    bool Azm_result, Elv_result;
    Azm_result = Azm.tick();
    Elv_result = Elv.tick();
    
    return Azm_result || Elv_result;
}

int main() {

    // シリアル通信の速度設定
    usbSerial.baud(115200);
    char str[256];
    int i = 0;

    //指令値保存用
    double AzmAngle,ElvAngle;

    int cnt = 0;    //通信エラー排除用カウンタ値

    //PWM周期100us
    AIN1.period(1e-4);
    AIN2.period(1e-4);
    BIN1.period(1e-4);
    BIN2.period(1e-4);

    //一回転のステップ数, ステップ用関数
    Azm.init(100*MICRO_STEP, step);
    //10ステップを加減速に使い, 開始速度は10000us
    Azm.beginSmooth(10*MICRO_STEP, 10000);
    //通常速度は1000us
    Azm.setSpeed(1000);

    //方位角を0度にリセットする
    Azm_home();
    //仰角を0度にセットする。
    Elv.go(0);

    //制御ループ
    while(1){

        //PCから指令値受信 & 翻訳
        if(usbSerial.readable()){
            str[i] = usbSerial.getc();
            if(str[i] == '\n' || str[i] == '\r'){
                str[i] = '\0';

                //制御停止要求
                if(strncmp(str,"SA SE ",6) == 0){
                    Azm_home(false);
                    Elv.move(0,true);

                //現在角 読み込み要求
                }else if(strncmp(str,"AZ EL ",6) == 0){
                    usbSerial.printf("AZ%.1f EL%.1f \n",get_Azm(),get_Elv());

                //指令値受信
                }else if( sscanf(str,"%lf,%lf",&AzmAngle,&ElvAngle) == 2 || sscanf(str,"AZ%lf EL%lf ",&AzmAngle,&ElvAngle) == 2 ){
                    //方位角を0~360度に制限
                    while(AzmAngle < 0){
                        AzmAngle += 360;
                    }
                    while(AzmAngle > 360){
                        AzmAngle -= 360;
                    }

                    //仰角を0~90度に制限
                    if(ElvAngle < 0){
                        ElvAngle = 0;
                    }
                    if(ElvAngle > 90){
                        ElvAngle = 90;
                    }

                    //現在の方位角より、指令値に30度~ の差があるとき(速度早め)
                    if(abs(AzmAngle - get_Azm())>30){

                        //同じ値が3回以上きたら適用する(たまに仰角方位角ともに0度のエラー値を送ってくるためその対策)
                        if(cnt < 3){
                            cnt++;
                        }else{
                            Azm.endSmooth();
                            //通常速度は700us
                            Azm.setSpeed(700);
                            Antenna(AzmAngle,ElvAngle,false);
                        }

                    //現在の方位角より、指令値に5度~30度の差があるとき(速度ふつう)
                    }else if(abs(AzmAngle - get_Azm())>5){
                        Azm.endSmooth();
                        //通常速度は7000us
                        Azm.setSpeed(7000);
                        Antenna(AzmAngle,ElvAngle,false);
                        cnt = 0;

                    //現在の方位角より、指令値に ~5度の差があるとき(速度ゆっくり)
                    }else{
                        Azm.endSmooth();
                        //通常速度は20000us
                        Azm.setSpeed(20000);
                        Antenna(AzmAngle,ElvAngle,false);
                        cnt = 0;
                    }
                }                
                i = 0;  //シリアル受信文字数をリセット
            }else{
                i++;    //シリアル受信文字数をカウントアップ
            }
            //文字バッファ満杯時にシリアル受信文字数をリセット
            if(i == 256){
                i = 0;
            }
        }
        tick();     //ステッピングモータ処理
    }
}