// #include #include "encoders/abs_inc_combine/AbsIncCombineSensor.h" #include "esp32-hal.h" #include #define NODE_NAME "N17BLDC" #define VERSION_MAJOR 0 #define VERSION_MINOR 1 #define VCS_REVISION_ID 0 #include "Arduino.h" #include "pin_def.h" #define USE_USBSERIAL #ifdef USE_USBSERIAL #include "USB.h" USBCDC usbserial; #ifdef Serial #undef Serial #endif #define Serial usbserial #else #define Serial Serial1 #endif // #define Serial Serial #include "canard.c" #include #define spi_dev SPI // #include "Wire.h" #include #include "SimpleFOCDrivers.h" #include "encoders/calibrated/CalibratedSensor.h" #include "encoders/abs_inc_combine/AbsIncCombineSensor.h" #include "encoders/as5047/MagneticSensorAS5047.h" // #include "encoders/esp32hwencoder/ESP32HWEncoder.h" #include "DRV8323S.hpp" #include "HybridStepperMotor.h" #include "esp32-hal-adc.h" #include "esp32-hal-gpio.h" #include "udral_servo.hpp" #include #define TEMP(v0, b, rt, r1, vdd) \ ((1.0 / \ ((1.0 / 298.15) + ((1.0 / b) * log((v0 * r1) / (rt * (vdd - v0)))))) - \ 273.15) #define temp_pcb \ (TEMP(analogRead(TERMISTOR_PCB) * 3.3 / 4096.0, 3435.0, 10000.0, 10000.0, \ 3.3)) #define vdrive_read (analogRead(VSENSE_PIN) * 20.08f / 845) //* 20.8f/ 21033.75) #define MOTOR #define FW_NO_WATCHDOG #ifndef FW_NO_WATCHDOG #include #define WDT_TIMEOUT_s 1 // struct esp_task_wdt_config_t wd_config = { // .timeout_ms = 100, // .idle_core_mask = ~0x00000000, // .trigger_panic = true // }; #endif const int voltage_lpf = 50; // ESP32HWEncoder encoder = // ESP32HWEncoder(ENC_A, ENC_B, 4096 / 4); // The Index pin can be omitted MagneticSensorAS5047 encoder_absolute(18); Encoder encoder(ENC_A, ENC_B, 4096 / 4, 0); AbsIncCombineSensor abs_inc_sensor(encoder, encoder_absolute); float encoder_calibration_lut[90]; CalibratedSensor encoder_calibrated(encoder_absolute, sizeof(encoder_calibration_lut) / sizeof(encoder_calibration_lut[0]), encoder_calibration_lut); // MagneticSensorAS5600 encoder = MagneticSensorAS5600(0x36); #ifdef MOTOR struct drv8323s_foc_driver drv8323s; // BLDCMotor motor = BLDCMotor(100); // 24N22P HybridStepperMotor motor = HybridStepperMotor(50); //, 3.7, 10, 4.5 / 1000); #endif void read_i2c(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len) { Wire.beginTransmission(addr); Wire.write(reg); // MAN:0x2E int error = Wire.endTransmission(); if (error != 0) { return; } delayMicroseconds(50); int ret = Wire.requestFrom(addr, len); Wire.readBytes(buf, ret); return; } void write_i2c(uint8_t addr, uint8_t reg_lsb, uint8_t val) { Wire.beginTransmission(addr); uint8_t data[] = {reg_lsb, val}; Wire.write(data, sizeof data); int error = Wire.endTransmission(); if (error != 0) { return; } } void write_dual_i2c(uint8_t addr, uint8_t reg_lsb, uint8_t val1, uint8_t val2) { Wire.beginTransmission(addr); uint8_t data[] = {reg_lsb, val1, val2}; Wire.write(data, sizeof data); int error = Wire.endTransmission(); if (error != 0) { return; } } SemaphoreHandle_t mutex; struct UdralServoState servo_state = {0}; void mutexed_state_sync(UdralServoState *const state) { xSemaphoreTake(mutex, portMAX_DELAY); servo_state.target_force = state->target_force; servo_state.target_acceleration = state->target_acceleration; servo_state.target_velocity = state->target_velocity; servo_state.target_position = state->target_position; servo_state.arming = state->arming; servo_state.pid = state->pid; *state = servo_state; xSemaphoreGive(mutex); } TaskHandle_t taskCommHandle; void comm_task(void *parameter) { udral_loop(mutexed_state_sync); } void doA1() { encoder.handleA(); } void doB1() { encoder.handleB(); } void setup() { pinMode(LED_PIN, OUTPUT); mutex = xSemaphoreCreateMutex(); #ifdef USE_USBSERIAL Serial.begin(); USB.begin(); Serial.setDebugOutput( true); // sends all log_e(), log_i() messages to USB HW CDC Serial.setTxTimeoutMs(0); #else Serial.begin(460800, SERIAL_8N1, 44, 43); #endif digitalWrite(LED_PIN, 0); // enable delay(500); digitalWrite(LED_PIN, 1); // disable delay(100); Serial.println("Start"); delay(1000); pinMode(SPI_DRV_SC, OUTPUT); pinMode(INHA, OUTPUT); // digitalWrite(INHA, 0); // enable pinMode(INHB, OUTPUT); // digitalWrite(INHB, 0); // enable pinMode(INHC, OUTPUT); // digitalWrite(INHC, 0); // enable pinMode(INLABC, OUTPUT); digitalWrite(INLABC, 0); // enable pinMode(CAL_PIN, OUTPUT); digitalWrite(CAL_PIN, 0); // enable pinMode(SPI_MISO, INPUT_PULLUP); SPI.begin(SPI_CLK, SPI_MISO, SPI_MOSI, SPI_DRV_SC); //SPI.setFrequency(100000); // initialise magnetic sensor hardware encoder.pullup = Pullup::USE_INTERN; encoder.init(); encoder.enableInterrupts(doA1, doB1); encoder_absolute.init(&spi_dev); abs_inc_sensor.init(); Serial.printf("offset: %f\nvalue: %d", abs_inc_sensor.offset, abs_inc_sensor.getAngle()); #ifdef MOTOR SimpleFOCDebug::enable(&Serial); drv8323s_init(&drv8323s, INHA, INHB, INHC, SPI_DRV_SC, DRVEN, &spi_dev); digitalWrite(INLABC, 1); // enable // driver.init(&SPI); // status(); motor.linkSensor(&encoder_calibrated); motor.linkDriver(drv8323s.focdriver); // motor.foc_modulation = FOCModulationType::SinePWM; motor.foc_modulation = FOCModulationType::SpaceVectorPWM; motor.voltage_sensor_align = 4; motor.voltage_limit = 6; // motor.controller = MotionControlType::velocity_openloop; // motor.controller = MotionControlType::velocity; motor.controller = MotionControlType::torque; motor.torque_controller = TorqueControlType::voltage; motor.useMonitoring(Serial); drv8323s.focdriver->voltage_power_supply = vdrive_read; motor.init(); delay(1000); static Preferences pref; pref.begin("simpleFOC"); // set voltage to run calibration encoder_calibrated.voltage_calibration = 3; encoder_calibrated.init(); // Running calibration const char *encoder_calibration_lut_str = "enc_cal_lut"; const char *zero_electric_angle_str = "zero_el_angle"; const char *sensor_direction_str = "enc_dir_str"; const int settle_time_ms = 150; if (!pref.isKey(encoder_calibration_lut_str) || pref.getBytesLength(encoder_calibration_lut_str) != sizeof(encoder_calibration_lut)) { encoder_calibrated.calibrate(motor, settle_time_ms); pref.putBytes(encoder_calibration_lut_str, &encoder_calibration_lut[0], sizeof(encoder_calibration_lut)); pref.putFloat(zero_electric_angle_str, motor.zero_electric_angle); pref.putInt(sensor_direction_str, (int)motor.sensor_direction); } else { pref.getBytes(encoder_calibration_lut_str, &encoder_calibration_lut[0], sizeof(encoder_calibration_lut)); Serial.println("Skipping calibration"); } if (!pref.isKey(zero_electric_angle_str)) { motor.initFOC(); pref.putFloat(zero_electric_angle_str, motor.zero_electric_angle); pref.putInt(sensor_direction_str, (int)motor.sensor_direction); } else { motor.zero_electric_angle = pref.getFloat(zero_electric_angle_str); motor.sensor_direction = (Direction)pref.getInt(sensor_direction_str); motor.initFOC(); } pref.end(); motor.move(0); digitalWrite(INLABC, 0); // enable #endif xTaskCreatePinnedToCore(&comm_task, // Function name of the task "comm", // Name of the task (e.g. for debugging) 65536, // Stack size (bytes) NULL, // Parameter to pass 10, // Task priority &taskCommHandle, // Assign task handle 0 // Run on the non-Arduino (1) core ); // esp_task_wdt_init(WDT_TIMEOUT_s, true); // enable panic so ESP32 restarts // esp_task_wdt_add(NULL); // add current thread to WDT watch } int i = 0; void loop() { #ifdef MOTOR bool armed = false; float curr_pcb_temp_kelvin = temp_pcb + 273.15f; xSemaphoreTake(mutex, portMAX_DELAY); armed = servo_state.arming.armed; float target = servo_state.target_force; servo_state.controller_temperature = curr_pcb_temp_kelvin; servo_state.motor_temperature = NAN; float curr_angle = encoder_calibrated.getAngle(); float curr_vel = encoder_calibrated.getVelocity(); unsigned long now = millis(); static unsigned long last_update = now; unsigned long tdelta = now - last_update; last_update = now; float curr_accel = tdelta ? (curr_vel - servo_state.curr_velocity) / tdelta : 0; servo_state.curr_acceleration = curr_accel; servo_state.curr_velocity = curr_vel; servo_state.curr_position = curr_angle; servo_state.curr_force = servo_state.target_force; servo_state.curr_velocity = encoder.getAngle(); servo_state.curr_acceleration = encoder_absolute.getAngle(); servo_state.curr_force = abs_inc_sensor.getAngle(); servo_state.vcc_volts = drv8323s.focdriver->voltage_power_supply; servo_state.current = NAN; xSemaphoreGive(mutex); if (!armed) { if (motor.enabled) { motor.move(0); motor.disable(); digitalWrite(INLABC, 0); } } else { if (!motor.enabled) { digitalWrite(INLABC, 1); motor.enable(); } motor.move(target); } digitalWrite(LED_PIN, armed ? LOW : HIGH); drv8323s.focdriver->voltage_power_supply = vdrive_read; motor.loopFOC(); #else encoder.update(); // optional: Update manually if not using loopfoc() #endif }