Baffling problem with torque mode, and pole pair checks

I’ve had basically the same set of baffling problems with 3 different hardware setups.

I’ve tried the lepton, a bluepill with a darlington output stage (with some buffers and using 5 volts as the motor input, just to try to work on the code), and the b-g431b-ESC1 board.

I’ve tried two different AS5600 encoders.

I recall that I was able to get very similar sketches working with the uno+shield. I used the same sensor. Same motor. The main difference appears to be the 6 pin pwm vs 3 pin.

What happens is that, first of all the pole pair checking is erratic. This seems to have been partly caused by slightly less than ideal pull up resistors in some cases, but I think that was just one of several things that was wrong. I have been able to stabilize the pole pair check results to within about 5 degrees sensor angle each time, however it’s never actually 7 poles. It thinks there are 10 poles with the pole pair check sketch, and bafflingly, a whole range from 4.5 to 9 poles when I try to run the full commander example sketch.

Example sketches are suitably adapted to my sensor and 6 pin pinout, and otherwise minimally changed.

My goal is to get it working in torque control mode so I can see how it sounds and how fast I can go with it, I need about 3000 rpm max, and it is unclear if that is possible with the lepton or even the ESC board. Obviously I would rather use the lepton as the ESC board actually is very expensive to make, ST sells them below cost as dev boards, so using them in a product is pretty sketch and I would rather minimize my engagement with motor driver design as it’s not something I can economically undertake.

When I tell it the motor is 8 poles manually, it will sometimes spin if I give it a boost with my hand. This is a fan actually not a bare motor. Otherwise it will sit there and oscillate. If I reduce the voltage it stops oscillating.

I have adjusted the gap between the magnet and sensor within a fair range and that seems unlikely to be a cause. Apparently these sensors are not that flexible, they are supposed to have a magnetic field exposure of between 30 and 70 mT, which is not that wide a range. I sort of figured if a compass can work these things should work no problem. Maybe not.

However nothing I can see in the hardware can explain the erratic results of the commander pole pair check.

I’m going to experiment with an AS5048B (I2C sensor) I bought from digikey tomorrow but am not optimistic it will lead to anything better.

Here is the commander example I used. I posted all the recent code I used with the ESC in the forum entitled "“b-G431B-ESC1…”
Angle sensor appears to work, open loop works. Should work, right?

/**
 * Comprehensive BLDC motor control example using magnetic sensor
 *
 * Using serial terminal user can send motor commands and configure the motor and FOC in real-time:
 * - configure PID controller constants
 * - change motion control loops
 * - monitor motor variabels
 * - set target values
 * - check all the configuration values
 *
 * See more info in docs.simplefoc.com/commander_interface
 */
#include <SimpleFOC.h>

// magnetic sensor instance - SPI
MagneticSensorI2C sensor = MagneticSensorI2C(0x36, 12, 0X0C, 4);
// magnetic sensor instance - MagneticSensorI2C
//MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
// magnetic sensor instance - analog output
// MagneticSensorAnalog sensor = MagneticSensorAnalog(A1, 14, 1020);


// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(7);
BLDCDriver6PWM driver = BLDCDriver6PWM(A_PHASE_UH, A_PHASE_UL, A_PHASE_VH, A_PHASE_VL, A_PHASE_WH, A_PHASE_WL);
// Stepper motor & driver instance
//StepperMotor motor = StepperMotor(50);
//StepperDriver4PWM driver = StepperDriver4PWM(9, 5, 10, 6,  8);

// commander interface
Commander command = Commander(Serial);
void onMotor(char* cmd){ command.motor(&motor, cmd); }

void setup() {

  // initialise magnetic sensor hardware
  sensor.init();
  // link the motor to the sensor
  motor.linkSensor(&sensor);

  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 12;
  driver.init();
  // link driver
  motor.linkDriver(&driver);

  // choose FOC modulation
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

  // set control loop type to be used
  motor.controller = MotionControlType::torque;

  // contoller configuration based on the control type
  motor.PID_velocity.P = 0.2f;
  motor.PID_velocity.I = 20;
  motor.PID_velocity.D = 0;
  // default voltage_power_supply
  motor.voltage_limit = 4;

  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.01f;

  // angle loop controller
  motor.P_angle.P = 20;
  // angle loop velocity limit
  motor.velocity_limit = 50;

  // use monitoring with serial for motor init
  // monitoring port
  Serial.begin(38400);
  // comment out if not needed
  motor.useMonitoring(Serial);

  // initialise motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();

  // set the inital target value
  motor.target = 2;

  // define the motor id
  command.add('A', onMotor, "motor");

  // Run user commands to configure and the motor (find the full command list in docs.simplefoc.com)
  Serial.println(F("Motor commands sketch | Initial motion control > torque/voltage : target 2V."));

  _delay(1000);
}


void loop() {
  // iterative setting FOC phase voltage
  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();

  // user communication
  command.run();
}

Have you ever tried running a different motor without any load? Can you tell us any more about the motor you are using? I assume it’s a 12N14P outrunner by the 7 pole pairs, but how big is it? What kv? Not that it should really matter, but I am curious.

What is the full printout of the pole pair example? Or at least the value of angle_end-angle_begin. Maybe try setting pp_search_angle=7*_2PI and visually confirm that the motor makes exactly one revolution.

Is it possible, that you use the wrong type of magnet? I read reports in this forum that some sensors were delivered with the wrong magnets.

Edit: I just saw in your post that the sensor seems to work, so the magnet is probably ok…

I can copy paste the pole pair printout.

The commander printout is like this, I started it several times and logged the output in putty:`MOT: Monitor enabled!
MOT: Init
MOT: Monitor enabled!
MOT: Init
MOT: Enable driver.
MOT: Align sensor.
MOT: sensor_direction==CW
MOT: PP check: fail - estimated pp: 4095.99
MOT: Zero elec. angle: 0.10
MOT: No current sense.
MOT: Ready.
Motor commands sketch | Initial motion control > torque/voltage : target 2V.
MOT: Monitor enabled!
MOT: Init
MOT: Enable driver.
MOT: Align sensor.
MOT: sensor_direction==CW
MOT: PP check: fail - estimated pp: 4.39
MOT: Zero elec. angle: 2.83
MOT: No current sense.
MOT: Ready.
Motor commands sketch | Initial motion control > torque/voltage : target 2V.
MOT: Monitor enabled!
MOT: Init
MOT: Enable driver.
MOT: Align sensor.
MOT: sensor_direction==CW
MOT: PP check: fail - estimated pp: 4.18
MOT: Zero elec. angle: 1.51
MOT: No current sense.
MOT: Ready.
Motor commands sketch | Initial motion control > torque/voltage : target 2V.
MOT: Monitor enabled!
MOT: Init
MOT: Enable driver.
MOT: Align sensor.
MOT: Failed to notice movement
MOT: Init FOC failed.
Motor commands sketch | Initial motion control > torque/voltage : target 2V.
MOT: Monitor enabled!
MOT: Init
MOT: Enable driver.
MOT: Align sensor.
MOT: sensor_direction==CCW
MOT: PP check: fail - estimated pp: 4.69
MOT: Zero elec. angle: 4.53
MOT: No current sense.
MOT: Ready.
Motor commands sketch | Initial motion control > torque/voltage : target 2V.
MOT: Monitor enabled!
MOT: Init
MOT: Enable driver.
MOT: Align sensor.
MOT: sensor_direction==CCW
MOT: PP check: fail - estimated pp: 8.59
MOT: Zero elec. angle: 3.76
MOT: No current sense.
MOT: Ready.
Motor commands sketch | Initial motion control > torque/voltage : target 2V.

`

The KV rating of the motor is about 200KV. Resistances of the phases is 5 ohms each, I have several very similar motors and may have messed up and said it was 12 ohm at some point.

Typical small gimbal motor. 32 mm in diameter, an outrunner. Hollow shaft. It’s very similar to the flycat 2805.

I’ll do those checks. But given the erratic nature of things, the problem seems likely to be something else.

Huh, that definitely looks like the sensor isn’t working right yet…

What was the source of the magnet? Are you sure it’s good? Axial magnets (the wrong kind) often sort of work when turning the motor by hand, but fail once the motor is powered and moving by itself…

Noise on sensor lines could be another problem.

Or a correct magnet, but too weak or mounted too far/too close to the sensor…

Oh, I had it in my mind that you were running the find_pole_pairs_number.ino example… That pole pair check is in BLDCMotor::alignSensor and doesn’t look quite so straightforward to change it to make a full rotation for my previous suggestion of visually verifying. But if the motor works open loop, then we can pretty safely assume that it is moving properly, and the sensor is what’s giving bad readings.

I suppose you could add a couple more debug prints to show mid_angle and end_angle, to get a better idea in what way the readings are wrong.

Also make sure the magnet is held firmly in place. A while back a guy was getting bad sensor readings and it turned out his magnet mount was a tiny bit loose. But in his case the readings were very consistent despite being wrong, which is not what you’d normally expect from a loose magnet so it took us all a great deal of head banging before Runger finally suggested it :slight_smile:

Guess, who that was :wink:.

1 Like

Ok, I made some progress! It is starting to work in torque mode, voltage, now. It still accelerates slightly once per revolution, which I have to solve as it causes noise. That may be due to misalignment with the sensor. I remember reading something about sensor calibration, maybe that can help me.

There were two problems. One was that the magnet was either too strong or too close, apparently, or the magnetic field was not uniform or something.

After I replaced the magnet with a different, one, a small 4 mm diametrically magnetized circular magnet, and made sure it was about 1 mm away from the sensor, measuring everything with calipers, it would start to spin when I ran the above commander/torque mode program, then it would make grinding noises and stop spinning.

I added the 4.7kOhm (which my multimeter says are more like 3.7) pullup resistors to the I2C line and that seems to have solved that problem, however. There are internal pull up resistors on the B-G431 board so it wasn’t clear if they were needed, however apparently they are at least while the motor is running.

The next step is to try to achieve the speed necessary, and try to get rid of that non-smoothness in the rotation.

Here is the exact code I used:

/**
 * Comprehensive BLDC motor control example using magnetic sensor
 *
 * Using serial terminal user can send motor commands and configure the motor and FOC in real-time:
 * - configure PID controller constants
 * - change motion control loops
 * - monitor motor variabels
 * - set target values
 * - check all the configuration values
 *
 * See more info in docs.simplefoc.com/commander_interface
 */

 float oldangle = 0;
 long int oldtime = 0;
#include <SimpleFOC.h>

// magnetic sensor instance - SPI
MagneticSensorI2C sensor = MagneticSensorI2C(0x36, 12, 0X0C, 4);
// magnetic sensor instance - MagneticSensorI2C
//MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
// magnetic sensor instance - analog output
// MagneticSensorAnalog sensor = MagneticSensorAnalog(A1, 14, 1020);


// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(7);
BLDCDriver6PWM driver = BLDCDriver6PWM(A_PHASE_UH, A_PHASE_UL, A_PHASE_VH, A_PHASE_VL, A_PHASE_WH, A_PHASE_WL);
// Stepper motor & driver instance
//StepperMotor motor = StepperMotor(50);
//StepperDriver4PWM driver = StepperDriver4PWM(9, 5, 10, 6,  8);

// commander interface
Commander command = Commander(Serial);
void onMotor(char* cmd){ command.motor(&motor, cmd); }

void setup() {

  // initialise magnetic sensor hardware
  sensor.init();
  // link the motor to the sensor
  motor.linkSensor(&sensor);

  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 24;
  driver.init();
  // link driver
  motor.linkDriver(&driver);

  // choose FOC modulation
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

  // set control loop type to be used
  motor.controller = MotionControlType::torque;

  // contoller configuration based on the control type
  motor.PID_velocity.P = 0.2f;
  motor.PID_velocity.I = 20;
  motor.PID_velocity.D = 0;
  // default voltage_power_supply
  motor.voltage_limit = 24;

  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.01f;

  // angle loop controller
  motor.P_angle.P = 20;
  // angle loop velocity limit
  motor.velocity_limit = 50;

  // use monitoring with serial for motor init
  // monitoring port
  Serial.begin(38400);
  // comment out if not needed
  motor.useMonitoring(Serial);

  // initialise motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();

  // set the inital target value
  motor.target = 2;

  // define the motor id
  command.add('A', onMotor, "motor");

  // Run user commands to configure and the motor (find the full command list in docs.simplefoc.com)
  Serial.println(F("Motor commands sketch | Initial motion control > torque/voltage : target 2V."));

  _delay(1000);
}


void loop() {
  // iterative setting FOC phase voltage
  for (int j = 0; j <5; j++){
  for (int i = 0; i<1000; 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();
  }
  // user communication
  command.run();
  sensor.update();
  //Serial.println(sensor.getAngle());
  Serial.println("rads per second:");
  Serial.println((sensor.getAngle()-oldangle)/((millis()-oldtime)/1000));
  oldangle = sensor.getAngle();
  oldtime = millis();
}

I timed it, and it is running the main loop at one cycle every 6 seconds, which means about 3.3 kHz for the motor.loopFOC() command.

Edit:
Ok it maxes out at about 100 rad/s, at about 6.5 volts to the motor… I need about 270 rad/s. I’ll keep working on it. Deku’s interpolator might help.

I also noticed that it is consuming way too much current, more than two or three times as much as it should at the RPM of concerned, for the motor alone (that is, subtracting the current from the). I can’t have that, it means low efficiency and that will lead to overheating. It may improve some when I get the sensor aligned, but I don’t think it will improve that much.

Calling move() only once per 1000 calls to loopFOC() is probably a bit low. You don’t need to do this in the loop manually actually, you can just set the field motor.motion_downsample = 1000; - but as mentioned this won’t be frequent enough, I don’t think.

Maybe something like this is better, code along these lines should print the angle and the iterations per second, once per second, and run with a move() downsample of 4 calls to loopFOC() for every call to move():


long ts;
int its = 0;

void setup(){
  ... // your other code
  motor.motion_downsample = 4;
  ts = millis();
}

void loop() {
  motor.loopFOC();
  motor.move();
  command.run();
  its++;
  long now = millis();
  if (now - ts >= 1000) {
    Serial.print("A: ");
    Serial.println(sensor.getAngle());
    Serial.print("I/s: ");
    Serial.println(its);
    its = 0;
    ts = now;
  }
}
1 Like

ok cool, will try it :slight_smile: I just tried to use open loop to see if I could carefully increase the speed as that would allow me to eliminate sensor misalignment issues etc. But it pegged the current to 1 Amp and I had to shut off the power supply. will keep trying… The motor is already hot even though the whole system was only drawing 200 mA, indicating very poor efficiency :(.

edit: with the code modified to below the loop frequency actually goes down to 2 kHz, and it wobbles and makes a lot of noise sporadically.

/**
 * Comprehensive BLDC motor control example using magnetic sensor
 *
 * Using serial terminal user can send motor commands and configure the motor and FOC in real-time:
 * - configure PID controller constants
 * - change motion control loops
 * - monitor motor variabels
 * - set target values
 * - check all the configuration values
 *
 * See more info in docs.simplefoc.com/commander_interface
 */

 float oldangle = 0;
 long int oldtime = 0;
 long ts;
int its = 0;
#include <SimpleFOC.h>

// magnetic sensor instance - SPI
MagneticSensorI2C sensor = MagneticSensorI2C(0x36, 12, 0X0C, 4);
// magnetic sensor instance - MagneticSensorI2C
//MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
// magnetic sensor instance - analog output
// MagneticSensorAnalog sensor = MagneticSensorAnalog(A1, 14, 1020);


// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(7);
BLDCDriver6PWM driver = BLDCDriver6PWM(A_PHASE_UH, A_PHASE_UL, A_PHASE_VH, A_PHASE_VL, A_PHASE_WH, A_PHASE_WL);
// Stepper motor & driver instance
//StepperMotor motor = StepperMotor(50);
//StepperDriver4PWM driver = StepperDriver4PWM(9, 5, 10, 6,  8);

// commander interface
Commander command = Commander(Serial);
void onMotor(char* cmd){ command.motor(&motor, cmd); }

void setup() {

  // initialise magnetic sensor hardware
  sensor.init();
  // link the motor to the sensor
  motor.linkSensor(&sensor);

  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 24;
  driver.init();
  // link driver
  motor.linkDriver(&driver);

  // choose FOC modulation
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

  // set control loop type to be used
  motor.controller = MotionControlType::torque;

  // contoller configuration based on the control type
  motor.PID_velocity.P = 0.2f;
  motor.PID_velocity.I = 20;
  motor.PID_velocity.D = 0;
  // default voltage_power_supply
  motor.voltage_limit = 24;

  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.01f;

  // angle loop controller
  motor.P_angle.P = 20;
  // angle loop velocity limit
  motor.velocity_limit = 50;

  // use monitoring with serial for motor init
  // monitoring port
  Serial.begin(38400);
  // comment out if not needed
  motor.useMonitoring(Serial);

  // initialise motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();

  // set the inital target value
  motor.target = 2;

  // define the motor id
  command.add('A', onMotor, "motor");

  // Run user commands to configure and the motor (find the full command list in docs.simplefoc.com)
  Serial.println(F("Motor commands sketch | Initial motion control > torque/voltage : target 2V."));
motor.motion_downsample = 4;
ts = millis();
  _delay(1000);
}


void loop() {
  // iterative setting FOC phase voltage
 motor.loopFOC();
  motor.move();
  command.run();
  its++;
  long now = millis();
  if (now - ts >= 1000) {
    Serial.print("Angle: ");
    Serial.println(sensor.getAngle());
    Serial.print("iterations of the main loop/s: ");
    Serial.println(its);
    its = 0;
    ts = now;
    Serial.println("rads per second:");
     Serial.println((sensor.getAngle()-oldangle));
     oldangle = sensor.getAngle();
  }



}

Edit: great, something broke, now it runs for a few seconds and starts making more and more noise, then comes to a halt and keeps grinding. I tried cutting and pasting the code I previously posted to restore things. Doesn’t work.

Similar situation to before I added the pullups, but longer time before it grinds and stops working, also the radians per second displayed is right, so data is still coming in from the sensor.

Edit: ok I moved the wires around just a little, to get the motor wires away from the I2C wires, and it works for longer but still craps out eventually. Must be cumulative errors or something.

Ok, now it comes and goes. Might be because I am moving the wires, or it might be some kind of oscillation in the torque pid loop?

There is no PID in torque mode without current sense.

The heating should improve when you tune the voltage-based torque limiting (which still doesn’t have a PID controller, btw). But first you need to get it running reliably without that.

how do I tune the voltage based torque limiting?

If I leave it for 20 minutes, the fan will run for longer, about 2 minutes, before it starts making the noises, more and more frequently until it escalates into grinding noise and the motion halting… Then if I power cycle I only get 10 seconds or less of motion before the noise starts and things deteriorate again. Maybe something to do with heating of the sensor or something… it was only drawing 120 mA for the whole system though, can’t do much heating with that.

Set the phase resistance to the datasheet value or whatever you measure with a multimeter, and then fiddle the kv value up and down until it acts right.

Without resistance/kv, the target value is in volts. With them, the target value is in amps. With an un-loaded motor, it should take a fairly small current to get it started and then it will accelerate up to full speed for the voltage limit you have set. Then setting target to 0 should stop spinning. If kv is too low or too high, it will either not accelerate to full speed, or will not be able to stop. Usually kv has to be a fair bit higher than the datasheet value.

2 Likes

I actually measured the back emf, other motor controllers ask you for the bemf in voltsRMS/hz or voltspeaktopeak/hz of driving frequency, so I can determine the exact KV values. It is actually really easy to measure and a handy trick, you use an oscilloscope on single shot mode and just measure the voltage and period of the waveform from two leads of the motor as you spin it by hand :slight_smile:

Why does simplefoc continue rotating the magnetic field when the sensor clearly indicates nothing is moving???

It seems to be a problem with the code base, except that it changes with each reboot, as I said appears to get worse after things have run for a while. Makes me think maybe the sensor is giving erratic values due to getting slightly warm or something, but the sensor readings that are printed out do not indicate any erratic readings.

Velocity open loop mode doesn’t work in the commander, it goes in large jerks instead of continous motion.

SimpleFOC has no control logic to decide situations like this. Is the motor stalled, or is the sensor misbehaving? Will the motor turn, but the power just isn’t enough, or is it permanently blocked? SimpleFOC can’t know.

It follows what it is told: set a 5V voltage in torque-voltage mode, or try to turn at 20rad/s in velocity mode, etc… any higher-level logic to decide things like stall vs. sensor error is up to higher level application code, and currently not in scope for the library. So the application should decide what is required for the given situation, and then command the library to stop the motor, if appropriate.

That’s strange. Is there a lot of serial logging going on?

no, no serial logging at all was going on.

I solved the most recent main problem, the problem was that you have to ground the direction pin of the AS5600. This is exactly why we have to have exact, complete systems or examples with all the details. One tiny detail like that can make for a whole day of extra work, or make someone conclude the code base is crap and give up.

To be fair, it could have given some kind of useful error message when it noticed the angle sensor was not reading properly. Also if there had not been so many other problems previously, I would not have suspected the I2C communication or the magnet positioning yet again to be the problem.

Anyway I’m grateful that it’s solved, now I have to get on with solving the once per rotation wobble and the efficiency issue, hopefully tuning as Deku says will be enough, and I won’t need current mode. The B-g431… has current sensing but I want to be able to switch to the lepton after I have the other stuff figured out, and also who wants to bet there won’t be another two days of baffling problems getting current sense and the other torque mode working with this exact hardware…

My bafflement with the magnetic field continuing to rotate despite the angle sensor indicating a fixed position is because I would have thought that the magnetic field is supposed to be a certain angle to the magnets. That is, it’s not open loop. If the angle of the rotor has no effect on the rate of rotation or angle of the magnetic field, how does it commutate??? Is that not the essence of commutation? Clearly I need to read more on how simpleFOC works, I have read through the documentation but it appears that as usual there are many details the people need to know when they really go to do things that are not in the documentation, although again what has been done is good and everyone always does that with documentation, I do believe that documentation does not have to be either too detailed or insufficiently detailed, instead I would produce two different sets.

One quick start guide, and then another datasheet style doc. Unfortunately even datasheets these days often omit important details. It’s a style thing I think, people look at the docs and think they aren’t “nice” when they include all the details you really need. People who already know the system don’t notice the details are missing. People who don’t know and aren’t actually building something judge the documentation prematurely. This is why it is critical imo to pay attention to what happens when people come along and start actually using the system, to identify missing stuff.

Edit: I tried to tune the motor with the known-good figures for phase resistance and KV rating with this line, replacing the old motor object

BLDCMotor motor = BLDCMotor(7,4.58,106);

It’s set to 2 volts on startup. It immediately starts drawing 1.26 amps, the power supply fortunately automatically reduces the voltage to prevent something from exploding. Pretty sure if I didn’t have a CCCV power supply something would have blown up.

It occurs to me that the resistance might be expecting a terminal-to terminal resistance, not a phase resistance, which is half the terminal value. However that would not account for the sudden excessive current.

Nothing can be easy… I have no idea and have to go to bed, is anyone able to shed light on this perhaps? I read the documents that I could find. This should work…

complete code was:

 * Comprehensive BLDC motor control example using magnetic sensor
 *
 * Using serial terminal user can send motor commands and configure the motor and FOC in real-time:
 * - configure PID controller constants
 * - change motion control loops
 * - monitor motor variabels
 * - set target values
 * - check all the configuration values
 *
 * See more info in docs.simplefoc.com/commander_interface
 */

// float oldangle = 0;
// long int oldtime = 0;
#include <SimpleFOC.h>

// magnetic sensor instance - SPI

MagneticSensorI2C sensor = MagneticSensorI2C(0x36, 12, 0X0C, 4);

// magnetic sensor instance - MagneticSensorI2C
//MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
// magnetic sensor instance - analog output
// MagneticSensorAnalog sensor = MagneticSensorAnalog(A1, 14, 1020);


// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(7,4.58,106);
BLDCDriver6PWM driver = BLDCDriver6PWM(A_PHASE_UH, A_PHASE_UL, A_PHASE_VH, A_PHASE_VL, A_PHASE_WH, A_PHASE_WL);
// Stepper motor & driver instance
//StepperMotor motor = StepperMotor(50);
//StepperDriver4PWM driver = StepperDriver4PWM(9, 5, 10, 6,  8);

// commander interface
Commander command = Commander(Serial);
void onMotor(char* cmd){ command.motor(&motor, cmd); }

void setup() { 
  // initialise magnetic sensor hardware
  
  sensor.init();
  
  // link the motor to the sensor
  motor.linkSensor(&sensor);

  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 24;
  driver.init();
  // link driver
  motor.linkDriver(&driver);

  // choose FOC modulation
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

  // set control loop type to be used
  motor.controller = MotionControlType::torque;

  // contoller configuration based on the control type
  motor.PID_velocity.P = 0.2f;
  motor.PID_velocity.I = 20;
  motor.PID_velocity.D = 0;
  // default voltage_power_supply
  motor.voltage_limit = 24;

  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.01f;

  // angle loop controller
  motor.P_angle.P = 20;
  // angle loop velocity limit
  motor.velocity_limit = 50;

  // use monitoring with serial for motor init
  // monitoring port
  Serial.begin(38400);
  // comment out if not needed
  motor.useMonitoring(Serial);

  // initialise motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();

  // set the inital target value
  motor.target = 2;

  // define the motor id
  command.add('A', onMotor, "motor");

  // Run user commands to configure and the motor (find the full command list in docs.simplefoc.com)
  Serial.println(F("Motor commands sketch | Initial motion control > torque/voltage : target 2V."));

  _delay(1000);
}


void loop() {
  // iterative setting FOC phase voltage
  for (int j = 0; j <5; j++){
  for (int i = 0; i<1000; 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();
  }
  // user communication
  command.run();
// sensor.getAngle();
  //Serial.println(sensor.getAngle());
 // Serial.println("rads per second:");
 // Serial.println((sensor.getAngle()-oldangle)/((millis()-oldtime)/1000));
  //oldangle = sensor.getAngle();
 // oldtime = millis();
}

Now that I think about it, I think maybe that KV rating is wrong, it may be more like 140. It can’t be quite that because they go like 3200 no load at 24 volts…but that’s what the motor profiler from ST electronics said… hm.

How did you end up with the direction pin floating? From what I can see, all the breakout boards have it pulled one way or the other, and the datasheet says connect it to VDD or GND. I think adding special code to try and detect such a rare problem would be more hurt than help…

As for the current overload, like I said before, when you set the resistance and kv parameters the target is in amps, not volts. So with that code it should draw 2 amps when tuned properly. And yes, the resistance is between terminals, not a single un-terminated phase.

Thinking more about it, this may actually not reduce heating during continuous running in velocity mode… only provide overload protection during acceleration and in case of hitting an obstruction. I’m just used to working in angle mode where it does make a big difference since it’s having to accelerate and decelerate all the time.

EDIT: Also, you need to set motor.current_limit. In velocity mode the PID will be controlling the current and needs to know what its safe range is.

This breakout board just has the pin floating :(. I thought it was an output pin, not an input pin. I realized what was going on only when I noticed the problem arose when my finger got near the pin, then disappeared when my finger got further away, lol. Perhaps things should be divided into the “core” code, and then a small wrapper that is used for configuration purposes would be advisable. But that is more stuff to do. The best thing is a flagship combo of hardware and software that is known to work, that collapses the uncertainty and sheer quantity of complications that must be waded through.

I noticed other motor controllers almost always mean the phase resistance as half of the terminal to terminal resistance. That is, one actual phase’s resistance. Current flows through two phases at once. That should be clarified and/or brought into alignment with the standard approaches at some point, I can do that sort of thing some day after my own fires are put out.

If it doesn’t improve efficiency, I have a serious problem. The fan (so loaded motor) was drawing 70 mA only using the texas instruments driver at 1070 RPM, according to my spreadsheet of test data. That’s the actual fan, so total minus standby current of the driver. Here, it’s drawing >400 mA at 106 rad/s, which s about the same rpm. That indicates extremely poor energy efficiency, and excessive heating will result.

I can try current regulation mode, that might help a little… But there has got to be some way to do a little better. I asked Valentine how the efficiency was and he said it was good.

Dang, you’ve had the worst luck with this project. Motor control is extremely difficult as far as programming tasks go, but with SimpleFOC as a starting point it should only be moderately difficult :slight_smile:

With resistance of one phase alone, you’d also have to specify the termination style… I wonder what calculation those other controllers use it for. If they have current measurement hardware, then they don’t need the terminal-to-terminal resistance to calculate the approximate current like we do.

As for efficiency, the real question is not how to improve it, but why you’re getting poor efficiency right now. The only way to get high current at low RPM without a heavy load on the motor is to have the magnetic field direction wrong so it’s just squeezing radially on the rotor rather than pulling tangentially to produce useful torque. All loopFOC does is call sensor->update and setPhaseVoltage. That puts the stator field 90 electrical degrees ahead of the rotor field, so all magnetic force produces useful torque (this is called q-axis, whereas d-axis is the useless radial component of the magnetic force). There should be very little time lag due to inductance at 1000RPM on a little motor like this, and even a slow I2C sensor shouldn’t introduce a problematic amount of time lag either.

Hm. I’ll keep thinking and trying. I respect that this stuff is not easy, but that’s exactly why I think that the logical approach is to make a small number of quality designs ready to go instead of leaving everyone to mix up their own at the last minute…

After adjusting things again, at a target of 0.3 it pulls 470 mA and turns at 730 RPM. Even worse than before…

I think the resistance is actually probably the resistance of a single phase. When I set it to 9, which is the sum of two phases, and set the current to 0.2, it draws 680 mA.

It is fairly smooth open loop, which is the only thing that gives me hope at this point. And it can do open loop at the needed RPM. I just need it to watch the position sensor and make sure the electrical angle stays close enough to 90 degrees, then control the voltage/current to the minimum needed to prevent loss of “steps” as it were, as though it were a stepper motor. If I learn enough about the code base and get in there I might be able to get something working… I think I am likely to need the interpolator, that is the logical approach with a continously moving motor at significant speed, there is no need to depend on the sensor to update at a high rate.

edit: my latest shiny new desperate bid to use SimpleFOC is to try to get open loop working, and write code to check the sensor angle and electrical angle maybe ten times per second or something, and have some simple PID-like code to regulate the angle to 90 degrees by changing the speed of the open loop commutation. Then, I make the voltage of the open loop go up as the RPM goes up, to some limit which is configurable by the user.

So probably recreating the same thing the other code is supposed to be doing, but with a lower update rate, in a way that is only safe when you are assuming continuous rotation with little momentary variation or acceleration.

I don’t need the system to check the sensor like a thousand times a second, and I think it is causing noise in torque mode and limiting the rpm.

Basically, the smoothness of the waveform is sacrosanct, if the electrical vs. mechanical angle is off by a bit it uses a bit more current than it needs to but that’s not a big deal. Noise is.

Is this a really terrible idea? I’ll have to tune the pid controll stuff which I’m not looking forward to.