Sensor not linking to Motor completely

TL;DR

I have linked a working sensor (writes to serial fine). The angle varible in the motor class is not updating even after linking, init, initFOC and motor.move in the loop. However, the velocity is updating…(see Motor Class section below).

System details:

IDE: Platform IO (MacOS)
MCU:STM32 F401CC
Board: We Act BlackPill
Motor: Portescap 16ECP36 Ultra EC + 30:1 planetary gear head (this is niche)
Encoder: 3 hall effects on motor, placed by manufacturer.

Deep Dive

I am using a hall effect encoder to control a motor.
(I know hall effects have limitations)

The encoder is working.

(I used the example)

I get output which looks like the following, this updates as I drive the motor by hand:

18.85   0.00
18.85   0.00
18.85   0.00
17.80   -29.73
17.80   -29.73
17.80   -29.73
17.80   -29.73

Commander

However, when I link the sensor to the motor and monitor the motor I dont get position updates!
motor.linkSensor(&sensor);

I am using the commander to monitor the motor.
However, when I call MMG6 (to get the angle) it always gives 0.

Telemetery

I have tried usin telemetery instead of the commander.

motor.useMonitoring(Serial);
motor.monitor_variables = _MON_TARGET | _MON_VEL | _MON_ANGLE; 
motor.monitor_downsample = 100; // default 10

and then in the loop:

motor.monitor();

I get the following:

0.0000  0.0000  0.0000
0.0000  0.0000  0.0000
0.0000  0.0000  0.0000
0.0000  0.0000  0.0000

Global variables

Finally I have used the raw motor variables to monitor what the motor thinks is happening:

Serial.println(motor.shaft_angle);// print current motor position to the serial terminal

This also reads zero.

Motor class

This appears to be linked to various motor methods not reading/updating appropriately.

When I add motor.move() for instance the velocity seems to update appropriately but still not the position.

In this case the velocity is correct for commander, telemetery and global vars

main.cpp:

This should demonstrate my issue
(this is Platform IO code, Arduino will need to remove the `#include <Arduino.h>)

The output should show the following:

  • The motor position increments continuously (steps of 0.01 rads) from 0 - 2pi before returning to 0:
Motor class angle (rads): 6.28, Sensor class angle (rads): -12.57
Motor class angle (rads): 0.00, Sensor class angle (rads): -12.57
  • The sensor position increments in large steps related to the wide (120 degree) hall sensor placement:
Motor class angle (rads): 0.39, Sensor class angle (rads): -12.57
Motor class angle (rads): 0.39, Sensor class angle (rads): -13.61
  • The senor position reacts to me backdriving the motor, the motor position does not.
#include <Arduino.h>
#include <SimpleFOC.h>

BLDCMotor motor = BLDCMotor(1, 4.05,  1200);
BLDCDriver3PWM driver = BLDCDriver3PWM(PA7, PA6, PA5, PA4);

HallSensor sensor = HallSensor(PA1, PA2, PA3, 1);

// Interrupt routine initialization (3 sensors = 3 callbacks)
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}

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

void setup() {
  Serial.begin(115200);

  SimpleFOCDebug::enable();

  // Hall sensor working!
  sensor.pullup = Pullup::USE_INTERN;
  sensor.init();
  sensor.enableInterrupts(doA, doB, doC);

  motor.linkSensor(&sensor);
  // Diver (20kHz PWM)
  driver.pwm_frequency = 20000;
  driver.voltage_power_supply = 24;
  driver.voltage_limit = 3;
  driver.init();

  // Link sensor and driver to motor
  motor.linkDriver(&driver);

  motor.voltage_sensor_align = 3;

  motor.foc_modulation = FOCModulationType::SinePWM;
  motor.controller = MotionControlType::velocity_openloop;
  motor.voltage_limit = 3;   // Volts
  // or current  - if phase resistance provided
  motor.current_limit = 0.5; // Amps
  
  //motor.useMonitoring(Serial);
  motor.monitor_variables = _MON_TARGET | _MON_VEL | _MON_ANGLE; 
  motor.monitor_downsample = 100; // default 10
  
  motor.voltage_sensor_align = 3;

  motor.init();
  motor.initFOC();

  motor.target = 1;

  // add target command T
  commander.add('M',onMotor,"target setting");

}

void loop() {

  motor.monitor();
  motor.loopFOC();
  motor.move();
  Serial.print("Motor class angle (rads): ");
  Serial.print(motor.shaft_angle); // Print current motor position to the serial terminal

  sensor.update();
  Serial.print(", Sensor class angle (rads): ");
  Serial.println(sensor.getAngle()); // Print current sensor position to the serial terminal


  commander.run();

}
1 Like

Can you post the minimum amount of code in a main.cpp file that you can reproduce this problem with?

1 Like

if you hop on source.simplefoc.com/ and browse around, you might find that the velocity is measured separately. So the info may branch out separately to the motor class and down a separate path that gives the velocity.

What happens if you hunt around, what’s your best guess for the first point at which the problem appears to arise? You can modify the code on your hard drive by putting Serial.print(); statements in various places to get information out and track down what’s not doing what it looks like it should be doing.

Also yeah as bdog said, post some code, simplified if you can although I have difficulty simplifying things before posting because I have to test it all over again to be sure it exhibits the same symptoms…you can post your exact code verbatim.

Thanks @bdog I have added this to the question.

Please not that this code is for an STM32 and PlatformIO so may need some minor modifcation to work on an arduino.

SOLVED: Open Loop Control blocks realtime position updates.

When using openloop velocity control the monitoring updates are all synthetic.
The sensor values are not used.

This makes sense for the motor. The motor thinks it is in certain positions and ignores the measured sensor position.

However this also true for the monitoring output and calls via the commander which both seem to get their information form the Motor class.

I cant update the main question for some reason, hence this is left in the replies.

1 Like

Hi @Harry_de_winton , welcome to SimpleFOC!

I am not sure yet where the problem lies, but the main loop can’t really work as you have it. Please change it more like this:

long ts;

void setup(){
...

ts = millis();
}


void loop() {

  motor.monitor();
  motor.loopFOC();
  motor.move();

  // sensor.update(); don't call sensor.update() if you're calling motor.loopFOC() - it gets called there
  long now = millis();
  if (now - ts > 1000) { // print only once in a while when printing from the main loop
    Serial.print("Ma: "); // don't print so much stuff when printing from the main loop
    Serial.print(motor.shaft_angle); // Print current motor position to the serial terminal
    Serial.print(", Sa: ");
    Serial.println(sensor.getAngle()); // Print current sensor position to the serial terminal
    ts = now;
  }

  commander.run();
}

what kind of output are you getting from the motor initialisation? Is the PP check successful?

And is your motor really a 1-PP motor? This could be a problem for our initialisation routines, not sure.

Hi @runger thanks for the help.

I have found my issue (and it was my issue), when running in open loop control none of the montioring uses the sensor data. I switched to closed loop and it works as i would like it.

1 Like