Wednesday, April 18, 2012

Sensorless Start-Up / Speed Control

It's spring demo season again. I'll be at the Cambridge Mini Maker Faire on Friday, along with the MITERS crew, with an assortment of projects. Come check it out. Follow-up post to come.

For now, time for a massive multi-controller update. The Sensorless, Sine-Commutated Field-Oriented Current Control (SSCFOCC) algorithm I've been working on has been sufficient abstracted now that I can develop for it on two different motor controllers (3ph v3.1 and FFv1.0) at the same time. (3ph v4.0 is coming soon and DirectDrive v1.0 still exists, I promise...)

Before I start developing new hardware and potentially writing a entirely different sensorless control algorithm, though, there were some loose ends I wanted to clean up in the current algorithm. Once these points are addressed, I will go back and write up a summary of my first-generation sensorless code since by now it's too complex for individual blog posts.

But First...

More Position Filtering

Loose End #1 was a problem with the rotor position estimating filter used to clean up the rotor angle at high speeds. I added this at the end of the last sensorless post and even though it immediately improved the high-speed performance of FFv1.0 on the hexrotor motors, there was a weird side-effect on the flux vs. angle graph. The flux estimate would begin to lead the rotor angle estimate at high speeds, which should not happen since the rotor angle estimate is derived from the flux estimate. The flux vs. angle curve should be constant. What the?

After staring at the code for a little while, I identified this a rather complex software error on my part tracing all the way back to a subtlety of BWD's sensored FOC code... I'll spare you the details, but I fixed it and now the flux estimate is much nicer:

Pneu Scooter w/ 3ph v3.1. Compare to unfiltered flux estimate.
Much of the "noise" from the 2d plot is shown to be offset at low speed (<200rpm).
Hexrotor motor with FFv1.0. Compare to the unfiltered flux estimate.
And in nauseating pseudo-3d.
The low-speed offset is a known issue having to do with the fact that the integrator at the heart of the flux estimate is implemented as a low-pass filter. There is also a phase offset in the flux estimate resulting from this practical non-ideality:

Since this is a known offset, it could potentially be subtracted off. Or the low-pass filter could be designed such that at the start-up routine exit speed, the offset is less than 15º or so. For the data above, that would be about 150rpm. Speaking of start-up routines...


Loose End #2 was the lack of any start-up routine for either controller. I've been putting it off for a number of reasons. For one, Pneu Scooter really doesn't need a start-up routine. The sensorless algorithm has no trouble picking up the rotor speed at as low as 50rpm and that's well within single-kick speeds:

One kick gets to 75rpm, at which point the flux estimator has locked in.
Also, Pneu Scooter really doesn't have enough torque to justify a no-kick start-up routine. Even at peak current (40A), the acceleration is something like 150rpm/s. The sensorless start-up will achieve far less than peak torque, though, since it won't have the benefit of optimum current vector placement. So it could mean a couple seconds of balancing on a barely-moving scooter while the speed ramps up. It's just much more natural to kick start.

FFv1.0 and the hexrotor motors, on the other hand, almost definitely need a start-up routine. Even though in this video, a very large (14x4.7SF) prop starts cleanly and quickly with no start-up routine at all. The command PWM goes high enough that the motor is forced to do something, and by luck it gets kicked in the correct direction at sufficient speed for the flux estimator to lock in. But this is unreliable (works maybe 50% of the time) and inelegant, so it should really have a slow-ramping startup routine as well.

Maybe the real reason I haven't implemented a start-up routine yet is because it's easy. At least, the most obvious way of doing it is easy. Lacking position information, there isn't much choice in how to drive a brushless motor: it becomes a coarse stepper. Except with sinusoidal commutation it can be like a microstepping coarse stepper, which is still pretty smooth. The point is, the only way to drive it with no knowledge of the rotor position is to put current in somewhere and wait long enough to know that the rotor has most likely reached the position you told it to go to. With that in mind, I wrote a simple start-up routine with four states:
  1. IDLE: Wait at zero speed until the user commands a positive torque or speed.

  2. PARK: Place current vector at a fixed angle and wait for some time for the rotor to reach a stable position.

  3. RAMP: Rotate the current vector with a constant angular acceleration that is sure to be achievable by the rotor given the amount of current commanded and the estimated load inertia.

  4. RUN: After a certain speed, switch to sensorless field-oriented control using the rotor angle predicted by the flux observer.
The ramp state here differs a little from BLDC-style sensorless start-up routines that use six-step voltage-mode commutation. Since this ramp state is still current controlled, the possibility for variable user-commanded acceleration during "open-loop" start-up is present. The angular acceleration of the ramp is linked to the amount of current commanded. If you go light on the throttle, the ramp takes longer.

Since the load inertia can't be exactly known, the start-up ramp acceleration has to be conservatively chosen. The start-up torque will therefore be significantly less than the run torque, and the efficiency will be very low. This is a common trait of sensorless start-up algorithms and the best way to minimize the effect is probably to get out of start-up as soon as possible. Transitioning to closed-loop sensorless control at 5-10% of the maximum speed seems to be achievable.

Anyway, enough hypothesizing. Here is my first shot at a sensorless start-up for Pneu Scooter, the harder of the two challenges:

The ramp goes from 0 to 150rpm in about 3 seconds with 30A commanded current. This is about 50% of the acceleration that would be expected from closed-loop control, so it feels sluggish for the first three seconds. But, it is smooth and transitions cleanly to run-state closed-loop control at 150rpm. Making the ramp faster results in pole slipping, so this is about as good as it will get.

One option for improving the start-up is to get out of the ramp state earlier. The flux estimator is able to pick up the rotor movement at as low as about 25-50rpm, so waiting around until 150rpm sounds silly. But, the low-pass filter-induced phase lead is still very high at those speeds, so the transition doesn't work reliably. It's clear that the low-pass filter time constant and the ramp exit speed are coupled in this way. Something to think about for future optimization.

Another option is to use more current. This doesn't help the efficiency, but it will create a faster ramp. 60A for a short period of time shouldn't hurt the motor or controller, but I'll wait for 3ph 4.0 to test that.

Start-up for the hexrotor motors is a much simpler problem. For one, they have essentially no load at start-up when the prop is moving too slowly to create significant thrust or drag. The performance of the controller is also not at all dependent on low-speed torque characteristics since the minimum RPM seen in flight will be well above the run-state threshold. Here's a very light ramp (<5A) for the 14x4.7SF prop:

The threshold for transitioning from ramp state to run state is 600rpm, and once it transitions to run state the torque increases dramatically. The ramp can afford to be much faster without slipping poles, but for the purpose of reaching a safe idle speed for the prop, it almost doesn't matter. Note that the speed goes directly to idle speed, 1,000rpm, and sits there. That brings me to...

Speed Control

Loose End #3 is speed control for FFv1.0. Pneu Scooter, as a vehicle, is happy with current (torque) control. But for the hexrotor, the master controller may want to command an exact speed for each rotor. Speed is directly related to static thrust (though not linearly). Steady-state current is also related to static thrust (close to linearly). But with inertial transients to deal with, the performance of a speed-based controller might be better.

Actually, the simple way to do "speed" control is to directly vary the PWM duty cycle, bypassing the current control entirely. This controls speed because motor speed is approximately proportional to applied voltage, which is controlled by the PWM duty cycle. As it turns out, it's definitely possible with the modified Synchronous Current Regulator (mSCR) to use this control mode, bypassing the q-axis current controller but leaving the d-axis (phase) controller working. This gives the benefits of FOC (dynamically adjusted motor timing) but the simplicity of direct PWM control. In fact, this was what I used for the first few tests of FFv1.0. Here's some data showing it executing step "speed" commands:

At each step, the q-axis and d-axis current spike due to the inertia of the motor and prop. But, the back EMF brings the q-axis current back to a steady-state value as the prop speeds up or slows down, and the mSCR adds or subtracts from the phase to bring the d-axis current back to zero.

The benefits of direct PWM magnitude control are simplicity and robustness. With current limiting to prevent the spikes from damaging components, I think this could be a pretty good way to run a multirotor controller. It's how most ESCs operate, so it would feel normal. But, it has several downsides:

  1. It can't achieve minimum rise time. The step in voltage magnitude will give only as much current as the motor resistance will allow. A smarter controller could slew the motor faster using a voltage that is higher than the steady-state value at the target speed.

  2. It can't accommodate minor difference in motors/ESCs/props. If one motor is slightly weaker than the others, it will spin slower under PWM magnitude control. The master attitude controller's integral term can correct for this, but why rely on this?

  3. Motor speed is only roughly proportional to applied voltage. The actual speed depends on the back EMF, which is V-IR. At higher loads, the speed per applied volt is lower. Does this matter? Maybe not, since none of this is linearly proportional to thrust anyway.
A classical approach to true speed control would be to wrap an outer PID control loop around everything:

The speed control loop, a generic PID with saturation, feeds the q-axis current reference a value between the maximum braking current and the maximum accelerating current, depending on the speed error. The d-axis controller is still simply trying to maximized torque per amp by adjusting motor phase. (The more I think about it, the more the mSCR strategy makes sense in this regard.)

This video shows the start-up and PID-based speed control for FFv1.0 with the 14x4.7SF props:

The nice thing about PID control is that it's easy to understand and easy to tune. Unfortunately, the load in this case is very nonlinear. As the speed increases, the damping due to propeller drag goes up. So, the step response changes depending on the speed:

Real data from the 14x4.7SF prop.
From 1,000-2,000rpm, the chosen gains exhibit a lot of overshoot. From 4,000-5,000rpm, they're overdamped. With this data as a starting point, I made a quick simulation including the nonlinear prop load. Another nice thing about PID is that it's very easy to work with in a Simulink:

This is what grad students do all day.
After some shady parameter estimation, I could almost predict the step response shapes:

The real-life response is actually a bit faster than the simulated response, for some reason. Not going to complain about that. But, they're both pretty slow overall. The motors never reach peak current during speed steps. The slew rate can and should be much faster for the best possible speed command tracking. By tweaking the gains in Simulink, I can now get a feel for which way they should be pushed in real life to speed up the response and kill off some overshoot.

I also think there's a better way. This post is already quite long so I'll have to save that for next time, but there is a hint of it in the Simulink diagram...

For now, I leave you with a Kramnikopter that I bought for basically nothing and will be doing absolutely zero custom development for:

Yay, not-complicated flying things.


  1. What motors did you use for the frame? I'm looking to make a cheap quad-copter myself and I need some recommendations on parts...

  2. I'm using these FC 28-22 1200rpm/V motors:

    with 9x5 props.

    Can't beat the price...

  3. Hi Shane, first of all your blog is very nice ;) I come here lots times.

    Can you tell how you do these grafs? (not from simulink)


    How do you know how much power can a mosfet handling? do you just calculate de power dissipate?


    1. Most of my graphs are from MATLAB. The colors are inverted.

      For the MOSFETs, I can compare the power dissipated (from I^2*R, switching, and diode losses) with the thermal resistance (degC/W). The latter depends a lot on heat sinking so it's hard to estimate.

  4. Hey Shane, nice blog! Have a question regarding the "normal ESC control". When you mention "At higher loads, the speed per applied volt is lower." Does it mean at higher load there is more phase lag to correct and higher coil current?

    1. Thanks! Yes, assuming higher speed also implies higher load, both the I*R component and the I*omega*L component will be larger. More resistive loss and more phase lag. So to get to the same back EMF/speed requires more voltage.