Programming the Lepton from start to finish

Make sure you have optimization set to “Smallest (-Os) with LTO”. That should give you around 10kb to work in.

How do I set the optimization in arduino?

It’s in the Tools menu.

1 Like

lol, I assumed I would have to modify some buried file, which is different in the latest arduino IDE and no one knows where it is…

Ok, with Deku’s advice it compiles and uploads, but it says

MOT: Monitor enabled!

MOT: Init

MOT: Enable driver.

MOT: Align sensor.

MOT: Failed to notice movement

MOT: Init FOC failed.

got this far

It doesn’t actually do any attempt to move the motor properly. I think it might be trying to move it extremely slowly as the current changes slowly and sometimes it moves by one pole. I will keep trying for a bit, I think there was one more sample of code that might have worked.

update:
ok one of the motor wire connectors was subtly borked, I only just managed to figure it out. However it still gives the same output.

the motor now moves, but only very very slowly in very small maybe 1/50th of a rotation jumps after it says align sensor. It takes several minutes to move a fraction of a rotation, and then back again. I don’t remember it being that slow with the arduino. It’s not clear if the encoder is working, but I think it’s reading the angle ok, I have to go to bed now but can check that directly tomorrow.

And so ends another 10 hour work day…

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 PlatformIO B-G431-ESC1 Code not working - #12 by Kacko
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 :frowning:

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 :slight_smile:

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.

2 Likes