# karplus4arduino

## 2011 October 25

### HexMotor 2.3 and pressure-sensor boards

Top view of my second PC board. 3 copies of HexMotor 2.3 and 2 copies each of 3 different breakout boards for a pressure sensor.

I got the boards back from 4pcb.com about a week ago.

The HexMotor rev2.3 boards have several new features: LEDs for +5v and +6.25v, a reset button, 16-bit shift register instead of 8-bit, servo outputs connected to pins 13, 7, 2, 9, 10 (rather than to the pins used for PWM).  The new board should be able to do either 6 PWM motors or 4 PWM motors, 5 servos, and 2 non-modulated reversible motors.  I was going to have the robotics club solder the board today, but they did not have time.

I made some breakout boards for the MPXHZ6250A pressure sensors from Freescale Semiconductor,  which gave me my first taste of SMD soldering.  At least the design uses gull-wing pins, which can be hand soldered.  The breakout board that I think that the robotics club will end up using puts a pressure sensor on one side and headers for a piggyback ADXL335 breakout board on the back.  that way there only need to be one set of wires for connecting the analog inputs and power to the sensors.

That is the board I soldered a sensor to.

Top view of the breakout board with the sensor and headers soldered in place.

The pressure sensors are tiny! I found it fairly difficult to solder the  sensor to the boards, even holding it with clamping tweezers. I did eventually get everything to stick with no shorts between the 3 signal wires, but I did have some trouble with the unused copper pads delaminating from the board.  For future reference: all pads should have wires going to them (even the unused pads) to have enough surface area for good adherence and so that some of the pad is tucked under the solder mask.

Here are the solder connections on the side where none of the pins are used.

Here are the solder connections for the power and signal pins (and an SMD capacitor).

Despite the rather sloppy soldering, the pressure sensor does work.  It turns out that the port size is just the right size for Lego pneumatics components, so testing was pretty easy.

Sensor attached to Lego pump and gauge for testing.

Here are the results of calibration tests with the (probably not very accurate) Lego gauge, done by my son and me.

0 367
5 518
6 542
7 576
8 599
9 632
10 657
11 683
12 710
13 734
14 775
15 801
16 832
17 861
18 887
19 915
20 941
21 967
22 1000

The range is about right, since 22 psi plus one atmosphere is about 250kPa, which is supposed to be the high end of the sensor’s range. Also, 600″ (50′) of water is 21.67 psi, so the range from 367 to 1000 corresponds to about 50′, so the sensor should give the robotics team a resolution of about 1″ for measuring depth, as expected from the spec sheet.

The data are well fit by $\mbox{Arduino reading}= 28.57 \mbox{psi} + 371.$ The club members will have to recalibrate the pressure sensor in water, to get calibration as depth in cm. They’ll probably have to re-zero the sensor every day they use it, to compensate for atmospheric pressure, since it is an absolute pressure gauge.

## 2011 September 27

### 4pcb.com sticklers for the \$50 multiple-image surcharge

4pcb.com put a hold on my second order from them, asking for an extra \$50 (bringing the cost up to \$100.30) for the new board, because there were multiple images.

I asked them on the phone what the rule was now for defining multiple images.  Although they did not give an exact algorithm, basically they are looking for separate pieces unconnected by copper traces.  I suspect that they either do a quick look at the board manually or have some very crude program to detect probable repeats.

They are not looking just for exact repeats (which is the rule that Gabriel Elkaim told me they used), but anything that looks like multiple boards. Now I have to decide whether to pay the \$50 surcharge, find another vendor, or redesign the board.

For the tiny breakout boards I may be better off with a BatchPCB.com order, at \$2.50/sq in + \$10 setup. I had 3 (slightly different) copies of the hexmotor 2.3 board, plus 2 each of 3 different breakout board designs for the pressure sensor.

The areas and prices for the boards (not including shipping) are

board dimensions area BatchPCB.com price
pressure 1.3 0.7″ × 1.45″ 1.015 sq in \$15.08 for 2
pressure 1.4 1.5″ × 1.0″ 1.5 sq in \$17.50 for 2
pressure 1.5 0.475″ × 0.8″ 0.38 sq in \$15.00 for 2
hexmotor 2.3 3.95″ × 3.15″ 12.44 sq in \$41.11 for 1, \$103.32 for 3
combined 7.537″ × 6.737″ 50.78 sq in \$136.94 for 1

So if I keep the original order, I’m better off with 4pcb.com pricing, but if I get only 1 motor controller board, I could reduce the price to about \$75+shipping (with a new combined board, to avoid the repeated \$10 setup).  If I just want the breakout boards, I could do all of them without the hexmotor board as 2 copies of  a combined 1″ × 3.825″ board  for \$29.13+shipping.

UPDATE: I decided I want the new features of the hexmotor 2.3 board enough to spend the extra \$60 rather than just using the old hexmotor 1.3 board.  When I want tiny boards, though, I’ll try BatchPCB.com, which will be cheaper for boards smaller than about 13 square inches (depending on shipping and how many are ordered).

## 2011 September 23

### New board designed

I’ve just sent a new set of boards for fab.  The HexMotor rev2.3 boards have several new features: LEDs for +5v and +6.25v, a reset button, 16-bit shift register instead of 8-bit, servo outputs connected to pins 13, 7, 2, 9, 10 (rather than to the pins used for PWM).  The new board should be able to do either 6 PWM motors or 4 PWM motors, 5 servos, and 2 non-modulated reversible motors.

I’m also making some breakout boards for the MPXHZ6250A pressure sensors from Freescale Semiconductor, which will require doing some SMD soldering.  At least the design uses gull-wing pins, which can (supposedly) be hand soldered.  One of the breakout boards also has a place for mounting an ADXL335 accelerometer, which may be more difficult to solder.  I don’t think I want to spend the money for a hot-air rework station, and I’m a bit dubious about my ability to solder using a toaster oven.

The pressure sensors are tiny!  My original suggestion to the robotics club was to drill a hole in the dry box and superglue the pressure sensor to the inside of the box (after the pressure sensor had been attached to the breakout board, of course).  Now I’m not so sure that there will be enough glue area to hold firmly enough.  Perhaps a dab of some sealant on the outside of the box might help, if we can keep from plugging the hole in the sensor.

The breakout board that I think that the robotics club will end up using puts a pressure sensor on one side and headers for a piggyback ADXL335 breakout board on the back.  that way there only need to be one set of wires for connecting the analog inputs and power to the sensors.

One limitation of the Arduino for use with this combination of sensors is that the accelerometer is a 3v part and the pressure sensor is a 5v part. We’ll have to set up the analog-to-digital converter on the Arduino to have a 5v range, which reduces the precision of the acceleration readings.

I’ve also bought some other sensors (not for the underwater vehicle, but for physics class and dry robotics): a couple of ultrasonic rangefinders.  More on those in a separate post, after I’ve had a chance to play with them.

## 2011 August 9

### Board fully populated and tested

Top view of the HexMotor rev 1.3 board fully populated.

I got the board fully populated yesterday, plus I made a heat sink out of a piece of ¼” × ¾” aluminum bar stock.  The heat sink makes an enormous difference.  Before using it, running a small motor at low power for 20–30 seconds was enough to make the H-bridge uncomfortably hot.  Now running the same 12v motor stalled at full current (3A) for a full minute raises the temperature only to 100ºF.

The motor got warmer than that, and I think I burned it out, since it no longer runs and has a 400kΩ resistance.  I’m not really surprised—it was a cheap door-lock actuator, and only intended to be used with fraction of a second pulses.  Further testing will require a more robust motor.

As you can see from the photo, the screw terminal for motor 4 (second from the bottom) is a bit crooked—I’ll have to unsolder it and straighten it.  For the HexMotor 2 board, I’ll use slightly smaller holes so alignment is easier.

The thermal grease I used (Cooler Master IceFusion High Performance Thermal Compound 40G RG-ICF-CWR2-GP) was more liquid than I expected, especially since it comes with a little spatula for applying it.  I had to put on a fairly thick layer, because the aluminum extrusion was not very smooth, and when I tightened the bolts the stuff oozed out making a sticky mess. Next time, I’ll sand the aluminum smooth first and use much less thermal grease.

Closeup, showing the excess thermal grease puddling under the H-bridges, where it is very difficult to wipe off.

This closeup photo, in addition to showing the pooled excess thermal grease, shows the header pins with shorting jumpers to configure the H-bridges for either lock antiphase or sign-magnitude control.  (Because of the last-minute change from TLE-5205 to TLE-5206 chips, the silk-screen labeling of the header pins is wrong—this board is actually configured for sign-magnitude throughout not lock antiphase.

The photos also show that I did not leave room for the heat sink between the electrolytic capacitors.  The HexMotor 2.0 board will fix this problem also.

The HexMotor software now can handle 3 different boards: the HexMotor rev 1.3 board shown here, the Adafruit Motor Shield, and the HexMotor rev 2 board, which I am just about done fussing with the design for.  I’ve only tested with an Arduino Duemilanove board, but the software should work with an Arduino Mega as well.

## 2011 August 6

### HexMotor.h expanded to Adafruit Motor shield

Filed under: Hexmotor H-bridge board,Software — gasstationwithoutpumps @ 16:33
Tags: , , ,

I expanded the HexMotor.cc and HexMotor.h library today, so that I can use the same library with both my HexMotor board and the Adafruit Industries motor shield.  The only differences from a user’s standpoint are

• Use motors 1,2,3,4 instead of 0,1,2,3,4,5.
• motor.release() works on the AdafruitMotorBoard, but is not usable on the HexMotorBoard, which only brakes when off.

I also figured out a way to get some debugging capability into the library, so that people could check that their configuration is consistent (though there is no way to check whether the jumpers and wiring are actually what the user says they are supposed to be).  I can’t use “assert” statements the way I’m used to, so I did explicit if-statements and provided output through `Serial.print()` calls.  This only works for tests that come after the `Serial.begin()` call, so I put the tests in the `HexMotorBoard::setup()` method, assuming that it would be called after `Serial.begin()` in `setup()`.

The tests can be turned off by commenting out the `#define HEX_MOTOR_DEBUG 1` line in the HexMotor.h file, reducing the size of the downloaded program by 860 bytes.  Actually, almost everyone will have to turn the debugging off, since every run() command sends debugging output to the serial line, so the default is to have the debugging off.

The software library is pretty much done for controlling brushed motors, except for changing PWM frequency.  Currently motors 0 and 1 (1 and 2 on the Adafruit board) run at 490Hz, while motors 2 and 3 (3 and 4 of the Adafruit board) run at 976.5Hz and motors 4 and 5 at 490Hz.  I don’t want to mess with the PWM for motors 2 and 3, since that timer is also used for the `delay()` and `millis()` calls, so I probably want to change the PWM frequency for the other PWM pins.

Update 8 October 2011: Since I’ve just found out how to put source code into WordPress blogs, let me put the latest versions of HexMotor.h and HexMotor.cpp here:

```// HexMotor.h
// copyright Kevin Karplus 8 August 2011

#ifndef _HexMotor_h_
#define _HexMotor_h_

#include <inttypes.h>
#include <avr/io.h>

// Define HEX_MOTOR_DEBUG if you want to get error messages from setup() for erroneous setup.
// #define HEX_MOTOR_DEBUG 1

// Declaring a HexMotorBoard gives the jumperable configuration for the board.
// The relevant jumpers are which pins drive the motor speed inputs
// and whether the H-bridges are configured for lock antiphase or sign-magnitude.
//
// IN2 of the H-bridge is always connected to SIGN XOR MAG
//
// IN1 of the H-bridge can be connected to either SIGN  or MAG.
//		If IN1 is connected to SIGN, then the TLE-5206 H-bridge will
//			be running in a sign magnitude mode, with the Speed pin low meaning BRAKE
//				and Speed pin high meaning RUN (with the sign bit indicating which way to turn).
//		If IN1 is connected to MAG, then the TLE-5206 H-bridge will
//		    be in lock antiphase, running if the SIGN bit is high and BRAKING if the SIGN bit is low.
//			The MAG bit determines which way the motor runs.
//      If the MAG bit is not a PWM output, then IN1 should be connected to MAG.
// Note: on the rev 1.3 boards, the silkscreen for the jumpers is misleading.
//      The center of the 5 holes for header pins is MAG and the outer one is SIGN.

// The PWM frequency for all channels defaults to 1kHz (actually 16Mz/ 2^14 = 976.56Hz)
// Changes could be made in the HexMotorBoard::setup() routine if other PWM frequencies are needed.

class HexMotorBoard
{ protected:
uint8_t SpeedPins[6];
// which pins are connected to the "speed" (MAG) inputs of each H-bridge?
// Numbers 0-54 are for Arduino pins
// Numbers 0xA0..0xA7 are for the low byte of the serial output latch
// Numbers 0xA8..0xAF are for the high byte of the serial output latch
//		(on rev2 or later)
// Number 0xFF means that the MAG bit is tied to +5V
//
// Note: all SpeedPins should be connected to something.

// Note: on Arduinos other than Mega, using the Servo library means that pins 9 and 10
// are not PWM pins.  If used, they should be set up as ON/OFF pins.

enum{NOT_THERE, SIGN_MAG, ANTIPHASE, FORWARD_BACKWARD_BRAKE, ONE_BIT, ADAFRUIT} MotorMode[6];	// MotorMode[i] is
// NOT_THERE if motor_i is not usable on this board
// SIGN_MAG if IN1 of motor i is connected to SIGN, and MAG is assumed to be PWM
// ANTIPHASE if IN1 of motor i connected to MAG and MAG is a PWM bit
// FORWARD_BACKWARD_BRAKE if IN1 of motor i connected to MAG, but MAG is ON/OFF, not PWM.
// ONE_BIT if IN1 is connected to MAG, which is tied to +5v, so the
//		the motor is always either running forward or backward, controlled by the SIGN bit
// ADAFRUIT if this is not a HexMotor board, but an Adafruit Motor shield
//

uint8_t LatchPin, ClockPin, DataPin;
// which Arduino pins are used for talking to the Hexmotor shift register?

uint16_t ShiftRegister;  // the current or future contents of the HexMotor shift register

uint8_t Version;	// which model of board is used

// set (or clear) a bit in the ShiftRegister corresponding to the specified motor
inline void set_signbit(uint8_t motor, bool value=1)
{   digitalWrite(0xA0+motor, value);
}

void serial_out(void);	// transfer the shift register to the HexMotor board.
public:
HexMotorBoard(
const char *antis,
const uint8_t *pins=0,	// defaults to {11, 3, 6, 5, 9,10}
uint8_t version=1,
uint8_t clock=4,
uint8_t data=8,
uint8_t latch=12);
// An array of pins is given to indicate where the MAG output for each motor goes.

// The 6 antis characters are
// '-' for NOT_THERE
// 'S' or 's' for SIGN_MAG (IN1==SIGN)
// 'A' or 'a' for ANTIPHASE (IN1==MAG)
// 'F' or 'f' for FORWARD_BACKWARD_BRAKE (IN1==MAG, but MAG is not PWM bit)
// 'O' or 'o' for ONE_BIT
// 'M' or 'm' for ADAFRUIT motor shield

// The version is the integer part of the board rev number (rev1.3 is 1, rev 2.3 is 2).
// This indicates, for example, whether the board has 8 or 16 bits of shift register.
// Use rev 0 to indicate an Adafruit motorshield.
// latch, data, and clock are Arduino pins that are used for the serial output to the shift register.

void setup(void);
// makes sure that PWM frequencies are appropriately set and turns all motors off.
// Should be called during the global setup() procedure.
// QUERY: should PWM frequency be settable here (or even as separate call?)

void digitalWrite(uint8_t pin, bool value);	// write a single bit to a pin (using SpeedPins naming convention)
friend class HexMotor;
};

// Declaring an AdafruitMotorBoard sets up the HexMotorBoard interface for an AdaFruit Industries Motor Shield,
// rather than for a HexMotor board.
// The declaration has no parameters, as the AdaFruit motor shield is not configurable.
// For compatibility with the M1 through M4 labeling on the motor shield, motors 1 through 4 are used,
// rather than 0 through 3.

{  protected:
typedef enum{FORWARD, BACKWARD, BRAKE} MotorDir;
void change_motor_bits(uint8_t motor,  MotorDir control);
public:
friend class HexMotor;

};

class HexMotor
{  protected:
uint8_t Motor;
HexMotorBoard* Board;

public:
HexMotor(HexMotorBoard &board, uint8_t motor_num);

void run(int speed);
// speed is between -256 (full reverse) and 255 (full forward)
// 0 is off (braking on HexMotor, released on Adafruit)

void brake(void);

void release(void);		// Available on Adafruit Motor shield,
// but not on HexMotor boards rev1 or rev 2
// since the TLE-5206 chips do not have a Hi-Z output
};

#endif
```
```// HexMotor  library
// Kevin Karplus

#include <avr/io.h>
#include <pins_arduino.h>
#include <WProgram.h>
#include "HexMotor.h"

// The PWM frequency for all channels defaults to 1kHz.
// Changes could be made in the HexMotorBoard::setup() routine if other PWM frequencies are needed.

// The frequencies below are approximate.
// The actual frequency in fast PWM mode is f_clk/(256*prescale)
// For the 16.000MHz crystal of the Arduino, the frequencies are
// 62.5KHz, 7.125KHz, 1.9531 kHz, 976.56Hz, 488.28Hz, 244.14 Hz, and 61.035Hz

// Don't mess with timer 0, since it is used for "delay()" and "millis()"
#define OCR0_64KHz (1)  // no prescale
#define OCR0_8KHz (2)   // divide by 8
#define OCR0_1KHz (3)  // divide by 16

// Timer 1 (and Timers 3, 4, 5 on Arduino Mega) have limited
//	prescale choices, because they allow external clock as well.
#define OCR1_62KHz	(1)	// no prescale
#define OCR1_7KHz	(2)	// divide by 8
#define OCR1_1KHz	(3)	// divide by 64
#define OCR1_240Hz	(4)	// divide by 256
#define OCR1_61Hz	(5)	// divide by 1024

#define OCR2_62KHz	(1)	// no prescale
#define OCR2_7KHz	(2)	// divide by 8
#define OCR2_2KHz	(3)	// divide by 32
#define OCR2_1KHz	(4)	// divide by 64
#define OCR2_490Hz	(5)	// divide by 128
#define OCR2_240Hz	(6)	// divide by 256
#define OCR2_61Hz	(7)	// divide by 1024

// The Adafruit Motor Shield has an extra output bit for its serial interface:

/////////////////
// HexMotorBoard
/////////////////
const uint8_t defaultPins[6]={11, 3, 6, 5, 9,10};

HexMotorBoard::HexMotorBoard(
const char *antis,
const uint8_t *pins,
uint8_t version,
uint8_t clock,
uint8_t data,
uint8_t latch)
{
if (pins==0) {pins= defaultPins;}
// Save all the jumper information.
for(int8_t i=5; i>=0; i--)
{   SpeedPins[i] = pins[i];
switch (antis[i]) {
case 'A': case 'a':
MotorMode[i] = ANTIPHASE;
// should check that pins[i] is legal PWM pin
break;
case 'S': case 's':
MotorMode[i] = SIGN_MAG;
// should check that pins[i] is legal PWM pin
break;
case 'F': case 'f':
MotorMode[i] = FORWARD_BACKWARD_BRAKE;
// should check that pins[i] is consistent with board version
break;
case 'O': case 'o':
MotorMode[i] = ONE_BIT;
// should check that pins[i] is 0xFF (indicating MAG tied to +5v)
break;
case 'M': case 'm':
// should check that 1<=i<=4 and pins[i]=AdafruitDefaultPins[i] and version==0
break;

default:
MotorMode[i] = NOT_THERE;
break;
}
}
Version=version;
ClockPin=clock;
DataPin=data;
LatchPin=latch;
}

void HexMotorBoard::setup(void)
{
// setup the serial output pins and clear the shift register
pinMode(LatchPin, OUTPUT);
pinMode(DataPin, OUTPUT);
pinMode(ClockPin, OUTPUT);
if (Version==0)
}

ShiftRegister=0;
serial_out();

for (int8_t m=5;m>=0;m--)
{
switch (MotorMode[m])
{   case NOT_THERE: case ONE_BIT:
#ifdef HEX_MOTOR_DEBUG
if (SpeedPins[m]!=0xFF)
{   Serial.print(m,DEC);
Serial.println(" motor shouldn't have speed pin");
}
#endif
continue;

case FORWARD_BACKWARD_BRAKE:
if (SpeedPins[m] >= 0xA0)
{
#ifdef HEX_MOTOR_DEBUG
if (Version<2 && SpeedPins[m]>0xA7)
{   Serial.print(m,DEC);
Serial.println(" motor has SpeedPin>0xA7");
}
#endif
continue;	// no need to set pinMode for HexMotorPins
}
pinMode(SpeedPins[m], OUTPUT);
continue;	// no PWM to check

#ifdef HEX_MOTOR_DEBUG
if (Version!=0)
{   Serial.print(m,DEC);
Serial.print(" mode M, but board version");
Serial.println(Version,DEC);
}
#endif
break;

default:
break;

}

if (SpeedPins[m] >= 0xA0)
{   // A HexMotor shift register output or tied to +5v, can't do PWM.
#ifdef HEX_MOTOR_DEBUG
Serial.print(m,DEC);
Serial.print(" motor has one-bit speed in mode ");
Serial.println(MotorMode[m]);
#endif
continue;
}

//real Arduino pin (not HexMotor shift register)
pinMode(SpeedPins[m], OUTPUT);

// Set up PWM frequency
switch (digitalPinToTimer(SpeedPins[m])) {
case NOT_ON_TIMER:
#ifdef HEX_MOTOR_DEBUG
Serial.print(m,DEC);
Serial.print(" pin ");
Serial.print(SpeedPins[m]);
Serial.println(" not a PWM pin");
#endif
break;

// timer 0 is used for delay() and millis(),
// so don't mess with its frequency
case TIMER0A:
TCCR0A =  (TCCR0A & 0x30) | _BV(COM0A1) | _BV(WGM00) | _BV(WGM01); // fast PWM, turn on OC0A
OCR0A = 0;
break;
case TIMER0B:
TCCR0A =  (TCCR0A & 0xC0) | _BV(COM0B1) | _BV(WGM00) | _BV(WGM01); // fast PWM, turn on OC0B
OCR0B = 0;
break;

// Timer 2 is used for pins 11 and 3 of Arduino (not Arduino Mega)
// default pins for motors 0 and 1, (M1 and M2 on Adafruit Motor shield)
case TIMER2A:
TCCR2A = (TCCR2A & 0x30) | _BV(COM2A1) | _BV(WGM20) | _BV(WGM21); // fast PWM, turn on oc2a
TCCR2B = OCR2_1KHz & 0x7;
OCR2A = 0;
break;
case TIMER2B:
TCCR2A =  (TCCR2A & 0xC0) | _BV(COM2B1) | _BV(WGM20) | _BV(WGM21); // fast PWM, turn on oc2b
TCCR2B = OCR2_1KHz & 0x7;
OCR2B = 0;
break;

// Timer 1
case TIMER1A:
TCCR1A = (TCCR1A & 0x3C) | _BV(COM1A1) | _BV(WGM10); // fast PWM 8-bit, turn on oc1a
TCCR1B = (OCR1_1KHz & 0x7) | _BV(WGM12);
TCCR1C = 0;
OCR1A = 0;
break;
case TIMER1B:
TCCR1A  = (TCCR1A & 0xCC) | _BV(COM1B1) | _BV(WGM10); // fast PWM 8-bit, turn on oc1b
TCCR1B = (OCR1_1KHz & 0x7) | _BV(WGM12);
TCCR1C = 0;
OCR1B = 0;
break;
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// Timer 3
case TIMER3A:
TCCR3A = (TCCR3A & 0x3C) | _BV(COM3A1) | _BV(WGM10); // fast PWM 8-bit, turn on oc3a
TCCR3B = (OCR1_1KHz & 0x7) | _BV(WGM12);
TCCR3C = 0;
OCR3A = 0;
break;
case TIMER3B:
TCCR3A  = (TCCR3A & 0xCC) | _BV(COM3B1) | _BV(WGM10); // fast PWM 8-bit, turn on oc3b
TCCR3B = (OCR1_1KHz & 0x7) | _BV(WGM12);
TCCR3C = 0;
OCR3B = 0;
break;
case TIMER3C:
TCCR3A  = (TCCR3A & 0xF0) | _BV(COM3C1) | _BV(WGM10); // fast PWM 8-bit, turn on oc3c
TCCR3B = (OCR1_1KHz & 0x7) | _BV(WGM12);
TCCR3C = 0;
OCR3C = 0;
break;

// Timer 4
case TIMER4A:
TCCR4A = (TCCR4A & 0x3C) | _BV(COM4A1) | _BV(WGM10); // fast PWM 8-bit, turn on oc4a
TCCR4B = (OCR1_1KHz & 0x7) | _BV(WGM12);
TCCR4C = 0;
OCR4A = 0;
break;
case TIMER4B:
TCCR4A  = (TCCR4A & 0xCC) | _BV(COM4B1) | _BV(WGM10); // fast PWM 8-bit, turn on oc4b
TCCR4B = (OCR1_1KHz & 0x7) | _BV(WGM12);
TCCR4C = 0;
OCR4B = 0;
break;
case TIMER4C:
TCCR4A  = (TCCR4A & 0xF0) | _BV(COM4C1) | _BV(WGM10); // fast PWM 8-bit, turn on oc4c
TCCR4B = (OCR1_1KHz & 0x7) | _BV(WGM12);
TCCR4C = 0;
OCR4C = 0;
break;

// Timer 5
case TIMER5A:
TCCR5A = (TCCR5A & 0x3C) | _BV(COM5A1) | _BV(WGM10); // fast PWM 8-bit, turn on oc5a
TCCR5B = (OCR1_1KHz & 0x7) | _BV(WGM12);
TCCR5C = 0;
OCR5A = 0;
break;
case TIMER5B:
TCCR5A  = (TCCR5A & 0xCC) | _BV(COM5B1) | _BV(WGM10); // fast PWM 8-bit, turn on oc5b
TCCR5B = (OCR1_1KHz & 0x7) | _BV(WGM12);
TCCR5C = 0;
OCR5B = 0;
break;
case TIMER5C:
TCCR5A  = (TCCR5A & 0xF0) | _BV(COM5C1) | _BV(WGM10); // fast PWM 8-bit, turn on oc5c
TCCR5B = (OCR1_1KHz & 0x7) | _BV(WGM12);
TCCR5C = 0;
OCR5C = 0;
break;

#endif
default:
break;
}

}
}

void HexMotorBoard::serial_out(void)
{
#ifdef HEX_MOTOR_DEBUG
Serial.print("shift 0x");
Serial.println(ShiftRegister,HEX);
#endif
digitalWrite(LatchPin,LOW);
// Output high order bits first
if (Version>=2)
{	shiftOut(DataPin,ClockPin, MSBFIRST, highByte(ShiftRegister));
}
shiftOut(DataPin,ClockPin, MSBFIRST, lowByte(ShiftRegister));
// rising edge on latch pin transfers shift register to output register
digitalWrite(LatchPin, HIGH);
if (Version==0)
{   digitalWrite(AdafruitEnablePin, LOW);	// enable output
}
}

void HexMotorBoard::digitalWrite(uint8_t pin, bool value)
{
if (pin<0xA0)
{   ::digitalWrite(pin, value);
return;
}
if (pin==0xFF)	return;	// pin is +5v and can't be changed
uint16_t pos = (1 << (pin-0xA0));
bool old_bit = ShiftRegister & pos;
if ((value && ! old_bit) || (!value && old_bit))
{   ShiftRegister ^= pos;
serial_out();
return;
}
}

//////////////////////
//////////////////////

const uint8_t AdafruitDefaultPins[6]={0xFF, 11, 3, 6, 5, 0xFF};

{
}

// Map the motor number to the two control pins for the motors, based on the
// mapping from the AFMotor.h file:
//      MOTOR1_A 2
//      MOTOR1_B 3
//      MOTOR2_A 1
//      MOTOR2_B 4
//      MOTOR3_A 5
//      MOTOR3_B 7
//      MOTOR4_A 0
//      MOTOR4_B 6

const uint8_t AdafruitMotorAPin[5]={0, 1<<2, 1<<1, 1<<5, 1<<0};
const uint8_t AdafruitMotorBPin[5]={0, 1<<3, 1<<4, 1<<7, 1<<6};

MotorDir control)
{
if (MotorMode[motor] != ADAFRUIT) return;	// error
switch(control)
{    case FORWARD:
break;
case BACKWARD:
break;
case BRAKE:  // set both outputs low
break;
}
serial_out();

}

/////////////////////
// HexMotor
/////////////////////

HexMotor::HexMotor(HexMotorBoard &board, uint8_t motor_num)
{
Board=&board;
Motor=motor_num;
}

// speed is between -255 (full reverse) and 255 (full forward)
// 0 is off (braking)
void HexMotor::run(int speed)
{
// clip to legal range
if (speed>255) speed=255;
else if (speed<-255) speed= 0-255;
#ifdef HEX_MOTOR_DEBUG
Serial.print(Motor, DEC);
Serial.print(" motor running at ");
Serial.println(speed);
#endif

switch (Board->MotorMode[Motor])
{
case HexMotorBoard::NOT_THERE:
#ifdef HEX_MOTOR_DEBUG
Serial.print(Motor, DEC);
Serial.println("motor NOT_THERE. Can't run");
#endif
return;
case HexMotorBoard::SIGN_MAG:
// (Sign-magnitude) IN1 is connected to SIGN, and MAG is assumed to be PWM
Board->set_signbit(Motor, speed<0);
analogWrite(Board->SpeedPins[Motor], speed>=0? speed: 0-speed);
return;
case HexMotorBoard::ANTIPHASE:
// (MotorMode) IN1 is connected to MAG, and MAG is PWM
if (speed==0)
{   // Brake
Board->set_signbit(Motor,0);
analogWrite(Board->SpeedPins[Motor], 0);
return;
}
Board->set_signbit(Motor,1);
analogWrite(Board->SpeedPins[Motor], (256-speed)>>1);
return;
case HexMotorBoard::FORWARD_BACKWARD_BRAKE:
// (Forward/Backward/Brake) IN1 is connected to MAG, and MAG is ON/OFF only
if (speed==0)
{   // Brake
Board->set_signbit(Motor,0);
return;
}
Board->digitalWrite(Board->SpeedPins[Motor], speed<0);
Board->set_signbit(Motor,1);
return;
case HexMotorBoard::ONE_BIT:
// IN1 connected to MAG=+5V
Board->digitalWrite(Board->SpeedPins[Motor], speed<0);
return;
// shift_register pins are interpreted differently by Adafruit board
if (speed>=0)
analogWrite(Board->SpeedPins[Motor],speed);
}
else
analogWrite(Board->SpeedPins[Motor],0-speed);
}
return;

}
}

void HexMotor::brake(void)
{
switch (Board->MotorMode[Motor])
analogWrite(Board->SpeedPins[Motor],255);
return;
case HexMotorBoard::NOT_THERE:
case HexMotorBoard::ONE_BIT:
#ifdef HEX_MOTOR_DEBUG
Serial.print(Motor,DEC);
Serial.println("motor NOT_THERE or ONE_BIT. Can't brake.");
#endif
return;	// no such operation exists
default:
run(0);
return;
}
}

void HexMotor::release(void)
{
switch (Board->MotorMode[Motor])
analogWrite(Board->SpeedPins[Motor],0);
return;
default:
#ifdef HEX_MOTOR_DEBUG
Serial.println("Not Adafruit motor shield, can't release.");
#endif
run(0);	// not a release, but a brake on HexMotor boards.
// The closest the TLE-5206 chips can get.
return;
}
}
```

## 2011 August 5

### Board (partially) populated and tested

My 4-up board about to be cut apart on the board shears. The adjustable railing for the back edge of the board and a railing along the bottom make it fairly easy to line up boards for repeated identical cuts (which I did not need). The bottom rail was useful for making sure that the cut was square, though.

Yesterday, I went to the basement shop where the support team for the enginineering teaching labs have their offices, and used their board shears to cut my PC board up. The shears are like a souped-up paper cutter. The noise they make when cutting through the PC board is a bit scary, though as it it sounds like you are crushing the board, rather than cutting. It makes a pretty clean cut, despite how it sounds.

HexMotor rev1.3 board with one H-bridge installed.

This morning I woke up early and decided to populate the board. I soldered in the switching power supply (and associated resistors and capacitors) first, and checked that there were no shorts and that it produced the correct output voltage. I then added the digital logic, the sockets for connecting to the Arduino, and the various headers.

It turned out that most of the headers did lock in place nicely with the Sparkfun offset-hole header design, making soldering much easier. A few of my 3-pin headers seem to have slightly smaller posts, and they did not lock in place as nicely. The hardest thing to solder in place were the 0.1″ jumper wires (which are not part of the next design). I may want to leave another 1–2 mm for the resistor, also, as I found it a bit difficult to fit the resistor I had into a 5mm spacing. Perhaps I should go with a 7mm spacing.

I only put in one H-bridge for testing, as I did not want to unsolder H-bridges if the board did not work.  If I’d been really careful, I would have waited on the switching regulator as well, since it is not really needed when there are no servos and the Arduino is powered over the USB line.

I spent most of the day writing driver code for the Arduino.  I came up with a pretty simple interface (much simpler than the AFMotor library for the Adafruit motor shield—I may want to extend the library to cover that board as well).

There is one global declaration of a HexMotorBoard to explain how the board is configured. As a minimum, you need to specify for each motor whether it is configured for Antiphase, Sign-Magnitude, or On-Off control. I suppose that if you connected the boards with ribbon cables, you could control several HexMotorBoards from a single Arduino Mega board, though with a standard Arduino there’s not  much point to having more than one HexMotorBoard, as there are only 6 PWM pins (unless you just need  full-on Forward/Backward and brake).

In the setup() procedure, you call the setup() member function of the HexMotorBoard.  To control a motor, you just use a single function: motor_name.run(speed).  The speed is always in the range -256 to 255, with a speed of 0 meaning brake. The software takes care of translating the speed into appropriate commands for the H-bridge, depending on how the H-bridge is jumpered.  (For convenience, I provided an inline function for motor_name.brake() that just expands to motor_name.run(0).)

I couldn’t come up with a much simpler user interface: declare the board, declare each motor, one setup() call for the board, and one function (run) to control each motor.  I suppose that I could get rid of the setup() function, since all it currently does is set the appropriate pins to be output pins and that could be folded into the run() function, but I’ll have to think about the value of keeping the HexMotorBoard::setup() function around to provide a place for consistency checks (like whether the configured pins are capable of PWM output).

Because I’m using the standard analogWrite() and digitalWrite() commands, and not fussing with the PWM frequency, very little code is needed to run on any Arduino.

I tested the board with its single H-bridge using a 12v door-lock actuator, and it worked in all three modes (antiphase, sign-magnitude, and on/off).  I did notice that the TLE-5206 got quite hot when the actuator was run for a few seconds, so I’m definitely going to need a heat sink.  I was planning on using a shared heat sink for the 6 H-bridges, but the electrolytic capacitors get in the way a little.  I’ll make sure to leave more clearance for heat sinks in the next revision.

I don’t have much time over the next few days, but on Sunday I hope to bring the board up to 4 or 6 H-bridges and make and  hook up the heat sink. Hmm—I don’t have any thermal grease—yet another thing to order.

## 2011 August 2

### Boards arrived

The hexmotor rev 1.3 boards before cutting them apart.

The printed circuit boards for hexmotor rev1.3 came today from 4pcb.com. I ordered the boards on July 21, so the total turnaround time from order to delivery was only 12 days. No wonder the company is so popular for student projects—low prices and fast service will do that!

The boards looked pretty good, so the first thing I did was to check some crucial dimensions:

• I put headers into the holes for the connection to the Arduino board and checked that it would plug in.  No problem!
• I checked that I could spread the pins of the TLE-5206-2S chips to fit the holes where they were supposed to plug in.  No problem!  In fact, it was surprisingly easy to get the right spacing, by using the board itself as a tool for bending the pins.
• I checked that I could put in both the MTR2 TLE-5206-2 chip and capacitor C5 without conflict (as I’d noticed that the silk screen outlines overlapped only after I’d sent in the order).  This also turned out not to be a problem
• I checked that the mounting holes on the board lined up with those on the Arduino.  Only 2 out of 3 do.  What is going on???I got the hole placement from the Adafruit library for Eagle, and it has 3 holes, but they are not in the same places as the Arduino board.  It turns out that two of the holes correspond to holes on the Arduino board, and two to holes on the Arduino Mega board, which has holes in different locations.  Neither pair corresponds to the holes on the  Adafruit motor shield, which has only 2 diagonally opposite holes, the two holes that are actually in common between the Arduino and the Arduino Mega footprints.  For the next revision of the boards, I have to decide whether to use the 3-hole design of this board, or to go with the pair of diagonally opposite holes.  Or put in 4 holes, so that either Arduino or Arduino Mega can be securely attached with 3 screws. I think that there is room for the fourth hole, if I move one of the electrolytic capacitors.
• I also did some continuity checks on the power lines.  The power and ground lines connect to the right pins on the TLE-5206-2 footprints, and they aren’t shorted.  The 6.25v and 5v lines also seem fine.
• I had to make some Eagle library components for the screw terminal blocks I was using, and they seem to be fine, except for two little problems: I put a silkscreen mark for the bump on the side of the 5mm block on the wrong side, and the holes specified by the manufacturer seem a bit too big for the pins.  I’ll specify a smaller drill hole (closer to the spec for the pin size) in the next revision.  Neither of these little problems will interfere with functionality.
• I checked out the Sparkfun header pattern, with the slightly staggered holes to hold the headers while soldering.  The holes must be a bit bigger than Sparkfun gets from their manufacturer, or my headers smaller, because the headers were not held by the staggered holes.  They fit fine, but the holes are loose enough that they aren’t held.

Tonight, I’ll fix up my Eagle library to have a 4-hole Arduino template and to have a better 5mm screw terminal component.

Here's a 12" board shear that costs \$379 from Circuit Specialists.

Tomorrow I’ll go up to campus and see if I can cut the boards apart with the board shears.

I took a look at  printed circuit board shears on the web (you need to include “printed circuit” if you search, or you get book-binding equipment), and they range in price from \$125 to \$500, depending on size and quality.  I don’t plan to buy one for myself, but it seems like the sort of low-price, special-purpose tool that a place like Makers Factory ought to get.

## 2011 July 31

### More design errors in hexmotor rev1.3

I should have known better than to send the PC board to fab before I wrote the software.  That’s precisely the sort of optimistic thinking I chide my students for.  There are all sorts of design errors that can be uncovered when you work out the details of how to use the hardware.

In my case, the motor functionality of the board all looks ok (so far), but the extra servo functionality is somewhat messed up, because I had not really understood how servos are controlled and how the Arduino servo library uses pins.  I “knew” that servos used pulse width to control position, but I had not bothered to look into the details or think about exactly what that meant—I just assumed that you had to use the PWM pins for the purpose.  Wrong!  If I’d ever actually used a servo with the Arduino, I would have known better.

Servo control is based on the actual on-time of the pulses, not the ratio of on-time to off-time (as is the case for controlling brushed DC motors).  You do have to give up one of the timers used for PWM in order to control the pulse width, but you can provide the pulses on any output pin.  The Arduino Servo documentation clearly says

The Servo library supports up to 12 motors on most Arduino boards and 48 on the Arduino Mega. On boards other than the Mega, use of the library disables analogWrite() (PWM) functionality on pins 9 and 10, whether or not there is a Servo on those pins. On the Mega, up to 12 servos can be used without interfering with PWM functionality; use of 12 to 23 motors will disable PWM on pins 11 and 12.

So putting servo control on the PWM pins is precisely the wrong choice of pins for maximum flexibility.  The hexmotor rev1.3 board has more or less the capabilities I thought it had (I can do up to 6 servos or up to 6 motors, and I can trade off servos for PWM control of motors, though I always have to give up PWM control of motors 4 and 5 to get any servos).  The initial application of the hexmotor board called for 4 fully PWM-controlled motors and 2 extra controls that could be motors or servos.  We can still do that, though we have a choice of 2 PWM-controlled motors or 2 servos and 2 forward/backward/brake (not PWM control), and can’t mix a servo with a 5th PWM-control motor.

But there is no reason to limit the board the way I did.  With slightly different wiring I could have simultaneously allowed 4 PWM-controlled motors, 2 forward/backward/brake motors, and 5 servos, with the main limitation being the power to the servos (due to the 1.5A limit of the switching regulator).  Three extra servo outputs could be really handy!

I also did not think about making the board compatible with the Arduino Mega board.  The current design does not use the Arduino Mega’s extra pins, which is no big deal, but it also blocks access to those pins, which could be a problem.  Furthermore, I did not look at what pins the Arduino Mega provides PWM on, nor which it gives up for the Servo library.

Incidentally, I was frustrated in looking on the Arduino site for the pin mapping of the Arduino Mega boards—they’d hidden that essential information behind a password (for no discernible reason).  I finally found the Mega pinout info on the forums, where someone frustrated by the inaccessibility of the pin mapping page had re-created it from other documentation.  It turns out that all the digital pins 2 through 13 can be used for PWM on the Mega, so any redesign I do on the board would have at least as much functionality on the Mega as on the standard Arduino.  I will have to be careful to put in conditionals for the pins in the software, though, as some of the pins are mapped from different ports on the Mega.

Redesigning the board to pass through the Arduino Mega pins would be a pain, as the pins take up three sides of the 1.825″×4″ footprint of the Mega board, and the remaining side is where the USB and power connectors are, so through-hole components can’t be mounted there.  I don’t think I can fit in all the TLE-5206-2 chips and screw terminals for the 12v power and motors and stay below the Eagle 8cm×10cm board size limit if I have to put in connectors for all the Arduino Mega pins.

I won’t be able to stack boards above the motor board anyway, as the electrolytic capacitors I’ve designed in to clean up the power are very tall (2cm), as are the TLE-2506-2 chips: particularly if I put on heatsinks.  I’ve bought a strip of 1/8″ thick, 3/4″ wide aluminum bar stock for a heatsink—I plan to drill 6 holes in it to bolt the TLE-5206-2 chips to.  It won’t matter if the bar connects the chips electrically, as they all have a common ground connection anyway.

I think that I’ll populate one rev 1.3 board with only 4 TLE-5206-2 chips, the minimum for the robotics club to be able to experiment with their underwater vehicle, and see how it works before making a new set of boards with full functionality.

So, for rev 2.1 I’m definitely going to change the way that the servo outputs are wired and make sure the software can work with the Arduino Mega boards, but I won’t be trying to connect to the Arduino Mega’s other pins. (Hmmm—I just had an idea for how I could pack everything in, with a massive rearrangement of components.  I might try that as separate branch of the design, to see whether it really is feasible.)

## 2011 July 26

### Time to start doing software

The PC board for the hexmotor H-bridge is ordered and supposedly going to arrive soon, and I’ve ordered all the components from Digi-Key. The total coast of the project is looking like about \$180 (including the PC board and shipping) for 2 fully populated boards (not counting an enormous amount of my time). I’ve already started designing a revised board (rev 2.0) that will be designed around the TLE-5206-2 from the beginning, and will have more versatility. I’m thinking that I’ll populate one rev 1.3 board for testing, finalize the rev 2.0 design, and send it out for fab, rather than populating a second rev 1.3 board.

Here is a preview of what my panel of 4 boards should look like.

In addition to the 6 TLE-5206-2 H-bridges, both boards have 74HC594 serial-to-parallel converters for control signals and 74HC86 XOR gates. The serial-to-parallel conversion is similar to that of the Adafruit Industries motor shield (which I have, but which does not have enough current capacity as it uses L293D H-bridges, which only support 0.6A per channel, and I need at least 2.5A per channel).

Copying the choices on the Adafruit board, I made the pin mapping LATCH=Arduino pin 12, DATA=Arduino pin 8, CLOCK=Arduino pin 4. I was wondering at first why they did not use the built-in SPI interface (which would simplify the programming of the serial output), but then realized that the output bit of the SPI interface (MOSI=pin 11) is also OC2A, one of the PWM outputs. Since there are only 6 PWM outputs (one per motor), and the serial interface does not need to be very fast, using software control of other pins is a good idea.

I’ve also brought out all the PWM signals to 3-wire servo connections, so that I can use each PWM signal as either a servo control or a motor speed control. All the connections to the Arduino digital pins are jumpered, so I can reconfigure the board if needed. For example, if I just want forward/backward/brake control of a motor, without speed control, I can rewire the input that would normally be to a PWM bit to be to a different digital pin, and free up that PWM bit for servo control.

On the hexmotor rev 2.0 board I added another 74HC594 chip (in series) so that I have 16 control bits available. Six of them are used for motor control, as on the rev 1.3 board. Another 6 are brought out to header pins adjacent to the speed control pins, so that those pins can be jumpered either to the Arduino PWM pins or to the shift register outputs, allowing 6 motors and 6 servos to be controlled by the board, as long as only 6 continuous values are needed, and the servos don’t exceed the 1.5A capacity of the switching regulator. The remaining 4 of the 16 parallel bits of the rev 2.0 will be brought out to individual header pins, so that they can be used as arbitrary digital outputs. (Also, the hexmotor 2.0 board will have an LED to indicate that 5v power is properly being provided—if the board is used as intended, with the Arduino powered from the switching regulator on the hexmotor board, this tests that all the power connections are made and the Arduino board plugged in.

I will have to start writing software for the hexmotor board soon. I’ll probably base some of the software on the Adafruit AFMotor package, to make it easier for the robotics club to switch between the Adafruit motor shield and the hexmotor board, but there will be some important differences. Since the hexmotor board has several jumpers that can customize it, but no way for the Arduino to read that configuration, I need an easy way to tell the software how the board is configured. I want software that will work with either revision of the hexmotor board. Since the rev 2.0 board has more possibilities for configuration than the rev 1.3 board (thanks to the 8 extra output bits), I’ll design the software for that, making sure that the rev 1.3 board is covered as a special case.

I’m going to have to dive into both the ATMega328 data sheet and the Arduino code to find out how to get access to all 6 PWM signals.  I already know that the Arduino initialization messes with the PWM frequencies, so the AFMotor.h control for the PWM frequencies doesn’t work.  It may turn out that using OC1A and OC2A (which the Adafruit board does not use, but which I use for motors 4 and 5) interacts in some unpleasant way with other Arduino functions.  I may have to put up with some constraints on PWM frequency, as I want to retain clock and analog input capabilities.

## 2011 July 23

### Possibly salvage the boards

My son and I were looking together about whether we could salvage the board design by using the TLE-5206-2 parts that are available.

The pinout is identical, but the functionality is different.

In1 In2 5205 out1/out2 5206 out1/out2
0 0 1/0 0/0
0 1 0/1 0/1
1 0 0/0 1/0
1 1 Z/Z 1/1

The arrangements of signals that I have available to jumper to were S, PWM, and S+PWM.  The easy jumper arrangements I had were (IN1=S, IN2=PWM) and (IN1=PWM, IN2=S+PWM), which with the TLE-5205 were supposed to give me lock anti-phase drive and sign-magnitude drive.

With the 5206, lock anti-phase would require (IN1=PWM, IN2=not PWM), which I don’t have available, but the jumper setting (IN1=S, IN2=PWM) now almost makes sense as active collapse (run/brake) mode (except that it is not quite sign magnitude, since the interpretation of the pulse width is flipped depending which way the motor is supposed to turn).  The other jumper setting makes no sense.

So now I have choice:

1. Populate a board with TLE-5206 chips and have only the run/brake mode (I could solder in jumpers, since there are no choices).  I could also omit the now-useless OR gates.
2. Design a new board with the TLE-5206 chips in mind, with jumpering between two modes:
• (IN1=S, IN2=S xor PWM)   run/brake with consistent magnitude interpretation
• (IN1=PWM, IN2=S xor PWM)  lock anti-phase if S=1, brake if S=0

Wait a second!  I don’t need a new board for that! If I replace the 74HC32 quad nor-gate with a 74HC86 quad Xor, then the 5-pin headers will be

 S IN1 PWM IN2 S xor PWM

I can solder the IN2 pin to S xor PWM, and just have a 3-pin header to connect IN1 to either S (for run/brake) or PWM (for lock anti-phase). The labeling on the silk screen will be wrong, but the board will be fully usable!

The interpretation of the pulse width modulation if  IN1 is set to PWM is that 0 means always on and 255 means always braking, which is kind of weird, but easily compensated for in the software. S determines the direction the motor turns.

If IN1 is set to S, then S is interpreted as RUN if it is high, STOP if it is low, and PWM gives the direction and magnitude when running (with 0 being full on in one direction and 255 being full on in the opposite direction).  PWM should probably be set to constant 0 when braking.

I think the board can be saved, and still have all the functions we needed, though we switched from sign-magnitude to active collapse as one of the modes.  The next revision of the board (if I need to make more) would fix the silk screen and replace the 5-pin header with a 3-pin header for each chip.

Next Page »

Create a free website or blog at WordPress.com.