Pages

December 31, 2017

In an out-of-character move for me, this post has no actual hardware in it. Sorry to to disappoint you, dear readers.

This a simple but interesting controls problem relevant to a project I'm working on:

Problem: How do you move a thing from somewhere (point A) to somewhere else (point B) in the shortest possible amount of time, and stop dead on point B? Elsewhere, you might see this called "minimum time control", "time optimal control", or something similar.

Let's say the thing is a mass \(M\), and we can apply a force \(F\) to it, and the problem is 1-D: the mass moves along a line.

Ignoring the shortest possible time part of the question for a second, the obvious linear control approach to this is a PD controller. If the controller gains are chosen so that the closed-loop response isn't underdamped, \(M\) will converge to B without ever overshooting it. By cranking up the gains, it will converge faster and faster, assuming the system is perfect (i.e. it's a perfect mass with no other dynamics, and you can instantaneously take perfect measurements and apply perfect force. Not that these are realistic assumptions).

Here's what that looks like, with gains chosen such that all the closed-loop responses are critically damped. The legend shows the closed loop natural frequency. As that increases, response gets faster and faster, but the force required also increases.

And here's an animation of the performance of the ideal PD controller, for the Wn = 2 case. The box is the mass, and the red arrow is the force applied to it.

Now add in one simple constraint: Limit to how big \(F\) can be. Here's how those PD controllers perform on the otherwise ideal linear system. Now they all start off the same, since they saturate the force limit. And though the Wn = 10 case is higher gain, by most metrics its step response looks worse than the others. So why not just pick the best looking one (probably red or yellow in this case), and run with those gains?

Here's how they look taking a smaller position step: Now the high-gain green curve has the best performance, because the controllers are barely saturating the force limit, and still behaving mostly linearly. So with this linear control strategy, there isn't one single control law that gives identical performance for different step sizes.

Fortunately, in this limited-force case there's a very intuitive answer for the original question of How to get from point A to point B as fast as possible and come to a complete stop. Clearly, you should apply maximum force for as long as possible while accelerating, then part way there, apply maximum force in the other direction to come to a stop as quickly as possible.

Here's what that looks like:

So how do you write down the control law that gives you this behavior for any starting position, starting velocity, and step size? It turns out to be pretty straight forwards by taking a look at the system in the phase plane.

This system has 2 states, position \(x\) and velocity \(\dot{x}\). The phase plane plot is just a parametric plot of \(x(t)\) and \(\dot{x}(t)\). The goal of the controller is to bring the mass back to the origin, i.e. position = 0 and velocity = 0. To figure out the control law, work backwards from the origin: First, what happens when a constant force \(F\) or \(-F\) is applied to the mass? Starting with \(F = Ma\), and the stopped-at-the-origin initial conditions \(x = 0\) , \(\dot{x} = 0\) , we can integrate to get velocity, and again to get position, giving the result \(\dot{x} = \frac{Ft}{M}\) , and \(x = \frac{Ft^{2}}{2M}\) . To plot these trajectories in the phase plane, we need to get rid of the time variable, so we get \(\dot{x}\) as a function of \(x\). This gives \(\dot{x} = \sqrt{\frac{2Fx}{M}}\), so the resulting solution curves are sideways parabolas, expanding to the left for \(-F\) and to the right for \(F\).

The following plot shows these two trajectories, with arrows indicating the direction of motion. The orange trajectory corresponds to negative force, and the blue trajectory positive force. The bold areas of the trajectories are the paths to the origin - i.e., if the mass is on one of these trajectories, it will reach the origin.

The bold curves form a switching surface, and nicely divide the state space into two halves. When the mass is to the left of/below the switching surface, the control action should be to apply positive force. This will move the mass such that it reaches the bold orange curve. Then, once it has reached the orange curve, the controller should switch to applying maximum negative force, so that it follows the orange curve and stops at the origin. Similarly, if the mass starts to the right of/above the curve, the controller should apply maximum negative force, until the state reaches the bold blue curve. Then it should switch to applying maximum positive force, until the state reaches the origin.

Here's a shaded version of the above plot, indicating those two regions. Where it's shaded orange, the controller should apply negative force, and where it's shaded blue, the controller should apply positive force.

The explicit control law that implements this is:
$$F = F_{max}\cdot sgn(-F_{max}x - \frac{M\dot{x}|\dot{x}|}{2})$$
Which you can get by solving the equations above for \(F\), and carefully paying attention to signs. And to get to some point other than the origin, just replace the \(x\) on the right side with \(x-x_{desired}\).

A probably more intuitive way to get the same result is to look at energy. The kinetic energy stored in the mass is \(\frac{1}{2}M\dot{x}^{2}\). The energy the controller can remove from the mass before it reaches the origin is the integral of force over distance, or in this case just \(F_{max}x\). So the controller should switch at the point where the energy it can remove is equal to the kinetic energy stored in the mass - as in, the "stopping distance" is the same as the distance to the origin. This gives you the same control law as before.

The phase-plane version of the previous animation looks like this. The trajectory the mass follows is shown in red, the blue parabola shows the trajectory it starts out on, with positive force, and once it hits the orange trajectory it switches to negative force, to to stop at the desired position.

So that's pretty cool. But what if there's a different limitation than a maximum force? For example, say the mass is driven by a real actuator like a DC motor, and there is a maximum voltage \(V\) that can be applied to the motor terminals.

Ignoring inductance, the DC motor's performance is described by the following equations:

$$V = Ri + K_{t}\omega$$

$$\tau = K_{t}i$$

Where \(i\) is the current through the motor, \(R\) is the motor's resistance, \(K_{t}\) is the motor's torque constant, \(\omega\) is the motor's angular velocity, and \(\tau\) is torque.

Now the controller is voltage limited, rather than force or torque limited. But we can take the same phase-plane view of the system and derive the switching surface which goes to the origin as fast as possible.

Before actually solving for the switching surface, I found it helpful to use a little intuition to predict what I'd expect the constant-voltage solution curves to look like. Most obviously the maximum voltage constraint imposes a speed constraint - the no-load speed of the motor. So in the first and third quadrants, velocity should level off to a value of \(\omega =\frac{V}{K_{t}}\).

For the second and fourth quadrant, it's not intuitively clear what the exact behavior should be, but as speed increases, force also increases, so the curve should slope more steeply than the constant-force parabola. Around the origin, where the motor is at low speed and behaves mostly like a resistor, the curves should look more or less like sideways parabolas, like the constant-force case.

Here's a sketch of what I thought it would look like:

To find the new switching surface, like before, write down the dynamics with a constant voltage applied, and calculate out the solution curves. To keep notation consistant with the constant force example, here \(F = \tau\), \(\dot{x} = \omega\).

November 2, 2017

To better characterize the big kart motor, I threw together a stall torque test stand. This was actually several months ago, but I'm just now getting around to documenting things.

The stall-tester consists of a precision-length stick attached to the motor shaft, and a 50 kg load cell on the end of the stick. I added ball joints on each end of the load cell, to ensure that it is in pure tension or compression.

To visualize and log the data, I made a pared-down version of my dyno control gui:

The basic goal of testing was to brute-force determine the motor torque vs D and Q current. Ideally, torque should be easy to calculate from the D and Q axis inductances and permanent magnet flux linkage, by the classic torque equation \(\tau =\frac{3}{2}\cdot p \cdot i_{q}(\lambda_{pm}+(L_{d} - L_{q})i_{d})\). But we're driving the motor hard enough that it saturates fairly substantially. This changes both the inductances and flux linkage, and makes analytically solving for torque (and modeling the motor in general, without FEA) challenging. Using our various motor-models, we've gotten decent results, but a bit of low-end torque has been eluding us.

To take the measurements, we swept current phase angle from pi/2 to pi, and current magnitude from 0 to 180A. At each phase setpoint, current was ramped up from zero to 180 over about 2 seconds. Torque was logged from the load cell, and D and Q axis currents were logged over serial from the motor controller.

The time-series data looked like this:

After a little processing (3-sample median filter to throw out some single-sample glitches from the strain gauge amplifier, and torque-constant sanity check to throw away points between each ramp), the 3-D scatter plot of the points looked like this:

A problem I seem to run into all the time is trying to fit a smooth surface to time-series data. In the past I've usually used MATLAB's griddata to do it like this, but this approach has a number of annoying problems, like that it can't extrapolate, and the surface generally ends up kind of "lumpy". Fortunately, I finally found an excellent script, gridfit, which worked beautifully for this problem.

Finding the phase that produces the most torque for each current magnitude, you get the following trajectory. As you'd expect, at low currents most of the current is on the Q-axis (phase equal to pi/2), and it shifts onto the D axis as current increases.

Superimposed on top of the surface of all the data, the trajectory looks like this. It's pretty coarse looking at low currents, but that part isn't too important anyway.

This is the maximum torque per amp (MTPA) trajectory, which is what the motor should operate along until it reaches base speed and you no longer have enough voltage to operate along the trajectory.

Excitingly, the motor seems like it still has plenty of torque capability left, even at 180 amps. Torque constant is dropping off somewhat, but it looks like breaking 60 N-m should be no problem. On one motor we should be able to hit just over a G of acceleration, and with 2 motors, easily break traction on command.

October 26, 2017

Brief Introduction:Go read Bayley's introduction. TL:DR: Racing kart frame with hybrid car parts based powertrain and custom motor control. We've done a lot of motor modeling, characterization, and control over the last year, and the go kart is getting quite performant. But we're not quite squeezing all the possible performance out of the KIA HSGs yet. And the kart's going to get a second motor.

Sprockets
Right now the go kart uses Gates Micro-V belts, because the HSG's come with those pulleys pre-attached. However, we're driving the motors a fair bit harder than the car they came from did. The v-belts, even with a huge amount of tension, slip at ~45 N-m of torque, and we've been able to hit nearly 60 N-m at 180 phase amps. So we're switching the kart over to Gates PolyChain GT Carbon belts, which are basically the best synchronous belts you can get. The inch wide Micro-V belt is getting replaced with a 12mm wide, 8mm pitch PolyChain belt, which should be good for substantially more torque.

You can download CAD models of the sprockets from Gates, but, as they warn you on the website, the tooth geometry of the sprockets is not actually accurate, since the tooth profile is proprietary. My first plan was to try to figure out the tooth profiles from the patents (1, 2), but it turns out if you just ask nicely, Gates will send you the tooth profile drawings drawings for the sprockets you want.

We went for a reduction of 4:1, with a 20 tooth motor sprocket and an 80 tooth sprocket on the axle. The big sprockets were too big to fit on the MITERS CNC mill, so I did them on my lab's Haas SMM. For fun I GoPro'd the entire machining process for one of them:

Getting a good finish on the teeth required many very shallow passes - the minimum curvature radius in the grooves is very close to matching the 3mm end mill I was using, so I had to go really slowly to avoid chatter at the high-engagement areas.

The motor-side sprocket was done on the MITERS CNC. I still need to broach the keyway in it, and turn a clamping hub for the big sprocket.

Here's one of them partially installed on the go kart. Still needs a hub to clamp the axle.

So low profile!

Back to the subject of squeezing all the performance out of the KIA HSG, next kart post will be about a stall test stand we through together for motor characterization.

The motor had basically no shaft to speak of - it has a left-hand threaded stud on the end, and 2 flats which engage with a stamped #25 chain sprocket. Since there wasn't enough shaft to grab onto with a collet, I made a "terrorist coupling", with three steel pins that engage with the sprocket teeth:

I plugged the analog output of the talk-to-everything board into the throttle connector so I could sweep throttle commands in an automated way. It was a little tricky to tune the throttle ranges, because of how the e-bike controller works. As far as I can tell, the throttle commands voltage, not current, until you hit the DC bus current limit. That means that at low-speed, the torque vs. throttle position curve is really steep: very small changes in throttle position mean huge changes in torque, thanks to the voltage-mode control. The motor is also capable of slightly more than the ~10 N-m the dyno is good for, so I had to carefully tune the throttle range so that the dyno could regulate speed.

Dyno-ing in progress:

Initially I put the dyno in inertia-simulation mode, and did a spin-up using a hand held twist throttle to see what the full-throttle performance was like. Data below ~1200 RPM was cropped because it was pretty noisy. This whole spin-up only lasted a few seconds so the plot is little rough. The motor is legitimately good for almost 2000 mechanical watts. Surprising given the 1500 watt rating on the motor controller. Efficiency is rather poor, topping out at around 80%.

The high-speed end of the torque curve is a little bit strange looking, and I don't have a good explanation as to why. Probably something to do with the internal hall sensors and commutation scheme of the controller.

After figuring out what throttle ranges worked at a range of speeds, I did a full automated sweep of speeds and throttle setpoints to get the full operating maps. Again, the full data is in the database. The e-bike controller wasn't set up for regen, so all the maps are 1st quadrant only.

September 17, 2017

I finished putting together a housing for a single driver. CNC milled aluminum goodness:

The machining was done in two operations. All the fancy 3d profiling was done with the part flipped over and held in soft jaws.

Front side:

Back side, before gluing in the magnets:

Here's the assembled driver. I'm using a cheap off-the-shelf pair of earpads.

This version sounded pretty terrible. The pcbway flex-pcb was way too thick, making it both too heavy and too stiff. The response was way to heavy at low frequencies, with a terrible ~100 hz resonance, and there were all sorts of weird notches in the frequency response. But it did make sound, so that was a good start.

I ordered some Pyralux samples from Dupont, and tried etching my own drivers. I first tried with the LF7012R variety, which has 1/2 oz copper, 13 micron kapton layer, and 13 micron adhesive. I measured the total thickness to be 45 microns where there was copper, and ~25 microns without copper, which is half the thickness of the pcbway material. At the time I thought that was their thinnest material, but I hadn't looked through their datasheets carefully enough. The AC 091200EV material has 1/4 oz copper, 12 micron kapton, and no adhesive layer, so it should be in total something like 20-25 microns thick with copper, and 12 without. I've got a sample of that on the way, and will report back when I've etched some.

After a few tries I figured out a pretty good process for etching the pyralux. I did the classic toner transfer and ferric chloride etching method. The etching part worked really well, but doing the toner transfer proved finicky. It took a few tries with a few different laser printers to get the process to work.

Etched:

Assembled into the driver:

This one sounds much, much better, although there's definitely still a little weirdness going on. Listening to it plugged into a function generator and sweeping frequencies, the low-frequency resonance is gone, and over all it's much flatter, but there are still some strange notches in the response. Unfortunately I don't have a good setup for quantifying the frequency response at the moment, but it's definitely a little off right now. But it's getting better. I'm hopeful that the even thinner flex pcb material will improve the situation further. Reducing tension in the membrane might help as well.

September 1, 2017

Now that I have a good process for collecting data on the motor dynamometer, and the appropriate scripts for quickly processing the data, I put up a page dedicated to motor dyno data. You can also find it in the navigation bar up top. There's only one motor two motors on it right now, but it will slowly get populated as I get a chance to run more tests.

I'm not sure if anyone else will actually find this useful, but it seems like there's a growing number of people doing legitimate robotics and other cool stuff with hobby-grade motors, so I might as well share what data I've got.

Instead of a voicecoil actuator which drives a stiff cone back and forth, like a conventional speaker driver, a thin membrane with conductive traces sandwiched within a funny magnet arrangement moves back and forth.

image credit: innerfidelity.com

I won't try to argue that this is "better" than a conventional driver in any way, because frankly I don't care. It is cool, though, and also a perfect excuse to send out for some flex-PCB's, which my go-to PCB vendor, PCBWay, recently started offering for quite reasonable prices

I started out by playing with magnet arrangements in FEMM, to see how sensitive this arrangement was to changes in magnet dimensions and spacing, and I ended up here:

This uses 1/8" square N52 magnets, with a 2mm airgap, and 9mm pitch. The array 2 inches long (into the page), and each bar is a pair of 1/8" x 1/8" x 1" magnets, which are cheaply available on ebay:

Here's the tangential flux density (which is the normal force producing component) in the middle of the air gap:

Doubling the depth of the magnets got it up to .5T peak (the path around the magnet gets longer, so less flux leaks through it), but I decided it wasn't worth the more than double magnet cost (they are harder to find magnetized through the small face).

Here's what the actual flex pcb coil looks like. The traces go up and down in the regions of ±.35T field in the plot above. This was very unpleasant to draw in Eagle. 0.25mm trace width with .5mm pitch. PCBWay claims to be able to do .1mm between traces, but I didn't want to push it.

For the actual PCB, I chose single layer, 75µm flexible adhesiveless base, .1mm FPC thickness, no solder mask, and 1/3 oz copper, to keep the board as light and flexible as possible. Maybe a 2-sided trace would have been better, for a higher ratio of conductor to pcb material, but this whole thing is an experiment anyway.

Front: A few of them came out a little wrinkly. Not sure why, or if it will cause problems. In retrospect, it might have been a good idea to put a thick copper trace around the outside of the whole board, to stiffen up the perimeter. Coil resistance came out to 16 ohms.

Back:

I CNC milled half of a housing out of some Delrin:

Glued in the magnets:

There's a lip on the housing that will apply some tension to the flex pcb to hold it flat, once both halves of the housing are made, but it was secure enough for some testing with only one half.

It actually works even with only half of the magnet arrangement - half the magnet gets you half the flux density. It should produce the same volume on roughly half the power, once the whole thing is assembled.

I'll reserve qualitative judgement until the whole thing is assembled, but from the brief testing I've done on this single partially assembled driver, it seems promising.