Works perfectly for 2 minutes then spins randomly

I’m using the SimpleFoc mini with Arduino Uno and AS5048A (SPI) magnetic sensor. And, it’s working perfectly open loop (velcoity) separately and together (both motor control and sensor readings). But, in closed loop (velocity) it only works perfectly for about 2 minutes. Then it spins randomly. This happens every single time. What am I doing wrong ???

Some people on the forum have had issues like this related to thermal problems with their fixtures. How are you holding the encoder to the motor? Is it a 3d printed jig, etc? If the magnet or the encoder can somehow delaminate or shift from becoming warm, it can cause problems like this.
You could also have some error in your code that is accumulating over the period and causes an overflow.

Do you also get this behaviour if you put it in closed loop angle mode and let that sit for a few minutes?

Thanks VIPQualityPost,

Using the GM5208-120T Gimbal Motor w/Encoder. I have it just stuck to my desk with double sided tape. Doesn’t feel hot at all. Works great in the Closed Loop Angle mode example code. Snaps right to position. But, after 2 minutes and 19 seconds,it shakes into position. Works perfect again on reset every time but only for 2 minutes and 19 seconds each time.

Feels like a timer issue. Something is happening at 2 minutes and 19 seconds from reset. Some sort of overflow?? Maybe related to the PID??

And, if left long enough in Closed Loop Angle mode (with the example code), it just starts spinning fast ~20 Rad/s

Print the important variables to serial wherever you can and just watch things work, I often found I was able to track down problems like that. Print a whole bunch and then zero in to find the thing that’s not doing what’s expected.

If you half the speed does it take twice as long to mess up?

Thanks Owen,
No, if you set it to 0 Rad/s it starts spinning fast (~20 Rad/s) at 2:19. And, if I set it to 10 Rad/s it starts spinning fast (~20 Rad/s) at 2:19. Interestingly, if I give it a sequence of speeds with changes in direction, it starts doing a seemingly random sequence at 2:19.

Thanks Anthony,
Ran it in closed loop velocity mode (with the example code) and added this to see…

Serial.print(sensor.getAngle());
Serial.print(“\t”);
Serial.println(sensor.getVelocity());

Angles worked perfect the entire time. But, the velocity only works for the first 2 minutes and 19 seconds. After that, it locks to some number like 0.00 or -1.15 and then after another few minutes it jumps to a huge number like 46390.10 or -1548902.12 and stays there (doesn’t matter if the motor is unplugged, moving or not). And, I am no longer able to set the speed at that point. The motor just spins fast at like ~20 Rad/s. This is the same result every time I reset it. But, the angle seems to be correct the entire time.

Strange. Doesn’t sound like an overflow problem if it’s dependent only on time and not velocity. Post your full code.

1 Like

So I would go back upstream, then, now you know the velocity is the problem, look at the code at source.simplefoc.com/ and browse around to ascertain what the velocity is dependent on. Print some of that stuff, and try to zero in on where the flake out is happening?

Sorry I know it’s a lot of work but it’s probably faster than trying to get answers in other ways. Sometimes it works pretty fast.

Thanks Dekutree64,
Just using the example code for closed loop Velocity_Control

What I would do is put a bunch of Serial.print calls in the sensor getVelocity function to find out exactly which variable(s) have gone bad. You’re using the MagneticSensorSPI class, correct? It uses the base Sensor::getVelocity, so try putting this in Sensor.cpp:

float Sensor::getVelocity() {
    // calculate sample time
    float Ts = (angle_prev_ts - vel_angle_prev_ts)*1e-6;

    static unsigned long last_print_time = 0;
    if (millis() >= last_print_time + 1000) {
        last_print_time = millis();
        Serial.print("\nTs               "); Serial.println(Ts);
        Serial.print("angle_prev_ts      "); Serial.println(angle_prev_ts);
        Serial.print("vel_angle_prev_ts  "); Serial.println(vel_angle_prev_ts);
        Serial.print("full_rotations     "); Serial.println(full_rotations);
        Serial.print("vel_full_rotations "); Serial.println(vel_full_rotations);
        Serial.print("angle_prev         "); Serial.println(angle_prev);
        Serial.print("vel_angle_prev     "); Serial.println(vel_angle_prev);
    }

    // TODO handle overflow - we do need to reset vel_angle_prev_ts
    if (Ts < min_elapsed_time) return velocity; // don't update velocity if deltaT is too small

    velocity = ( (float)(full_rotations - vel_full_rotations)*_2PI + (angle_prev - vel_angle_prev) ) / Ts;
    vel_angle_prev = angle_prev;
    vel_full_rotations = full_rotations;
    vel_angle_prev_ts = angle_prev_ts;
    return velocity;
}
1 Like

Yeah that’s what I’m talking about. I am betting there is a better way to do this in platformIO, sometimes things move considerably too fast for printing to serial. If you keep the printing small enough and at low enough frequency, it appears to have only very minor impact on the operation of the program because the information just shoops into a buffer, which takes very little time, and then goes out automatically with the serial peripheral hardware. If you add a lot of print stuff at once Arduino has to wait for it to go out the serial port and then send the next batch of stuff, I think. This can lead to complications, in my experience, changing total program loop time etc. Just something to watch out for.

Obviously increasing clock speed can help, I had no problems with 1 million baud.

Thanks Anthony,
Looks like the micros() is dropping when it hits 4290000000. This happens 2 minutes and 19 seconds in. The drop happens at the same time that the motor starts to spin randomly. ???

1 Like

Thanks Dekutree,

The printed angle readings work fine. But, the printed velocity readings freeze and get strange at 2 minutes and 19 seconds in.

Max size for 32 bit number is 4,294,967,296

Which, if my maths is right would overflow after 71 mins (1hr 21 mins)

Does your micro function seem to be accurate? Feels like it might be running ~16x speed

Open loop has a comment talking about a fix in this area, perhaps it needs to be applied to closed loop?

1 Like

Yes I know the velocity is bad. The code I posted is to help find out why it’s bad. What values do you get for all those other variables after 2:19?

1 Like

There are bits of code that are supposed to be able to handle that kind of wrap-around. As Scott notes your micros() must also be going too fast for some reason, so now you have two problems to sort, but one by one, line em up and knock em’ down and you can get things straightened out. Somewhere that micros() is being used it must not be handling the wrap around quite right? I would get micros() working and see if that extends the time period, it’s something that sort of needs to be done anyway and reveals whether you are on the right track or not.

Here’s the answer… This worked!

Go to line 21 of the file src/common/base_classes/Sensor.cpp

At line 21, add these lines:

if (Ts < 0.0f) { // handle micros() overflow - we need to reset vel_angle_prev_ts
vel_angle_prev = angle_prev;
vel_full_rotations = full_rotations;
vel_angle_prev_ts = angle_prev_ts;
return velocity; }

1 Like

Interesting, so it was an overflow problem. It seems your micros() is ticking 32x faster than it should, making the problem easy to reproduce whereas it normally would take over an hour.

I think we should add a sanity check on the input value of the low-pass filter. This isn’t the first time I’ve seen it get permanently stuck due to receiving a single corrupt reading.

1 Like