HÄRDBÖRD: Hardcore Electric Longboard

So I’m going to start using my blog as a build log for projects. All the cool kids are doing it.

Introducing HÄRDBÖRD, the new reason for my keyboard layout

Today, I want to turn your atten­tion to HÄRDBÖRD1, this wire­less, all-aluminum elec­tric longboard/deathtrap project I got myself involved in. My room­mate Jami­son and I are the prin­ci­pal design­ers (engi­neers? build slaves?) on a pair of these for fun and… lever­age against The Man? The idea here is to get some learn­ing done, but we do end up with ridicu­lously cool look­ing, possi­bly over­pow­ered boards to ride around campus on:

Take that, campus shut­tle!

I’m mostly in charge of the elec­tron­ics, which are pretty simple compared to the all the other stuff. Most of it was done in about a week2. The plan is to use a Wii Nunchuk to wire­lessly control the motor controllers. Why a Nunchuk? Why wire­less? These tran­scen­den­tal ques­tions of painful grav­ity are endless, but I can not answer them.

Jami­son has done much of the mechan­i­cal design and machin­ing, though I’ve been able to contribute a bit in the shop by learn­ing the trade (i.e. the OMAX water­jet cutter in the Inven­tion Studio at Geor­gia Tech). The boards are almost all water­jet-cut 6061 aluminum, with custom trucks, wheel hang­ers, deck—the whole shebang. We’ve run into a few snags where the wheel hang­ers don’t center with as much force as we’d like (in fact, not enough to be ride­able); I have an elegant solu­tion involv­ing one spring and a cam, but it’s unma­chine­able and appar­ently patented or licensed by Orig­i­nal

Power runs from huge 4000mAh 6S1P pack lithium-poly­mer batter­ies (22.2V nomi­nal, 25.2V max). They’re really not that big, but I haven’t built large bots for a long while so their size still surprises me. This juice runs to a pair of Turnigy brush­less motors mounted within 4-inch 30A durom­e­ter poly­mer-core wheels, though what goes in between the motors and the batter­ies is still up for debate with the bean counters—no motor control solu­tion for the pair of the boards costs less than $300.

For more infor­ma­tion on “getting the boards to move,” see Jamo’s posts on Härd­börd.

Mean­while, we’re think­ing of using a pair of Maxon DEC 50/5 (PDF) sensored brush­less control modules. Now I’d person­ally prefer to build my own brush­less controllers, but we really want to see this on the road. These take in a few digi­tal signals and a 0–5V analog signal for speed. Unfor­tu­nately, every­thing elec­tronic I covet and hold dear (includ­ing my low-MIPS micro­con­troller of choice, the Microchip dsPIC33FJ128GP802) use 3.3V, and I hate analog like that flat watered-down Sprite you get from really stingy restau­rants in NYC’s China­town. No sir, no op-amps in my design; I’d rather drink diet.

An aside on my choice of µC

The nice thing about the dsPIC33FJ128GP802 is that it’s chock-full of every sort of periph­eral, as described in its 386-page datasheet. If you don’t have a soft­ware solu­tion, it has a hard­ware solu­tion. If you don’t have a hard­ware solu­tion, it has a hard­ware solu­tion. If you already have a solu­tion, IT HAS A HARDWARE SOLUTION.

In my computer archi­tec­ture class, the profes­sor was talk­ing about the DEC VAX having a POLYD instruc­tion to eval­u­ate poly­no­mi­als and every­one laughed at the ridicu­lously complex ISA co-designed by two Stuy alums. Then I real­ized, “dang, the dsPIC has a poly­no­mial eval­u­a­tor for CRC calcu­la­tions!” Hard­ware bloat is not fastest in Intel’s newest SIMD float­ing point SSE6.8d exten­sion, but in these little 8- and 16-bit buggers by means of the memory-mapped periph­eral.

I mean seri­ously, in addi­tion to the usual timers, ADCs, I²C, SPI, U(S)ARTs, CAN, and other junk, it’s got freak­ing DMA and multi-prior­ity inter­rupt system for all of those. Then they decide that wasn’t enough and crammed an extra ALU and barrel shifter in there with 40-bit accu­mu­la­tors and called it a DSP engine. But wait, there’s more! There’s more space on the die! Let’s shove a compara­tor and a real-time clock in there! Now they had more hard­ware than they had pins, so what do they do? STICK MUXES AND TRISTATE DRIVERS EVERYWHERE. Yeah, that’s right, almost every periph­eral on this thing can be mapped to any pin. This thing even solves your PCB layout issues because you can recon­fig­ure your pinout in soft­ware.

Oh yeah, this thing also doesn’t need a crys­tal to run at its full 40MIPS, has a free offi­cial GCC compiler, and comes in 28-pin bread­boad­able through hole (as free samples!). Life doesn’t get more perfect.

The receiver

Aside aside, I wanted to output 0–5V analog from my dsPIC33F. Well, first thing I see is that it’s got this DAC periph­eral. Every­thing is fine and dandy unti—AUGH IT OUTPUTS A DIFFERENTIAL SIGNAL. In other words, not only is it not 0–5V, it’s not even 0–3.3V. It’s some janky 0.8–2.8V (-ish. Don’t quote me.) swing for audio use. Darn, now I have to ghetto-hack a DAC from the PWM hard­ware.

Fortu­nately, this is extremely straight­for­ward. The Output Compare module, as the “PWM” module is called in the dsPIC33F/PIC24H lines, is one of the most pleas­ant hard­ware periph­er­als I’ve ever used, on any computer, ever. Put it like this: it’s easier than the soft­ware way. You set up a timer with some prescaler values against system clock, as well as a period match regis­ter for when it should reset the timer counter to 0. That’s right: not only can you set the frequency of the timer tick, but also the period by which it resets. Awsm.

static inline void configTimer2(void) {
	T2CON = T2_OFF | T2_IDLE_CON | T2_GATE_OFF | T2_32BIT_MODE_OFF | T2_SOURCE_INT | T2_PS_1_1;
	PR2 = usToU16Ticks(PWM_PERIOD, getTimerPrescale(T2CONbits)) - 1;
	TMR2 = 0; //clear timer2 value
	_T2IF = 0;
	_T2IP = 1;
	_T2IE = 1; //enable the Timer2 interrupt
}

Anyways, next you just set up the output compare module to use that timer.

static inline void configOutputCompare1(void) {
	T2CONbits.TON = 0; //disable Timer when configuring Output compare
	CONFIG_RB14_AS_DIG_OUTPUT();
	CONFIG_OC1_TO_RP(14); //map OC1 to RP14/RB14
	//assumes TIMER2 initialized before OC1 so PRE bits are set
	OC1RS = 0; //initially off
	//turn on the compare toggle mode using Timer2
	OC1CON = OC_TIMER2_SRC | //Timer2 source
			OC_PWM_FAULT_PIN_DISABLE; //PWM, no fault detection
}

The way this work is basi­cally described by this timing diagram:

When the timer counter is less than regis­ter OC1RS, the OC1 pin (recon­fig­ured by soft­ware as described above, to RP14) is output high. Other­wise, it’s output low. The period of rollover is defined by the timer’s period regis­ter PR2. In other words, the duty cycle (and thus aver­age volt­age) is exactly3 OC1RS/PR2.

Aside: you know why this would be useless on your ATMEGATRON9000KFLASH4BYTERAM AVRDUINO CAPPUCCINO2001 device? It’s 8-bit. All of these regis­ters would be 8-bit, and you’d either have crappy 8-bit timers that can’t do straight­for­ward PWM like this or some janky concate­nated 2×8-bit monster with terri­ble latency and 40 pages in errata. End aside.

OK, so now we know how the PWM works. But how do we get 5V output? Surely we’ll need an op amp to up our range to fiv—CATSLAP. We don’t like your kind here.

Yeah, so there’s a dsPIC periph­eral solu­tion here. The digi­tal pins on the dsPIC have an open-drain oper­a­tion mode4. A pin in open-drain output mode is hard pull to low (drain) when its port regis­ter bit is 0, and tris­tated (high-imped­ance, Z, float­ing) when its bit is 1. This means you can hook up 5V pull-up resis­tor to it, and get 5V output from a 3.3V device.

Now all I need to do is feed that 5V signal to a RC filter tuned to atten­u­ate the PWM frequency, and I’ll have a clean 5V DAC output. I feel like freak­ing 诸葛亮 right here.

The test

I’m work­ing on all of this in the Inven­tion Studio because I want an oscil­lo­scope for this. Now the Inven­tion Studio is an Mechan­i­cal Engi­neer­ing shop, so the o-scope is a bit dinky, but hey, it’s digi­tal, there are work­ing probes around, and it works… for the most part.

"Try a USB flash drive which has a smaller memory size." OK, what?

Anyways, I don’t have real o-scope captures, so bear with my cell­phone camera photos of the vari­ous test cases. So here’s the circuit under test:

The trans­mit­ter and receiver ghet­toed up to a power supply and scope

Now let’s get some data:

This is the PWM output from the dsPIC, with­out open-drain

Being able to adjust the duty cycle of the wave­form with a joystick is some hot stuff, espe­cially if you fiddle with the trig­ger settings a bit. Now let’s hook up a 100KOhm×0.1µF RC filter on that. This has a cutoff frequency of about 16Hz, at which point half the signal is atten­u­ated. Higher frequency signals are atten­u­ated at 20dB per decade, so the 3.28kHz PWM frequency is atten­u­ated by at least 40dB. Good enough for me to play Etch-A-Sketch on the scope with my Nunchuk:

With RC filter and slooow sweep scope samples

And just for the hell of it, I measured the ripple of the analog:

About 30mV. Not bad. Taking this measure­ment was a real pain: I had to keep my joystick finger steady while zooming/panning on a tiny sliver of the verti­cal scale, throw in measure­ments, and pray­ing that a little twitch won’t throw the wave­form off the trig­ger­ing level.

So, that concludes this really boring part of “reduc­ing part count of every­thing to just a dsPIC.” Next time, I’ll show how I did this with the trans­mit­ter side.

  1. Credit goes to Charles for this awesome name. Note that the Umlauts are metal umlauts, not actual German. []
  2. Much of that time was spent coding with my shirt off while Ramm­stein blasted from my work­sta­tion. []
  3. Actu­ally, there’s a fence­post error here I’m gloss­ing over, but which is covered by my code snip­pet. []
  4. Well, all of the I/O pins on the equiv­a­lent PIC24H do, but you’re not supposed to use the dsPIC analog pins in open-drain since they’re not 5V toler­ant. Yes, it does work, but this puts your app outside of spec. []