We made a video to show the difference in noise between the Pololu A4988 Stepper Motor Driver Carrier, which has 1/16 steps, and the DRV8825 Stepper Motor Driver Carrier which has 1/32 steps. These drivers are common in RepRap 3D printers. The resistor soldered onto the DRV8825 is not required on their latest versions of the board.

The goal for this video was originally to capture the difference in sound that I noticed when I switched from one driver to the other, and this test seemed to do that. I updated it to be a bit more scientific than it was originally by carefully setting the current limit, adjusting the steps per unit, and including details about the setup.

For this test:

12.17V DC

Kysan 1124090 (1.8°, 1.5A/phase) stepper motor

18T Aluminum GT2 2mm Belt/Pulley

PLA bushings on W1 tool steel smooth rod with white lithium grease

This came out a couple of years ago, but someone reminded me of it just this weekend so I thought I’d share it. It’s a great little introduction to soldering. Click on the image or the following link to visit the site and see the full cartoon tutorial. (http://log.andie.se/post/397677855/soldering-is-easy)

I suppose this doesn’t *need* the ATMega, but they’re only a few bucks, so what the hey. This uses an old GI SP0256-AL2 speech synthesizer IC containing all 59 English phenomes. It sounds very computer-like (even though the original documentation boasts “natural sounding speech”. The DIP switches allow the user to specify a unique device ID for the network. Because it makes noise, I added brown-out detection — something I probably should add to all the devices eventually. The PWM speech output is filtered though a 5KHz low-pass, then sent through a volume control pot, then on to a low-power amplifier. The same 4-pin input is at the upper left, and the 2-pin speaker connection is at the lower right (above the big cap). Bonus: A programmable LED nestled between the ICs! (Oooo!)

An even tinier 4-amp dual stepper motor controller and driver, providing 500mA per phase for two 4-phase unipolar steppers, or 1A per phase for 1 motor when signals are combined (separate input for motor power). Four-position DIP switches assign a unique device number for addressing within the network, and various motor commands received via the 4-pin interface (+5V, GND, SCL, SDA) are translated and clocked out by the onboard microprocessor, completely freeing the controlling device of this tedious task. Quite small — less than 1.75″ x 1.5″ including mounting area.

I should say that there’s another version of this as a low-end PIC application (PIC12C505, and alternatively the 8-pin 12C508). The 14-pin version takes a 6-pin input, with power, ground and direction & step bits for each motor. This offers the user very simple motor control with just a few pins and the PIC just acts as a translator. Then I got the itch make it smaller. The 8-pin version takes a cable with +5V, GND, Device, Direction and Step, leaving only three pins for all the dirty work. I used a 74LS595 shift register with latch to maintain the motor states. The PIC waits to receive commands for both motors then updates the motor phases. (e.g. Sending pins 3-5 a “011” followed by a “101” will set motor 0 to step one phase forward, and motor 1 will step one phase back. Note that the last bit may be 0, meaning no step will be taken.) The microcontroller then goes into low power sleep while the shift register holds the motor.

I ended up wanting a bit more flexibility with an I2C interface. But, since a 4MHz PIC runs at only 1 MIPS (It uses four clocks per instruction cycle.), it’s a little difficult to implement even the “slow” I2C mode at 100kbps. I do want to go back and see if this is doable by continually forcing the master into wait states. Regardless, it turned out to be more trouble than it was worth — especially if I could get an AVR micro for a fraction of the cost, use it to replace the shift register (it’s only 4 pins larger), and crank out 12 MIPS. This gave me room on the board for the DIP switches and even a flashing LED! Anyway, the PCB is no-frills and still needs some work.

P.S. If you were wondering why, in paragraph 2, I felt the “Device” pin was necessary when the controller waits for two commands anyway, it’s because the user doesn’t have to send both commands. The PIC will time out waiting for the second command and simply update the motor state as appropriate. So then why is the “Step” pin necessary?? Now THAT’s a good question!

NOTE: Each picture on this page has its own scale.BlueBot is a platform for autonomous robot experimentation, engineered around a specific set of motors. It’s in itself an experiment in mixing easy-to-find components and custom components, with the end goal being a well-engineered, compact, flexible and expandible platform for experimentation and development. It’s a learning tool in development, construction and customization. Some of the requirements were predefined, while others were dictated by available tools and parts.

Drive Motors It all started with four Globe motors I picked up on Ebay. These particular motors are apparently used for autonomous robotics competitions, so I thought they’d be perfect for this application.

Two of these drive gearmotors are fastened under the chasis, each driving one side wheel. To keep BlueBot compact, I decided to offset these motors from the center axes of the wheel axels. This has a couple of benefits. First, it’s easier to control the wheel-to-motor speed ratio. Second, I avoid the temptation of mounting the wheels directly onto the motor shafts. Although these motors could probably handle the weight of the robot with no problem, I though it best to separate the two.

Chasis The chasis is constructed from sheet metal and requires a few cuts, a few bends and a bunch of holes for mounting. My goal in designing the chasis was to make it compact and as easy as possible to produce. I started off with a flat piece, and made a few cuts and bends to contain the motors. The motors are housed underneath the chasis in the two narrower sections. You can see one set of mounting holes on each side of the chasis. Because the motors hang under the chasis, a single bend of the sheet metal is not strong enough to hold them in place. Therefore, a strap is added to the non-mounted end of the motor to hold it steady. (Mounting holes for the strap are not shown.) The long slots at the back of the chasis allow for circuitry venting. The back corners were cut diagonal to match the general octagonal shape I ended up with.

Drive I decided on interchangable sprockets with a #25 roller chain for drive. Here’s a couple of bottom views (top=front). The chain is not shown in their views, and the sprockets pictured are not notched all the way around, but you can get the general idea of how they are aligned.

Here you can see the two motors mounted onto the sheet metal chasis. The top (front) motor controls the wheel shown on the left (though it’s actually the right wheel). You can also see a few of the custom parts from this view. The first is the wheel itself, which was designed around easy-to-find vacuum cleaner o-rings. The next custom part is the wheel hub, and the final custom part is the pillow block. The four (yellow-gold) pillow blocks used to hold the axles in place. The “wings” that support the wheels are strengthened from above (more later). There is space between the two axles to house the encoder electronics. The holes at the bottom (rear) of the chasis are used to fasten circuit boards and provide venting. An enclosed motor driver circuit (not shown) and a fan (if necessary, not shown) are also mounted beneath the chasis at the rear of the bot. If a fan is used, it is pointed down, bringing cool air through the PCBs above the chasis and the heat sinks of the motor driver board below the chasis. I suppose you could point the fan up if you want BlueBot to vaccuum, but you’ll end up with dirty electronics.

Drive Wheels I originally wanted to make the wheels with the stack of AOL CDs I’ve collected over time. The ~4 3/4″ diameter of the CDs would give the bot more speed and the ability get over simple household obsticles. (The gear motors offer a pretty good torque rating.) For tread, I considered a number of easy-to-find products, such as rubber bands, balloons, o-rings, and even the plastic tubing you use in fish tanks. O-rings look the best, and I figured they’d be easy to find and cheap. Unfortunately o-rings of this size are neither easy to find nor cheap ($6 each locally, or I could buy a lot of 20 online and pay shipping, too).

I did, however, find ~4″ diameter o-rings in the vacuum cleaner section of the hardware store, and since kludging the CD wheel solution was giving me problems, I went back to the drawing board and designed a custom wheel, which can be cut from 1/4″ plastic. I added holes for the axle and for mounting, and a groove to hold the vacuum cleaner o-rings into place.

The hubs are another custom part and serve to fasten each wheel to its own axle. Only the set screw holes are threaded, and since the threads need to be strong enough to hold the wheels to their axles, I thought this should be a metal part. The following images show an enlargement of the hub, and the wheel assembly.

Wheel Mount The drive wheels are held in place with four custom bearing housings. The body of each housing is broken into four secions: the base (shown at the top of the image), the top (shown at the bottom) and two shims. The shims allow the user to adjust the distance from the chasis to the axle in four 0.1″ increments, thereby assuring a resonably tight chain fit. The base is slightly narrower than the other parts to allow it to fit snugly between two easy-to-find L-shaped aluminim bars. I use sections of these L-shaped bars to reinforce chasis, and for other porposes as well. The half-circle between the mounting screws allows space for wires to be run.

The following image shows how the wheel (grey), hub (brass), pillow blocks (yellow), L-shaped strengthening bars (green), motor and sprockets fit on the chasis (blue). Note the notch cut out of the opposite end of one of the green structural supports (lower right-hand corner of the image). This notch allows extra space for the chain for the wheel that is not shown. There’s a notch for the other wheel, too, but it’s mostly hidden by the wheel sprocket. I chose sprockets, by the way, because there are a few online sources for inexpensive surplus sprockets. Gears would have provided a little less flexibility at a higher cost.

Caster BlueBot’s back wheel has the same mounting holes as the front wheel but is sized to fit smaller o-rings. There’s a 30-degree bend in the axle to allow it to swivel as the robot turns. The axle is held in place with a couple of shaft collars on either side of a mounting block, allowing the height to be adjusted up and down as needed. The mounting block is fastened to the back of the chasis.

Deck 1 In this configuration, BlueBot’s motors are powered by a standard sized 7AH sealed lead acid (SLA) battery, positioned so that the bot’s center of gravity is low and adequately behind the front axles. There is space behind the SLA battery for 3 full-sized circuit boards (many are smaller), and space in front of it for sensor circuitry. You can see the additional L-shaped structural support (green) in this image as well. The tall square spacers support Deck 2.

Head & Deck 2 The head mechanism is built around a standard hobby servo and a 1.8-degree stepper motor that I salvaged from an old HP ScanJet scanner. It’s pictured here attached to Deck 2. The stepper motor is mounted below Deck 2 and provides panning for the head. Some bots simply turn the wheels to pan, but I believe this is the more ideal solution because the wheels should only be concerned with moving the robot. This also allows the robot, for example, to scan side to side while driving.

The hobby servo motor (black), which provides the tilt, is mounted to the shaft of the stepper motor with a custom plastic piece (dark gray). You can just see how the corners of the pice are rounded to allow full tilt of the head without interfering with the sheet metal shell.

A sensor or camera (not shown) is mounted behind the front of the head (the face) by drilling the appropriate mounting holes. Supporting circuitry resides behind the head so as not to add unnecessary weight to the head.

The Result This is what I ended up with. (Same pictures as at the top of this page.)

A tiny I2C master controller designed to monitor and handle sensor loop and control operations. Conditioned power (+5V) is brought into this board, where it is coupled with the TWI for twelve external devices on three independent clock and data lines. I2C need not be implemented on each bus. Additionally power is combined with three weak-high pins, and three floating for other control applications. Includes an analog comparator (ANC) and a programmable LED.

This is how I chose to solve the problem of making trig calculations with the PICmicro MCU.

Note that this does not use the CORDIC method because I imagine that would hog too much valuable computing time. This solution probably should not be used to try to get someone to Mars or anything — I’ll work on a more complete solution at a later date. Until then, I hope this will do.

First of all, I attacked this problem with a few basic assumptions:

256-degree circle – It makes sense, when using a computer, to base everything on powers of two. Here I’m going to consider circle in terms of only 256 degrees. This is because 256 can be represented nicely by one byte and it’s close enough to 360 degrees that results shouldn’t be too far off base. Also, common angles can be easily represented as well, with a half-circle, quarter, eighth, sixteenth, etc, all settling nicely at a power of two. If it’s difficult to think of a circle in 256 degrees, just remember that the number 360 was completely arbitrary in the first place. (You can thank the ancient Babylonians for it, as well as for the number of minutes in an hour and seconds in a minute. They used a base-60 counting system.)

Unsigned magnitude, zero to 255 – Sines and cosines are usually represented by fractions. Since computers can’t tolerate fractions very easily, I chose to return results as a positive number from zero to 255, where zero is, well, zero, and 255 represents 1. Why only positive numbers? Because when you take the sine of an angle in a 256-degree circle, the most significant bit of the angle you’re looking for will quickly tell you if the result should be positive or negative. This is because quadrants 3 and 4 (angles 128-255) generate negative sine values. (As it turns out, the MSB for all these numbers is 1.) This allows me to use the full byte for sine values, effectively doubling the granularity of the result.

One-quadrant sine-only look-up table – The sine values for any one quadrant can be used to determine any of the other trig values for any other quadrant. I’ll provide a refresher on trigonometric identities below. Suffice it to say that one quadrant of sine values is all we need.

Non-CORDIC Solution – CORDIC would take too long to implement with a negligable increase in accuracy for typical applications. This solution is a look-up table that essentially digitizes the first quadrant of a sine wave as shown below.

The code listed below was written for mid-range PIC MPU’s like the 16f84, but can be ported down with a few minor changes. (For example, you may need to use comf and incf to negate values in the lower-end divices.) It finds the unsigned sine of an angle in eight instruction cycles (32 clock cycles), or 8us on a 4MHz microprocessor. With a few extra instructions (about 13 total) you can determine the sign as well as the magnitude. Determining the not-as-accurate signed sine requires 17 instruction cycles and returns a value ranging from -127 to 127. It takes about 15 cycles to determine the 8-bit cosine magnitude and discover its sign, while the signed cosine requires 18 instruction cycles. If you see a more efficient way of doing this, please let me know. Because instruction cycles vary, I don’t recommend using this for bit-banging routines where timing is critical. Maybe later I’ll do a version that takes the same number of cycles regardless of what function its performing.Before you forget, please help spread the word about this site by referring friends and associates!

The sinw subroutine does not call any other routines. This should be helpful if you’re working with a device that has a short call stack. If I were to return a signed value for the sine, I would have needed to make an additional call on the stack. I believe the way I’ve done it works out nicer. As it is, only ten or so instructions are required to determine both the sine of the angle and it’s sign (positive or negative).

The code below is well commented and includes examples of how to compute both sine and cosine (signed and unsigned) using the sine look-up table. Also, in the comments I’ve listed all the other trig equations I can think of — you can use these to figure out tangents, cosecants, etc.

It might be helpful to remember when sines and cosines are positive or negative. In our 256-degree circle, each quadrant is represented by 64 degrees. So Q1 is angles 0-63, Q2 is 64-127, etc.

Q1 (0-63 deg) – Sine and cosine are both positive. Bits 6 and 7 are both clear.

Q2 (64-127 deg) – Sine is positive, cosine is negative. Bit 6 is set and 7 is clear.

Q3 (128-191 deg) – Sine and cosine are both negative. Bit 6 is clear and 7 is set.

Q4 (192-255 deg) – Sine is negative, cosine is positive. Bits 6 and 7 are both set.

Bit seven (the MSB) of the 8-bit angle indicates if the sine is positive or negative (zero or one, respectively). Bit six indicates whether or not the sine wave is a mirror image of the preceeding quadrant. (Q2 is a mirror image of Q1 and Q4 is a mirror image of Q3.) This bit can therefor be used to indicate whether or not we need to read from the start or the end of the look-up table. The following rules always apply:

If bit 7 (MSB) is set, the angle is in Q3 or Q4, where sine is always negative.

If bit 7 (MSB) is clear, the angle is in Q1 or Q2, where sine is always positive.

If bit 6 is set, the angle is in Q2 or Q4, which are mirror-images of Q1 and Q3, so read the table backwards.

If bit 6 is clear, the angle is in Q1 or Q3, which can be read directly from the look-up table.

We only use the table to look up a sine value. Rather than trying to use the table to also look up a cosine, figure out what angle’s sine returns the same value and go to the table for that. This will ensure you can determine the correct sign (positive or negative) of the magnitude returned. To really drive this point home, let’s take a look at each case for the two most significant bits in an 8-bit unsigned angle:

00 – Angle is in Q1, the sine is positive, and it can be looked up directly from the table

01 – Angle is in Q2, the sine is positive, and it can be looked up by indexing the table backwards

10 – Angle is in Q3, the sine is negative, and it can be looked up directly from the table

11 – Angle is in Q4, the sine is negative, and it can be looked up by indexing the table backwards

Skip this paragraph if you’re not a beginner. Why does rolling (shifting) bits to the left or right magically double or halve whatever number your shifting? It works in a similar way for any counting system — just think about the numbers you’re used to using. If you “shift” the digits in the decimal number 123 to the left you get 1230 — effectively multiplying the original number by ten, which is the base of the decimal counting system. Likewise, shifting the hexadecimal value F3 to the left you get F30. F3 in decimal notation is 243. 243 times 16 (the base of hex) is 3,888, which in hexadecimal is F30.

Feel free to use this code, but be sure to leave the copyright information intact.

#define _version "0.01"
; Author: Alex Franke
; Copyright: (c)2002 by Alex Franke. All rights reserved.
;
; Title: sin
; Description: Computes the sine of an angle given in degrees of a
; 256-degree circle.
;
; Device: Microchip PIC MCU, p16f84
; or other mid-range PIC MCU's
;
; Update History: 6/11/02 Created
;
LIST R=DEC
INCLUDE "p16f84.inc"
; Registers
CBLOCK 0x020
sinTemp, theta, temp, temp2
ENDC
__CONFIG _CP_OFF & _WDT_OFF & _RC_OSC & _PWRTE_ON
; Main
org 0
Start
; Set up
movlw 84 ; specify an angle value
nop ; pause here to change value if desired for testing
movwf theta ; save that angle for use later
; now start the examples...
; Assume the angle you're trying to find is in theta and you want to find...
; ...its sine (0 to 255) and its sign (positive or negative)
movf theta, w ; copy to w so we can work with it
call sinw ; we now have the sine in w
btfsc theta, 7 ; test the original angle to see if it's in Q3 or Q4
nop ; ... if so, we know it's a negative, so handle that here
; ...its sine (-127 to 127)
movf theta, w ; copy to w so we can work with it
call sinw ; we now have the sine in w
movwf temp ; store result in temp register
bcf STATUS, C ; clear the carry bit if it's set -- we're about to roll
rrf temp, w ; roll temp result right to cut in half, store in w
btfsc theta, 7 ; test the original angle to see if it's in Q3 or Q4
sublw 0 ; ...it is, so negate w
nop ; sine (-127 to 127) is now in w
; ...its cosine (0 to 255) and its sign (positive or negative)
; A cosine is basically a sine, but shifted to the left one quadrant. This means
; that a sine is a cosine shifted to the right. So the cosine of any angle is
; equal to the sine at the same position one quadrant to the right, or
; cos(x)=sin(90+x). So to convert to sine we add 90 deg (64 degrees in our 256-deg circle)
; to the original angle.
movf theta, w ; copy to w so we can work with it
addlw 64 ; add pi/2 so we can just take the sine
movwf temp ; move new angle to temp because we test this later
call sinw ; we now have the sine in w
btfsc temp, 7 ; test the original angle to see if it's in Q3 or Q4
nop ; ... if so, we know it's a negative, so handle that here
; ...its cosine (-127 to 127)
movf theta, w ; copy to w so we can work with it
addlw 64 ; convert cos to sin
movwf temp2 ; store in temp2 register so we can compare for negative
call sinw ; we now have the sine in w
movwf temp ; store result in temp register
bcf STATUS, C ; clear the carry bit if it's set -- we're about to roll
rrf temp, w ; roll temp result right to cut in half, store in w
btfsc temp2, 7 ; test the original angle to see if it's in Q3 or Q4
sublw 0 ; ...it is, so negate w
nop ; sine (-127 to 127) is now in w
; ...its tangent, cotangent, secant, cosecant, etc
; Rather than going into a dissertation on how computers divide numbers,
; let me just recommend using a good divide macro and any of the following
; equations...
;
; tan( x ) = sin( x ) / cos( x )
; cot( x ) = 1 / tan( x ) = cos( x ) / sin( x )
; csc( x ) = 1 / sin( x )
; sec( x ) = 1 / cos( x )
;
; These Pythagorean identities may also be useful
;
; sin^2( x ) + cos^2( x ) = 1
; sec^2( x ) = 1 + tan^2( x )
; csc^2( x ) = 1 + cot^2( x )
;
; These will help with adding and subtracting
;
; sin( x + y ) = ( sin( x ) * cos( y ) ) + ( cos( x ) * sin( y ) )
; sin( x - y ) = ( sin( x ) * cos( y ) ) - ( cos( x ) * sin( y ) )
; cos( x + y ) = ( cos( x ) * cos( y ) ) - ( sin( x ) * sin( y ) )
; cos( x - y ) = ( cos( x ) * cos( y ) ) + ( sin( x ) * sin( y ) )
; tan( x + y ) = ( tan( x ) + tan( y ) ) / ( 1 - ( tan( x ) * tan( y ) ) )
; tan( x - y ) = ( tan( x ) - tan( y ) ) / ( 1 + ( tan( x ) * tan( y ) ) )
;
; And for doubled angles...
;
; sin( 2x ) = 2 * sin( x ) * cos( x )
; cos( 2x ) = cos^2( x ) - sin^2( x ) = ( 2 * cos^2( x ) ) - 1 = 1 - ( 2 * sin^2( x ) )
; tan( 2x ) = ( 2 * tan( x ) ) / ( 1 - tan^2( x ) )
;
; And as we've used above... What's a cosine? It's on of several cofunctions:
;
; sin( 90 deg - x ) = cos( x ) cos ( x - 90 deg ) = sin( x )
; sec( 90 deg - x ) = csc( x ) csc ( x - 90 deg ) = sec( x )
; tan( 90 deg - x ) = cot( x ) cot ( x - 90 deg ) = tan( x )
;
; And finally... What's an arcsine, arccosecant, arccosine, arcsecant, arctangent,
; and arccotangent? They're simply the inverses...
;
; arcsin ( sin(x) ) = x arccos ( cos(x) ) = x
; arcsec ( sec(x) ) = x arccsc ( csc(x) ) = x
; arctan ( tan(x) ) = x arccot ( cot(x) ) = x
;
goto Start
Finished
goto $
sinw
; If bit 7 is clear, we're in quadrant 1 or 3
; If bit 8 is clear, we're in quadrant 1 or 2
;
; bit 8 bit 7
; Quadrant 1 0 0 read from begining of table
; Quadrant 2 0 1 read from end of table
; Quadrant 3 1 0 read from begining of table and negate
; Quadrant 4 1 1 read from end of table and negate
;
; Angles in quadrants 3 and 4 result in negative sines. Because returning
; a negative value from this subroutine would require an additional entry
; on the call stack (a call to the sine table to get the value before
; negating it), we'll just leave it up to the user to negate the result
; if necessary. This saves us an additional call.
; This table returns a value sclaed 0 to 255
movwf sinTemp ; Move input to temp variable to test it
andlw 0x03F ; Clear the first two bits of input - number needs to be <= 64
btfsc sinTemp, 6 ; read from the begining or the end of the table?
sublw 64 ; ...read from end, so w = TableSize - Input
addwf PCL, f ; Position program counter to appropriate result
dt 0, 6, 13, 19, 25, 31, 37, 44
dt 50, 56, 62, 68, 74, 80, 86, 92
dt 98, 103, 109, 115, 120, 126, 131, 136
dt 142, 147, 152, 157, 162, 167, 171, 176
dt 180, 185, 189, 193, 197, 201, 205, 208
dt 212, 215, 219, 222, 225, 228, 231, 233
dt 236, 238, 240, 242, 244, 246, 247, 249
dt 250, 251, 252, 253, 254, 254, 255, 255, 255
end