First try open loop velocity mode to make sure all the motor business is working. Then voltage-torque mode to make sure the encoder is working and tune the voltage-based current limiting. Then velocity mode to tune velocity PID. And finally angle mode, which in my case required a few more tweaks to velocity PID in addition to tuning angle P.
fortunately I only need torque mode, I donât need velocity or angle mode Will try open loop now, then.
ok open loop works, for anyone else has the same problem:
âââ
// Open loop motor control example
#include <SimpleFOC.h>
#include "SoftwareSerial.h"
#define SS_USB_RX PA15
#define SS_USB_TX PA2
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 8;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
// BLDC motor & driver instance
// BLDCMotor motor = BLDCMotor(pole pair number);
BLDCMotor motor = BLDCMotor(7);
// BLDCDriver3PWM driver = BLDCDriver3PWM(pwmA, pwmB, pwmC, Enable(optional));
BLDCDriver6PWM driver = BLDCDriver6PWM(PA8, PA7, PB3, PB0, PB6, PB1);
SoftwareSerial SoftSerialUSB(SS_USB_RX, SS_USB_TX);
// Stepper motor & driver instance
//StepperMotor motor = StepperMotor(50);
//StepperDriver4PWM driver = StepperDriver4PWM(9, 5, 10, 6, 8);
//target variable
float target_velocity = 0;
void setup() {
// driver config
// power supply voltage [V]
driver.voltage_power_supply = 24;
// limit the maximal dc voltage the driver can set
// as a protection measure for the low-resistance motors
// this value is fixed on startup
driver.voltage_limit = 6;
driver.init();
// link the motor and the driver
motor.linkDriver(&driver);
// limiting motor movements
// limit the voltage to be set to the motor
// start very low for high resistance motors
// currnet = resistance*voltage, so try to be well under 1Amp
motor.voltage_limit = 3; // [V]
// open loop control config
motor.controller = MotionControlType::velocity_openloop;
// init motor hardware
motor.init();
SoftSerialUSB.begin(38400);
SoftSerialUSB.println("Motor ready!");
SoftSerialUSB.println("Setting target velocity [rad/s]");
target_velocity = 2;
_delay(1000);
}
void loop() {
// open loop velocity movement
// using motor.voltage_limit and motor.velocity_limit
motor.move(target_velocity);
}
âââ
compiling is still extremely slow, and given the commander doesnât work and serial hardly works, that means frequently recompiling⌠I disabled the antivirus and tried to read up on it, it appears to be a flaw with the arduino ide somehow according to other people
update: ok same behaviour as the torque control mode last night. It moves extremely slowly for about 5 minutes, one way and then back the other. Then it says it failed to notice movement.
/**
* Torque control example using voltage control loop.
*
* Most of the low-end BLDC driver boards doesn't have current measurement therefore SimpleFOC offers
* you a way to control motor torque by setting the voltage to the motor instead hte current.
*
* This makes the BLDC motor effectively a DC motor, and you can use it in a same way.
*/
#include <SimpleFOC.h>
#include "SoftwareSerial.h"
#define SS_USB_RX PA15
#define SS_USB_TX PA2
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 8;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
// magnetic sensor instance - I2C
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
// BLDC motor & driver instance
// BLDCMotor motor = BLDCMotor(pole pair number);
BLDCMotor motor = BLDCMotor(7);
// BLDCDriver3PWM driver = BLDCDriver3PWM(pwmA, pwmB, pwmC, Enable(optional));
BLDCDriver6PWM driver = BLDCDriver6PWM(PA8, PA7, PB3, PB0, PB6, PB1);
SoftwareSerial SoftSerialUSB(SS_USB_RX, SS_USB_TX);
// voltage set point variable
float target_voltage = 2;
void setup() {
// initialise magnetic sensor hardware
sensor.init();
// link the motor to the sensor
motor.linkSensor(&sensor);
// power supply voltage
driver.voltage_power_supply = 24;
driver.init();
motor.linkDriver(&driver);
// aligning voltage
motor.voltage_sensor_align = 5;
// choose FOC modulation (optional)
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
// set motion control loop to be used
motor.controller = MotionControlType::torque;
// use monitoring with serial
SoftSerialUSB.begin(38400);
// comment out if not needed
motor.useMonitoring(SoftSerialUSB);
// initialize motor
motor.init();
// align sensor and start FOC
motor.initFOC();
Serial.println(F("Motor ready."));
Serial.println(F("Setting the target voltage"));
target_voltage = 4;
_delay(1000);
}
void loop() {
// main FOC algorithm function
// the faster you run this function the better
// Arduino UNO loop ~1kHz
// Bluepill loop ~10kHz
motor.loopFOC();
// Motion control function
// velocity, position or voltage (defined in motor.controller)
// this function can be run at much lower frequency than loopFOC() function
// You can also use motor.move() and set the motor.target in the code
motor.move(target_voltage);
}
hm, searching the forum for this error state, I found this guy https://community.simplefoc.com/t/platformio-b-g431-esc1-code-not-working/2957/12
but he makes no mention of the align being extremely slow. It seems like that might be an important clue.
I hypothesized maybe the motor was going the wrong way and the system wasnât advanced enough to notice and compensate, but I reversed motor rotation direction by swapping two of the wires and behavior is the same, except that it turns the opposite direction now.
Iâm pretty baffled. Will keep reading the forum and the docs.
update: tried removing all the software serial stuff in the off chance the interrupts might be interfering or something. Same behaviour.
Update: ok so trying to get the sensor working, should this code work to tell me the angle of the sensor?
#include "SoftwareSerial.h"
#include <SimpleFOC.h>
#define SS_USB_RX PA15
#define SS_USB_TX PA2
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 8;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
// BAUD RATE MUST BE BETWEEN 9600..38400
// ANY OTHER BAUD RATE WILL CHOKE
SoftwareSerial SoftSerialUSB(SS_USB_RX, SS_USB_TX);
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
void setup()
{
//set pins for Software Serial communication
SoftSerialUSB.begin(38400);
pinMode(SS_USB_RX, INPUT);
pinMode(SS_USB_TX, OUTPUT);
sensor.init();
delay(1000);
}
void loop()
{
SoftSerialUSB.println("TEST SSERIAL_USB");
SoftSerialUSB.println(F_CPU);
SoftSerialUSB.println(sensor.getAngle());
sensor.update();
delay(100);
}
The output on the serial monitor is:
TEST SSERIAL_USB
64000000
12.56
But it just keeps saying 12.56 no matter what angle the motor is at. I tried holding a magnet close to the sensor and rotating it. This sensor worked with the arduino. Should the above code work or is it borked?
The connections for theI2C interface appear to be sound.
ok, I had not set up the I2C interface right as Deku had told me, I thought maybe it was not needed, however it seems to work if I do this:
#include <SimpleFOC.h>
#include <Wire.h>
#include "SoftwareSerial.h"
#define SS_USB_RX PA15
#define SS_USB_TX PA2
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 8;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
// MagneticSensorI2C(uint8_t _chip_address, float _cpr, uint8_t _angle_register_msb)
// chip_address I2C chip address
// bit_resolution resolution of the sensor
// angle_register_msb angle read register msb
// bits_used_msb number of used bits in msb register
//
// make sure to read the chip address and the chip angle register msb value from the datasheet
// also in most cases you will need external pull-ups on SDA and SCL lines!!!!!
//
// For AS5058B
// MagneticSensorI2C sensor = MagneticSensorI2C(0x40, 14, 0xFE, 8);
// Example of AS5600 configuration
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
SoftwareSerial SoftSerialUSB(SS_USB_RX, SS_USB_TX);
void setup() {
Wire.setSDA(PB7);
Wire.setSCL(PB8);
Wire.begin();
pinMode(SS_USB_RX, INPUT);
pinMode(SS_USB_TX, OUTPUT);
// monitoring port
SoftSerialUSB.begin(38400);
// configure i2C
Wire.setClock(400000);
// initialise magnetic sensor hardware
sensor.init();
SoftSerialUSB.println("Sensor ready");
_delay(1000);
}
void loop() {
// iterative function updating the sensor internal variables
// it is usually called in motor.loopFOC()
// this function reads the sensor hardware and
// has to be called before getAngle nad getVelocity
sensor.update();
SoftSerialUSB.println("TEST SSERIAL_USB");
SoftSerialUSB.println(F_CPU);
// display the angle and the angular velocity to the terminal
SoftSerialUSB.print(sensor.getAngle());
SoftSerialUSB.print("\t");
SoftSerialUSB.println(sensor.getVelocity());
}
I spliced the two peices of code together, the working encoder code and the voltage torque control example that sets the clock, prints to serial, and very slowly turns the motor to initialize. Doesnât work⌠I had high hopes for this one, but itâs the same behaviour and output as before. Iâm goig to the post office and to get something to eat, when I get back I will try printing the ecoder values in a loop after the initialization to see if the encoder stuff still works after being spliced into itâs new home.
This is what I tried:
* Torque control example using voltage control loop.
*
* Most of the low-end BLDC driver boards doesn't have current measurement therefore SimpleFOC offers
* you a way to control motor torque by setting the voltage to the motor instead hte current.
*
* This makes the BLDC motor effectively a DC motor, and you can use it in a same way.
*/
#include <SimpleFOC.h>
#include "SoftwareSerial.h"
#include <Wire.h>
#define SS_USB_RX PA15
#define SS_USB_TX PA2
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 8;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
// magnetic sensor instance - I2C
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
// BLDC motor & driver instance
// BLDCMotor motor = BLDCMotor(pole pair number);
BLDCMotor motor = BLDCMotor(7);
// BLDCDriver3PWM driver = BLDCDriver3PWM(pwmA, pwmB, pwmC, Enable(optional));
BLDCDriver6PWM driver = BLDCDriver6PWM(PA8, PA7, PB3, PB0, PB6, PB1);
SoftwareSerial SoftSerialUSB(SS_USB_RX, SS_USB_TX);
// voltage set point variable
float target_voltage = 2;
void setup() {
Wire.setSDA(PB7);
Wire.setSCL(PB8);
Wire.begin();
Wire.setClock(400000);
pinMode(SS_USB_RX, INPUT);
pinMode(SS_USB_TX, OUTPUT);
// initialise magnetic sensor hardware
sensor.init();
// link the motor to the sensor
motor.linkSensor(&sensor);
// power supply voltage
driver.voltage_power_supply = 24;
driver.init();
motor.linkDriver(&driver);
// aligning voltage
motor.voltage_sensor_align = 5;
// choose FOC modulation (optional)
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
// set motion control loop to be used
motor.controller = MotionControlType::torque;
// use monitoring with serial
SoftSerialUSB.begin(38400);
// comment out if not needed
motor.useMonitoring(SoftSerialUSB);
// initialize motor
motor.init();
// align sensor and start FOC
motor.initFOC();
SoftSerialUSB.println(F("Motor ready."));
SoftSerialUSB.println(F("Setting the target voltage"));
target_voltage = 4;
_delay(1000);
}
void loop() {
// main FOC algorithm function
// the faster you run this function the better
// Arduino UNO loop ~1kHz
// Bluepill loop ~10kHz
motor.loopFOC();
// Motion control function
// velocity, position or voltage (defined in motor.controller)
// this function can be run at much lower frequency than loopFOC() function
// You can also use motor.move() and set the motor.target in the code
motor.move(target_voltage);
}
update: yeah, when I add SoftSerialUSB.println(sensor.getAngle()); to the loop, it prints the angles fine. The angle seems to be in radians.
So the encoder works fine, the motor turns in open loop, but even using the most elementary example code simplefoc isnât able to put two and two together.
It seems like there is an issue in the code deeper than I can deal with ![]()
You can increase motor.velocity_index_search to make it turn faster for calibration. Itâs in radians per second and defaults to 1. I canât see any actual problems though. If youâre getting good angle readings now, it should spin. What exactly is the motor behavior? Holding strongly in one position, vibrating, no force at all, or something else?
The motor behavior is that it goes very very slowly one way, then reverses direction and goes about the same distance, then it gives the error and goes unpowered. It takes like 4 minutes to complete. Definitely way slower than 1 radians per second. Open loop went at about the right speed, I think. I set it to 3, so if in radians per second that would be roughly one rotation every two seconds, which it did.
Iâm thinking about swapping the uno back in and trying to see if I can get that working, then swapping back and forth to see if I can zero in on whatever is different. But I sort of already did that, the code that worked with the uno I adapted with minimal change, I had to get rid of the commander but that shouldnât matter to initialization. I noticed that with the uno and the commander on it checked the direction of rotation with the angle sensor, but without the commander it gives a different output. Maybe the sensor didnât initialize properly, the angle can be read and printed but the connection between the two software modules or something⌠maybe I haz no clue
Oh, that is messed up then. I would suggest setting your sights on BLDCMotor::alignSensor. It doesnât look like absoluteZeroSearch on line 166 will be called when using MagneticSensorI2C, so the slow movement must be during the for loops on lines 175-190. That leaves the _delay(2); calls or the I2C communication during the sensor->update as the primary suspects. Comment out one or the other and see which results in fast spinning. It is technically possible to mess up the delay tick rate with the clock config, but the function youâre using was generated by STM32CubeIDE and works on mine so that shouldnât be it.
Side note, looking at the code there, velocity_index_search wonât affect the calibration speed after all. Itâs only used in BLDCMotor::absoluteZeroSearch.
Ok, will investigate tomorrow, thanks for the advice. As you can tell I am quite out of my depth messing with C. Iâm anxious to ascertain if this can give the rpm and what kind of noise it results in. Iâve been very foolish to pour so much time into my erv project and have too many chips in this basket of being able to roll my own quiet fan.
update:
I got inspired and tried uncommenting those two lines. When I uncomment the the sensor update line only and not the delay, it does go at a more reasonable speed for about 1/7th of a rotation, but then starts turning super slow again, I didnât let it finish.
Sounds like itâs the i2c communication, then, but when I did the sensor.update() and printed the sensor readings it seemed as though it worked fine. Something to do with the connections⌠or maybe it actually updates extremely slowly and I donât notice when I just have a loop that checks it and prints to serial⌠the motor initialization takes different amounts of time depending on if I am powered off the 24 volt supply or allow things to work off of the stlink adapter, and sometimes when running on the stlink adapter it says pole pair check fail etc but doesnât say no movement detected. If I turn the motor by hand while running off the stlink adapter, it says
OT: Init
MOT: Enable driver.
MOT: Align sensor.
MOT: sensor_direction==CW
MOT: PP check: fail - estimated pp: 5.36
MOT: Zero elec. angle: 4.80
MOT: No current sense.
MOT: Ready.
Motor ready.
Setting the target voltage
Obviously itâs confused but it finishes the proceedure quickly and moves on.
Something that makes the updates extremely slow only when running off the external power⌠or when the motor is turning only in small increments. No, because when itâs not turning at all it still gives up and concludes there is no motion in a couple of seconds. This super slow updating only happens when externally powered, I think. And yet I can print the angles to serial no problem. Maybe I just donât notice the slow updating when printing to serial. But no, because it does update, and yet motor init fails to notice any motion. The update seems to not only be very slow but also to not actually give a legit return value in that context, and that context specifically.
Wait, I donât know if I ever actually tried reading the sensor and printin got serial when externally powered. But itâs 10:30 now and I havenât showered, I have to try again tomorrow. If the external power borks the i2c connection maybe I can use the SPI encoder, perhaps a second visit to that would get results.
ok, now I commented out the second of the two updates, when it moves the motor back again, and instead of moving slowly it stutters gives a bit of a grinding sound for a fraction of a second and then remains powered but in a fixed position.
I checked the wires for the i2c connection are a centimeter or more from the motor wires and any other suspected source of interference, like the buck regulatorâs inductance. Moved some stuff, same deal.
ok, now it appears to be related to the difference between being powered off of the st-link vs the bench supply/from the vmot terminal. Sometimes, it continues working to print the angle to serial after I transition power from the stlink to the bench supply (turn on the bench supply without turning the sti-link off). Sometimes it doesnât. When it doesnât, it usually says 6.28 is the angle, sometime 0.48 I think. Sometimes it prints one for a long time and switches. obviously something pretty borked.
Good call checking for electromagnetic interference.
Try putting some calls to micros() in MagneticSensorI2C::read and print the differences between them to see where all the time is being spent.
Since those loops in BLDCMotor::alignSensor do 500 iterations each, then if the whole process takes 4 minutes then it should be around 240ms per iteration. That would be pretty unnoticeable when taking a single reading, but is ridiculously slow for such a short transmission.
I suppose you could try a lower I2C clock rate and see if it makes any difference. And try removing the CPU clock config to leave it at 16MHz and see if that makes any difference. Something weird is going on, but I donât know what. But donât lose faith, we just need to keep prodding it a bit longer and it will surely give up its secret ![]()
ok, experimentation continues. just want to post quickly that there is some kind of problem with the sensor driver for the SC8022 encoder, it reads only 1pi radians per full revolution, it should be 2 pi correct? 2 pi radians per circle.
update, ok so I switched back to the sc8022 encoder to see if I could circumvent the problem with the I2C communication.
It gets further than it did but still doesnât work.
output is:
got this far, testing serial port
64000000
MOT: Monitor enabled!
MOT: Init
MOT: Enable driver.
MOT: Align sensor.
MOT: sensor_direction==CW
MOT: PP check: fail - estimated pp: 15.11
MOT: Zero elec. angle: 5.59
MOT: No current sense.
MOT: Ready.
Motor commands sketch | Initial motion control > torque/voltage : target 2V.
1.89
1.89
motor behaviour: it turns back and forth a bit to do the sensor align, then it twitches briefly, and then stays locked with about 50 milliamps draw, but the current is more than enough to turn the fan, I can tell itâs got a fair bit of force if I turn the fan by hand.
This is the code I used:
#include "SoftwareSerial.h"
#include <SimpleFOCDrivers.h>
#include "encoders/sc60228/MagneticSensorSC60228.h"
#include <SimpleFOC.h>
// SENSOR SPI SC60228
// SPI2 PINS
#define CSN2 PA4
#define CLK2 PA5
#define MISO2 PB4
#define MOSI2 PB5
#define SS_USB_RX PA15
#define SS_USB_TX PA2
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 8;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
// BAUD RATE MUST BE BETWEEN 9600..38400
// ANY OTHER BAUD RATE WILL CHOKE
SoftwareSerial SoftSerialUSB(SS_USB_RX, SS_USB_TX);
MagneticSensorSC60228 sensor(CSN2);
BLDCMotor motor = BLDCMotor(7);
BLDCDriver6PWM driver = BLDCDriver6PWM(PA8, PA7, PB3, PB0, PB6, PB1);
SPIClass SPISensor(MOSI2, MISO2, CLK2);
void setup()
{
//set pins for Software Serial communication
SoftSerialUSB.begin(38400);
pinMode(SS_USB_RX, INPUT);
pinMode(SS_USB_TX, OUTPUT);
SoftSerialUSB.println("got this far, testing serial port");
SoftSerialUSB.println(F_CPU);
sensor.init(&SPISensor);
delay(1000);
motor.linkSensor(&sensor);
driver.voltage_power_supply = 24;
driver.init();
motor.linkDriver(&driver);
motor.controller = MotionControlType::torque;
motor.voltage_limit = 12;
motor.useMonitoring(SoftSerialUSB);
// initialise motor
motor.init();
// align encoder and start FOC
motor.initFOC();
// set the inital target value
motor.target = 2;
// define the motor id
SoftSerialUSB.println(F("Motor commands sketch | Initial motion control > torque/voltage : target 2V."));
delay(1000);
}
void loop()
{
for (int i=0; i<10000; i++) {
motor.loopFOC();
// iterative function setting the outter loop target
// velocity, position or voltage
// if tatget not set in parameter uses motor.target variable
motor.move();
}
for (int i=0; i<100; i++) {
motor.loopFOC();
// iterative function setting the outter loop target
// velocity, position or voltage
// if tatget not set in parameter uses motor.target variable
motor.move();
SoftSerialUSB.println(sensor.getAngle());
sensor.update();
}
delay(10000);
}
I noticed the value of the encoder keeps going up and up, 2pi radians per circle. But it doesnât wrap around at 2pi, it just keeps going up. Is that how itâs suppose dto be?
update: I wnt back to the as5600 on i2c and thought it might be some kind of noise on the power supply messing up the sensor, so I added a 10uf ceramic cap to the supply lines near the chip. The first time I powered it up it didnât work, then I tried disconnecting the motor, and it did get past motor initialization (failed pp check etc of course as the motor wasnât connected, but it read the sensor ok) And it showed some values of the encoder for ilke a second Then it started showing the usual 6.28 radians. itâs always the same. 2 pi radians. Spooky. IT never worked again after that first time I powered it up without the motor connected. Indicates some kind of noise issue, due to the randomness, to me
The magnet is super close to the sensor, I donât think it could be some kind of magnetic field issue, and in any case that wouldnât explain the extremely slow (probably a timeout error, so takes a long time and never returns anything good in the end) I2c communication, which only occurs when the board is powered through the Vmot terminal, and not when the logic is powered with the 3.3 volts of the stlink.
My best guess for now, which is not a great guess, is that I2C doesnât work because of interference on the signal line caused by some of the power stag stuff, causing the I2C peripheral to get messed up or something.
Valentine, did you use an I2C sensor or an SPI sensor? The SPI seems to work fine.
But then the problem is that some other aspect of the system does not work with the SC8022 sensor. There is likely more than one problem with the driver code. One is the directory structure. The other is that the reading wraps around at 1 pi radians. I donât know if itâs supposed to wrap around or keep going. The sensors act differently, the I2C sensor doesnât wrap around, at least for a long time, whereas the SPI wraps around every revolution.
Serial interface still doesnât work. I donât need it to, for the application, but⌠There are a lot of things here that donât work. Iâm definitely at the end of the line regarding my own limited ability to get stuff working. Iâm going to put it down until I get a promising idea, from here or elsewhere, or thing to try, and work on other aspects of the energy recovery ventilator.
updats: while reviewing the above, I noticed the suggestion to change the clock rate of the I2C port. Sorry Deku I did not respect your suggestion more before, there was a lot of stuff going on. I changed it to 100000 from 400000 and now the sensor will read when the motor in unconnected, but not when it is.
tried changing it further to 30000, still doesnât work. It did move during align at a reasoable speed for a fraction of a second one time when I had the motor connected. Might indicate that it is some issue that persists over reboots. Could be some kind of high voltage injecting charge somewhere that takes a while to clear out.
I used only SPI, never tried i2c.
Yes, the angle includes the full rotations from the zero point. Thatâs important for position control modeâŚ
This I consider very unlikelyâŚ
Do you mean the SC60228?
Itâs quite possible the driver has some error, although this would be MCU specific, as I have personally successfully tested the SC60228 with our driver (but canât recall right now what MCU I used).
Noise can indeed be a problem, usually more so for SPI than I2C. Increasing distance between motor and sensor wires, using short wires (no more than 10cm), or using a shielded cable (ground the shield) could help. Also be sure to lower SPI speeds to 1Mhz or less and see if it helps.
Also, if sensor values are changing by themselves, it can be the motorâs magnetic field influencing the sensor. That can be solved with a stronger magnet, or more distance between motor and sensor.
For I2C, missing or too high valued pull up resistors are often a source of errors.
Finally power and grounding problems are a frequent source of problems⌠make sure all grounds are actually connected to each other, and power supply is stable even when the motor is onâŚ
Yeah, it must be SC60228, I was looking at the letters at an angle, though I did check.
The power and ground is solid. Itâs a proper lab bench supply and all connections I tested with a multimeter.
To be clear, the I2C sensor fails because of an issue with serial communication that causes some failure with the serial communication when the board is powered from Vmot pin, but the approach using the SPI sensor fails for other reasons.
With the SPI/SC60228 sensor: there does appear to be several problems with the driver. One is the directory structure not matching the contents of the files. When I apparently get that fixed by copying the scr folder of the SimplFOCdrivers into the SimpleFOC directory, (merging the two src folders) it only counts to 1pi and then wraps back around.
It fails the pole pair check thinking there are 2x as many poles as there should be, which is about right. Then it carries on and just locks the motor, making no to attempt to commutate or produce rotation, apparently.
Open loop does work ok.
Maybe the problem starts with this directory structure problem, and my attempt to fix it led to the other problems.
I may try shortening the spi sensor wires today.
update: ok so I shortened the wires down to about 7 cm, and it works a bit better now. It does the sensor align, but it fails the pole pair check, it says slightly different values each time, from 8 to 10, or thereabouts, so pretty messed up.
then it locks in position, but it apparently does try to commutate, I have to rotate it one full rotation before it snaps into a new position, otherwise it snaps back to the old position.
sooo⌠fixed one thing, still more problems lined up for me down the road. MOT: Monitor enabled!
about to init motor
MOT: Init
MOT: Enable driver.
MOT: Align sensor.
MOT: sensor_direction==CW
MOT: PP check: fail - estimated pp: 9.78
MOT: Zero elec. angle: 4.92
MOT: No current sense.
MOT: Ready.
5.32
Motor ready.
Setting the target voltage
5.33
code:
/**
* Torque control example using voltage control loop.
*
* Most of the low-end BLDC driver boards doesn't have current measurement therefore SimpleFOC offers
* you a way to control motor torque by setting the voltage to the motor instead hte current.
*
* This makes the BLDC motor effectively a DC motor, and you can use it in a same way.
*/
#include <SimpleFOC.h>
#include "SoftwareSerial.h"
#include <Wire.h>
#define SS_USB_RX PA15
#define SS_USB_TX PA2
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 8;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
// magnetic sensor instance - I2C
// BLDC motor & driver instance
// BLDCMotor motor = BLDCMotor(pole pair number);
BLDCMotor motor = BLDCMotor(7);
// BLDCDriver3PWM driver = BLDCDriver3PWM(pwmA, pwmB, pwmC, Enable(optional));
BLDCDriver6PWM driver = BLDCDriver6PWM(PA8, PA7, PB3, PB0, PB6, PB1);
SoftwareSerial SoftSerialUSB(SS_USB_RX, SS_USB_TX);
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
// voltage set point variable
float target_voltage = 2;
void setup() {
Wire.setSDA(PB7);
Wire.setSCL(PB8);
Wire.begin();
Wire.setClock(30000);
pinMode(SS_USB_RX, INPUT);
pinMode(SS_USB_TX, OUTPUT);
// initialise magnetic sensor hardware
sensor.init();
// link the motor to the sensor
motor.linkSensor(&sensor);
// power supply voltage
driver.voltage_power_supply = 24;
driver.init();
motor.linkDriver(&driver);
// aligning voltage
motor.voltage_sensor_align = 2;
// choose FOC modulation (optional)
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
// set motion control loop to be used
motor.controller = MotionControlType::torque;
// use monitoring with serial
SoftSerialUSB.begin(38400);
// comment out if not needed
motor.useMonitoring(SoftSerialUSB);
// initialize motor
SoftSerialUSB.println("about to init motor");
motor.init();
// align sensor and start FOC
motor.initFOC();
SoftSerialUSB.println(sensor.getAngle());
sensor.update();
SoftSerialUSB.println(F("Motor ready."));
SoftSerialUSB.println(F("Setting the target voltage"));
target_voltage = 4;
_delay(1000);
}
void loop() {
// main FOC algorithm function
// the faster you run this function the better
// Arduino UNO loop ~1kHz
// Bluepill loop ~10kHz
SoftSerialUSB.println(sensor.getAngle());
sensor.update();
motor.loopFOC();
// Motion control function
// velocity, position or voltage (defined in motor.controller)
// this function can be run at much lower frequency than loopFOC() function
// You can also use motor.move() and set the motor.target in the code
motor.move(target_voltage);
}
update: tried removing the softwareserial stuff, it does the same as before but with less humming noise.
Also tried switching to SinePWM mode instead just in case, doesnât work. It now locks in 2 separate positions instead of 1, and it is more floppy, can be rotated a few degrees close to the snapping positions and stay there.
Better be sure, otherwise itâs not surprising the driver doesnât workâŚ
I donât understand this? What do I2C and Serial have to do with each other? Are you trying to use them on the same pins?
Are you including the drivers library? I.e with a
#include <SimpleFOCDrivers.h>
Thereâs nothing wrong with the directory structure, I use it as is all the time.
This is possible, and would be a bug. Similar problems have been reported in the past, although as I said I use this sensor driver successfully myself⌠so perhaps itâs a MCU specific issue. Iâll look into it.
If the sensor is not working then closed loop cannot possibly work. Itâs not worth looking into anything else until the sensor problem is fixed.
Are you saying it now counts to 2PI?
By " issue with serial communication" I just mean there was some kind of issue with the I2C communication. Not the uart. Sorry for the mix up.
That appears to have been mostly solved by shortening the wires. However itâs not clear. As I mentioned, the pole pair test gives different results every time, so maybe there are errors sneaking in due to noise now or something. I donât know.
The As5600 sensor, the I2C sensor, counts up and keeps counting, without wrapping around.
The SPI sensor, which looking straight at it now, is yes an SC60228DC sensor (sorry the 6 looks a little like an 8 the silkscreen is a bit wonky, the chip says Semiment 60228 23453), wraps around. It counts one full revolution as 1pi, and then it wraps around. So borked on two counts.
I did include the SimpleFOCdrivers.h file, the problem arises when the SC60228 driver tries to include some file. The compiler says it cannot find the file. If I go hunt down the file in explorer, and change the location of the file in the header, it gets past that, but it throws the same error down the line when that file in turn has an include where the compiler cannot find the file. I donât know if all the files are borked or itâs just one thing that is propagating, I donât know enough about C programming unfortunately.
If I just look at the location where the files are expected to be according to the includes, and then copy the files to that location, it compiles fine. Are you using the master copy? Maybe the latest publication of the master copy got borked?
Is this on Windows? Can it be an issue with too long file paths? Itâs a common problem.
Indeed, Iâm almost always on the dev branch. I will test it out with the master.
yeah, windows. The path to the library is C:\Users\anthony\Documents\Arduino\libraries . Doesnât seem too long?
Youâd have to check what the compiler says - it builds the paths out of recombinations of relative paths which can get pretty long in some casesâŚ
In any case, I tried it out here and works without problems (master branch, release version) but then again Iâm not on windows, so not exactly your environment.
In further news Iâve created a board description in PlatformIO for the lepton, so far untested but at least everything compilesâŚ
Once I can test it out and everything works Iâll port it over to ArduinoIDE as well.
Deku, did you use windows? I think a lot of people are going to be using windows. I donât know what I can do to fix it.
Yes, but Iâm not using the dev branch or SimpleFOCDrivers.h
The first error in the chain is: `In file included from c:\Users\anthony\Documents\Arduino\libraries\SimpleFOCDrivers\src\encoders\aeat8800q24\MagneticSensorAEAT8800Q24.cpp:1:
c:\users\anthony\documents\arduino\libraries\simplefocdrivers\src\encoders\aeat8800q24\magneticsensoraeat8800q24.h:5:10: fatal error: common/base_classes/Sensor.h: No such file or directory
5 | #include âcommon/base_classes/Sensor.hâ
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
exit status 1
Compilation error: exit status 1`
I just want to reaffirm Iâm chips in for SimpleFOC. A situation just arose where I canât get more of the low cogging motors I was totally planning on. It highlights how important it is to have a good, flexible motor driver.
Having that encoder, and open source, modifiable code on the driver is very important. Otherwise I will get stuck being unable to match a motor with a driver. The texas instruments chip was unable to drive the gimbal motor, itâs built in algorithm was poorly written and got confused by the combination of characteristics of the motor. I did a conference call with a guy who was willing to help me from texas instruments (tech support, I bought their eval board). He couldnât get it working at all. Even the experts canât get it working, so itâs not me, itâs the chip.
There is a good chance the allegro chip is similar, these companies tend to assume the same things. Also it doesnât have any kind of anti cogging, and itâs clear that cogging is a primary source of noise at this point, and these are relatively good motors, so I need to be prepared to use crummier motors.