Velocity measurement problem, magnetic sensor

@blackblue007 has pointed out that while using the as5048 magnetic sensor using SPI the velocity measurement is very unstable.
I have not had an experience like this so far with the as5047 so I am not exactly sure why it happens. And I am definitely interested to investigate and solve this issue!

@blackblue007 could you please explain a bit better how it happens and in which conditions.
Is your motor velocity unstable?
Can the control loop maintain the velocity?
How fast are you outputting the value?
Are you using the motor commands or monitoring function?
What is the precision of your sensor (12,13,14 bit?)

Thanks,
Antun

I haven’t made a video of the test at present, so let me describe the test process first.
1,The visual observation of motor speed is stable, but the measured value of speed is not stable, but note that the measured value of sensor angle is stable.
2,I looked at two documents MagneticSensor.cpp and BLDCMotor.cpp I have excerpted the parts related to speed measurement.

  float BLDCMotor::shaftVelocity() {
  float Ts = (_micros() - LPF_velocity.timestamp) * 1e-6;
  // quick fix for strange cases (micros overflow)
  if(Ts <= 0 || Ts > 0.5) Ts = 1e-3; 
  // calculate the filtering 
  float alpha = LPF_velocity.Tf/(LPF_velocity.Tf + Ts);       
  float vel = alpha*LPF_velocity.prev + (1-alpha)*sensor->getVelocity();
  // save the variables
  LPF_velocity.prev = vel;
  LPF_velocity.timestamp = _micros();
  return vel;
}

motor.shaftVelocity() -->It’s just “LPF.”_ velocity.Tf ”And the “ts” value makes a low-pass filter, but the object of this filter is “* Sensor - > getvelocity()”!
Then we’ll see“ sensor.getVelocity (), excerpt as follows:

float MagneticSensor::getVelocity(){
  // calculate sample time
  float Ts = (_micros() - velocity_calc_timestamp)*1e-6;
  // quick fix for strange cases (micros overflow)
  if(Ts <= 0 || Ts > 0.5) Ts = 1e-3; 

  // current angle
  float angle_c = getAngle();
  // velocity calculation
  float vel = (angle_c - angle_prev)/Ts;
  
  // save variables for future pass
  angle_prev = angle_c;
  velocity_calc_timestamp = _micros();
  return vel;
}

Obviously, another calculation of “ts” value is carried out here. Do I think the second calculation of TS value is redundant?
Should it be quoted directly“ sensor.getVelocity () as motor.shaftVelocity () value?

Then I gave up“ motor.shaftVelocity (), change to direct use“ sensor.getVelocity ()”,
Result: the motor speed measurement is still unstable!!!
So I believe that in function“ sensor.getVelocity" Reference in“ sensor.getAngle () "is there something wrong?
Is the overflow processing part of “getangle()” incomplete?

My idea is as follows:

void getVelocity(){
static int data_sensor_0,  real_sensor_data,  d_sensor_data_0;
static float dt; 

dt=(_micros()-dt)*1e-6;

int data_sensor = Sensor.read();
float d_sensor_data =data_sensor - d_sensor_data_0;

int data_overflow=16384;
int data_max = 0.80*data_overflow

if (fabs(d_sensor_data) >data_max){
     if(data_sensor > data_sensor_0){								
	d_sensor_data = -(data_overflow -data_sensor+data_sensor_0);  
	}else if(data_sensor < data_sensor_0){                      
		d_sensor_data = data_overflow -data_sensor_0 +data_sensor;
	}
     }

//low pass filter
d_sensor_data = (dt / (dt + LPF_velocity.Tf))*(d_sensor_data) + (1 - (dt / (dt +LPF_velocity.Tf)))*d_sensor_data_0;

d_sensor_data_0 = d_sensor_data;
data_sensor_0 = data_sensor;
real_sensor_data +=d_sensor_data;

float motor.velocity = d_sensor_data / dt;
float motor.position = real_sensor_data;

dt = _micros();
}

----I haven’t had time to test this part of the code, so I have no results for the time being!

This is definitely a problem I agree. But this is not a questions of stability but the question of how I implemented the monitoring functionality.

The idea of calling the functions for calculating the angle and the velocity is to be called the minimum number of times and to be the fastest possible.

This is how it works st the moment.
The motor asked the sensor to calculate the velocity buy calling sensor.getVelocity() then it filters it in the function motor.shaftAngle() and stores it to the public variable motor.shaft_velocity the same is done for the angle motor.shaft_angle.

These two variables are ment to be used for external use(outside BLDCMotor class), and the functions motor.shartAngle() and motor.shaftVelocity() are meant to be run only once per loop cycle.
motor.shartAngle() is run in motor.loopFOC() and
motor.shaftVelocity() is run in motor.move().

This is not an overflow problem, the overflow is handled in the MagneticSensor class directly.
The reason why the velocity measurement is more noisy when you call the shaftVelocity() is because it is called in motor.move() first where it calculates a good velocity but then if you call it in the loop once more afterwards, you will just not have big enough difference in angle or difference in time to get a nice value.

velocity = (difference in angle)/(difference in time)

I should probably make the functions motor.shartAngle() and motor.shaftVelocity() private and implement better the getter functions to avoid these problems. Thanks for the heads up @blackblue007.

So in conclusion, when accessing the motor state variables from outside the BLDCmotor class please use the variables:

motor.shaft_angle
motor.shaft_velocity

For the full list of the motor variables and the monitoring examples please visit the https://docs.simplefoc.com/monitoring.

Thank you for your prompt. After using motor.shaft_velocity, it is normal

I do not really know whether my question/observation is right in this topic, but it seams the most fitting place here because I use an as AS5048 that was mentioned as probably unstable. MCU is a NucleoF103RB. Driver is 8302.

I did some experiments with the velocity control loop and recognized a very exciting misbehavior of the library.
Example: When I set the velocity to 100 rpm and let it run for a couple of micros, seconds or even minutes I recognize that the real speed of the loop is 100/1,23=81,3 rpm. First I thought that is is an error in measuring angle and time, but I repeated the measurement with an speedometer and also with an stop watch. Always 1.23

We all are using synchronous motors. So what the hell makes this error?
Any idea?

I have no idea :smiley:
I never noticed this before. I’ll look into it. It might be a timing problem.

So you want to say that the library measures 100 but it is actually 81.3rpm.
Is it the radian / RPM conversion problem maybe?

If you have some time it would be super helpful if you could try few different velocities and see if it is the same. Also if you can test it with Arudino devices that would be great.

I am going to dig into it as soon as I have a bit more time. :smiley:

The tests with different velocities are still done. Absolute linear error of 1.23. Lowest velocity was 1 rad/sec. Than I tried 10 speeds more. Highest was 220 rad/sec. Always the same.
See measurement data and chart below.

image

Also the calculation without conversion I tried. 1 rad/sec input leads to an output of 0.81 (=1/1.23).

The usual suspect would be the time constant _micros. But not really. Input, timing and measuring was done by it. As far as I understood the code. I’m not the best programmer, but this is not to difficult.

Also the measurement by hand leads to the same result.
First I marked 0 on a lever at the motor shaft. Than I set speed to 2 rpm and measured the time for 1 rev. Result 37sec. (=1.23 x 30).

Also a manual Tachometer gives me the same.

I will try an Arduino Uno, but that may last a week. Going to holiday :grinning:

@Juxo - did you get to the bottom of your speed discrepancy?
Here are a couple of potential causes:

  • pole pairs wrong. This might cause incorrect speed if you were using an encoder but I don’t think it would cause problems on magnetic sensors
  • zero integral term. If you’ve set a zero integral term on your PID then the actual speed will either lag your desired speed or will be unstable (osciallate above and below desired speed) depending on how much proportinal term you’ve set.

@Owen_Williams
Thanks for thinking about my problem. I was on holiday for a week :sunglasses:. So, no progress till now.
I have not opened the motor but the regular number of pole-pairs is 2 related to the datasheet. I run the motor down to 0.05 rad/min with smooth movement, what would not be possible if the pp - count would be wrong. Would you agree?

// contoller configuration based on the controll type
motor.PI_velocity.P =0.1;
motor.PI_velocity.I = 10;

That is my PI configuration.
Missing I-term would cause unstable speed because of overshoot. But in my case I have very smooth and stable movement - but with the wrong speed :smirk:
Nevertheless I will try different I-P-combinations. Could be that the ratio of I and P is to high.

I’m going to play with different pp without the hope to fix it. Also I will implement different sensors this week. Will see. I will publish the results.

Hey @Juxo,
I dont think the pp is the cause of this behavior. Because if you set the pp wrong your position measurement will be wrong and your foc wont work at all.

So for me this is a timing problem. @Owen_Williams already pointed out in one of our conversations that the there could be slight error of time measurement due to the time stamping choice I made. Since then I’ve updated the code for each sensor so please check if the new version of the library 1.5.0 has the same problem. :smiley:
The problem Owen noticed would produce the velocity to be measured higher than it really is (exactly what you see in your case). And faster control loops would see higher influence. Basically Arduino UNO may not have this problem and Nucleo would. I did not think the influence would be as high as 1.23 but the reality is really surprising sometimes :smiley:

@Antun_Skuric,
full hit. The problem is disappeared with the new library version.
Thank you for that and the whole library.