programming

You are currently browsing articles tagged programming.

I built a framework for robot wheels a while back using OpenSCAD and used it to create a few different wheel styles. I recently decided to combine them all into one massively configurable wheel model, and add a number of new features as well. The result is an OpenSCAD file with 46 parameters that provides a limitless set of combinations and wheel designs. I call it One Wheel To Rule Them All.

It includes twelve tread patterns (all configurable in often surprising ways), eight core spoke patterns (also highly customizable), configurable support for o-rings, bands, and even optical encoder timing slots (directional and non-directional), and a lot more. Plus, I’m still adding features as I think of them.

First, here are a few images of the types of the various basic elements, as well as a few variations that show the flexibility of the designs. For example, as shown in these images, the Spiral style can be used to create a variety of interesting designs that you might not think of when you think “spiral.” After the images you’ll find full details on the parameters.

It’s important to note that you can configure this wheel to such an extend that it may not be printable at home with extruded plastic printers. In these cases, services such as Shapeways could come in handy.

The source file is available at http://www.thingiverse.com/thing:21486, or on github at http://github.com/alexfranke/Highly-Configurable-Wheel.

Tire Parameters

Often wheels are built around the tires. In this section, specify the properties of the tires you’re using, and this will define the diameter of the wheel. If you’re using o-rings, the tireCSDiameter should be the cross-section diameter of the o-ring, or if you’re using some other flat tire material (such as rubber bands), jsut specify the its thickness. If you’re not using any tire at all, set the tireCSDiameter to zero.

  • wheelWidth: The width (or thickness) of the the wheel
  • tireCSDiameter: Cross-sectional diameter (CS) — How thick is the tire rubber?
  • tireID: Internal diameter (ID) — How wide is the inside opening?
  • tireStretch: Circumferential stretch percentage (usually 1 + 0-5%) — How much to you want to stretch it to get it on?

Rim properties

The rim sits at at the outside of the spokes and supports the tires or added treads. Installed tires (such as o-rings, rubber bands, etc) are set into grooves carved out of therim, while trads are added onto it. Keep this in mind when you’re using tires — as an example, the rim height should not be smaller than the radius of o-ring tires.

The rim also supports rotary encoder timing holes for wheel feedback. Use the padding parameters to adjust the location of those holes. See the compiler output for helpful information about the distance indicated by each timing hole. Directional timing holes will produce a second set of holes that are 90 degrees out of phase with the first. This allows you to stack sensors at the same location over the wheel instead of trying to position them along the circumference. Directional timing holes essentially double the resolution. You can also double resolution by looking for both rising and falling edges.

  • rimHeight: The height of the rim portion of the wheel
  • timingHoles: The number of timing holes to carve into the rim
  • timingHoleInPad: The inside padding for the timing holes
  • timingHoleMidPad: The middle padding if direction timing holes is selected
  • timingHoleOutPad: The outside padding for the timing holes
  • directional: A directional encoder renders two sets of slots, 90 deg out of phase

Tread Parameters

In this section, specify the properties of the tire tread you want to render. If you’re using a wheel (e.g. o-ring, rubber bands, etc), then use either the “o-rings” or “slots” settings, which will cut a groove (or grooves) in the wheel rim to fit the tires. The othertreat styles will render a tread pattern protruding out from the tire surface by the amount you specify in third part of “knobSize”.

Imagine the tire is mounted on a robot and facing straight at you. The “knobSize” parameter defines the size and shape of knobs in an [x,y,z] format, where x goes across the rim, y goes up and down along the perimeter of the wheel, and z protrudes out from the wheel toward you.

The “staggerOffset” parameter allows you to stagger knobs across the tire by an amount you specify. Set this to zero if you want all the knobs lined up along the perimeter and aligned with the edges of the rim.

“numberOfKnobs” specifies how many knobs there are across the tire, and “lineThickness” specifies how thick the lines are from “drawn” tire styles, such as “x”, “cross”, and “zigX”. You can use these pameters together in creative ways — for example to extend a single tread profile across the width of the tire, or to create a contiguous zig-zag.

Finally, “radialTreadSets” defines how many sets of treads are rendered around the wheel. Each set contains two rows in order to create the staggered effect.

Tread styles are:

    • none: No tread is rendered
    • cross: Each knob is the shape of a plus sign with the specified lineThickness
    • o-rings: Grooves are cut into the rim to accept o-ring tires
    • squares: Each knob is a rectangle, whose size is specified by knobSize
    • spheres: Each knob is a smooth bump, whose size is specified by knobSize
    • cylindersX: Each knob is a cylindrical shape running across the wheel, whose size is specified by knobSize
    • cylindersY: Each knob is a cylindrical shape running along the perimiter of the wheel, whose size is specified by knobSize
    • cylindersZ: Each knob is a cylindrical shape protruding from the surface of the wheel, whose size is specified by knobSize
    • spikes: Each knob is a cone or spike protruding from the surface of the wheel, whose size is specified by knobSize
    • slots: Grooves are cut into the rim to accept flat tires, defined by numberOfKnobs (number of grooves), the first and third numbers in knobSize to define the width of the slots and the depth, and spaceBetweenTires for the distance between the tires and also from the outside edges to the first slots.
    • x: Each knob is in the shape of an “x” protruding from the surface of the wheel, whose size is specified by knobSize
    • zigX: Each knob is in the shape of a zig-zag protruding from the surface of the wheel, whose size is specified by knobSize
    • v: Each knob is in the shape of a “v” protruding from the surface of the wheel, whose size is specified by knobSize
  • treadStyle: none, cross, o-rings, squares, spheres, cylindersX, cylindersY, cylindersZ, spikes, slots, x, zigX, v
  • knobSize: The size of each knob [across wheel, along the perimeter, prodruding]
  • radialTreadSets: How many sets of treads to render around the wheel (2 rows per set).
  • numberOfKnobs: The number of knobs to render per row.
  • staggerOffset: A distance to offset the staggered rows.
  • lineThickness: The line thickness for “drawn” styles, such as “x” and “zigX”
  • maxTires: For o-rings, the maximum number of tires per wheel
  • spaceBetweenTires: For o-rings, the space between each tire, if there are more than one

Spoke-related Parameters

This section is used to define the spoke style of the wheel. Some of the properties are only applicable to certain wheel types, and these properties can be used together in creative ways to create a wide range of tire designs.

The “proportion” property affects how some spokes are rendered. The first number is the proportion of the design from the center of the wheel to the inside of the rim, and the second number is the proportion of the width inside of the wheel. For example, to create spokes that are roughly in the shape of a “U”, you can use a “circle” style, and set the proportion to [1.5, 1.0], for cirle spokes that are 150% as long as the distance from the center to the inside of the rim, 100% as wide.

Use spokeInset to specify the inner and outer inset of the spoke area from the inner and outer faces of the wheel. You can use a negative number to make the spoke area stick out further than than the rim. The hub position will be based on the inner surface resulting from this inset.

The spoke styles are:

    • biohazard: A biohazard logo-inspired design. Set numberOfSpokes to 3 to mimic the logo.
    • circle: Spokes in a circlar or oval form, defined by spokeWidth and proportion.
    • circlefit: The maximum number of circles that will fit between the center and the rim, with a set of smaller outer circles specified by outerHoleDiameter.
    • diamond: Spokes in the shape of a diamond (rhombus), defined by spokeWidth and proportion.
    • fill: Fills in the spoke area with a solid cylinder.
    • line: Straight line spokes, like you would see on a typical wagon wheel.
    • none: Leaves the spoke area empty and does not make for a very useful wheel.
    • rectangle: Spokes in the shape of a rectangle, defined by spokeWidth and proportion.
    • spiral: Spokes in the shape of a semicircle, defined by curvature, reverse, spokeWidth.
  • spokeStyle: none, biohazard, circle, circlefit, diamond, line, rectangle, spiral, fill
  • spokeInset: The [inner,outer] inset of the spoke area from the surface
  • numberOfSpokes: Number of “spokes.” Set this to three if you’re doing the biohazard design
  • spokeWidth: This is how wide each spoke is.
  • proportion: proportion to rim, proportion of width
  • curvature: For “spiral”, this is how curvey the spokes are. >0, but
  • reverse: For “spiral”, setting this to “true” reverses the direction of the spirals
  • outerHoleDiameter: For “circlefit”, the diameter of the outer holes, or zero for non
  • concavity: Concavity distance of spoke area for [inside, outside] of wheel

Hub Parameters

These properties define the hub — or how the wheel connects to the motor. The default values for the captive nut are precise for a M3 nut and will make the nut a very tight (if not impossible) fit. I prefer this because it allows you to “melt” the nut into place with a soldering iron. However, if you don’t have a solder iron or prefer a looser fit, then just adjust the nut diameter and thickness. (M3 hardware is, by default, set to 3mm screw diameter, 5.4mm nut diameter, and 2.3mm nut thickness.) Similarly, the holes for the motor shaft and grub screw are also precise. This allows the holes to be drilled out for a more precise fit. Again, you can adjust these to suit your needs.

The hubZOffset can be used to “sink” the hub into the wheel, and it defaults to half the wheel thickness. For example, when the hubHeight is 10 and the hubZOffset is -2, then the hub will protrude 8mm from the wheel, but the shaft hole will be 10mm deep. The set screw will still be positioned in the middle of the exposed vertical height, and the fillet/chamfer will also be rendered in the correct position. This property is also useful if you want to poke a hole entirely through the wheel. (e.g. If the wheel is 6mm thick, set the hub height to 16 and the hubZOffset to -6, and you’ll get a hub that protrudes 10mm from the wheel surface with a hole that extends all the way through the wheel.)

To mount a servo motor, set includeHub to false, set shaftDiameter so that the hole will accommodate the servo horn screw and any bit that protrudes from the top of the servo horn. Then set the servoHoleDiameter to the size of your mounting hardware, and set servoHoleDistance1 and servoHoleDistance2 to the total distance between mounting holes on your servo (not the distance from the center). These sets of mounting holes will be rendered at 90 degree angles from one another. If you only want one set of holes, set one of the values to zero. Adjust the angle of all the holes to avoid openings in your wheel design if necessary using servoArmRotation.

Use innerCircleDiameter to specify a solid inner circle to use as a base for the hub. This can be useful if you need a a solid surface for servo mounting hardware or for the base hub fillet/chamfer.

Use outerNutTrap to create a nut or bolt head trap on the outside (bottom) of the hub area. Used in conjunction with shaftDiameter and false for includeHub, this will create a wheel that can drive a bolt much like the large gear on Wade’s Extruder. (This feature is inspired by that design.)

Use servoNutTrap to create nut traps for bolts used to mount the wheel onto servo arms. This feature was suggested by AUGuru.

  • includeHub: Set to false to remove the hub and only include the shaft diameter hole.
  • hubDiameter: The diameter of the hub portion of the wheel
  • hubHeight: The total height of the hub
  • hubZOffset: The Z position of the hub, negative numbers from the surface of the wheel
  • shaftDiameter: The diameter of the motor shaft
  • innerCircleDiameter: The diameter of the solid inner circle under the hub, or zero for none.
  • setScrewCount: The number of set screws/nuts to render, spaced evenly around the shaft
  • setScrewDiameter: The diameter of the set screw. 3 is the default for an M3 screw.
  • setScrewNutDiameter: The “diameter” of the captive nut, from flat to flat (the “in-diameter”)
  • setScrewNutThickness: The thickness of the captive nut
  • baseFilletRadius: The radius of the fillet (rounded part) between the hub and wheel.
  • topFilletRadius: The radius of the fillet (rounded part) at the top of the hub.
  • chamferOnly: Set to true to use chamfers (straight 45-degree angles) instead of fillets.
  • servoHoleDiameter: The diameter of servo arm hounting holes, or zero if no holes
  • servoHoleDistance1: Distance across servo horn from hole to hole (0 to ignore)
  • servoHoleDistance2: Distance across servo horn from hole to hole, rotated 90 degrees (0 to ignore)
  • servoArmRotation: The total rotation of all servo holes
  • servoNutTrap: Size [indiameter, depth] of servo arm captive nut, or 0 (any) for none.
  • outerNutTrap: Size [indiameter, depth] of a captive nut, or 0 (any) for none.

Quality Parameters

  • $fn: Default quality for most circle parts.
Share

Here’s a 3D printed T10 lamp shade that I designed and printed last night. A few weeks ago while searching for LEDs, I noticed an ebay listing for very inexpensive 12V automotive lamps that combine nine bright white LEDs. I believe these are sometimes called “wedge lights,” and are used as turn signals or interior lights.

Because reprap printers typically operate with 12V power supplies, I figured this would be a perfect way to light up the print bed. When the lamps arrived last night, I got out the calipers, worked up a design, and printed it out. I had a little difficulty removing the support material, but I’m pleased with the results.

Here it is on Thingiverse: http://www.thingiverse.com/thing:20809

The ebay listing for the LEDs (which were $1.50 for two) was titled “2 pcs WHITE Xenon SMD 9 LED HID 194 168 T10 Car Light.” It was designed exclusively with OpenSCAD.

Creative Commons License
T10 LED Lamp Shade by Alex Franke (codecreations) is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

Share

He we’re test-driving the our latest robot creation for the first time. It’s the boy’s design and made mostly of wood. The tires are o-rings, and there’s a 12V AA batter pack sandwiched between the two pieces of plywood. The system right now consists of a drive controller using a Modern Device‘s RBBB (small Arduino-compatible) and the Pololu TB6612FNG Dual Motor Driver Carrier, a robot controller, which is a standard Arduino Uno (which doesn’t do a whole lot right now expect forward messages from the remote), and a remote controller, which is another RBBB, joystick and display.

Right now there are two driving modes. The first is a tank drive, where, for example, if the joystick is moved far left, the right wheel moves forward at full speed and the left week backward at full speed. The second mode is what I call “target drive,” in which you set the target speed and direction of each wheel. Soft starting and stopping is built in to the controller, and the jerkiness you see sometimes is a bug in the keep-alive timer — if the robot stops getting messages in target drive mode, then it will stop.

Music is “Don’t you” by stefsax (CC BY 2.5).

Share

Here’s an Arduino-compatible GI-SP0256-AL2 speech synthesizer module that I’m finishing up. It’s a great 1980′s-era allophone speech synthesizer chip that was used in Intellivision expansion modules and sold at RadioShack stores for years for about $12. You can still find them from time to time on ebay, and they produce a fantastic synthesized speech sound. The chip is sometimes called the “SPO256-AL2″ (with the letter “O” as opposed to the numeral “0″) due to a typo in the original documentation from RadioShack.

First, here’s a video of the speech synthesizer in action:

The chip works by sending it a series of allophones (59 to choose from) that make up all the sounds of the English language. It’s a real rats nest when wired up on a breadboard, so I thought I’d throw it together on a little 5cm circuit board. (Let me know by commenting below if you’re interested in one.)

The board leaves open (and accessible) four analog pins and four digital pins (two with PWM), plus two additional analog pins in you use the serial clock and data lines that are set up for I2C communication by default. The eight non-I2C pins are paired with ground pins, and three are set up by default to configure the device address for I2C communication. It requires regulated 5V via a standard 6-pin FTDI connection (you don’t need to use all pins unless you’re programming it), and there’s an output jumper at the bottom that can be amplified to power a speaker.

Here’s the design. It’s about 2 inches square. I’ll post the code when I get it finished up. Let me know if you’re interested!

Arduino-compatible SP0256-AL2 Speech Synthesizer

Arduino-compatible SP0256-AL2 Speech Synthesizer

Some Code

Here’s some of the code I used for my test. I’ve updated the code on Februay 18, 2012 to include the required loop() method (which I’d accidentally left out) and to rename the “SS” constant so it doesn’t conflict with the Slave Select constant in case that’s defined.

// Voice Pins -- The SP0256 address pins are all on the same port here.
// This isn't necessary but it does make it a lot easier to pick an
// allophone in code using PORTC in this case.
#define PIN_A1  A0
#define PIN_A2  A1
#define PIN_A3  A2
#define PIN_A4  A3
#define PIN_A5  A4
#define PIN_A6  A5
#define PIN_ALD  2
#define PIN_LRQ  12

// some words to say
byte purple[] = {PP, ER1, PP, LL };
byte monkey[] = {MM, AX, NN1, KK1, IY };
byte garden[] = {GG1, AR, PA3, DD2, IH, NN1 };
byte moment[] = {MM, OW, MM, EH, NN1, TT2 };

void setup() {
  // Set pin modes
  pinMode( PIN_ALD, OUTPUT );
  pinMode( PIN_LRQ, INPUT );
  DDRC = B00111111;  // Sets Analog pins 0-5 to output

  digitalWrite(PIN_ALD, HIGH);

  speak( purple, (byte)(sizeof(purple) / sizeof(byte)) );
  speak( monkey, (byte)(sizeof(monkey) / sizeof(byte)) );
  speak( garden, (byte)(sizeof(garden) / sizeof(byte)) );
  speak( moment, (byte)(sizeof(moment) / sizeof(byte)) );
}

void loop() {
}

void speak( byte* allophones, byte count ) {
  for( byte b = 0; b < count; b++ ) {
    speak( allophones[b] );
  }
  speak( PA4 ); // short pause after each word
}

void speak( byte allophone ) {
   while ( digitalRead(PIN_LRQ) == HIGH )
    ; // Wait for LRQ to go low

  PORTC = allophone; // select the allophone

  // Tell it to speak by toggling ALD
  digitalWrite(PIN_ALD, LOW);
  digitalWrite(PIN_ALD, HIGH);
}

Allophones

Here are the allophone definitions:

#define PA1 0x00
#define PA2 0x01
#define PA3 0x02
#define PA4 0x03
#define PA5 0x04

#define OY  0x05
#define AY  0x06
#define EH  0x07
#define KK3 0x08
#define PP  0x09
#define JH  0x0A
#define NN1 0x0B
#define IH  0x0C
#define TT2 0x0D
#define RR1 0x0E
#define AX  0x0F
#define MM  0x10
#define TT1 0x11
#define DH1 0x12
#define IY  0x13
#define EY  0x14
#define DD1 0x15
#define UW1 0x16
#define AO  0x17
#define AA  0x18
#define YY2 0x19
#define AE  0x1A
#define HH1 0x1B
#define BB1 0x1C
#define TH  0x1D
#define UH  0x1E
#define UW2 0x1F
#define AW  0x20
#define DD2 0x21
#define GG3 0x22
#define VV  0x23
#define GG1 0x24
#define SH  0x25
#define ZH  0x26
#define RR2 0x27
#define FF  0x28
#define KK2 0x29
#define KK1 0x2A
#define ZZ  0x2B
#define NG  0x2C
#define LL  0x2D
#define WW  0x2E
#define XR  0x2F
#define WH  0x30
#define YY1 0x31
#define CH  0x32
#define ER1 0x33
#define ER2 0x34
#define OW  0x35
#define DH2 0x36
#define SSS 0x37
#define NN2 0x38
#define HH2 0x39
#define OR  0x3A
#define AR  0x3B
#define YR  0x3C
#define GG2 0x3D
#define EL  0x3E
#define BB2 0x3F
Share

Here’s a small, inexpensive, modular, and easy-to-customize motor controller I’m working on that incorporates the Modern Device RBBB ($13), and Pololu’s TB6612FNG Dual Motor Driver Carrier ($8.50). If I fry or want to retask the brain or the driver or both, I can just pop them out and move along. Plus, because the RBBB is essentially a little Arduino, I’m in complete control of the code; I can rest assured that my robot will adequately obey the Three Laws. :)

It’s precisely 50 mm square. The ADDY jumpers will allow it to be addressed on an I2C network if desired. I’m working through some DC motor code, but I’m also planning some bipolar stepper code as well. The PCB was designed with Fritzing, which I found to be very usable but a bit limiting.

I’ve decided to sell off the extras either as kits or bare PCBs, so let me know if you’re interested by commenting below.

DMD: Dual Motor Doohickey v1.0 - A flexible motor controller

DMD: Dual Motor Doohickey v1.0 - A flexible motor controller

UPDATE: The circuit boards arrived in three weeks time (detailed at SeeedStudio PCB Turn-Around Time (Registered Mail) ), and I’m very pleased with the results. Here are a few pictures of the boards below. Click on the thumbnail for a larger image.

This was updated again on November 7, 2011 to add Fritzing reference, and the ebay link.

Share

Here’s a little SQL gymnastics used to parse and query against a predictably-formatted long text field.

The challenge: We have a single text field that contains a list person_id-to-area mappings, and we need the query the database for a list of those people with their names.

For example, this it the query used to fetch the mapping field:

select value  -- a "text" field (e.g. not a varchar) 
from setting		
where setting_name = 'InstructorAreaMap'

And that query returns “42|Accounting\r\n51|Marketing\r\n69|Strategy“. But what we want is a set of records that contains not only the Person ID and Area, but also the name of the person from the Person table, where Person ID is the key.

We can do this in a single query like so:

  1. Convert the text field into a varchar that we can use for replace operations.
  2. Replace the delimiters with xml tags.
  3. Convert the result into an XML data type.
  4. Select against that XML.
  5. Join in the Person table and select the result.

Step 2 builds an XML string that looks like “<r><i>42</i><a>Marketing</a></r><r><i>51</i><a>Accounting</a></r><r><i>69</i><a>Strategy</a></r>“, and Step 4 essentially converts that into a joinable table that looks like this:

42	Marketing
51	Accounting
70	Strategy

After this it’s easy to get the result we need:

Accounting     Fred Flintstone  51
Marketing      George Jetson    42
Communication  Barney Fife      70

Here’s the SQL query:

select assignments.area, p.display_name name, p.person_id
from (

	-- STEP 4: 
	-- Create a table of person_id (i), area (a) pairs from an xml string 
	-- in the form "<r><i>42</i><a>Area</a></r><r><i>..." called "assignments" 
	select c.value('(i)[1]', 'int') as person_id,
		c.value('(a)[1]', 'varchar(50)') as area
	from (

		-- STEP 3:
		-- select an XML type called "data" in the above form using 
		-- information in the "value" field of the "InstructorAreaMap" setting
		select cast (

			-- STEP 2: 
			replace( '<r><i>' + 
				replace( 

					-- STEP 1: 
					-- Convert the text field into something we can use 
					SUBSTRING( convert( varchar(max), value ), 1, DATALENGTH(value) ), -- search
					char(13)+char(10), -- find
					'</a></r><r><i>' ) -- replace with
				+ '</a></r>', -- outer serach
				'|', -- outer find
				'</i><a>' ) -- outer replace with
			as xml ) data

		from setting
		where setting_name = 'InstructorAreaMap'
	) as t

	cross apply data.nodes('r') as t2(c)
) as assignments

-- STEP 5:
-- Join against the Person table to get the name. 
inner join person p
	on p.person_id = assignments.person_id
order by area, name
Share

The goal was to crawl on the cheap, and what’s cheaper than popsicle sticks craft sticks and fishing line? Next we’ll wire up a 555 circuit so it can roam untethered, but until then, here’s how to make one of your own. But first the video! :) (UPDATE: Details about the untethered “version 2″ with the 555 timer circuits can be found at StickBot V2.0 - Untethered!.)

Supplies

  • 4 Popsicle craft sticks (like Popsicle brand ice pop sticks)
  • 3 small eye screws
  • A few feet of mono-filament (fishing line). We used 10 lb test.
  • 3 pipe cleaners (one is just decorative)
  • 1 small cable tie
  • A bit of masking tape
  • 1 mini micro hobby servo

How to Make It

  1. Body: Stack four popsicle craft sticks, and drill three pilot holes through all of them — one in the center and one at each end. Three of the sticks will be the legs, and one will be the body.
  2. Joints: Arrange the legs on top of the body, and fasten them together with three small eye screws. On most eye screws, the threads will not go all the way to the top, so the legs should be free to move back and forth.
  3. Muscle: With a small cable tie (and possibly a dab of glue), fasten a 3.7g mini micro hobby servo to the body stick, centered between the middle and hind legs, with the motor shaft at the rear. Attach a servo arm so that it points out like the legs when the motor is in its center position. (You can get these motors on ebay for a couple bucks.)
  4. Tendons:Cut six lengths of monofilament, each about 9 inches long. For each line, tie a knot into one end, and thread it from the bottom through the hole at the end of the leg. The knot should be big enough that it won’t slip through the hole. Thread the mono-filament from the legs as follows (in this order):
    • Front left: Left to right, though the center eye, and through the right end of the servo horn.
    • Front right: Right to left, though the center eye, and through the left end of the servo horn.
    • Back left: Left to right, though the center eye, and through the left end of the servo horn.
    • Back right: Right to left, though the center eye, and through the right end of the servo horn.
    • Middle left: Left to right, though the front eye, and through the right end of the servo horn.
    • Middle right: Right to left, though the front eye, and through the left end of the servo horn.
  5. Adjustment: Carefully pull each line snug so that the legs are all perpendicular to the body, and tape them down to the servo horn. Trim off the ends, leaving an inch or so for later adjustment or tightening.
  6. Legs: Cut some pipe cleaners into six 3-inch lengths and wrap each one around the end of a leg. Bend the legs so that they all touch the surface, and are angled toward the back of the crawler. It can take a little time to get it just right, and you’ll probably want to adjust it when you get the motor hooked up.
  7. Antennae: Add some antennae if you wish by wrapping a couple 5-inch lengths of pipe cleaner to the front legs.
  8. Brain: Power the servo with an Arduino, Basic Stamp, or other micro controller, and program it to turn left and right continuously. There’s a sample sketch below.

A Simple Arduino Sketch

#include <Servo.h>

#define SERVO_PIN       9    // what pin is the servo on?
#define LEFT_EXTENT     0    // how far left should the servo go?
#define RIGHT_EXTENT    180  // how far right?
#define PAUSE           500  // how many milliseconds between steps?

Servo myservo;

void setup() {
  myservo.attach(SERVO_PIN);
}

void loop() {
  myservo.write( LEFT_EXTENT );
  delay(PAUSE);
  myservo.write( RIGHT_EXTENT );
  delay(PAUSE);
}

Video Music Credits

The music in the video is by Morusque (CC BY-NC): http://ccmixter.org/files/Nurykabe/32448

Updated Name

I realized that Popsicle was actually a registered brand name and not just a common word, so in order to avoid any confusion or trouble, I changed this little guy’s name to StickBot. This project does not (and never did) have anything to do with Popsicle brand ice pops. In fact, I’m not even sure the craft sticks I uses were actually from Popsicle brand ice pops. So my sincere apologies to the Popsicle people; I hope you continue to let me eat your ice pops because life would simply not be the same without them!

Share

To mark the 63rd anniversary of the first stored computer program to run (June 21), I rewrote the original code in C# last night, both using the original algorithm (that was never intended to be efficient) and using a more modern structure. The Kilburn Highest Factor Routine finds the highest factor of 2^18, and completed with the correct answer in 52 minutes with 3.5 million operations. It was written by the late computer pioneer Tom Kilburn and run on the Machester SSEM (“Baby”).

The code is written in lines 1-19, lines 20-22 contain some control flow values, lines 23 and 24 contain 2^18 and the current factor to test, and lines 25-27 are working memory.  Click for a larger version of the original image from The National Archive for the History of Computing.

Kilburn Highest Factor Routine

Kilburn Highest Factor Routine

The last three columns (labelled 13, 14, and 15) are the instructions, and there are only a few of them. They are:

  • 100 – Jump forward or backward in code by the amount at the address given.
  • 010 – Load the negative of the value at the given address into the accumulator.
  • 110 – Store the value in the accumulator to the given address.
  • 001 – Subtract the value at the given address from the value in the accumulator, and keep the result in the accumulator.
  • 011 – Skip the next line if the value in the accumulator is greater than zero.
  • 111 – Halt

The first version in the listing below follows the original algorithm (and yes, you can use “goto” in C#). There’s a lot of subtraction involved because if you’re short on space and only want to implement one arithmetic operator, you’re better off implementing subtraction, because you can so addition with it, too. “S” is used here to indicate the Storage tube, which stored both the program and the working memory. The accumulator (represented by the variable “acc”) and the program counter used different tubes. The program counter is what kept track of where the computer was in the program during execution.

The only slightly optimized C# version at the bottom takes less than a millisecond today.


Stopwatch sw = new Stopwatch();
sw.Start();
int s20_jump_rel = -3;     // unused in code, provided for completeness
int s21_const_1 = 1;       // the amount to decrement the number being tested
int s22_jump_addy = 4;     // unused in code, provided for completeness
int s23_number_neg = -262144; // the number to solve (find the factor of)
int s24_div_init = 262143; // the initial number to test

int acc = 0;

acc = -s24_div_init;        // S01 - Load and negate the initial number to test
int s26_div_neg = acc;      // S02 - Store that number into S26

S03:
acc = -s26_div_neg;         // S03 - Load and negate the negated current number to test

int s27_div_pos = acc;      // S04 - Store that number into S27

acc = -s23_number_neg;      // S05 - Load and negate the number to solve

S06:
acc -= s27_div_pos;         // S06 - Subtract the current number to test

if( acc &gt;= 0 )           // S07 - If the accumulator is &gt; 0...
goto S06;                   // S08 - ...go back to S06

acc -= s26_div_neg;         // S09 - Subtract the negated current number to test
int s25 = acc;              // S10 - Store that number into S25
acc = -s25;                 // S11 - Load and negate the number in S25

if( acc &gt;= 0 )           // S12 - If the accumulator is &gt; 0...
goto HALT;                  // S13 - ...End

acc = -s26_div_neg;         // S14 - Load and negate the negated current number to test
acc -= s21_const_1;         // S15 - Subtract 1

s27_div_pos = acc;          // S16 - Store that number into S27
acc = -s27_div_pos;         // S17 - Load and negate the number in S27
s26_div_neg = acc;          // S18 - Store that number into S26

goto S03;                   // S19 - Go back to S03

HALT:
sw.Stop();
Console.WriteLine( "Elapsed={0}", sw.Elapsed );  // Write the elapsed time
Console.WriteLine( s27_div_pos );                // Write the result

sw.Restart();                // Restart the stopwatch for a more modern version
int i = 262143;              // Set the initial number to test
while( 262144 % i-- != 0 ) ; // Decrement until the number to solve modulus zero is zero
sw.Stop();
Console.WriteLine( "Elapsed={0}", sw.Elapsed );  // Write the elapsed time
Console.WriteLine( i + 1 );                      // Write the result

Share

We were using a web service that wasn’t quite up to interoperability standards. When attempting to use the service from .Net, we saw a number of errors and warnings related to the how the response is deserialized. In particular, .Net seemed to have trouble with the arrays (ArrayOfString or ArrayOfStrings).

Some of the warning or exceptions I saw are listed here, the solution is below it, and some of the root causes are below that. I don’t think it’s important to know about the specific web service or WSDL I was using, except to say that it didn’t pass the WS-I Basic Profile.

These were the original symptoms:

  • Error in deserializing body of reply message for operation ‘myMethodName’. (System.ServiceModel.CommunicationException)
  • There is an error in XML document ([line], [position]). (This was the inner exception to the above, and is common when an XML document doesn’t deserialize.)
  • The specified type was not recognized: name=’ArrayOfStrings’, namespace=’[namespace]‘, at [location]. (The was the inner exception of the above line, and explains where deserialization failed.)
  • Exceptions were thrown specifically at System.Xml.Serialization.XmlSerializationReader.GetPrimitiveType()
  • Undefined complexType ‘http://schemas.xmlsoap.org/soap/encoding/:Array’ is used as a base for complex type

The solution was to intercept the XML within WCF and deserialize it manually. There’s not a lot of instruction or examples for this online, so I thought I’d provide some here. Read the comments in the code carefully, and remember to change the return values in the Reference.cs file.

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click( object sender, EventArgs e )
        {
            MyServiceReference.MyService service = new MyServiceReference.MyService();

            // In this case we have HTTP authentication
            service.ClientCredentials.UserName.UserName = "username";
            service.ClientCredentials.UserName.Password = "password";

            // Add a behavior to the operations we want to override
            service.Endpoint.Contract.Operations.Find( "getArrayOfStrings" ).Behaviors.Add( new FormatterBahavior() );
            service.Endpoint.Contract.Operations.Find( "getSomthingElse" ).Behaviors.Add( new FormatterBahavior() );

            // Call the web services
            var result1 = service.getArrayOfStrings();
            var result2 = service.getSomthingElse();
        }

        // This operation behavior changes the formatter for a specific set of operations in a web service. 
        public class FormatterBahavior : IOperationBehavior
        {
            #region IOperationBehavior Members
            public void AddBindingParameters( OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters )
            { }

            public void ApplyClientBehavior( OperationDescription operationDescription, ClientOperation clientOperation )
            {
                // The client should use a different, custom formatter depending upon which operation is called.
                switch( operationDescription.Name )
                {
                    case "getArrayOfStrings":
                        clientOperation.Formatter = new MyCustomFormatter1( clientOperation.Formatter );
                        break;
                    case "getSomthingElse":
                        clientOperation.Formatter = new MyCustomFormatter2( clientOperation.Formatter );
                        break;
                }
            }

            public void ApplyDispatchBehavior( OperationDescription operationDescription, DispatchOperation dispatchOperation )
            { }

            public void Validate( OperationDescription operationDescription )
            { }
            #endregion
        }

        // This customized formatter intercepts the deserialization process and handles it manually.
        public class MyCustomFormatter1 : IClientMessageFormatter
        {
            // Hold on to the original formatter so we can use it to return values for method calls we don't need.
            private IClientMessageFormatter _InnerFormatter;

            public MyCustomFormatter1( IClientMessageFormatter innerFormatter )
            {
                // Save the original formatter
                _InnerFormatter = innerFormatter;
            }

            #region IClientMessageFormatter Members
            public object DeserializeReply( System.ServiceModel.Channels.Message message, object[] parameters )
            {
                // Create a new response object.
                MyCustomResponseObject retVal = new MyCustomResponseObject();
                System.Xml.XPath.XPathDocument doc = new System.Xml.XPath.XPathDocument( message.GetReaderAtBodyContents() );
                var nav = doc.CreateNavigator();

                // Pulling out the data we need from the XML
                foreach( System.Xml.XPath.XPathNavigator item in nav.Select...() )
                {
                    // Populate retVal with the data we need from the XML
                }

                // IMPORTANT: Be sure to change the return type of the operation (and also its interface) in
                // the service's Reference.cs file to object or you will get a cast error.
                return retVal;
            }

            public System.ServiceModel.Channels.Message SerializeRequest( System.ServiceModel.Channels.MessageVersion messageVersion, object[] parameters )
            {
                // Use the inner formatter for this so we don't have to rebuild it.
                return _InnerFormatter.SerializeRequest( messageVersion, parameters );
            }

            #endregion
        }

        public class MyCustomFormatter2 : IClientMessageFormatter
        {
            // ...
        }
    }

    public class MyCustomResponseObject
    {
        public List&lt;Report&gt; ReportList = new List&lt;Report&gt;();
    }

Here are some specifics on where the web service failed to pass the WS-I Basic profile:

  • R2110 specifies that soapend:Array declarations must not extend or restrict the soapenc:Array type.
    • ArrayOfStrings restricts this type. ArrayOfStrings is an array type, and the other complex types in the service depend on ArrayOfStrings.
  • R2111 specifies that soapenc:Array types must not use wsdl:arrayType attribute in the type declaration.
    • It was used in the only attribute of the only restriction on that type.
  • R2706 specifies that a wsdl:binding in a description must use the value of “literal” for the “use” attribute in body (and other) elements because the profile prohibits the use of encodings.
    • The body elements of the binding use the value “encoded” for the “use” attributes.
  • R2801 specifies that a description must use XML Schema 1.0 recommendations as the basis for user-defined types and structures.
    • The prefix “wsdl” in the attribute of ArrayOfStrings is unbound.
Share