Monday, January 30, 2012

Did you know that Flinch still exists?

If you don't even know what a Flinch is, I don't blame you, since I last posted about it in June 2011, and it's been sitting on a shelf ever since. It's a miniature Mecanum-wheel robot that was supposed to be a smaller companion to Twitch:


Unfortunately, I ran into trouble with the FingerTech 2.125" Mecanum wheels. The rollers are nicely-molded rubber, but the shafts are just 1/8" brass rods riding directly on the plastic hubs. Steel washers separate the rubber from the face of the plastic, but there is still way too much friction for the rollers to do what they're designed to do. (For reference, here's a smooth-driving ~40lb Mecanum wheel chassis. And here's the full ~110lb robot.)

FingerTech does sell a bearing upgrade kit, but I have my doubts. The bearings they sell are needle roller bearings, which can only handle radial force. The roller shafts can still slide sideways, allowing the metal washers to rub against the plastic face of the wheel. That, if anything, is the large-surface-area friction culprit of these wheels. So, I decided to go my own way and get much more expensive SR144ZZ ball bearings:

Pictured: Lunch money for three days.
Additionally, I bought some 1/8" ID bearing shaft shims, McMaster P/N 99040A316. These tiny shims keep the metal washers that come with the Mecanum wheel rollers separated from the inner race of the bearings, spacing them out from the side face of the wheel. This allows the ball bearings to take up the thrust load, rather than the face of the wheel. Here's the roller, stock washer, and extra shaft shim all in place on one shaft:


The next step was boring out each of the 24 roller shaft holes from 1/8" to 1/4" to accept the new bearings. Since the faces on which these holes are drilled are at 45º to the rotational axis of the wheel, and spaced 60º radially from each other, and there are two different (mirror image) wheels, this was not a simple task.

Or maybe it was, and I made it way more complicated.
In any case, I managed to increase the roller bores to 1/4" in a way that isn't idiotic. The next step in this already-too-long-and-expensive process was to take apart all the wheels:

Sigh...
Then, I pressed in the bearings one by one and...realized I only ordered half as many SR144ZZ's as I needed.

...

FFFFFFFUUUUUUUUUu

...

A few days and $70 later, I finally got around to reassembling all four wheels with the new bearings.


And after all that work I had four wheels that look exactly the same as they did before, but cost 122% more than FingerTech pretends they do. At least they will be more functional. Except they weren't, at first. After just a minute of driving around, half the bearings had slipped sideways, allowing the metal washers to contact the sides of the wheels again. This was mostly because the new bore was exactly 1/4", so the press fits were loose. So, I took all four wheels apart again...

...cursing myself for ever thinking this was a good idea.
And I very carefully added CA to each of the 48 bearings (two per shaft) to hold them in place:


I used a sharp object to spread CA around the bearing perimeter so it would wick into the bore, hopefully without getting into the bearing itself. I managed not to ruin any bearings, but the process took half a day. And then I still had to reassemble all the rollers. 

I wish I could say that the result of all this Mecanum wheel re-engineering was a wonderful drivetrain that will rival Twitch for its speed and maneuverability. I wish I could say it was all worth the effort and the money. But, after putting it all together and running it, it's still only barely passable as a Mecanum, drive:


Yes, it moves sideways. But it's a jerky, bumpy, inefficient sideways. All Mecanum drives are less efficient sideways than they are forward, but this one is really fighting. It tends to rotate while moving sidways as well, which is a sign of mismatched wheel friction and bad weight distribution. That can mostly be compensated out by gyro feedback. But the gyros won't be able to stop it from bouncing around like a cockroach bot. That's mostly a function of the wheel shape and twitchy nature of small/light robots with oversized motors.

So I'm not sure how much more time or money I'm willing to spend on it. I feel like adding weight, switching to a higher gear reduction, and adding closed-loop rotation control would help a lot. But the thought of buying new gearboxes, a gyro, and possibly stiffer chassis plates makes me cringe. I'm glad it isn't just sitting half-finished on a shelf anymore, though.

Monday, January 23, 2012

tinyKart: More Abuse

Poor tinyKart. Pretty much ever since we built it and it didn't fall apart, it's been put through a series of tests it was never designed for, including off-roading, hill climbing, and Radu. But this week, it was given its toughest trial yet: New England winter weather rallying. The thing about living on the coast is that it's not just snow - it's cold rain, mist, sleet, salt, slush, dirt, and sometimes snow. To really handle all the crap that occupies the ground here during the winter months, you would need something like a small tank. But to make some attempt at handling the winter season, we splash-proofed the electronics and fitted Razor Dune Buggy tires to the rear wheels:


After that, there was only one thing left to do, and that was to hand it over to our tame racing driver. Some say his urine turns snow blue, and that he doesn't believe in polar bears. All we know is...

...he's called The Stig.

The aftermath was a very snowy and very dirty tinyKart:




But it was worth it. The kart behaves as a RWD ultralight kart with a lot of torque should in low-traction conditions, which is to say that it either goes in a straight line, if you are trying to decelerate, or spins in violent circles, if you are trying to accelerate. This wonderful combination of user-selectable understeer and oversteer makes it a lot of fun to drive, though not particularly practical for real rallying.

Somebody should make a 4WD version...

Thursday, January 19, 2012

Precision SMALL Prop Balancer

The biggest problem I've had with my PCB quadrotor has been mechanical vibration disturbing the rate gyros and causing the angle estimate to drift or be unstable. While the small and flexible frame exaggerates the vibrations, their source is imbalance of the propellers and, to a lesser extent, the motors themselves. So far, I've been balancing the propellers by spinning them on a small allen wrench and watching which way they prefer to settle, but this is obvious not ideal. The problem is, commercial prop balancers are useless for props this size:


Here's a commercial prop balancer from Hobby King, which has "very low friction bearings" on which a shaft with conical plugs rides. There are other types that use magnets to hold the shaft. They work pretty well for large props. This one can probably be useful for 8" or larger, and the magnetic one might be able to do 5" props. Smaller props weigh less and the friction in the bearings or at the shaft/magnet contact cannot be overcome by the slight imbalance of a 4" prop. My main beef with them is pretty simple:


For small props, they work better if you ditch the bearings altogether and use them as horizontal rails. (You could even argue that the same is true for any size prop...) Why not minimize the number of rolling contacts by using the shaft directly? There is much less friction this way. It's like somebody Google'd "prop balancer" and built something that looked like it should work without thinking about a simpler way to make the same thing. There are some commercial balancers that use simple rails, and no surprise, they tend to be for boat props and RC car wheels. If they work for such small things, they must work better for large props.

I know what you're thinking: How do you know the rails are level? The answer is the key to my new precision small prop balancer:


Those are two nice-but-cheap bubble levels from McMaster, P/N 2151A65. They are aluminum-and-plastic levels for $8.51 each. Add to that one precision-ground tool steel shaft, P/N 2900A222, and you have a precision small prop balancer for about $20. I use the prop adapters that come with these small 1.5mm-shaft motors to sandwich a prop on the shaft:


Then after finding a level surface, I place the shaft on the flat aluminum edges of the levels and let gravity do the rest:

Unbalanced.
Balanced!
It's almost that simple. There are a few subtleties:
  1. Make sure the level edges are clean and free of dust/dirt.

  2. Make sure the set screws are tightened evenly and facing perpendicular to the prop blades, so they don't contribute to the spanwise imbalance. (They will contribute to chordwise imbalance...no way around that.)

  3. Depending on the chordwise balance, you might get to a state where the prop seems bistable, so that it will settle on either side but never stay horizontal. If so, rotate 180º.
That's pretty much it. 4pcb's props were already pretty well-balanced, but after a bit of tweaking with the more precise balancer, it became even easier to fly. It takes off and hovers more smoothly and remains in one place for longer with no command inputs. Because of this, I took some time to learn a new trick: hand launching!

Monday, January 9, 2012

tinyKart: "Winter" Special

I was planning to keep tinyKart inactive for most of the winter to upgrade the power system and move to custom controllers, figuring that it's too cold to do any test driving anyway. But for some reason  it's 50ºF in early-January in Cambridge, MA. That, combined with tinyKart co-designer Max Hill being in town, along with a some other distinguished visitors, was enough reason to put the kart back together for a brief "winter" testing season.

The first things to fix up were a few loose screws in the steering assemblies. Normally, loose screws aren't a problem: take them out, add more Loctite, and re-tighten. But these screws were a little hard to access:


They're the six screws that hold the uprights together, and they were not designed to be accessed without taking the entire front chassis plate of the kart off. By dislocating some of the steering linkages, though, two out of three on each side could just barely be reached with a screwdriver. To make matters worse, they were stainless steel cross-head screws, which are easy to strip. So, after careful removal, they were replaced with alloy steel Torx-head screws which will hopefully never come loose:



Max and I also finished yet another motor swap. tinyKart started on Turnigy SK-6374-170 motors, which were excellent except for the lack of can bearings, which allowed them to tear themselves apart at high speeds. I then installed but never test drove the newer SK3-6364-190s. They have can bearings and nicer windings than the old SKs, but I'm still annoyed that they're not actually 63mm motors. They're 59mm and they have a smaller shaft than the old SKs (8mm instead of 10mm). The smaller diameter messes with the timing of the external Hall effect sensor boards I made, which were specifically designed for 63mm. The resistance of the SK3-6364-190 is also 60% higher than the old SK. So, we removed those and installed the third set of motors tinyKart has seen so far:


These are Turnigy EMP C6374-200s from Leaders Hobby. As far as I can tell, they're identical to the Turnigy C6374-200 that is no longer stocked on Hobby King. It is actually 63mm in diameter and it has a 10mm shaft, like the old SK. But it has a can bearing like the new SK3. The only noticeable shortfall is the messy/loose windings, characteristic of the old SK and old Turnigy motors in general. The SK3s are probably perfectly suitable motors, but right now these are a better deal, especially since Leaders Hobby ships them from the US. It's good to have a few options; I dread the day when the imported fruit-sized motors disappear and all that's left are the economically prohibitive purple-flavored ones.


Because the C6374-200 is actually 63mm, the sensor board fits nicely and the motors are relatively easy to time for forward and reasonable reverse, unlike the SK3s. These motors should have about the same amount of torque as the old SKs. Even though those were rated at 170rpm/V, our data showed something closer to 190rpm/V, almost the same as the new EMPs. These should be able to handle higher speeds, though, since they have a can bearing. At 190rpm/V and 40V, the no-load speed is 40mph. But we will have to solve the controller limits and find more testing space before that can happen.

The Kelly controllers have been okay, but quirky. When they don't like something, they cut power temporarily and give a useless "Frequent Reset" error code. It's dependent on load and motor timing, and seems to trip when the maximum current is set to 80A or above (on a 100A-rated controller). I think it's a hardware current limit being tripped by current spikes. I think the high speed firmware version would handle these motors a lot better, since the switching frequency is higher and the current ripple should be lower. But I'm not sure I want to spend $400 exploring that option when I could implement DirectDrive and, some day, have sensorless field-oriented control. For now, though, we have to live with these Kelly controllers.

We also installed new batteries to replace the 0.33kWh of LiPo high explosives that tinyKart has used up until now. This pack looks shadier, but it's LiFePO4, which is significantly less frightening to work with:

The orange straps make it safer.
The packs are custom 12S3P A123 26650 m1-sorta-B's (39.6V, 6.9Ah, about 30mΩ). They've got a little less energy storage than the LiPos (0.27kWh), so less run time per pack. But the packs are easy to swap now and can be fast-charged in under 30 minutes with Cap Kart's 15A charger. The also have a lower internal resistance than the LiPos or an equivalent pack of A123 M1A cells, which means higher peak power (theoretically up to 8kW).

With the new motors and battery installed, we took tinyKart out for some garage testing:


It's nothing as brutal as the last couple of garage runs, just making sure everything still works. The controllers seemed to be okay, although I was able to make the right side cut out a few times at full throttle. The new motors are equal in torque to the old ones, and the new battery seems fine. The handling is as wonderfully drifty as usual, and a close inspection afterwards revealed no loose parts.

So, while I sort out the details for converting it to custom controllers, we at least have something to play with if it stays warm. If not, we also have a back-up plan involving snow tires...

Wednesday, December 28, 2011

4pcb: √ Control Law + Teaser...

Yes, I am making another post about quadrotors. A made a few minor tweaks to the control of 4pcb. The most notable is a change to the output command for each motor, after all the P[I]D controller and motor mapping. The commands are now sent through a square root function. The force produced by the props is more related to rotational speed squared than to rotational speed. The speed is roughly proportional to the command. So, to produce a corrective a force, as the PID controller would like to do, the command generated in response to angle or rate error should follow a square root-type curve. Or so the story goes.

The remap sends the command through a square root function while normalizing to 1, to preserve the command range. Something like this:

// square root remap, command range is 0-255:
command_out = 255.0*sqrt(command_in/255.0);

This keeps the maximum command at 255 and the minimum at 0, but shapes the intermediate values to be a square root function. I don't actually do it like this because square root on a microcontroller is a horrible thing. Both the input and the output are 8-bit integers, and I have plenty of memory, so I use a look-up table instead:

// I'm a horrible person, generating my LUT at run-time:
unsigned char SQRT_LUT[256];
for(unsigned int i = 0; i <= 255; i++)
{
  SQRT_LUT[i] = (unsigned char)(255.0*sqrt((float)i/255.0));
}

...and later, in the loop...


command_out = SQRT_LUT[command_in];

Because it's an 8-bit integer table, there is some quantization near the extremes, but my upper and lower throttle limits (100 and 230) constrain it to a well-behaved part of the curve:


After implementing the remap, I noticed a significant improvement in the performance. For one, some of the high-frequency oscillation is gone. It doesn't seem to wiggle back and forth quickly when it's just hovering. It's also easier to hold it at a given altitude, probably due to the more linear stick-to-force relationship. I don't think it's just placebo effect, but who knows?

I also made one other ugly hack. One motor has been consistently and annoyingly slow compared to the other three, causing the roll axis to be hard to fly, especially as the battery drops below about 7.4V. I just multiplied this motor's rate gain by 1.3. I have no justification for this value, but it helps. Maybe I will replace that motor and ESC at some point. Here's some new video:


I can keep it in the air indefinitely in a small room, as long as the battery is above 7.4V. Below 7.4V, the roll axis still gets soft and it's hard to not crash into things. So for now I live with flying just a bit more than half the battery capacity. Even Charles can kinda fly it now. So it must be a little more stable.

The two hardest parts about flying it are maintaining altitude and remembering which way it's pointed. While I think you can learn to deal with both of these, I would like it to be easy enough for anyone to pick up and fly. I have, waiting to be installed, a sonar module that can be used for closed-loop altitude control. Then, the stick would control a climb rate or descent rate, but with no input it would hold altitude and you can focus on flying the rotational axes. I also have yet to implement the magnetometer on the new IMU, which can be useful for holding heading so you don't have to deal with yaw.

I really shouldn't be spending this much time on quadrotors, though. I'm pretty sure I had other things I was supposed to be working on. On that note...

......

Friday, December 23, 2011

More Sensorless

I'm still tweaking the sensorless routine for Pneu Scooter. The software framework for sensorless sinusoidal commutation and field-oriented current control is set, and now I am playing with the different parameters to see if they have the effects I think they should.

First, I hypothesized in the last post that the positive relationship between current and flux estimator offset (with respect to the Hall effect sensors), seen here, was due to underestimated inductance. At high current, the rotor electrical angle predicted by the flux estimator would lead the angle interpolated from the Hall effect sensors, which I trust to be more accurate. Based on this figure, if the inductance parameter is too low, the [-IL] vector will be too short and the estimated flux vector will lead the actual flux vector at high current. 

To test this, I changed only the L parameter in the sensorless code definitions, from 200μH to 300μH, leaving all other settings the same. After another 15-minute outdoor test drive, I plotted the flux estimator offset as a function of current once again. Here it is with the old data for comparison:


The effect is exactly what I thought it would be, flattening out the slope so that the offset is constant (near zero) though the entire range of load currents. I may have even gone a bit too far, creating a very slightly negative slope. But now I know that the inductance parameter has as predictable effect. The lead induced by using an inductance parameter that was 33% too low was about 20º electrical at maximum current. The error sensitivity is easy to predict using the vectors in this figure, but I will spare you the analysis in this post.

A closed-loop flux observer, which some day in the future I will certainly try out, would seek to minimize the effect of an over- or under-estimated inductance parameter. The ultimate goal would be plug-and-play sensorless that adapts to any motor on the fly. But for now, I can live with nicely-behaved dependencies like this. Though, without the parallel-processed Hall effect sensor data, I would be lost as to how to characterize any of it.

I also tried out the sensorless controller on a different motor:


The thing clamped to the table is Kitmotter, a demonstration motor with very similar characteristics to Pneu Scooter's wheel motor. They have virtually the same measured inductance. Kitmotter has a higher resistance, which I modified in the sensorless code definitions for this test. It also has a lower torque constant, which is not an explicit parameter in this sensorless algorithm. What it does mean, though, is that the flux magnitude should be lower:


And in fact it is, by a small amount. It's also interesting to see that the general form of the flux estimates is very similar for both motors. In particular, the gap between about 200º and 210º shows up in both cases. This eliminates the possibility that the gap is caused by some asymmetry in one motor's winding. It could be current sensor asymmetry, though.

Kitmotter also accidentally allowed me to test the fast overcurrent shutdown. The dangling mess of alligator clips seen above was not the best idea, and when two of the phase outputs shorted to each other, causing a large spark, the controller shut down properly and gave an overcurrent fault. No dead FET.

The next parameter I want to tweak is the low-pass filter time constant, which affects the low speed performance of the sensorless control. I mentioned that the low-pass filter causes the flux estimator to lead the true angle at low speeds, and showed the offset as a function of speed. Here it is again, but in pseudo-3D:

Is this nauseating?
Below 200rpm, the flux estimator angle is greater than the Hall effect sensor angle (trusted to be the true electrical angle). This causes the data, which should lie on the x = y plane, to slope off to the left at low speeds. Making the low-pass filter time constant longer should flatten out the plane and improve the low-speed torque. A lower "valid data" speed for switching to sensorless control will make start-up ramping, when I get around to that, just a bit easier.

I'm also worried about high-speed operation, which was the problem that magically disappeared when I made several code improvements. But, I'm still working with relatively slow motors, having commutation frequencies of 200Hz or less. I'm interested to see how things change (probably for the worse) when I try to run a non-direct-drive (indirect-drive?) motor like that of tinyKart, which can hit 750Hz or more.

More testing to come...

Sunday, December 18, 2011

Sensorless Pneu Scooter: Part 2

Pneu Scooter is now Sensorless Pneu Scooter! (Which means I can ride it again.)

This is the follow-up to Part 1: Where I make my code much fancier. Most of the work of the past two weeks went into setting up a new timing structure for the control code, which is summarized by this graphic. The controller has a fast loop, which runs at 15.625kHz, and a slow loop, which runs at just under 1kHz. The slow loop handles the computationally-burdensome Field-Oriented Control (FOC) calculations, and hasn't changed since I first implemented it on B.W.D. long ago. The concept of FOC is summarized in these two posts, and is shown in this, the first of many neon graphics I color-inverted for this post:


FOC seeks to keep stator current, I, in phase with back EMF, E, which is equivalent to saying that it keeps stator flux 90º ahead of rotor flux. This produces the most torque per amp. To keep the current and back EMF in phase, the voltage, V, is phase-advanced by the controller to counteract the effect of inductance. 

All these quantities are treated as vectors (really, the magnitude and relative phase of a set of balanced three-phase sine waves). The coordinate system is aligned with the rotor's magnetic field (hence, "field-oriented") and the axis on which the rotor flux is at a maximum is called the Direct (D) Axis. The Quadrature (Q) Axis leads the D-Axis by 90º electrical in the direction of rotation.

Because the coordinate system is locked to and spinning with the rotor, the position of the rotor must be known with good resolution for any of this to work. Previously, I used Hall effect sensors and time-based interpolation to derive the position. But, as the name would imply, Sensorless Pneu Scooter needs new tricks that do not rely on Hall effect sensors. To obtain the rotor position, the fast loop estimates flux on all three phases. The flux estimator I chose to start with is a very simple one:


It's an "open-loop" flux observer that derives the rotor flux linkage from measured currents, driven voltages, and a good estimate of the motor's resistance, R, and inductance, L. The vector version of this flux estimator is shown in the image above. Note that the integral of a given vector is another vector which lags by 90º and is scaled by the angular frequency:


Which brings up another good point: Unlike back EMF, flux does not vary with speed, so the flux estimator should produce a constant magnitude at any speed. As the V and E vectors increase in magnitude, the scaling by ω keeps the integral-form from growing.

The figure above is actually somewhat misleading. For one, the flux estimator doesn't run in the rotating D/Q coordinate system, but rather in the stationary frame, on each of the three phases independently. Also, the estimated flux on each phase is a scalar quantity; it's just the magnitude of the rotor flux seen by that particular motor phase at that particular instant. To derive position from this, I take an unusual approach of watching for flux zero-crossings (with hysteresis) and feeding these transitions to the same interpolation routine that my Hall effect sensors would have gone to.

In this way, the flux estimator is always running in parallel with the Hall effect sensors and control can be given to either one at any point in time. Additionally, they can be compared to each other. So, as I've been test-driving with the sensorless position estimate in control, I've been logging data from both. Cue the rest of the neon graph sequence:


All of the the data in this post was recorded during a five-minute outdoor test drive with the sensorless position estimate running the field-oriented control. The top plot above shows effective regulation of Q-Axis current to follow the throttle command, and the D-Axis current being held close to zero. The bottom plot shows the speed estimates produced by both the Hall effect sensors and the flux estimator. (Both calculate speed by measuring the time for one full period of rotor flux.) They are nearly identical at all speeds, including below 100rpm.

Speed is not sufficient for control, though; the flux estimator needs to be able to accurately derive the rotor position. Comparing the rotor position derived by the flux estimator to that of the Hall effect sensors reveals the following:


The ideal case would be a straight line with a slope of one, indicating perfect agreement between the flux estimator and the Hall effect sensors. There is a good deal of noise in the position estimate, but the general 1:1 correlation is there. The flux estimator angle leads the Hall effect sensor angle slightly, shifting the entire line upwards by about 15º. This is not necessarily the fault of the flux estimator; it could be interpreted as the Hall effect sensors being about 15º behind neutral timing.

To get more of a feel for the source of the noise around the 1:1 line, I plotted the relative phase offset between the flux estimator's angle and the Hall effect sensor angle as a function of a few other quantities. First, speed:


There are several interesting bits of information in this plot:
  1. At any speed, the band of uncertainty in the position estimate is still about 30º. Therefore, there must be factors other than speed which cause offset in the position estimate.
  2. The bulk shift of 15º (flux estimator leading Hall effect sensors) is clear in this plot too.
  3. At low speeds, the flux estimator leads the Hall effect sensors even more. This one is easy to explain. Instead of a pure integrator, I implemented a low-pass filter on (V-IR) as part of the flux esimator:
Pure integrator.
Low-pass filter.
The low-pass filter is used to keep the integral from drifting away. It's combined with a gain of τ, the filter time constant, so that at high frequencies it looks like a pure integrator. But at low frequencies, it has less than the -90º of phase a pure integrator would give:


At the corner frequency I chose for the low-pass filter, 0.053s, the low-pass filter causes the flux estimator to lead significantly at low speeds. The blue line in the offset vs. speed plot above is the theoretical lead induced by the low-pass filter. Setting the filter time constant to be longer would push the speed at which lead becomes significant down lower. Since the data seems to clearly show this effect, I would like to run some tests where all I change is the low-pass filter time constant. Obviously a longer time constant would be better for low speed operation. Integral drift might hurt the performance overall, though.

I also plotted the offset between the flux estimator angle and the Hall effect sensor angle as a function of load (Q-Axis current):


Here, another clear trend was revealed: the flux estimator lead increases with current. My hypothesis on this one is that the inductance estimate is low. In the first graphic of this post, the -IL vector would be too short if L were underestimated. This would cause the estimated flux to be somewhere in the upper-right quadrant, leading the true flux, which is on the D-Axis. Again, since the data shows a very clear trend, I would like to run some test where I vary only the inductance parameter to see if I can flatten out this line. 

This particular dependency (position error as a function of load) is one that I think can be avoided as I pursue more advanced sensorless algorithms. A "closed-loop" flux observer would be able to more readily handle misidentified motor parameters by using feedback to adapt the motor model or negate some of the effects of the misidentified parameter. Another valid option is to have the motor parameters self-calibrate, either at power-on or dynamically as it runs.

Lastly, my favorite graph of all:


I had the data spit back the actual flux estimate on Phase A along with all the phase currents. Plotting the Phase A flux as a function of the flux estimator's angle reveals a very nice sinusoidal flux that peaks at 180º and has an amplitude of about 15-17mWb. Not coincidentally, this is close to 1/7th of the motor's per-phase back EMF constant of 0.105V/(rad/s) = 0.105Wb. (The motor has seven pole pairs.)

The three phase currents are also plotted and are bounded by nice 40A sine waves, representing maximum positive throttle. Phase A's current (yellow) leads Phase A's flux (white) by about 90º, as it should if the field-oriented control is doing its job.There's a very interesting gap in the flux estimate angle just before 210º, which is also seen as a "staircase" effect in the flux estimator angle vs. Hall effect sensor angle plot. I still haven't tracked this one down or formed a theory about it yet, but this convinces me that it's an issue inherent to the flux estimate, since this plot has nothing to do with the Hall effect sensors.

Altogether, this "simple" sensorless routine has been working very well since I modified the controller timing. I can't say I understand exactly why (or even if) the changes I made to the loop timing caused it to start working, but I'm happy that it's now producing useful data and that I have new tests to try out. 

I'm even more happy that my Pneu Scooter riding ban can be lifted since it's now capable of propelling itself in 100% sensorless mode.