Archive for the 'Motor Controllers' Category

 

RageBridge 2: The Indiegogo Campaign

Aug 27, 2015 in Motor Controllers

Back my kickstarter.

- Charles in every ironic statement ever

Today, that statement ceases to be ironic (or perhaps, is even MORE ironic). For I’m proud to announce the RAGEBRIDGE 2 INGIEGOGO CAMPAIGN!

You’ve been following the story of RageBridge 2 behind the scenes here, so now you can support its production and be first in line to get them! Or, perhaps, run far away because you know how derpy the development process is!

The link to the campaign is:

 

After the campaign has been fulfilled, RageBridge2 will be available on e0designs.com.

RageBridge 2: The Rage Awakens

Aug 24, 2015 in Motor Controllers

At one point in time, I think I was working on some kind of motor controller. In fact, I might have sold a few here or there! And some of them might even still be working!

It’s been six months since I had an unexpected robot baby and had to drop RageBridge development efforts. But I’m glad to say that much progress has been made, and the first batch of beta testing units is almost ready for the SECOND Somewhat-annual RageBridge Breeding Program. We pick up the story again in June…

Here are some revision 3 boards under construction. Revision 2 was slated for immediately after Motorama 2015, but I discovered enough stupid board bugs on it to warrant skipping directly to revision 3. Namely, there were some incorrectly assigned pins to the ATMega chip and the current potentiometer was backwards. There were a few other trace optimizations made.

I use a small soldering tip – a Weller NT1 – to do everything but the “big power” components, then switch to a big chisel tip iron with a Weller LTD tip to restrain the FETs and other heat-grubbing parts, including the main capacitors. The gate drive chips, in ever-convenient TSSOP package, have their center thermal pads heat gun reflowed first, then the legs are soldered individually.

Two test units of Revision 3 built out and ready for abuse. At this point in development, the firmware was left in an R/C-only, hacked together mode. I began refactoring code I’d written “just to get by” for Motorama. At the same time, I started testing the boards using some standby motors:

Here’s Rage2 being tested on some motors it’s meant to drive – something roughly DeWalt sized, perhaps, and a scooter motor. I’m finding out some critical characteristics of the system, such as “Will my MOSFETS consume themselves?” (the answer is some times), and “Will it reset or stumble because of noise?”

Unfortunately, the answer to the last one is yes, and probably contributed to the Revision 1 unit that died at Motorama. With any hard reversing or command stepping – moments when the current draw increases sharply – the controller would reset, brown out, or exhibit other forms of bad behavior.

Uh oh. I’d been through this before, with RageBridge The Original, so I immediately checked the usual suspects. Poor ground routing. Placing capacitors in the wrong place such that they broke the grounding discipline. High power switching next to vulnerable signal traces, and so on. In the world of power electronics, where you put things is often more important than what you put there.

That’s my 5V logic power line, measured at the output of the power converter, being punched by nearly 1Vpp transients.

The brown wires are scoping points where I’d pay attention to the behavior of the system. The two blue wires were intended to jump the logic power input – which, up until this point, had been taken from the very end of the power plane feeding four gigantic MOSFETs – and gives it its own connection directly at the bus capacitors. It’s kind of like making a reverse Kelvin connection for the logic power.

As I suspected, I made a “cap derp”. The Allegro A3941 datasheet is not very clear (to me) about what it considered signal ground or power ground. In my view, it could stand to be a lot more descriptive about which pins need to be considered “dirty” – directly connected to switching power, so they should under no circumstances be routed to logic/analog ground. Instead, they choose to distinguish between “quiet ground” – what I’d call the logic ground – and “controller ground” vs. “power ground”.

I think I made a mistake here in routing the chip’s main bypass power – which is connected to VDD (battery positive) and “controller ground” – which I interpreted as logic ground for this board, but really should not be. I decided to try jumping this capacitor directly to the chip’s “ground” pin instead of taking it through the ground plane. I did the same for several other capacitors indicated on page 18 of the datasheet, forcing their “ground” sides to avoid the logic ground plane and basically making the only access point of the chip to the logic ground plane at its own ground pin (instead of in a few places).

These two hacks together basically resolved the resetting problem. I could no longer get the DeWalt – a very “dirty” motor, electrically speaking, to reset the board even with current limits off.

Once again – not what you put on the board, but where you put it.

With that cluster of issues resolved, I pushed a “revision 4″ with a few other changes like trace optimizations under the microcontroller, separating everything into a “tree” topology as much as I could – no longer was the 5V supply for the chip coming from 2 different places (!). All the microcontroller’s grounds were gathered and tethered to the plane at 1 location. I also separated the 5V line into a “clean” and “dirty” line – the dirty one is the one fed out to the headers, leaving the “clean” line, which is tapped after the final LC filter stage, to only the microcontroller and current sensors.

Some illustrations of trace optimization for the microcontroller region.

A week and some later, Revision 4 appears…

Okay, so I still had to put them together. This is what the board looks like.

Yes, on the last revision, I forgot to hit “Black LPI please!” and so it was green. I shall not make that mistake again.

This board refused to power on at all. No matter what, the 5V rail never came on, and instead hovered around a few tens of millivolts. What gives? How did I take that many steps back!?

I have a tendency to resort to “explosion debuggin” quickly. That means just running unlimited amps at a low voltage through what is shorted, and seeing what begins smoking first. Every motor controller I’ve made save for LOLrioKart’s controller has been “explosion debugged” at least once. And that’s only because I was running low on the large “brick” MOSFETs.

I took one of the spare boards and ran 10 amps through the 5V rail. Amazingly enough, nothing started smoking, indicating something very low impedance and near to the source. The board did get suspiciously warm in one corner, so it was under the microscope…

Oh my goodness.

It’s a left over stub of a trace that I thought I had erased, but in fact was still there, bridging my 5V straight to ground.

So you might be thinking… But Charles, wouldn’t DRC have caught this? Well yes, but my boards generate so many DRC errors (on the order of 1500+) I just ignore them all and use freedfm.com to check for the most obvious stupidity, but it doesn’t tell one net from another!

This is really just telling me I should set up design rules to actually conform to how I design boards ಠ________ಠ

Well, I suppose I’m glad I don’t have to do this for 250 boards.

A revision 4 board being absolutely hammered to death by the “end boss” of motors – the AM Equipment “D-pack” motor, a marine diesel engine starter motor that, many years ago, drove heavy- and superheavyweight Battlebots with contactor control because no ESCs existed which were hardcore enough to handle them. They can easily draw over 1,000 amps at 12 volts, and their no-load current alone is 30 to 40 amps.

And RageBridge passed the test spectacularly. Check out the “abuse video” here, featuring some other motors while I’m at it.

This is not to imply Rage can control 1,000 amp motors, but that the current limiting algorithm is robust. If I held onto the throttle for longer, the FETs would have unsoldered themselves and attempted to escape. It’s ultimately still thermally limited.

Some more brown fungus sprouts to double check that the noise demon has been exorcised enough within the performance envelope of the controller to not be a nuisance. Notice how I didn’t say eliminated. There’s no such thing in motor controller design.

The story, however, doesn’t end there. You know this to be true because if it did, I would be taking orders right now.

Ever since one of the late models of RageBridge 1 prototype, it has not wanted to operate above about 33 volts. The 5V converter would just shut off and enter what seemed to be a discontinuous mode, or some other mode where the frequency of switching was cut back drastically. Here’s an example, looking at the output pin of the converter BEFORE the inductor:

That’s normal – 24 volts in, 5 volts out. As soon as the voltage crests about 31-32 volts, this happens:

Less than 1 volt out! The ringing indicates that the buck converter is operating in discontinuous mode, but to enter it so quickly and suddenly? Something was going on. During this time, the LM2594 chip itself also got hot quickly, which is not advertised or documented behavior in discontinuous mode.

This fact has prevented RageBridge from operating above 30V reliably, forcing me to rescind the “up to 36V nominal” specification, which fortunately only affected a very small number of users.

So what gives? The LM2594HVM chip is supposed to run up to 60 volts. All my parts in that part of the circuit are 50V on the input, so it ought to at least be fine with that.

I ended up spending the night trying all sorts of stupid things, like making these inductor sculptures. Perhaps the inductance was still a little on the low side? After all, my HV requirements are still in the “coffin corner” of the LM2594 inductor selecton chart.

Nothing changed.

So what has been a constant factor in these boards? The LM2594 power converter design, which has been more or less copy and pasted from older schematics without change. However, everyone else seems to use them fine, including Shane. Since we talk about motor controllers like normal 20-something cosmopolitan guys talk about craft beers and beard maintenance (I have nothing in that department), I went to him for some more perspective.

Umm… let’s take a look at the schematic.

That part number – the MBR120VLSFT3G, is a 20V, 1A Schottky diode. In fact, I found the exact version of RageBridge 1 where I elected to put this diode in: it was when I switched back from the LT3433 buck-boost converter and remade the LM2594 circuit from scratch.

This sounds all too familiar.

Anyways, I likely picked that diode to minimize the losses associated with forward voltage, forgetting the fact that the Output pin of the LM2594 is connected to battery voltage periodically. The lesson here is therefore

don’t use 20v diode at 30v it doesn’t work

I shipped 94 of these.

Sounds good. I replaced both of the MBR120VLSFT3G parts with 50v parts – what I used in RageBridge versions long ago, the STP0560Z.

 

Three of the four Revision 4 boards in various stages of construction here.

Undergoing a little more stress testing here, now with the D-pack hooked up to a…. leftover propeller from the GLP electric boat class. I wanted a bit more viscous load such that it can draw more amps at higher duty cycles, as well as have a up to 950% greater chance of decapitation.

What else is new? After validating R/C mode, I used the same output driving kernel to make the “EV mode” a lot of you have been craving. I made the signal processing code as modular and functional block-like as possible, sacrificing some speed for the ability to pipe whatever garbage signal into it I please.

Analog mode has two submodes :

  • “unmixed”, using a sprung throttle. Single ended, expecting 1 – 4v active range to represent 0 – 100%, with a discrete reverse switch, or
  • “mixed” using 2 analog joystick axes centered at 2.5V, with a 0.1 to 4.9v active range, controlling forward and reverse and turning in one joystick. This was even easier to write, because that’s literally the same code as the R/C mixing mode.

Selecting the “Combine” jumper forces the outputs to act together, creating a single channel controller. Combine and Mix jumpers are mutually exclusive and logic-checked, since it can’t be single and 2 channel at the same time!

This single channel mode is still not entirely reliable. I’ve rebuilt one of the revision 4 boards twice, finally electing to scrap it.

Since it still is paralleling devices at the driver level, if one driver hiccups or lags, it’s easy to cause cross-conduction (a high side and low side FET of the same half-bridge turned on at once) and destroy everything instantly. To counteract this, I’ll likely increase the deadtime – which right now is just barely enough to not cause cross-conduction in one channel mode – to permit more timing slop.

Will from Hypershock paid a visit to help me test single-channel R/C mode on Hypershock itself. Unfortunately, the aforementioned unreliability made this test largely a flop. However, if I improve this reliability, Rage2 in single-channel mode is a great match to a single “short” Ampflow motor, which means it’s not out of the question for use in heavyweight / BattleBots classes.

The price of progress – the twice-rebuilt and scrapped board, along with some more destroyed parts. After a board blows up once, none of the semiconductors are really the same ever again, so I’m not sure why I even bothered with rebuilding.

When one Rage dies, 10 more take its place!

These are “revision 5″ boards – hopefully the last of the revisions, and once assembled, will go out for beta testing. A few are slated for appearance at Dragon Con in 2 weeks, another few are being sent to Power Racing Series competitors to see how it holds up under the rigor of racing. Two completely different loading regimes and set of input & output requirements!

It’s time to order more gate drivers.

Also, here is an interesting picture.

Motorama 2015, Part I: RageBridge v2 Drama

Mar 04, 2015 in Events, Motor Controllers, Überclocker ADVANCE

Let it be known! I shall not update my blog with the Motorama event report until all other MIT-based Motorama competitors update theirs. If you see the Part II, it means I’ve finally been satisfied… or got sick of waiting. I am a man of unyielding principle. For some background on this, through a spectrum of high-pressure sales tactics and peer pressure, an astounding number of new builders are attending; by my estimates, we had 6 totally new entries (and attendant totally new builders). One group elected to complete in the Antweight (1lb) tournament that runs on Friday, something that even I don’t normally do!

As I mentioned last time, none of the bots were in bad shape pre-Motorama, but I’ve been expending immense energy trying to get RageBridge v2 working in time. So why not start with it?

RageBridge v2

Previously in the adventures of RageBridge, I had gotten the bulk of the automatic input-reading organized through a depth of register-diddling greater than what I’ve ever dared do before. If you know me and how I program embedded systems, you know that registers are my most favorite things about the process, and there’s nothing I look forward to more when starting a new microcontroller project than hunting through the thousand-page programming manual and trying to write bit manipulation expressions.

Now, with the retching out of the way, time to try writing an input-taking routine.

One programming challenge for RageBridge v2 was the automatic input-mode detection. I don’t have a rail of jumpers to select the operating mode, and don’t intend on having one since the board is already SLAM-PACKED WITH RAGE!If I can get a reliable automatic input detection, then great! If not, then different firmwares will be made available.

The inputs to decide between are R/C, Serial packets, and analog. On power-up, Rage will take a second to let the inputs stabilize and any partner electronics like receivers and master microcontrollers boot up. Then it will, ever second, check for…

  • Serial buffer byte presence. It will read the first few bytes of the serial buffer and check for 64 or 192 (out of 255, an 8-bit value). These are “idle” commands for left and right motors. This convention is common to several robot controllers that have “simple serial” protocols, where 1 – 127 controls one motor and 128-255 controls the other. If these bytes are present, then assume Serial operation.
  • If there are no valid serial bytes, it will set up the channels 1 and 2 input pins for analog voltage reading. Additionally, it checks if the MIX jumper is set. MIX assumes “joystick mode” where the sticks are centered at 2.5v, so both inputs have to be at this level (within a small deadband) to select that mode. Else, if MIX is not in, it assumes 0-5v with 1-4v as the active range, meaning the signal must be approximately 1V (within a small deadband) to select.
  • If the analog voltages aren’t within the correct band (or it’s pegged to 5v due to the internal pullups) it will initialize the R/C inputs and wait to collect input pulses. Once valid input pulses for both Channels 1 and 2 are received – which must be 1500us +/- a deadband – then the mode is selected. The forced neutral-only mode selection acts as a zero-power-on-startup check too.

This pattern repeats once per second, and the motors will not drive until the appropriate signals are received. Overall, the code looks something like…

I had thought the Analog part would be the most difficult, with the deadband requirement and all. But in fact it was quite easy. With a few test potentiometers and scooter throttle handles, I could get it to reliably pop into Mix or non-mix mode every time. R/C mode proved to be the issue – no matter how much delaying or waiting I had it do, across different receivers even, I couldn’t get R/C mode to work!

As a bit of background, I use the PinchangeInt library to capture R/C pulsewidth signals without having to use the blocking (prevents rest of program from doing anything) pulseIn() function in Arduiono. After writing up a quick R/C only input-taking test program, I noticed something peculiar. All of the inputs read, no matter one channel or the other, simply looked like they were overflowing the variable over and over:

The PinChangeInt interrupt service function takes the difference between the micros() calls of two functions, a rising edge and a falling edge, to get the delta-time. micros() is an unsigned long (32 bit) type, and my R/C pulsewidth variables are signed integers (to be used later in mapping/scaling math). The pattern of values said to me that something was just counting further and further up – not taking the difference at all.

Checking with an oscilloscope confirmed that only one interrupt was being serviced:

I set and cleared a pin on the chip whenever the rising edge or the falling edge interrupt was being triggered. As expected, only one edge appeared. With this test, however, I couldn’t tell if it was the rising or falling edge…

…especially when it seemed that SOME TIMES, both interrupts were working! This shot clearly showed a 1000us pulse width, with two triggers. So what the hell was going on?

By the way, this is the first official usage of the DSO Nano 4 channel digital scope I picked up in Shenzhen! All of the initial debugging shenanigans happened at my desk as a result.

I reached out to the Arduino Forum, where the developer of PinChangeInt had a thread about the library, and learned some interesting facts… namely, that the code should never have worked the way I wrote it in RageBridge 1, and a couple of projects before that.

Well, hmmm.

To clarify without having to read the thread, here’s the difference. I’ve written all my R/C input code in the form of two separate interrupts, RISING and FALLING edge, since 2011 when I first started using the library. The form is similar to this, which was an excerpt from TinyCopter:

The takeaway is that there are two interrupts per pin. Allegedly, this should never have worked!

Yet, compiled in the latest version of Arduino, with the latest version of PinChangeInt, this is what happened. The same kind of nonsense I saw in my initial testing. It seemed to me that only the interrupt I defined last was executing, which contradicted what I saw on the oscilloscope – that some times both interrupt service routines did execute. But I freely admit that this could have been a oscilloscope artifact.

Pictured above is the structure that SHOULD HAVE been used this whole time – a single interrupt service routine, executed whenever the pin CHANGE’d states, and which subsequently read the state of the pin:

As the collected 1500us (approximate) pulsewidth shows, this works fine.

So what gives? Not even the developer knows, apparently! My “two interrupt” form was never supposed to work. I can only assume that between Arduino version 1.0.1 from 2013 andthe current 1.6, and from the first version of the PinChangeInt library I used to the current, that enough changed such that whatever loophole I used was no longer possible.

Either way, with the solution found, I backtracked a little and modified my “two interrupt” program to show which interrupt “won”, so to speak.

I changed the two-interrupt type to only increment or decrement a variable depending on which component was called. As I suspected, the last ISR to be declared always “won”. Here, vol_ch1_pw is being sampled by the main program loop, which shows it always decreasing. if I swapped the declaration order, it would keep increasing.

Whatever. Chalk it up to falling victim to the stochastic nature of Arduino developers, and y’all can lecture me about this is why you always use the programming manual yadda yadda I-don’t-care. It works now:

The PINC & [byte gibberish] portions of each ISR simply “select” the pin to read. Notice how it starts at 0b00000100 – this is because the first two bits represent the first two pins of port C, PC0 and PC1, which are reserved for the current sensors. PC2, PC3, and PC4 are the three channels of input.

With that mystery resolved, the entire automatic mode detection code worked instantly:

Shown above is Analog (unmixed, with a scooter throttle) and R/C mode inputs. Serial inputs are hard to capture on video since it’s one microcontroller talking to another. I assigned different blink patterns for the different modes to help during debugging, but they will be retained for actual operation.

The blink routine itself is interesting by itself. It’s the first time I’ve used an otherwise unused hardware timer (Timer 2 in this case) exclusively as a blinking machine. Here’s the code snippet that makes it work:

The software “prescaler” portion was carried over from my previous different motors controllers’ code, where it was part of the main loop. Either way, something executes that if() and builds up the prescaler variable. After enough times of this happening, it executes the blink part of the code.  Timer 2 was set up during the initialization as a simple counter with a hardware prescaler of 64 from the system clock of 16MHz. This resulted in a counting speed of 250KHz – every 4 microseconds, the count would increment. Left to its own devices, this count would overflow after 256 counts, or 1.024 microseconds. To obtain a clean (to us humans) number, we start the count at 6 (BLINK_INITIAL_VALUE) such that it only has to count 250 times per overflow, giving a clean 1 millisecond timer. With some frills, that’s basically the millis() function re-implemented. I could have included this in the main loop as a call to millis() and it probably would have worked just fine, but I wanted it on a separate interrupt to not hog main program loop time.

Next up is that horrific line of bit manipulation that somehow worked the first time. What this line does is turn PB5 – a.k.a Arduino pin 13, the LED, on and off according to the state of a byte that is being used purely as an 8-bit array, where a 1 means “LED on” and 0 means off. current_blink_pattern is this byte, and it’s assigned whenever the mode changes so the blinking pattern changes.

The line first takes PORTB (the output status of the pins) and masks off PB5. Next, it grabs a copy of current_blink_pattern and shifts it right by some number of bits – basically an array counter that is reset at the bottom every time it exceeds 7. It logical ANDs this with 0×01 to isolate the least sigificant bit (rightmost bit). Finally, it moves this bit leftwards 5 positions to line up with PB5, and jams the two together.

The result is that PB5 is always turned off every cycle but the result of (current_blink_pattern >> blink_index) & 0×01 turns it back on (or leaves it off for this cycle).

With BLINK_INTERVAL set to 100 and the interrupt happening every 1 ms, the result is a 0.1 second blink duration where the LED can on or off. Now, strictly speaking, with 8 bits I can only make 0.8 second-long blink patterns. That’s fine, I don’t care.

Yes, I get all the way to the end of this timing problem and don’t even care that I get clean 1-second long patterns.

One thing that all the scoping to get to the bottom of the interrupt issue was discovering that the input filter capacitance I put on the input pins, which are shared by both analog and digital signalling, was too great.

Ouch, that’s a 10us rise time there. The fall time is about twice as fast, but still bad. I put 4.7nf input caps on the pins, which I guess is too much for another little microcontroller’s pins to drive. I might have to compromise analog signal stability (or implement software filtering at some point) in favor of making the edges sharper.

Once the bizarre library behavior was accounted for, and the automagic mode selector finished, the rest of the code was actually quite easy. In concept, it was just like RageBridge 1, but better implemented.

First, the inputs are sampled and cleaned, with erroneous signals replaced with the “last known good” one and a signal-bad flag set. Next the signal is mapped to an output variable. The output variable is bounded by a maximum increment per loop (ramped), and the result deciphered into PWM + direction and output to the drivers.

Whereas in RageBridge 1 all of this took place messily within 1 loop, I organized it all into procedures so the different modes can be better isolated, even thought hey still acted on global variables:

Of course, right now, I only have the R/C code written.

I did away with the incredible machine that was the mapWithRampingAndDeadband() function of RB1. That was basically broken up to its constituents – the deadband was taken in the input processing stage, and the ramping output mapping just a compare and += or -=.

Soon, it was time to test. Without having made compatible heat sinks yet, I, uhh, created an innovative board clamping system to secure it to the old style Ragebridge 1 heat sinks.

Innovative. That’s the word.

It’s totally not “two binder clips and some electrical tape”.

The test subject was Clocker. By this point, it was Wednesday afternoon, so this was going to be a determinator as to whether or not I try running the new boards at Motorama or not.

During a few on-the-bench tests of pegging the throttle back and forth, I was able to get the board to reset several times. This is not a good sign, as it shows the design has noise coupling into it in some place that is making it all the way to the logic. I have a few suspects, namely the long analog power and ground traces feeding the current sensors and the less than optimal placement of the logic power supply taps from the main board power planes.

My first battle tactic is always to insert capacitance where it doesn’t belong to see where the noise was coming from. For starters, all the 0.1uF logic circuit buffering capacitors were changed to 1uf. Now, strictly speaking, I suppose it was capacitance that was there in RageBridge v1 but was removed, since all of those on version 1 were 1uf to begin with. I also changed the primary input bypass capacitor (on the Vcc pins of the micro) from 1uFto a 10uF.

For the most part, as far as I could tell, this resolved the issue. But capacitors are band-aids to the real problem, which is layout. I’m going to have to take a closer look at how the logic power is feeding in and out of the big patches of battery voltage and ground planes, all being switched hard tens of thousands of times a second.

There was also one particular pin connection on the A3941 gate drivers which I was unclear about, which may also contribute to noise coupling via ground fluctuation, but I will address that once I put together some more boards. In the mean time, I taped the board back into Clocker for some hard driving.

For the most part, the test went quite well…

This test revealed a very important hidden flaw in the drivetrain that I’m glad was caught. Namely, when I last took apart the DeWuts on Clocker to change the motors, I neglected to recheck the torque-limiting clutch screws. The clicking, clutch-slipping noise in the video is exactly that. A little bit of hex key wiggling – no sprocket removal even needed – and things were tightened up again.

During this and subsequent bench tests, I couldn’t get it to lock up or reset no matter how much I gunned the motors around. In fact, I did it so hard that…

What you see is a thin pall of DeWalt smoke from some rapid input reversal testing gone wrong. It seems that one of the motors had a borderline commutator short, which quickly became non borderline when rapidly smashed with +/- 26 volts.

The resulting quick short also took out one gate drive chip and two FETs on the half of the controller driving that motor. I replaced them both in 5 minutes, along with sending this motor to the pile of sad motors.

I ended up deciding not to run RageBridge v2 (board revision 1) in Clocker for this event, since I didn’t want to have to do ESC debugging in the field while my match is 2 minutes away. What I did do in the remaining day was add in the much-requested combine mode, which hard-parallels the two channels together at the hardware level. This enables Rage to function as a single large 1 channel ESC.

That part was easy. In combine mode, only channel #1′s current sensor is read and the assumed current is just twice that. The current control loop output calculated for channel 1 is applied directly to channel 2, making the assumption that the two halves, driven off the same PWM timer with the same gate driver, will switch on (within a small fraction of the total switching time) with eachother. This is not the most robust method, as it totally slaves channel 2 to channel 1′s mercy, and a failure on channel B will probably cause the whole thing to grenade. Maybe it’ll get revisited shortly.

Why did I put Combine mode together? Because another bot this time needed it…. and for that, we’ll need to wait for Part 2.

RageBridge Version 2 Roundup: ADC Auto-Triggering and Dungeon RPG Logic

Jan 26, 2015 in Bots, Motor Controllers

When I last talked about RageBridge, I was attempting to write current and throttle sampling code while on the plane to Shenzhen. I’m proud to say that every line of that session was scrapped because none of it made sense whatsoever. Do not attempt to code at 39,000 feet altitude after your complimentary in-flight red wine.

But as I promised, here’s the whole story of RageBridge v2 development up until now. The revision 1 boards came a week and a half before I left for China, so I was pretty much only able to put it together while tending to the end of semester project rush. The firmware was going to be sufficiently different that I couldn’t just plop the “production” RageBridge v1 firmware onto the chip, but some basic pin toggling showed me that all the hardware does work. In fact, the version 1 board claimed its first victim by slamming a poor RS-380 motor back and forth at full power 10 times a second…

Delicious version 1 boards arrive from Myro. These are 2oz copper boards – I wanted 4oz, but Myro informed me that their 4oz design rules need 10/12  (trace width / minimum spacing).

Maybe I’ll take the effort to try and route it with 12 mil spacing, which would be an immense undertaking and I might as well start from scratch… anyone have any (preferably inexpensive) PCB house recommendations that can do 10/10 in 4oz?

 

The same day, I commandeered the EE lab from the How to Make (a mess out of) Almost Anything students to assemble the board. I had, at this point, a few doubts about the sheer density of SMT component placement, such as small passives next to the larger inductor and capacitors in the logic power supply. These were echoed a bit by SeeedStudio when I showed them the board, but it is resolvable with a few minor design tweaks.

This firmware hacking session brought to you by Bawls Guarana. I wish you could find this stuff more readily, but if that were the case, I would have probably already died.

Before I started toggling pins, I first had to make a new Hobbyking Programming Socket Thing. I had one that I may have lent out to someone, but forgot who it could have been, so I considered it lost. This happens to something like 1/3rd of my stuff – lend it to a wide-eyed froshling, then immediately forget who it was. Some times, it even makes it back to me and I no longer remember the person and why I am being given something of mine that I swear was buried deep under a mountain of parts.

One bug I ran into right away: The gate drives wouldn’t enable. A little bit of prodding with an oscilloscope led me to discover that they were not receiving a power supply. Weird, but the 5v logic rail is feeding into the chip fine, and the chip is enabled, so the charge pump should be running…

That was when I discovered that I had mislabeled the charge pump pins when transcribing from datasheet to Eagle part.

On the A3941, there are a lot of doubled pins, like CP1/CP2, VBB, GND, and the like. In my infinite wisdom, I thought that VREG needed its own capacitor like CP1/CP2 does, instead of just needing to be 2 pins connected together, and a capacitor goes between VREG and GND.

So that’s why the gate drive rail was not energized – no capacitor, no fun.

Oops. Pretty much all version 1 boards need some little wire jumps. I upturned the capacitor and soldered a jumper wire to the nearest available GND pin. It will do for firmware work!

Onto the firmware itself. For this version of Rage, I wanted to try having the ADC running synchronously with PWM, to capture a real-time current every time the controller switches. Not only does this simply offer vastly increased current control resolution for the DC controller, but synchronous sampling of current is basically required for torque control of brushless motors. There are some hackish ways around it, of course, like the Chinese e-bike controllers’ hardware-implemented cycle by cycle current limiting, but if your microcontroller has the ADC horsepower, it’s possible to implement many different closed loop control methods in software. And I looooove software.

The ATMega328′s wimpy ADC is just fast enough to do this, somewhat overclocked, at 15.6kHz PWM. It will up the temporal resolution of the Hysterical Current Limiter by more than 8x – currently, it runs 1000 times a second using whatever current reading it had last. However, because there is only 1 ADC on the chip, it has to be multiplexed to read the two current sensors on alternating PWM cycles. Therefore, the real sampling rate of the current is more like 8kHz – hence the 8x instead of 15x speedup.

Whatever the case is, I consider it more software practice than anything for Brushless Rage.

So here’s all the setup that had to happen, written in the form of a code novel:

  //Set up Timer 1 for the following:
  //Change the WGM bits on TCCR1A and B to Phase Correct 9 bit PWM 
  TCCR1A &= ~(1 << WGM10);
  TCCR1A |= (1 << WGM11);
  TCCR1B &= ~(1 << WGM12);
  TCCR1B &= ~(1 << WGM13);
  //Change CS1:0 bits to no prescaling (31372hz pwm if we used 8-bit PWM that is standard, 15655hz with an extra bit of resolution)
  //As a result of the change to 9-bit, AnalogWrite( ) will take 0-511 instead of 0-255
  TCCR1B |= (1 << CS10);
  TCCR1B &= ~(1 << CS11);
  TCCR1B &= ~(1 << CS12);
  // Enable the Timer 1 overflow interrupt which will trigger a subroutine at the Bottom of every PWM cycle (16khz)
  TIMSK1 |= (1 << TOIE1); //Set TOIE1 and nothing else
  
  //Set up the ADC for the following:
  // Set ADC prescaler to generate a 1 MHz ADC clock; this increases the sampling speed 8x at a cost of ~ 1 LSB of resolution. 
  ADCSRA = ADCSRA & 0b11111000 | 0x04; //Set ADSDP2, clear ADSP1:0
  // Set ADC to auto-trigger on Timer 1 overflow interrupt
  ADCSRA = ADCSRA | (1 << ADIE); //Set ADC conversion complete interrupt 
  ADCSRA = ADCSRA | (1 << ADATE); //Set ADC auto trigger enable 
  ADCSRB = ADCSRB & 0b11111000 | 0x06; //Set ADTS2 and ADTS1; clear ADCTS0, to select Timer 1 overflow as the trigger source

The way I code is to write more comments than there are lines of functioning code, in excruciating depth of exposition. I do this not only because I can’t be buggered to remember what these registers do in a week, but so other people who are forging into non-Arduino territory can more easily get what’s going on. Manual register configuration, sadly, is still how much of embedded programming works.

(I promise to rip on manual register configuration EVERY TIME I make a software post. Every. Time.)

Down at the bottom of this short testing code, I have the ISRs for the ADC and the PWM timer:

ISR(TIMER1_OVF_vect) {
  //Quick Pin D5 (Port D pin 5, "COMBINE" on the RB2 board) toggle to indicate we are in the ISR, for debugging
  PORTD &= ~(1 << 5); 
  PORTD |= (1 << 5);
  
  slow_loop_prescale_counter++;
}

ISR(ADC_vect) {
  //Quick Pin D4 (Port D pin 4, "MIX" on the RB2 board) toggle to indicate we are in the ISR, for debugging
  PORTD |= (1 << 4);
  PORTD &= ~(1 << 4);
  
  byte low, high;
  low = ADCL;
  high = ADCH;
  hot_amps = (high << 8) | low;

}

The result of this is the following beautiful scope photograph:

 

The first trace up top is the PWM timer (Timer 1) overflow interrupt. This is the center of a PWM cycle, and is when the ADC is set off. A few (dozen) microseconds later, the ADC conversion complete interrupt service routine executes, which is the blue trace. At this point, a new current reading is available.

The purple trace is the ‘slow loop’, which runs a few hundred times a second using a software prescaler value. This is where inputs would be taken and new outputs calculated.

So how’s about the gate drives? Here’s a low-side trace directly at the gate of the FET. The total switching time is right around 1 microsecond… which is dismal for what I’m used to, but serviceable. Small fully-integrated driver chips are going to be wimpier than the IRS21844s that RageBridge v1 used, which are more often used on higher voltage systems with much larger devices.

Some differential scope probing and a high-side gate waveform also appears. Unless you have a scope with completely isolated channels, don’t try to probe both the high and low side gates at the same time. This kills the gate.

What happens is, non-isolated scope probe grounds basically short the high-side gate drive through the ground clips, resulting in (usually) the gate driver dying. Don’t make my past mistakes, kids. You’ve been (repeatedly) warned.

This was the extent of the firmware work before I left for China. I tried telling myself I’d work on it while traveling, but hah, yeah right. Looking ahead, however, I made some design changes while in Beijing, and right before leaving Japan, I fired them off. Here is board revision 2, featuring…. well, not much difference. Some component placements have been relieved, but otherwise the power side circuitry is identical.

The biggest “duh” moment of handling my revision 1 boards was… there are through-hole headers everywhere. If I’m going to make a plate-style heat spreader like RageBridge v1, the through-hole header elements should be as closely grouped as possible to minimize holes and cutouts. In board revision 2, I tried shoving as many of the headers to the left as possible – fortunately, with a little trickery, I got all of them.

The “Fan” pins are still located inboard because there’s no other good place for them. The difference between the 5V supplied by this set of pins vs. what comes out of the 5V pins on the left, and the one that goes to the microcontroller, is that Fan power is taken from the ‘dirty side’ of the regulator, before the feedback pin and the 2nd output filter. That means it’s really dirty, chunky 5V, pretty much only good for running dumb loads like fans or gaudy lighting.

A week and some later, Revision 2 board arrives, along with…

… Brushless Rage!

Much to many peoples’ disappointment, Brushless Rage is going to be addressed when Brushed Rage is working and out the door, because it has a more critical ship date.

The backside of these boards is mostly made of soldermask-stop due to the high currents they’ll be conducting. Between this and the heat spreader plate will be a silicone thermal sheet layer to discourage shorting.

I actually have not assembled the version 2 board yet, because power circuitry-wise, version 1 and version 2 are identical – only the jumper and header row is different (…and the mis-routed pins have been routed correctly…) Since I have a functioning version 1 board already, it will be the focus for firmware development, and probably the first one to get blown up.

Since confirming that the ADC auto-trigger-upon-PWM-timer-interrupt system works, I next had to work out how to differentiate one reading from another. Here’s the issue, though: it would be easy to say “every other reading is either one or the other current sensor”. It’s not as easy to incorporate reading other analog inputs. I’m planning on building “analog mode”, for small silly rideable things, from the outset this time instead of promising to get around to it eventually.

While it would be “easy” to have an Arduino analogRead() plow through my already set-up ADC triggers every once in a while, in the interest of more robust code structure I decided to create a convoluted state machine to have the ADC interrupt routine determine what in the name of Sam it just read.

The basic idea is this. Every “slow loop” will request a new set of inputs (if in analog mode). The ADC ISR will merge these requests in with the current sensor reads automatically and update temporary holding variables just like it would for current. If inputs are being requested at the time the ADC is reading a current, then it will immediately reload the ADC, switch it over to the input under scrutiny, and read again, ideally finishing in time for the next current sample.

The full state logic I wrote down literally read like a bad text-based RPG.

You wake up in a dark room. You are an ADC. In your hand is a conversion result.
You must figure out what variable to assign this conversion result to.
> look
 On the wall besides you are three lists of the same words over and over, all scratched out
except the bottom-most, and all stating that something is TRUE or FALSE.
> read

The list says:
READING_CURRENT = FALSE;
READING_CURRENT = TRUE;
...
and
INPUTS_REQUESTED = FALSE;
INPUTS_REQUESTED = TRUE;
...
and
WHICH_CURRENT_TO_READ = FALSE;
WHICH_CURRENT_TO_READ = TRUE;
...
It is clear the lists were made in your handwriting.
You can read the last thing you write using (current), (which), or (inputs).
When you are ready to guess what variable to assign your conversion result to, you can use (assign).
> inputs
INPUTS_REQUESTED is false.
> current
READING_CURRENT is true.
> which
WHICH_CURRENT_TO_READ is true
> assign
To take a guess at which variable to assign your conversion result to,
type the name of the variable (ia, ib, inputs[0], inputs[1], or inputs [2])
> ib
Before the memory bus was selected for a write, you were eaten by a grue.

 

See? It’s that simple!

The variable names are all real, and here’s how they interact.

Each PWM timer overflow interrupt, the READING_CURRENT flag is set, and the interrupt handler immediately sets the ADC going. When the ADC finishes about 15 microseconds later, the ADC conversion complete interrupt handler executes and sees that READING_CURRENT is true.

There are only 2 current sensors, so a simple logic inversion flag WHICH_CURRENT determines if it’s motor channel 1 or channel 2. It will save the current reading in the appropriate variable, invert the logic flag, set READING_CURRENT to false (since we’re done), and then move onto switching the ADC multiplexer to the other current sensor pin.

Every once in a while, the slow loop will call for an INPUTS_REQUESTED = true condition. When the ADC wakes up from converting, there’s two possible things that happen:

  1. That READING_CURRENT is true and that INPUTS_REQUESTED = true, which means the next cycle is an input read and has to start immediately, or
  2. That READING_CURRENT is false and that INPUTS_REQUESTED = true; which means the next cycle has to be a current read since THIS one was an input read, or

If this cycle was an input read based on the two state variables, then assign the reading to an input variable – this is in the form of an array, inputs[0:2] so it’s easy to iterate through.

Finally, based on the condition of the two state variables, the ADC interrupt handler will reassign the multiplexer to reflect the next desired read. If it’s an input, it will start the reading immediately. If no more inputs should be read, it sets INPUTS_REQUESTED = false so that part of the logic doesn’t happen until the slow loop causes it again.

It looks like this on a scope:

In this scope shot, channel 1 (yellow) is reading an output PWM that I hardcoded for convenience.

The next one down is the Timer 1 overflow interrupt handler, which sets off the ADC every PWM cycle.

The channel 3 (purple) spike that lags each channel 2 spike by about 15 microseconds is the ADC interrupt handler executing and reading current.

The channel 3 spike that immediately follows the rightmost two current reads are input reads. The first is inputs[0], the next inputs[1], and so on.

Channel 4 is the “slow loop” which, in this test code, serves only to set INPUTS_REQUESTED = true in order to irritate the ADC.

I was having trouble getting functional readings out of this setup, however. It seems like the current sensors were reading just fine, but the test inputs (which were potentiometers) were exceptionally noisy and inconsistent. I pondered for a while over this, and even refactored the above code from scratch to try and distill away any logic errors on my part.

No change. I even tried slowing down the ADC to only 4x the default Arduino speed – perhaps my potentiometers were too high impedance and it couldn’t fill the sample-and-hold capacitor fast enough? Seemed unlikely, but worth a try.

As the above scope photo shows, when I slowed the ADC down, the readings started running into each other and some of the input reads did not complete at all, being paved over by the externally triggered current reads.

I became suspicious when I noticed that the input reads succeeded when I grabbed the potentiometers in the right away. Uh oh…

To differentially diagnose, I put on some rubber gloves and tried again, figuring that my body impedance was messing with the potentiometers. Same result.

In disbelief, I grabbed a potentiometer that I knew to be working from using it to test other motor controllers, as well as a Hall Effect twist throttle from one of the scooters. Worked perfectly.

In summary, it is absolutely possible to have all three potentiometers you harvested from the depths of the shop to be scratchy or oxidized and making poor contact, and have that make you think it’s entirely your fault that you can’t write software.

Five minutes later, three perfect analog readings with three perfect in-sequence reads interleaved with current sensor reads. In this scope shot, the purple trace is only the portion of the logic that handles writing the inputs variable. It executes three times for three analog inputs.

Gee, that was a hilarious, rage-filled evening.

At this point, I’m ready to dive into writing the part of the firmware I actually care about – taking those inputs and doing something with them. I’m going to put in analog and R/C driving right away. Here’s the anticipated ‘state table’ of operating modes:

  • R/C: Responding to signals in the 1100us – 1900us range, since it seems like that’s what radios put out by default. Failsafing behavior will check for valid/present pulse lengths on Channels 1 and 2, and shut down motor output if the signal is invalid.
    In normal mode, channel 1 controls motor A, channel 2 controls motor B.
    In MIX mode, channel 1 affects differential speed of the motors and channel 2 affects offset – what is usually called “Elevon” mixing, the most common configuration for robots.
    In COMBINE mode, by popular demand, motor A and motor B PWM % is synchronized in the timer to turn rage into a 90-180A single channel controller.
    MIX and COMBINE both selected is not a valid mode and will default to MIX.
    In default and MIX modes, INVERT causes motor direction and speed to be swapped between A and B
  • ANALOG: By default, channels 1 and 2 respond to signals from 0.1 to 4.9 volts with ‘zero’ being 2.5 volts. Voltages below 2.5 cause that motor channel to run in reverse, above in forward (for your definitions of forward and reverse). The signal bounds are for fail-safe behavior since if control signals get disconnected, it is more common for them to hit the voltage rails (0 and 5v) instead of hover somewhere in the middle.
    Channel 3 has no function. I mean, it COULD be an Invert input, but are you really going to drive your motorized couch upside-down?
    Failsafe behavior requires signals be at 2.5v (within the deadband) at startup, or else the signals must be brought to 2.5v first, to prevent unintended couch acceleration.
    In MIX mode, it assumes the use of a centered joystick or similar control setup, and its output behavior is similar to MIX mode in R/C.
    In COMBINE mode, Rage becomes a 1 channel DC electric vehicle controller. The controller will respond to voltages of 1.0 to 4.0 volts, since that is the most common range for hand and pedal Hall Effect active throttles and potentiometer throttles set up as voltage instead of ohms (increasingly uncommon).
    Motor outputs A and B are paralleled by default.
    Channel 1 controls positive (driving) current from 0 amps to 2* IMAX amps.
    Channel 2 controls negative (regen braking) current from 0 amps to 2 * -IMAX amps. Continually holding brake will not result in reversing. This is a bit of an unusual setup, but in my past experience, more people want their vehicle to coast by default instead of brake (drag braking) by default.
    Channel 3 becomes a reverse switch depending on its digital logic state.
  • And of course, TTL Serial input, which is not high priority right now but will let Rage bust into the comically large servomechanism market. I suspect I will structure this as “simple serial”, compatible with many other small robot controllers – sending byte values 1 through 127 with 63 as center (0×01 to 0x7F with 0x3F center) controls channel 1 in forward and reverse, and 128 to 255 with 192 as center (0×80 to 0xFF with 0xC0 center) respectively for channel 2.
    Sending 0×00 shuts down all motors to coasting condition.
    In this case, Channel 3 is used as a ‘device select’ line.

These expectations might change once I get started coding. In particular, with respect to the ADC readings, I have yet to try to take any samples under power. It could be that system noise from the motors and FETs switching might make individual samples worthless. That might imply some more state machine trickery, such as if I have to read currents and inputs more than once, etc.

Right now, it’s anticipated that Rage will try to find the input mode on its own when it wakes up. After waiting for half a second upon power-up, it will…

  1. Obtain MIX or COMBINE status by reading those pins
  2. Check for bytes in the serial buffer; if there are, become Serial mode.
  3. Check for analog voltages at the 3 channel inputs, whether 1.0v or 2.5v depending on MIX/COMBINE mode; if there is the proper voltage present, enter Analog mode.
  4. Barring that, sit quietly for a few more milliseconds to listen for R/C pulsewidths; if there are valid ones, enter R/C mode
  5. If all of those steps fail, blink in futility, and re-attempt these steps once per second.

Man, it seems like “make it drive motors” is the easy part.

 

RageBridge: The Next Generation

Nov 20, 2014 in Motor Controllers

[David Attenborough's voice]

It’s autumn at Big Chuck’s Robot Warehouse & Auto Body Center.

As the cold descends over New England, the supply of Mountain Dew and burritos becomes scarce…. and we see the Charles is busily preparing for his winter hibernation.

Deep inside his expertly crafted nest of meticulously hand-picked post-industrial waste, we see him studiously lining his abode with layers… of warm, insulating motor controllers.

The Charles will get his nutrients from these motor controllers for the rest of the winter.

He will periodically set them aflame, taking in both their radiant heat… and exacting sustenance from the magic smoke.

[end David Attenborough's voice].

Anyways, what? I have no clue how it happened, but the entire first run of RageBridges is sold out! I am retaining a few units for legacy and warranty fulfillment, but other than that… It’s gone! I never actually expected this to be the case, by the way – RageBridge 1 was more of a crapshoot than I care to admit. I wouldn’t say it was pushed out the door, but I was definitely not confident about it.

However, it has proven to be a solid performer, and I have only ever gotten a handful of units back for failure analysis. That means there are several dozen healthy and working Rages in the wild. DOZEN!

I never said I was Foxconn.

The success of Generation 1 means it’s time to roll out the changes I’ve wanted to make since Generation 1, since even if I am involved something that’s in production, I still start thinking about version 2 before the version 1 is fully out the door. From the tales of experiences of Rage users, there is really not too much to change. However, I think there’s two big threads of “customer wishes”:

  • First, that dual power input setup is actually really tacky. I did originally design Rage to just drop into the wiring harness for two Victor 883s, and it just stayed that way up to “Ship It!” time. There was no good rhyme nor reason for making the power inputs on two sides of the board.
  • Wiring the two halves of the controller together into one more epic one. Hypothetically, Rage can drive up to 90 amps continously and 180 amps max current limit (or even more if you shut off the current limit!)
  • I’ve gotten a handful of reports that the board is spotty in functionality above ~33 volts. I highly suspect this is related to the inductor still being marginal in value, which was an issue I fought on the original board revision before it started working. The symptoms are the same – the regulator resets. I’m not sure why the original test units didn’t do this, but may it has to do with aging of the components? Hell if I know. However, at least I know how to fix it.

So, to the physical form factor of the board, I’ll have to do a better job at component verification, and play with the layouts some. Past that, in terms of part selection, there are some major changes I want to experiment with.

RageBridge 1, like many of my past motor controller experiments, uses several discrete half-bridge drivers instead of more integrated chips. It was great for learning layout and how these things work, but arranging 4 of them on a board is tedious and takes up more space than it needs. Their drive strength is also more suited for larger controllers, so I’ll definitely come back to them in the future. For months, I’ve been scoping out the market of integrated H-bridge gate drive chips which will let me wrap the functionality up into one chip (or at most two chips). I’m willing to try a few different H-bridge drivers, on different board revisions, if that’s what it takes, but I think many of the market options are equivalently functional.

I settled on the Allegro A3941K, which offered a good combination of reasonably easy to use package – TSSOP is my baseline for “pain in the ass electronic part packages I never want to deal with – drive strength (current), and lack of other fancy things like current sense resistors, since I’m still keeping the Hall Effect current sensors this time around. The thing that sold me on it was the retainment of the “PWM + Direction” input topology. While it actually has two inputs “PWMH” and “PWML”, one of those inputs can be held low and the other provided the PWM duty cycle to effect synchronous rectification if the “SR” mode, which stands for… guess what, synchronous rectification, is enabled. Then, the PHASE pin is basically the “direction”. This is the same effect that I had to add a 74LS08 logic chip to RageBridge 1 to achieve, since the IR21844s are only half-bridge chips and so the “direction” output is actually four selecting pins.

Next, it’s time to catch up with the latest in distressingly current-dense power MOSFETs. I’ve been drooling at the newest Infineon HSOF package units, like the IPT007N06. It’s so very beautiful and double-side heat sink-able….

Also, expensive. The competitor I selected against it is the IRFS7530, which has all the keywords I’m looking for in its applications description (“Brushed DC motor! Brushless motors! Battery powered! Synchronous rectification! Half bridges, full bridges, and onion-ring power supplies!) so I assume IR made it just for me.  Plus, even though D2PAK-7 is a bit of a weird package, it’s not nearly as proprietary as Infineon’s HSOF right now. The switching characteristics, namely the gate charge, aren’t any worse (…not are they better) than the IRFS3006 units on RageBridge 1. However, in the end, it doesn’t even matter, as Infineon and IR will soon be the same. Geez, way to make me switch to Fairchild and NXP, guys.

I’m also making an effort to transition to all SMD parts this time to lower assembly cost and streamline the process. This includes the big electrolytic bus capacitors. I went on a capacitor shopping spree prior to starting board layout, too, and realized that they pretty much don’t make better caps than what I’m already using, at least in terms of my size constraints and high voltage demands – it’s a whole ‘nother world in low voltage land.

With no further changes planned except those parts, I started creating new devices definitions in Eagle and playing with the major part layout. Power board design is as much about layout as anything, and having the Big Power in locations easy to join with huge traces and power planes is critical.

One of the candidate layouts. This one has the advantage of keeping both the big power and ground planes in the center. Check out the big Panasonic J package 16mm electrolytic capacitor profiles there – each one, based on the one I specified, is 1000uF. That’s actually a healthy 25% increase from RageBridge 1, though it’s still not to my liking…

An alternative layout with three of those caps. Now I’m happier, but sadly I’m much less enamored with the layout in general. Looking ahead a little, the right side of the board will be difficult to route in terms of getting the current sense signals and rightmost two gates through.

Sadly, three-across on the Panasonic caps juts way out of the 2″ board width. I’m trying to keep to the dimensions of Ragebridge 1 so transitioning users will not have to make much of a change in mounting facilities… myself included.

Let’s start playing with this layout for now. I’ve added candidates for input and output pins and drawn in some preliminary power planes.

The wavy header layout to the left is courtesy of Sparkfun. I’ve found their wavy-header hole footprint to be very useful, since it holds the headers in place as you’re trying to solder one pin down. You’d think I was about to slaughter them by the way mine try to wiggle out of the holes.

RageBridge 2 will ship with headers in the kit, but they will not be assembled. This cuts down on the thru-hole processing time and cost. The single-line layout will also benefit those who are still into soldering cables in place.

I’ve gotten a little ahead here, so let me explain. First, I’ve fleshed out the power plane routing more. Next, and probably more importantly, I already found ways to break out both the gate drive and current sense lines using both the top and bottom of the board, in the alleyway between the MOSFETs’ drain tabs and source legs. This actually means everything else will be easy! I have also put down the logic power regulator, this time actually following the advice of the LM2594HVM datasheet for one-layer layout.

I’m slowly growing the schematic as the major power routing occurs, so the jumble of parts on the left side is growing.

With all the passives and accessory parts loaded in… Well, at least there is physical space for everything, so that’s a good sign. In keeping with Rage tradition (and to keep fabrication easy), I’m putting all components on the top side.

One of the challenges in routing ICs with many required peripheral passive parts is you can get almost to the end and discover the rest is actually impossible. Hence, the starting configuration is important. The patterns that look the best might not be the best placement. In this trial layout, I’ve put all the gate drive resistors and bootstrap capacitors off to one side, and the logic side passives on the other. It seems promising!

Trying to play a game of snake…

There’s always that one trace you forgot about. At least this one wasn’t bad!

After getting pretty far into it, I decided to start over with the chip in a different orientation. I’m used to routing using SOIC packages and 1206 passives, where I can plop a via down and change layers whenever I want. Here, in the TSSOP package, the center pad really prevents me from doing so. I’m tempted to stray from the manufacturer’s recommended land size so I can squeeze some vias in the gap between the pins and the pad.

This new orientation ended up working out much better. However, it meant that I had to move the mounting hole closer to the left edge as a compromise. That’s fine, since this Rage version cannot share the same heat sink design anyway.

After another few evenings of playing the game, this is pretty much it. It might look daunting, but the rest of it actually went quite smoothly due to the severely reduced discrete passives count. The only reason I was able to devote far more space on this board for FETs and capacitors (the meat and potatoes of a motor controller, I might add) was because of the new gate drive ICs.

We’ll see if that comes back to bite me.

The little cheeky label in the middle refers to the fact that the top power plane has to neck down to about 0.35″ wide to clear the set of TVS diodes next to it. This means the area is kind of marginal for the current levels I want to push through the left set of FETs. I said this was a revision 1 board… To try and mitigate the trace detonation circumstances, that area (and other similar areas) is getting a stop-mask rectangle (pictured) and likely also a rectangle of solder paste deposited for some metallic reinforcement in the area. Worst case, I will have to commission copper ‘trace boosters’ like a lot of motor controllers have.

With some minor adjustments and board art, this is it.

Wait…

After letting this design sit out of sight for a day or two, I came back to it to add a 5V rail TVS diode and to move a few traces to be less twisty and convoluted. Now we’re ready to send out…

Check out the extra “combine” option – this is directly in response to Consumer Demand™, for people who want to run a single larger motor. RageBridge v1 is technically capable of this, as both halves are driven off the same hardware timer, but the firmware was never updated to fuse the two current sensor readings and modulate the PWM as one.

RageBridge2 revision 1 should get back to me next week.

brushless rage

Uh oh…

Something that has been eating at me for a long time is I’ve technically never made a functional brushless motor controller.

Okay, to clarify, I meant “to my liking”. 6.131-troller (Face Vector Modulation) worked just fine, cementing my love of hardware and hatred of programming and software. Next, Melontroller2 did work in RazEr Rev for several months before I swapped it out. But it was very unfinished; the firmware was left in a crude state and I never went back to change it. After that, all of my controllers began suffering from the Great Bypass Capacitance Drought of 2011-2012 before I discovered the issue with Ragebridge the original.  TinyTroller, the last brushless I attempted, ended pretty much in miserable, abject failure.

Perhaps it’s time to try again. Like what motivated me to build RageBridge v1, I find myself often disappointed by the small brushless controller market. The physically small ones (Hobbyking et. al, model controllers) are bare-bones and lack features like torque (current) control and Hall sensor inputs (or even Analog inputs). The good vehicle ones tend to be very bulky (like Kelly KBS controllers) or functional but extremely power limited (Jasontrollers/Wangtrollers). Furthermore, the Kelly controllers seem to have a control discontinuity in regenerative braking mode, which manifests itself as the vehicle suddenly jerking.

Granted, Alien Power controllers do exist, but I haven’t personally used one to know what they’re made of. Anyone know more about them and if they have a good reliability track record?

Brushless Rage will therefore be my redemption experiment, and maybe a future product down the line. For now, the specifications I’d like to hit include:

  • Sensored to start with. Both idiomatically, for simplicity in development, and literally: One thing I really like about the Jasontrollers is the use of Hall sensors only at low speeds, where they make sense. At high speeds, fixed Hall sensors introduce problems in phase lag. In reversing scenarios, they have a pretty large hysteresis band.
  • HV inputs – up to 60v is my preference, since I like running high voltage and lower currents. 17-60v (nominal ratings being 24-48v) is a common input voltage band.
  • 50 to 100 amps, much like Rage, since it will be fairly similar in size and device usage.
  • Relatively simple – Kelly controllers are set up for several different kinds of throttle and brake inputs and have features for more complete vehicles, such as contactor drivers and reversing beepers and whatnot. Jasontrollers have cruise control. I’d like to have at most 1 throttle input, 1 brake analog input, one switch (e.g. ‘reverse’), a blinky LED, and a…
  • Small number of operating modes. Conventional “one throttle, one brake” with reversing switch; One-throttle-only (drag braking, non-variable braking or just complete coasting), and one-input forward and reverse (continuous control variable, like for vehicles under closed loop control). These are the modes I see most often in small project vehicles.
  • High-resolution torque control. It’s fairly easy to sense current every PWM cycle and manage it from the reading. This is not quite the same as RB’s current limiting, which does not occur synchronously with PWM.
  • Sinewave output. This one is a bit of a stretch goal, but I would like to make a sine output version. The interesting thing is, regular “brushless motor” driving (block commutation) almost requires a different architecture in code than a sine wave interpolator. It may actually be tacky to be able to switch from one to the other. Small sinewave controllers are starting to make inroads into e-bikes: I know of some that do, but they apparently suffer from slow maximum speed.
  • “Training” mode, which is featured on most Chinese e-bike controllers now. Spin the motor up open-loop (or tell the user to give it a whirl), record Hall sensor transitions, apply to your state transition table. This is definitely another stretch goal, but I really want to give this a stab.

First, though, is getting a stable hardware base for development.

Component choice-wise, this controller is a bit beyond the capabilities of the ATMega328 I am fond of for DC RageBridge.The chief reasons are lack of timer compare outputs (for PWM generation), and the killer, a very slow ADC. I’m going to move up one tax bracket to the ATMega32U4, the current chip of the Arduino Leonardo, because it actually does have a “PWM6″ output mode where it will generate three sets of complementary PWMs, all in hardware. This is common in new and motor control optimized microcontrollers, but I’m all giddy and stuff since it means I will not have to bother with external hardware to generate complementary PWM. The ADC is also faster – still quite slow by modern micro standards, but it’s workable. I calculated the (more or less) exact times needed to perform the analog read operations I needed to do per PWM cycle, and that result was what told me that 328s were hopeless, the 32u4 would be a logical step up, and that everyone uses ARM Cortex chips for a reason.

I also spent quite a few off-cycles perusing Allegro’s selection of 3-phase motor drivers. They come in all sorts of sizes and features for many different industries – some are clearly designed for automotive fans and blowers, for instance, and others for servo drives… I’m currently fond of the A4910, which is basically three half-bridge drivers and current sense amplifiers put into a box. TI has some very feature-packed chips in the form of the DRV8301 and its related parts, but in talking with Shane (who literally does this for a living now, not just figuratively any more…), I think they’re a bit beyond the requirements of this project right now, and could be facing End-of-Life in the near future.

Here is a “parts splattering” with one proposed layout of the components. The bolt pattern and size for Brushless Rage (name to be determined – suggest ‘em in the comment box) is the same right now as for DC RageBridge2, but may not remain such if I find that another configuration is better suited to the task.

I suppose the “minimum viable product” of this thing is “Kelly KBS destroyer”.

One example implementation of the mode switches might be:

  • Neither jumper set: thr1 controls current up to imax, thr2 controls current down to imin (variable braking, negative current), rev controls… well, reverse. thr1 and thr2 both at minimum would just be 0 current (coasting).
  • Jumper mode1 set: thr1 controls current up to imax, no thr1 means a fixed drag brake where the imin potentiometer is interpreted as a percentage of imax.
  • Jumper mode2 set: thr1 controls current symmetrically between imax and -imax, and reversing is handled automatically (One-input torque control mode)
  • Jumper mode 1 and 2 both set: thr1 controls speed as hard as it can, with Vcc/2 as a center voltage (zero), using imax and imin as ‘acceleration limits’ only (One-input speed control mode with torque ceiling, kind of like how DC Rage is set up)

There’s a long way to getting this board better defined and routed. For instance, I might just go totally discrete with the gate drive (back to good ol’ half bridge drivers) and use my favorite Hall-effect current sensors instead of current sense resistors and amplifiers. I will have to decide how to balance “new things” with debuggability – the best case for which is only changing 1 major variable at a time.

Rage onwards!