Tanuki_Bayashin’s diary

電子工作を趣味としています。最近はラズベリーパイPicoというマイコンを使って楽しんでいます

倒立振子のコード その6 main() 関数内の処理

※なにか気になる点がありましたらコメント欄にご記入ください。


※この記事は以下のリンクから貼られており、倒立振子という創作物に関するコードの一部を載せています。詳しくはリンク元をご覧ください。
倒立振子に挑む - Tanuki_Bayashin’s diary

使用しているマイコンRaspberry Pi Pico と呼ばれるものです。
記述はC言語を用いています。(pico-SDK C/C++ という環境を使用しています)



ここでは、main() 関数内の処理について説明をします。

初めは、各種機能の初期化を行っています。
手順が進んで、制御のメインループに入ります。

メインループの手前で、ロータリーエンコーダーの処理(25μs置きに呼び出される)と、カルマンフィルタの推定の処理(2.5ms置きに呼び出される)をタイマー割り込みに設定しています。

メインループ内では、センサーから値を取り込み、処理を行い、PWMによりモーターへ所定の電圧を与えています。



リスト6 main() 関数内の処理


//=========================================================
// Main
//=========================================================
void main() {

    static char s[100];
    int i, j, count;
    bool start_control = false;
    int led_yellow = 0;
    int count_led_yellow = 0;
    int flag = 0;

    /////////////////////////
    // UART 初期設定       //
    /////////////////////////
    // process something important ?
    stdio_init_all();

    // Set up our UART with the required speed.
    uart_init(UART_ID, BAUD_RATE);

    // Set the TX and RX pins by using the function select on the GPIO
    // Set datasheet for more information on function select
    gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
    gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);

    // Use some the various UART functions to send out data
    // In a default system, printf will also output via the default UART

    /////////////////////////////
    // 加速度センサー 初期設定 //
    /////////////////////////////

#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN)
    #warning i2c / mpu6050_i2c example requires a board with I2C pins
        //uart_puts(UART_ID, "Default I2C pins were not defined");
#else
    //uart_puts(UART_ID, "Hello, MPU6050! Reading raw data from registers...");

    // This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
    i2c_init(i2c_default, 400 * 1000);
    gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
    gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
    gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
    gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);

    // Make the I2C pins available to picotool
    bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));

    mpu6050_reset();

#endif

    /////////////////////////////////////////
    // GPIO(for LEDs and BUTTONs) initialize
    /////////////////////////////////////////
    gpio_init(LED_RED);
    gpio_init(LED_GREEN);
    gpio_init(LED_YELLOW);
    gpio_set_dir(LED_RED, GPIO_OUT);
    gpio_set_dir(LED_GREEN, GPIO_OUT);
    gpio_set_dir(LED_YELLOW, GPIO_OUT);

    gpio_init(LED_PICO);
    gpio_set_dir(LED_PICO, GPIO_OUT);
    
    gpio_init(BUTTON_BLACK);
    gpio_set_dir(BUTTON_BLACK, GPIO_IN);
    //gpio_pull_up(BUTTON_BLACK);
    gpio_pull_down(BUTTON_BLACK);

    gpio_init(BUTTON_YELLOW);
    gpio_set_dir(BUTTON_YELLOW, GPIO_IN);
    //gpio_pull_up(BUTTON_YELLOW);
    gpio_pull_down(BUTTON_YELLOW); // add this statement (2022/12/25)
    sleep_ms(1);

    ///////////////////////////////////
    // Calibration Start
    ///////////////////////////////////

    gpio_put(LED_YELLOW, 1); // YELLOW LED is ON

    sleep_ms(500);
    gpio_put(LED_YELLOW, 0); // YELLOW LED is OFF

    sleep_ms(500);
    gpio_put(LED_YELLOW, 1); // YELLOW LED is ON

    Calibration();

    snprintf(s, sizeof(s), "%1.3e,%1.3e,%1.3e,%1.3e,%1.3e,%1.3e,%1.3e\n", acc_Y_offset, acc_Z_offset,
        gyro_X_offset, theta_mean, theta_variance, theta_dot_mean, theta_dot_variance);
    uart_puts(UART_ID, s);
    gpio_put(LED_YELLOW, 0); // YELLOW LED is OFF
    sleep_ms(500);

    count = 0;
    led_yellow = 0;
    count_led_yellow = 0;

    // While start_control is false,this while loop is running.
    // and pushing Yellow Button for 1 minute continueously,
    // start_control turned to true and get out from this loop!

/*    while (start_control == false) {
        if ((gpio_get(BUTTON_YELLOW) == 1) || (gpio_get(BUTTON_BLACK) == 1)) {
            gpio_put(LED_GREEN, 1);
            gpio_put(LED_RED, 0);
            sleep_ms(1);
        }
        else {
            gpio_put(LED_GREEN, 0);
            gpio_put(LED_RED, 1);
            sleep_ms(1);
        }
    }
 */
    while (start_control == false) {
        if (gpio_get(BUTTON_YELLOW) == 1) {
            sleep_ms(1);
            count++;

            gpio_put(LED_GREEN, 1);
            gpio_put(LED_RED, 0);

            if (count > 1000) {
                start_control = true;
                gpio_put(LED_GREEN, 0);
                gpio_put(LED_RED, 0);
                break;
            }
        }
        else {
            count = 0;
            gpio_put(LED_GREEN, 0);
            gpio_put(LED_RED, 1);
        }

        if (count_led_yellow % 250 == 0) {
            if (led_yellow == 0) {
                gpio_put(LED_YELLOW, 1);
                led_yellow = 1;
            }
            else {
                gpio_put(LED_YELLOW, 0);
                led_yellow = 0;
            }
            count_led_yellow = 0;
        }
        count_led_yellow++;
    }

    sleep_ms(1);

    // Set the phaseA and phaseB pins to GPIO
    gpio_init(rotary_encorder_phaseA);
    gpio_init(rotary_encorder_phaseB);
    gpio_set_dir(rotary_encorder_phaseA, GPIO_IN);
    gpio_set_dir(rotary_encorder_phaseB, GPIO_IN);

    encoder_value = 0;

    //////////////////////////////////
    // start controlling the machine
    // after send "a" 3 times.
    //////////////////////////////////
        // YELLOW LED is ON for 3 [sec]
    send_a_3times();

    /////////////////////////
    // A/D 変換の処理      //
    /////////////////////////  A/D 変換はお休み
    // ADC module initialize
    //uart_puts(UART_ID, "ADC Example, measuring GPIO26\n");
    //adc_init();
    // Make sure GPIO is high-impedance, no pullups etc
    //adc_gpio_init(26);
    // Select ADC input 0 (GPIO26)
    //adc_select_input(0);

    /////////////////////////
    // PWM の前処理          //
    /////////////////////////
    /* GPIOにPWMを割り当て */
    gpio_set_function(PIN_PWM0, GPIO_FUNC_PWM);
    pwm0_slice_num = pwm_gpio_to_slice_num(PIN_PWM0);

    /* clkdiv と wrap を指定 */
    pwm_set_clkdiv(pwm0_slice_num, 12.1875);
    pwm_set_wrap(pwm0_slice_num, 1023);

    /* レベル値(デューティカウント値)を設定(ここでは0) */
    pwm_set_chan_level(pwm0_slice_num, PWM_CHAN_A, 0);

    /* pwm0 start */
    pwm_set_enabled(pwm0_slice_num, true);
    //    pwm_set_enabled(pwm0_slice_num, false);
    /* END of PWM Module Setting */

    //-------------------------------------------
    //Motor driver intialization
    //-------------------------------------------
    // Set the IN0 and IN1 pins to GPIO
    gpio_init(Motor_IN1);
    gpio_init(Motor_IN2);

    gpio_set_dir(Motor_IN1, GPIO_OUT);
    gpio_set_dir(Motor_IN2, GPIO_OUT);

    gpio_put(Motor_IN1, 0);  //motor STOP
    gpio_put(Motor_IN2, 0);  //motor STOP
    //Motor driver intialization END

    //-------------------------------------------
    //Kalman filter (angle) initialization
    //-------------------------------------------
    //initial value of theta_data_predict
    theta_data_predict[0][0] = 0;
    theta_data_predict[1][0] = theta_dot_mean;
    
    //initial value of P_theta_predict
    P_theta_predict[0][0] = 1;
    P_theta_predict[0][1] = 0;
    P_theta_predict[1][0] = 0;
    P_theta_predict[1][1] = theta_dot_variance;

    //-------------------------------------------  
    //Kalman filter (all system) initialization
    //-------------------------------------------
    //initial value of x_data_predict
    for(int i=0; i<4; i++)
    {
        x_data_predict[i][0] = 0;
    }
    //initial value of P_x_predict
    for(int i=0; i<4; i++)
    {
        for(int j=0; j<4; j++)
        {
            P_x_predict[i][j] = 0;    
        } 
    }
    for(int i=0; i<4; i++)
    {
        P_x_predict[i][i] = 1e-4;   
    }
    //measurement noise matrix
    for(int i=0; i<4; i++)
    {
        for(int j=0; j<4; j++)
        {
            measure_variance_mat[i][j] = 0;    
        }
    }
    measure_variance_mat[0][0] = theta_variance * deg_rad_coeff;
    measure_variance_mat[1][1] = theta_dot_variance * deg_rad_coeff;
    measure_variance_mat[2][2] = encoder_error * encoder_error;
    measure_variance_mat[3][3] = encoder_rate_error * encoder_rate_error;
    /////////////////////////////////////////////  
    //  Timer
    /////////////////////////////////////////////

    // set P_angle to theta_data[0][0]
    theta_data[0][0] = get_P_angle();

    // start rotary encorder process (25 us)
    add_repeating_timer_us(-25, rotary_encoder_check, NULL, &timer_encorder);
    sleep_ms(1);

    // start estimation process (2.5 ms)
    add_repeating_timer_us(-2500, theta_estimation, NULL, &timer_esti);
    sleep_ms(1);

    // calculate W_angle [degree] as initial values
    W_angle[0] = (float)encoder_value / 1074.0 * 360.0;
    for (int i = 1; i <= 9; i++)
    {
        W_angle[i] = W_angle[0];
    }

    // calculate P_angle_dot [deg/s] as initial values
    P_angle_dot_data[0] = get_P_angle_dot();
    for (int i = 0; i < 9; i++) {
        P_angle_dot_data[i + 1] = P_angle_dot_data[0];
    }

    count_control = 250;
    // start main control process (10.0 ms)
    //add_repeating_timer_ms(-10, Control_Pendulum, NULL, &timer_control);
    //sleep_ms(1);

    uart_puts(UART_ID, "Start!!\n");
    sleep_ms(10);

    //===========================================
    //Main loop
    //it takes 10 msec (calculation)
    //===========================================
    Motor_Mode = 0;
    count = 0;
    //t_start = time_us_64();
    while(1)
    {
        t_start = time_us_32();

        Control_Pendulum();

        count++;
        if (count >= 50) {
            count = 0;
            if (flag == 0) {
                gpio_put(LED_PICO, 1);
                flag = 1;
            }else {
                gpio_put(LED_PICO, 0);
                flag = 0;
            }
        }

        if (count % 5 == 0) {
            uart_var();
        }
        else {
            sleep_ms(1);
        }
      
        t_end = time_us_32() - t_start;
    }
    //===========================================
    //Main loop (end)
    //=========================================== 

    cancelled_esti = cancel_repeating_timer(&timer_control);
    //uart_puts(UART_ID, "cancelled... _control");
    snprintf(s, sizeof(s), "ctl:%d\n", cancelled_control);
    uart_puts(UART_ID, s);
    uart_puts(UART_ID, "\0");

    sleep_ms(1);

    cancelled_esti = cancel_repeating_timer(&timer_esti);
    //uart_puts(UART_ID, "cancelled... _esti");
    snprintf(s, sizeof(s), "esti:%d\n", cancelled_esti);
    uart_puts(UART_ID, s);
    uart_puts(UART_ID, "\0");

    sleep_ms(1);

    cancelled_encorder = cancel_repeating_timer(&timer_encorder);
    //uart_puts(UART_ID, "cancelled... _encorder");
    snprintf(s, sizeof(s), "enco:%d\n", cancelled_encorder);
    uart_puts(UART_ID, s);
    uart_puts(UART_ID, "\0");

    sleep_ms(1);

    return;
}


このページのトップに戻る

リンクを貼られているページに戻る