/* Copyright 2021 codenocold codenocold@qq.com Address : https://github.com/codenocold/dgm This file is part of the dgm firmware. The dgm firmware is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The dgm firmware is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ //#include "anticogging.h" #include "calibration.h" //#include "can.h" #include "APP_Main.h" #include "APP_Task.h" #include "anticogging.h" #include "controller.h" #include "encoder.h" #include "foc.h" #include "pwm_curr.h" #include "usr_config.h" #include "util.h" #include #include typedef struct sFSM { tFSMState state; tFSMState state_next; uint8_t state_next_ready; } tFSM; static volatile tFSM mFSM; volatile tMCStatusword StatuswordNew; volatile tMCStatusword StatuswordOld; ; #define CHARGE_BOOT_CAP_MS 10 #define CHARGE_BOOT_CAP_TICKS (uint16_t)((PWM_FREQUENCY * CHARGE_BOOT_CAP_MS) / 1000) static uint16_t mChargeBootCapDelay = 0; static void enter_state(void); static void exit_state(void); static void led_act_loop(void); void MCT_init(void) { mFSM.state = BOOT_UP; mFSM.state_next = BOOT_UP; mFSM.state_next_ready = 0; StatuswordNew.status.status_code = 0; StatuswordNew.errors.errors_code = 0; StatuswordOld = StatuswordNew; } void MCT_reset_error(void) { StatuswordNew.errors.errors_code &= 0x0000FFFF; StatuswordOld.errors.errors_code &= 0x0000FFFF; } tFSMState MCT_get_state(void) { return mFSM.state; } // return // 0 Success // -1 Invalid // -2 Error code // -3 Calib invalid int MCT_set_state(tFSMState state) { int ret = 0; switch (mFSM.state) { case BOOT_UP: if (state == IDLE) { mFSM.state_next = IDLE; } else { ret = -1; } break; case IDLE: switch (state) { case IDLE: FOC_disarm(); mChargeBootCapDelay = 0; mFSM.state_next = IDLE; break; case RUN: if (StatuswordNew.errors.errors_code) { ret = -2; } else if (!UsrConfig.calib_valid) { ret = -3; } else { FOC_arm(); mChargeBootCapDelay = CHARGE_BOOT_CAP_TICKS; mFSM.state_next = RUN; } break; case CALIBRATION: if (StatuswordNew.errors.errors_code) { ret = -2; } else { FOC_arm(); mChargeBootCapDelay = CHARGE_BOOT_CAP_TICKS; mFSM.state_next = CALIBRATION; } break; case ANTICOGGING: if (StatuswordNew.errors.errors_code) { ret = -2; } else if (!UsrConfig.calib_valid) { ret = -3; } else { FOC_arm(); mChargeBootCapDelay = CHARGE_BOOT_CAP_TICKS; mFSM.state_next = ANTICOGGING; } break; default: ret = -1; break; } break; default: if (state == IDLE) { mFSM.state_next = IDLE; } else { ret = -1; } break; } mFSM.state_next_ready = 0; return ret; } static void enter_state(void) { switch (mFSM.state) { case BOOT_UP: break; case IDLE: break; case RUN: CONTROLLER_reset(); StatuswordNew.status.switched_on = 1; StatuswordNew.status.target_reached = 1; StatuswordNew.status.current_limit_active = 0; StatuswordOld.status = StatuswordNew.status; break; case CALIBRATION: CALIBRATION_start(); break; case ANTICOGGING: CONTROLLER_reset(); ANTICOGGING_start(); break; default: break; } } static void exit_state(void) { switch (mFSM.state) { case BOOT_UP: // CAN_reset_rx_timeout(); // CAN_reset_tx_timeout(); mFSM.state_next_ready = 1; break; case IDLE: if (mChargeBootCapDelay) { mChargeBootCapDelay--; } else { mFSM.state_next_ready = 1; } break; case RUN: FOC_disarm(); StatuswordNew.status.switched_on = 0; StatuswordNew.status.target_reached = 0; StatuswordNew.status.current_limit_active = 0; StatuswordOld.status = StatuswordNew.status; mFSM.state_next_ready = 1; break; case CALIBRATION: CALIBRATION_end(); USR_CONFIG_save_config(); printf("UsrConfig.motor_phase_resistance:%f\r\n", UsrConfig.motor_phase_resistance); printf("UsrConfig.motor_phase_inductance:%f\r\n", UsrConfig.motor_phase_inductance); printf("UsrConfig.motor_pole_pairs:%ld\r\n", UsrConfig.motor_pole_pairs); mFSM.state_next_ready = 1; break; case ANTICOGGING: ANTICOGGING_end(); mFSM.state_next_ready = 1; break; default: break; } } int time = 1; int count = 0; void MCT_high_frequency_task(void) { /* state transition management */ if (mFSM.state_next != mFSM.state) { exit_state(); if (mFSM.state_next_ready) { mFSM.state = mFSM.state_next; enter_state(); } } // if (time >= 0) { // time++; // } // // if (time == 5) { // StatuswordNew.errors.errors_code = 0; // int ret = MCT_set_state(IDLE); // printf("IDLE ret:%d\r\n", ret); // } // // if (time == 10) { // int ret = MCT_set_state(CALIBRATION); // printf("CALIBRATION ret:%d\r\n", ret); // // UsrConfig.control_mode = CONTROL_MODE_VELOCITY_RAMP; // // Controller.input_velocity = 0.01f; // // time = -1; // } // // // if (UsrConfig.calib_valid && time == -1) { // int ret = MCT_set_state(RUN); // printf("RUN ret:%d\r\n", ret); // UsrConfig.control_mode = CONTROL_MODE_POSITION_PROFILE; // Controller.input_position = 0.0f; // Controller.input_velocity = 0.0f; // time = -2; // } // // if (UsrConfig.calib_valid && time == -2) { // count++; // if (count < 50000) { // Controller.input_position = 5.0f; // Controller.input_updated = true; // } // if (count > 50000) { // Controller.input_position = 0.5f; // Controller.input_updated = true; // } // if (count > 100000) { // count = 0; // } // // time = -2; // } // ENCODER_loop(); // FOC_voltage(0,0.001f,Encoder.phase); // Foc.v_bus = read_vbus(); Foc.v_bus = 24.0f; UTILS_LP_FAST(Foc.v_bus_filt, Foc.v_bus, 0.05f); Foc.i_a = read_iphase_a(); Foc.i_b = read_iphase_b(); Foc.i_c = read_iphase_c(); switch (mFSM.state) { case BOOT_UP: break; case CALIBRATION: CALIBRATION_loop(); break; case ANTICOGGING: ANTICOGGING_loop(); case RUN: { CONTROLLER_loop(); // check motor current // If Ia + Ib + Ic == 0 holds then we have: Inorm^2 = Id^2 + Iq^2 = Ialpha^2 + Ibeta^2 = 2/3 * (Ia^2 + Ib^2 + Ic^2) float Inorm_sq = 2.0f / 3.0f * (SQ(Foc.i_a) + SQ(Foc.i_b) + SQ(Foc.i_c)); if (Inorm_sq > SQ(UsrConfig.protect_over_current)) { FOC_disarm(); MCT_set_state(IDLE); StatuswordNew.errors.over_current = 1; } // check I bus current if (Foc.i_bus > UsrConfig.protect_i_bus_max) { FOC_disarm(); MCT_set_state(IDLE); StatuswordNew.errors.over_current = 1; } } break; default: break; } } void MCT_safety_task(void) { // VBUS check if (mFSM.state != BOOT_UP) { // Over voltage check if (Foc.v_bus > UsrConfig.protect_over_voltage) { StatuswordNew.errors.over_voltage = 1; } // Under voltage check if (Foc.v_bus < UsrConfig.protect_under_voltage) { StatuswordNew.errors.under_voltage = 1; } // Enchoder state check if (MT6816.check_err_count > 50 || MT6816.rx_err_count > 50) { StatuswordNew.errors.encoder_offline = 1; } } watch_dog_feed(); } void MCT_low_priority_task(void) { bool isSend = false; // State check if (StatuswordOld.status.status_code != StatuswordNew.status.status_code) { isSend = true; StatuswordOld.status.status_code = StatuswordNew.status.status_code; } // Error check if (StatuswordOld.errors.errors_code != StatuswordNew.errors.errors_code) { if (StatuswordNew.errors.errors_code) { FOC_disarm(); MCT_set_state(IDLE); } isSend = true; StatuswordOld.errors.errors_code = StatuswordNew.errors.errors_code; } if (isSend) { CAN_tx_statusword(StatuswordNew); } led_act_loop(); CAN_comm_loop(); } static void led_act_loop(void) { static uint16_t tick = 0; static uint32_t tick_100Hz = 0; // 100Hz if (get_ms_since(tick_100Hz) < 10) { return; } tick_100Hz = SystickCount; switch (mFSM.state) { case IDLE: if (tick == 0) { LED_ACT_SET(); } else if (tick == 10) { LED_ACT_RESET(); } else if (tick > 100) { tick = 0xFFFF; } break; case RUN: if (tick == 0) { LED_ACT_SET(); } else if (tick == 10) { LED_ACT_RESET(); } else if (tick == 20) { LED_ACT_SET(); } else if (tick == 30) { LED_ACT_RESET(); } else if (tick > 100) { tick = 0xFFFF; } break; case CALIBRATION: if (tick == 0) { LED_ACT_SET(); } else if (tick == 10) { LED_ACT_RESET(); } else if (tick == 20) { LED_ACT_SET(); } else if (tick == 30) { LED_ACT_RESET(); } else if (tick == 40) { LED_ACT_SET(); } else if (tick == 50) { LED_ACT_RESET(); } else if (tick > 150) { tick = 0xFFFF; } break; case ANTICOGGING: if (tick == 0) { LED_ACT_SET(); } else if (tick == 10) { LED_ACT_RESET(); } else if (tick == 20) { LED_ACT_SET(); } else if (tick == 30) { LED_ACT_RESET(); } else if (tick == 40) { LED_ACT_SET(); } else if (tick == 50) { LED_ACT_RESET(); } else if (tick == 60) { LED_ACT_SET(); } else if (tick == 70) { LED_ACT_RESET(); } else if (tick > 200) { tick = 0xFFFF; } break; default: break; } tick++; }