Venturing into the inner workings of brushless motors

Hi,

I have just done some digging into the theory behind brushless gimbals and I spend a few evenings getting to know the problems. I fired up my arduino and a brushless motor. Interesting stuff!

Let me just start by saying that my objectives is not to build something finished - but rather to understand the inner workings in the strategy behind the control system. I hope that there might be somebody willing to share their approaches. Sadly I am not skilled enough to decipher the inner workings on the BruGi project, just by looking at the code. Which is, in my defense, quite comprehensive :slight_smile: On to the fun stuff:

To start with, I got my arduino out, and hooked up some experiments:

Powered up the arduino and coupled it with an L6234 H-bridge motor driver. Which seems to be the basic strategy for a number of projects out there.

I quickly got the phases right and was able to turn the motor slowly and precisely. I used a PWM frequency of 34KHz and an 8 bit resolution. So far so good. I noticed some irregular movement, which I learned is a common problem called cogging. This arises from the inner workings of the motor stators and magnets, which tends to "want" to be in specific places rather than others. I didn't dive to deep in this since it seems to be a unavoidable issue. I used a T-Motor GB-2208-80 for testing.

Okay, so I got the motor turning and moved on to implementing an IMU. I had an invensense MPU-6050 lying around so I hooked this up. This thing has some serious DMP capability which I immediately fond way too complex. Invensense documentation is also not the must friendly I have seen... Anyway, thanks to Jeff Rowberg and his work on the DMP I pretty quickly got it running, and supplying me with friendly 3-axis degree angles every 10ms. Great! Now to the first control experiment:

I made a very simple PID control loop that adjusted the motor speed towards the target. To my surprise this actually worked well... but not too well. I thought that with some PID tuning and some code optimization things could work out good. Boy, was I wrong. I hit a wall of problems, and started looking at the whole system again. These was my initial observations:

8 bit PWM resolution is fine. (thought it might not be)
Any PWM frequency above 8 KHz seems to be good
The 6050 IMU gives me readings at 100 Hz. Gyro only might be faster?
The response time for my motor was minimum 15ms with some rippling after
I fond that with almost plain vanilla arduino coding I could do a half decent job with processor-time to spare (should probably make me question my strategy :slight_smile: )

So my control strategy is this:
I get my current error in rotation every 10ms and run it through a basic PID.
Adjust the motor speed every 1ms, so linear motion for 10 ms until next IMU reading. This works fine at low speeds.

Now things got tricky (for me at least), since I quickly saw some oscillations at relatively high constant speed. I traced this back to the fact that I make the motor compensate for an error but the motor dosn't start doing this for another 15 ms. Before the 15 ms has passed the error might have gotten greater and the previous correction hasn't kicked in.. bummer. Now the PID control event (in between) thinks that things are worse than it is, and over compensates which gives my nasty 10-20 Hz shakes.

I am mainly experimenting with only the proportional of the PID active. So I don't make any (very easy to make) derivative screw-ups. PID tuning for gimbals can be extremely tricky...

This is pretty much where I am now.

I am considering if the speed should be the center of my control strategy or maybe a position target, which might be easier.

I seem to be stuck with how to handle the motor reaction delay. I tried to account for motor-compensation not yet "seen" by the IMU, but none the less known. Not much success, since the motor reaction curve is rather complex. It starts moving at 15ms and then overshoots the target and then wiggles in place for the next 40-50 ms. Annoying to describe in math... :slight_smile:

The 100Hz update rate for the IMU also makes me think if this is fast enough. Could this be done with gyro reading only, which I think could be done a lot faster. But then again the motor reaction time seems to be the bottleneck time-wise.

I hope that some of you have dived into similar projects or perhaps thinks that is could be fun to experiment along :slight_smile: Any feedback is much appreciated.

Looking forward to your insights

Best
Esben

Watching with great interest!

It occurred to me that I probably need to give a bit more clarification to get people on board with this adventure :slight_smile:

The first challenge is to control the brushless motor. This involves powering three phases that attract or repel the magnets in the motor. Think of it as three people each holding a line connected to a ball. Now try and coordinate moving the ball without it hitting the ground :slight_smile:
The solution is actually pretty simple: each phase of the motor need to either push or pull in a specific pattern. That pattern is regulated with a voltage that is 120 degrees different in phase. That you find with: sin(phase*(PI/180)) and scale it to match you PWM output. Sinus work with radians and the PI/180 converts this to degrees. All you have to do is to get the value with 0, 120 and 240 degrees. That's it! your motor is holding a tight grip on this position. Change all the angles a little and you have rotation! Since the arduino can't handle the power needed to drive the coils some FETS are needed. Those have been conveniently packaged in the L6234 motor driver. The arduino can't output a truly analog value, which is why we output this to a PWM pin instead and directly into the L6234 that in turn handles the power.

Since I want to use this for a gimbal, I need the motor to react to changes in orientation. If I had a camera sitting on the gimbal I want it to point the same way no matter how shaky it is held.

So we need an orientation sensor or IMU. The invensense MPU-6050 is pretty cool, but also a beast of a chip to control. Luckily this work is already done: Arduino Playground - MPU-6050

The 6050 will output three dimensional data at 100Hz. (every 10 ms). So now we have a tool to correct the angle. The whole trick is now to make it amazingly FAST :slight_smile:

One of the core principles in a lot of control regulation is PID control. A while back this took me some time to fully understand but this page took me on the right track: http://www.pc-control.co.uk/feedback_control.htm

If you have the patience to roll this into a sketch then you will end up where I am now. Please see the first post :slight_smile:

Best
Esben

Oscillation suggests some tuning is needed - start with just P, then PI, limit
the overshoot to something reasonably sane in the first place, then up the D
component to completely kill overshoot. That should be critical damping.
Then edge up P and I, increasing D to restore good damping until you
get to the real limits of the system, then back off everything a bit?

Very important point: tuning depends on the mechanical load, not just the
motor and sensor. Tune for the actual load.

I think one of the issues is getting a good estimate of the derivative, for which
the direct output of a gyro is perfect (its already a derivative, so use it
directly, don't recalculate it from the angle signal (which is already the integral
of the gyro signal).

Thanks MarkT

Good points! I will keep that in mind. I think I followed your route pretty exactly, which took me to a point where the control seems good but very slow. Your post makes me think if I am doing the PID calculations correct. At the moment I am doing this:

P:
The current angular error * some gain factor

I:
The accumulated angular errors over some time * some gain factor

D:
The acceleration in angular error * some gain factor

For the moment I am trying to get the most out of the P-factor before I move on. The thing that is puzzling me is how to account for a known (already made) adjustment that has yet to be detected by my sensor. Wouldn't it make sense to take that into the equation? A few loops could look like this:

0 ms: Lets say error is 100, and we correct with 50%
10 ms: The error is still 100 be course the correction has not yet kicked in. The accumulated error correction is now 50 + 50.
20 ms: The correction at 0 ms kicks in, so we have an error of 50 now. we correct with 25.
30 ms: we end up overshooting the target with 25%

Now, I know I could just lower the proportional error correction, but how about taking the error that we know will be corrected into account. In turn that would allow for higher P value and faster overall correction.

I hope you understand my point :slight_smile:

Best
Esben

In a PID controller the I and D terms have to represent all the previous
control inputs - for simple linear systems this works quite well. To do better
you may have to go to a non-linear algorithm, and then proving the
system cannot oscillate is much harder.

Remember if the D term is pushed up, then the maximum stable P and I terms also
increase. A system with little intrisic damping will ring (overshoot) readily on
step change input if there is no D term.

The worst case for a simple PID controller is step-change, so you can sometimes
improve performance by preventing step-change by slew-rate limiting the control
variable. Integral wind-up is an issue that often needs consideration.

Hi Mark

Thanks for the insights. It really made me think long and hard about this.
I might be missing soms basic concepts when describing this problem, but I'll try:

On the I and D: If I understand you correctly these two should always be used in combination with all the control corrections. So when applying the I and D we always know where we should be with all previous corrections taken into account, and act accordingly?

I have difficulties wrapping my head around why this shouldn't also be true for P. In my previous description I run into the problem of P overshooting the target be course of a delayed motor response. From my logic this is something that could be taken into account and would reduce the latitude of the errors that the PID loop need to handle. The problem is that the response characteristics of the motor is complex but previous corrections (that is not yet measured) are known.
Or is this behavior normally integrated into the PID setting itself?

I realize now that I am swimming in the deep end :slight_smile: My knowledge on PID controllers is probably too limited. Can you recommend some good resources for leaning more about this?

Best
Esben

esbennielsen:
On the I and D: If I understand you correctly these two should always be used in combination with all the control corrections.

Not at all, they serve completely different functions.

Both P and I can generate overshoot or instability, D is there to counter that and give
a damped response.

I is only to improve accuracy under load by raising the closed loop gain
to infinity at DC.