Re-Flashing Printrbot Simple Firmware Again

by Bill Maya on December 30, 2013

I had to re-flash the firmware of my Printrbot Simple this morning for the second time. It was printing fine last night but when I tried printing this morning I could connect to the printer and move the print head to the home position but I couldn’t move the print bed in individual millimeter increments. Also, when I tried to print the extruder wouldn’t heat up. (It’s interesting that this happens – definitely confirms my thoughts that we’re still in the innovators/early adopters stage of this market.)

So I dug out my notes from my last re-flash and followed these steps:

  1. Shorted out the jumper pins with a white rectangular jumper that I scavenged from an old PC (I’ll have to buy a spare this week).
  2. With the printer plugged in but not connected to the laptop, pressed the reset button for several seconds.
  3. Connected the printer to the laptop.
  4. Ran the Atmel Flip application.
  5. In the Flip application
    1. Clicked the Target Device icon and selected AT90USB1286 as the device.
    2. Clicked the Communication Medium icon, selected USB, and then clicked Open in the USB Port Connection dialog.
    3. Selected the Erase, Blank Check, Program, and Verify check boxes.
    4. Selected Load HEX File from the File menu and, in the Load HEX/A90 File dialog select the file named “Marlin-unified-v2.hex”.
    5. Clicked the Run button. The program displayed “Erasing, Programming, Verifying…” dialogs and ended with a “Verify PASS” in the status bar.
  6. Quit the Flip application.
  7. Unplugged the printer from the laptop.
  8. Removed the white rectangular jumper from the jumper pins.
  9. Pressed the reset button on the printer.
  10. Reconnected the printer to the laptop.
  11. Started Repetier-Host.
  12. In Repetier-Host
    1. Connect to the printer.
    2. In Manual Control
      1. Manipulated the print head along the printer’s X, Y, and Z axis’s.
      2. Sent G-Code “M92 X119 Y119 Z2020 E102″ to the printer  and received OK acknowledgement.
      3. Sent G-Code “M211 X100 Y100 Z115″ to the printer and received OK Acknowledgement.
      4. Tested heating up the extruder and turning on the fan.
  13. Quit Repetier-Host.
  14. Disconnect printer from laptop.
  15. Power down printer.
  16. Power up printer.
  17. Connect printer to laptop.
  18. Start Repetier-Host.
  19. Print 10mm test cube.

Steps 13-18 are necessary because if you start printing right after re-flashing the firmware and sending the calibration information to the printer via Repetier, the dimensions on the print are off. You can see this in the picture below.

IMG_0494

Both calibration cubes were printed from the 10mm cube STL. The one on the left, which was printed immediately after step 12, has the dimensions 13.9mm x 13.9mm x 10mm (width, depth, height). The cube on the left, which was printed after step 19, has the dimensions of 10.1mm x 10.1mm x 10.1mm.

Don’t know why this happens, maybe the printer has to be powered down so it reads all it’s configuration fresh from the EEPROM. (I’ll have to ask and next week’s 3D printer user group meeting at AS220).

Also removed the electrical components from a broken desk lamp that was handing around so I could use it to hold the spools of plastic filament and feed it to the printer without snarls. I’ve only got one spool right now but another one has been ordered and is on the way (the holder should be able to support two or three spools).

IMG_0493

Also printed a skull and two snakes (I’ve gone through the 1/2 kg. of clear filament that came with the printer so now I’m using the black filament that I purchases as part of my original order).

IMG_0495

{ Comments on this entry are closed }

Printing A Replacement Deadbolt Lever

by Bill Maya on December 27, 2013

We’ve got a deadbolt on one of our doors with a locking lever that went missing about a month and a half ago. I haven’t been able to find a replacement lever so I decided to make one.

IMG_0481

After measuring the stem I designed a parametric model for a lever replacement.

Snap5

And then printed it out. It took me two tries since my initial measurements with the digital fractional calipers was off (first time using them).

IMG_0483

Once I got the internal measurements correct the locking lever slide snugly over the stem and made it easier to lock the deadbolt. Voila, problem solved!

IMG_0482

And if it’s ever lost or broken, I can print out as many replacements as I need.

IMG_0485

Here’s the script to create the replacement lever.

outerLength = 30;
outerWidth = 10;
outerHeight = 8.68;

innerLength = 10.98;
innerWidth = 7.14;
innerHeight = 7.68;

xPosition = (outerLength - innerLength) - 1.96;
yPosition = (outerWidth - innerWidth) / 2;

difference() {
color("blue") cube(size=[outerLength, outerWidth, outerHeight]);
translate([xPosition, yPosition, 1.0])
color("red") cube(size=[innerLength, innerWidth, innerHeight]);
}

First we set the parameters for the lever’s overall dimensions (the “outers”) and then the space that we need to carve out in the lever so it can fit over the stem (the “inners”). Then, using the outer and inner lengths and widths we calculate the position of the inner cube and then use the translate command to position the inner cube in the correct place

Snap1

We use OpenSCAD’s difference command to subtract the inner cube from the the outer cube.

IMG_0483

{ Comments on this entry are closed }

The Tesseract – Part 3

by Bill Maya on December 26, 2013

I was able to make the tesseract model completely parametric so you can create hypercubes with inner and outer squares of different dimensions.

Snap4

I was also able to clean up the script that generates the model using some new things I learned about OpenSCAD scripting. Here’s the script broken down step by step.

First I set up some initial parameters.

$fn = 100;

withColor = true;

largeWidth = 20;
largeEdge = 3;

smallWidth = 10;
smallEdge = 2;

The $fn value sets the number of facets used to generate an arc. Setting it to a high number renders the cylindrical struts that connect vertexes and cubes much smoother. The withColor variable is a boolean that simply determines whether or not the outer cube, inner cube, and structs are rendered in different colors – blue, red, and green respectively (I found it easier to see changes on each piece of the hypercube when they were different colors but I wasn’t sure having different colors would affect the generated STL file and subsequent G-Code since my printer can only print one color at a time). And finally the width and edge variables are the dimensions for the cubes.

Then I created the outer and inner cube vertexes.

// Create outer cube vertexes
frontUpperLeftLarge = [-largeWidth / 2, -largeWidth / 2, largeWidth / 2];
frontUpperRightLarge = [largeWidth / 2, -largeWidth / 2, largeWidth /2];
frontLowerLeftLarge = [-largeWidth / 2, -largeWidth / 2, -largeWidth / 2];
frontLowerRightLarge = [largeWidth / 2, -largeWidth / 2, -largeWidth / 2];

backUpperLeftLarge = [-largeWidth / 2, largeWidth / 2, largeWidth / 2];
backUpperRightLarge = [largeWidth / 2, largeWidth / 2, largeWidth /2];
backLowerLeftLarge = [-largeWidth / 2, largeWidth / 2, -largeWidth / 2];
backLowerRightLarge = [largeWidth / 2, largeWidth / 2, -largeWidth / 2];

// Create inner cube vertexes
frontUpperLeftSmall = [-smallWidth / 2, -smallWidth / 2, smallWidth / 2];
frontUpperRightSmall = [smallWidth / 2, -smallWidth / 2, smallWidth /2];
frontLowerLeftSmall = [-smallWidth / 2, -smallWidth / 2, -smallWidth / 2];
frontLowerRightSmall = [smallWidth / 2, -smallWidth / 2, -smallWidth / 2];

backUpperLeftSmall = [-smallWidth / 2, smallWidth / 2, smallWidth / 2];
backUpperRightSmall = [smallWidth / 2, smallWidth / 2, smallWidth /2];
backLowerLeftSmall = [-smallWidth / 2, smallWidth / 2, -smallWidth / 2];
backLowerRightSmall = [smallWidth / 2, smallWidth / 2, -smallWidth / 2];

I initially thought to simply define each variable without a specific vertex value. Something like this:

frontUpperLeftLarge = [0, 0, 0];

But since variables are set at compile-time, not run-time, it wasn’t possible to to initialize each vertex variable to the origin at the beginning of the script and then set them to their actual value later in the program.

The remaining part of the “main” program is these three lines.

DrawOuterCube(withColor);
DrawInnerCube(withColor);
DrawStruts(withColor);

I discovered that OpenSCAD has a module command which lets you break your larger program into smaller methods that you can call with parameters. I don’t think it’s possible to return values but because OpenSCAD scripts have a notion of “scope”, it’s possible to declare a variable globally at the top of a script and change its value in a module (not great but workable).

The DrawOuterCube method calls two other methods.

module DrawOuterCube(withColor) {

PositionOuterVertexes(withColor);
ExtrudeOuterFrame(withColor);

}

PositionOuterVertexes creates the vertexes of the outer cube.

module PositionOuterVertexes(withColor) {

if (withColor) {
PositionVertexCube(vertex = frontUpperLeftLarge, length = largeEdge, shade = "blue");
PositionVertexCube(frontUpperRightLarge, largeEdge, "blue");
PositionVertexCube(frontLowerLeftLarge, largeEdge, "blue");
PositionVertexCube(frontLowerRightLarge, largeEdge, "blue");

PositionVertexCube(backUpperLeftLarge, largeEdge, "blue");
PositionVertexCube(backUpperRightLarge, largeEdge, "blue");
PositionVertexCube(backLowerLeftLarge, largeEdge, "blue");
PositionVertexCube(backLowerRightLarge, largeEdge, "blue");
}
else {
PositionVertexCube(vertex = frontUpperLeftLarge, length = largeEdge);
PositionVertexCube(frontUpperRightLarge, largeEdge);
PositionVertexCube(frontLowerLeftLarge, largeEdge);
PositionVertexCube(frontLowerRightLarge, largeEdge);

PositionVertexCube(backUpperLeftLarge, largeEdge);
PositionVertexCube(backUpperRightLarge, largeEdge);
PositionVertexCube(backLowerLeftLarge, largeEdge);
PositionVertexCube(backLowerRightLarge, largeEdge);
}

}

By calling the PositionVertexCube method, passing in the individual vertexes X, Y, and Z coordinates along with the length of the cube and, if withColor is true, the color that the cube should be drawn in. If withColor is false, no colors are drawn and the objects are rendered in what I assume is the standard mustardish yellow (turns out the color command only works when the script is compiled, not when it’s rendered). I also want to mention OpenSCAD’s ability to branch based on conditional expressions using a very simple if/else construct.

PositionVertexCube moves to the specified vertex, sets the color (if applicable), and then draws the cube, centering it on the vertex coordinates.

module PositionVertexCube(vertex, length, shade) {

translate(vertex) color(shade) cube(size = length, center = true);

}

After all the vertex cubes for the outer cube are created the sides of the cube are created by ExtrudeOuterFrame, which creates cylinders from one vertex to another by calling ExtrudeFrameStrut twelve times.

module ExtrudeOuterFrame(withColor) {

if (withColor) {
ExtrudeFrameStrut(frontUpperLeftLarge,[0, 90, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(frontLowerLeftLarge, [0, 90, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backUpperLeftLarge, [0, 90, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backLowerLeftLarge, [0, 90, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backUpperLeftLarge, [90, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backUpperRightLarge, [90, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backLowerLeftLarge, [90, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backLowerRightLarge, [90, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(frontLowerLeftLarge, [0, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(frontLowerRightLarge, [0, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backLowerLeftLarge, [0, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backLowerRightLarge, [0, 0, 0], largeWidth, largeEdge, "blue");
}
else {
ExtrudeFrameStrut(frontUpperLeftLarge, [0, 90, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(frontLowerLeftLarge, [0, 90, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backUpperLeftLarge, [0, 90, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backLowerLeftLarge, [0, 90, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backUpperLeftLarge, [90, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backUpperRightLarge, [90, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backLowerLeftLarge, [90, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backLowerRightLarge, [90, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(frontLowerLeftLarge, [0, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(frontLowerRightLarge, [0, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backLowerLeftLarge, [0, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backLowerRightLarge, [0, 0, 0], largeWidth, largeEdge);
}

}

ExtrudeFrameStrut take the following parameters – the starting vertexes’ X, Y, and Z coordinates, the rotation of the circle that the cylindrical side is created from, the length and diameter of the cylindrical side, and its color, if applicable.

module ExtrudeFrameStrut(vertex, rotation, strutLength, strutDiameter, shade) {

translate(vertex)
rotate(a = rotation)
color(shade)
linear_extrude(height = strutLength, center = false)
circle(diameter = strutDiameter);

}

The inner cube is drawn the same way as the outer cube using its own dimensions. DrawInnerCube calls its own custom methods, PositionInnerVertexes and ExtrudeInnerFrame.

module DrawInnerCube() {

PositionInnerVertexes(withColor);
ExtrudeInnerFrame(withColor);

}

Though they have different names, these two methods call the exact same “helper” methods that were used to draw the outer cubes vertexes and sides, PositionVertexCube and ExtrudeFrameStrut, respectively.

module PositionInnerVertexes(withColor) {

if (withColor) {
PositionVertexCube(frontUpperLeftSmall, smallEdge, "red");
PositionVertexCube(frontUpperRightSmall, smallEdge, "red");
PositionVertexCube(frontLowerLeftSmall, smallEdge, "red");
PositionVertexCube(frontLowerRightSmall, smallEdge, "red");
PositionVertexCube(backUpperLeftSmall, smallEdge, "red");
PositionVertexCube(backUpperRightSmall, smallEdge, "red");
PositionVertexCube(backLowerLeftSmall, smallEdge, "red");
PositionVertexCube(backLowerRightSmall, smallEdge, "red");
}
else {
PositionVertexCube(frontUpperLeftSmall, smallEdge);
PositionVertexCube(frontUpperRightSmall, smallEdge);
PositionVertexCube(frontLowerLeftSmall, smallEdge);
PositionVertexCube(frontLowerRightSmall, smallEdge);
PositionVertexCube(backUpperLeftSmall, smallEdge);
PositionVertexCube(backUpperRightSmall, smallEdge);
PositionVertexCube(backLowerLeftSmall, smallEdge);
PositionVertexCube(backLowerRightSmall, smallEdge);
}

}

module ExtrudeInnerFrame(withColor) {

if (withColor) {
ExtrudeFrameStrut(frontUpperLeftSmall, [0, 90, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(frontLowerLeftSmall, [0, 90, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backUpperLeftSmall, [0, 90, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backLowerLeftSmall, [0, 90, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backUpperLeftSmall, [90, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backUpperRightSmall, [90, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backLowerLeftSmall, [90, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backLowerRightSmall, [90, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(frontLowerLeftSmall, [0, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(frontLowerRightSmall, [0, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backLowerLeftSmall, [0, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backLowerRightSmall, [0, 0, 0], smallWidth, smallEdge, "red");
}
else {
ExtrudeFrameStrut(frontUpperLeftSmall, [0, 90, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(frontLowerLeftSmall, [0, 90, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backUpperLeftSmall, [0, 90, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backLowerLeftSmall, [0, 90, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backUpperLeftSmall, [90, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backUpperRightSmall, [90, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backLowerLeftSmall, [90, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backLowerRightSmall, [90, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(frontLowerLeftSmall, [0, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(frontLowerRightSmall, [0, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backLowerLeftSmall, [0, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backLowerRightSmall, [0, 0, 0], smallWidth, smallEdge);
}

}

Creating the struts between the outer and inner cubes was the most interesting programming part of this refactoring. If you remember from my previous post it was possible to create some “broken” hypercubes by entering certain parameters.

Snap8

This was because the length of each strut distance from an outer vertex to an inner vertex was calculated using the width and edge of the smaller, inner cube. The strut length was directly proportional to the cube width so when the width got smaller the strut length was smaller and it wouldn’t reach all the way to the inner vertex (and when the inner cube got bigger the struct reached and went past the inner vertex).

The solution was to calculate the strut length using the actual distance between the outer and inner vertexes.

Some quick googling turned up this formula for calculating the distance between two points in a three dimensional space:

Point 1 [x1, y1, z1]
Point 2 [x2, y2, z1]

xDistance = x2 - x1
yDistance = y2 - y1
zDistance = z2 - z1

Distance between Point 1 and Point 2 = Square root(xDistance * xDistance + yDistance * yDistance + zDistance * zDistance)

Which translates into this OpenSCAD code.

module ExtrudeStrut(start, end, rotation, strutDiameter, shade) {

strutDistanceX = end[0] - start[0];
strutDistanceY = end[1] - start[1];
strutDistanceZ = end[2] - start[2];

strutLength = sqrt(
strutDistanceX * strutDistanceX +
strutDistanceY * strutDistanceY +
strutDistanceZ * strutDistanceZ);

translate(start)
rotate(a = rotation)
color(shade)
linear_extrude(height = strutLength, center = false)
circle(diameter = strutDiameter);
}

After drawing the the outer and inner cubes the “main” program calls the DrawStruts method.

DrawOuterCube(withColor);
DrawInnerCube(withColor);
DrawStruts(withColor);

Which calls ExtrudeStrut eight times to connect each outer and inner vertex.

module DrawStruts(withColor) {

if (withColor) {
ExtrudeStrut(frontUpperLeftLarge, frontUpperLeftSmall, [0, 125, 45], smallEdge, "green");
ExtrudeStrut(frontUpperRightLarge, frontUpperRightSmall, [0, 125, 135], smallEdge, "green");
ExtrudeStrut(frontLowerRightLarge, frontLowerRightSmall, [0, 55, 135], smallEdge, "green");
ExtrudeStrut(frontLowerLeftLarge, frontLowerLeftSmall, [0, 55, 45], smallEdge, "green");
ExtrudeStrut(backUpperLeftLarge, backUpperLeftSmall, [0, 125, 315], smallEdge, "green");
ExtrudeStrut(backUpperRightLarge, backUpperRightSmall, [0, 125, 225], smallEdge, "green");
ExtrudeStrut(backLowerRightLarge, backLowerRightSmall, [0, 55, 225], smallEdge, "green");
ExtrudeStrut(backLowerLeftLarge, backLowerLeftSmall, [0, 55, 315], smallEdge, "green");
}
else {
ExtrudeStrut(frontUpperLeftLarge, frontUpperLeftSmall, [0, 125, 45], smallEdge);
ExtrudeStrut(frontUpperRightLarge, frontUpperRightSmall, [0, 125, 135], smallEdge);
ExtrudeStrut(frontLowerRightLarge, frontLowerRightSmall, [0, 55, 135], smallEdge);
ExtrudeStrut(frontLowerLeftLarge, frontLowerLeftSmall, [0, 55, 45], smallEdge);
ExtrudeStrut(backUpperLeftLarge, backUpperLeftSmall, [0, 125, 315], smallEdge);
ExtrudeStrut(backUpperRightLarge, backUpperRightSmall, [0, 125, 225], smallEdge);
ExtrudeStrut(backLowerRightLarge, backLowerRightSmall, [0, 55, 225], smallEdge);
ExtrudeStrut(backLowerLeftLarge, backLowerLeftSmall, [0, 55, 315], smallEdge);
}

}

Snap1

Here’s the entire script from start to end.

$fn = 100;

withColor = true;

largeWidth = 20;
largeEdge = 3;

smallWidth = 10;
smallEdge = 2;

/* Variables are set at compile-time, not run-time, so we have to set them to their actual
values here instead of initializing them to [0, 0, 0] and setting them later */

// Create outer cube vertexes
frontUpperLeftLarge = [-largeWidth / 2, -largeWidth / 2, largeWidth / 2];
frontUpperRightLarge = [largeWidth / 2, -largeWidth / 2, largeWidth /2];
frontLowerLeftLarge = [-largeWidth / 2, -largeWidth / 2, -largeWidth / 2];
frontLowerRightLarge = [largeWidth / 2, -largeWidth / 2, -largeWidth / 2];

backUpperLeftLarge = [-largeWidth / 2, largeWidth / 2, largeWidth / 2];
backUpperRightLarge = [largeWidth / 2, largeWidth / 2, largeWidth /2];
backLowerLeftLarge = [-largeWidth / 2, largeWidth / 2, -largeWidth / 2];
backLowerRightLarge = [largeWidth / 2, largeWidth / 2, -largeWidth / 2];

// Create inner cube vertexes
frontUpperLeftSmall = [-smallWidth / 2, -smallWidth / 2, smallWidth / 2];
frontUpperRightSmall = [smallWidth / 2, -smallWidth / 2, smallWidth /2];
frontLowerLeftSmall = [-smallWidth / 2, -smallWidth / 2, -smallWidth / 2];
frontLowerRightSmall = [smallWidth / 2, -smallWidth / 2, -smallWidth / 2];

backUpperLeftSmall = [-smallWidth / 2, smallWidth / 2, smallWidth / 2];
backUpperRightSmall = [smallWidth / 2, smallWidth / 2, smallWidth /2];
backLowerLeftSmall = [-smallWidth / 2, smallWidth / 2, -smallWidth / 2];
backLowerRightSmall = [smallWidth / 2, smallWidth / 2, -smallWidth / 2];

DrawOuterCube(withColor);
DrawInnerCube(withColor);
DrawStruts(withColor);

module DrawOuterCube(withColor) {

PositionOuterVertexes(withColor);
ExtrudeOuterFrame(withColor);

}

module PositionOuterVertexes(withColor) {

if (withColor) {
PositionVertexCube(vertex = frontUpperLeftLarge, length = largeEdge, shade = "blue");
PositionVertexCube(frontUpperRightLarge, largeEdge, "blue");
PositionVertexCube(frontLowerLeftLarge, largeEdge, "blue");
PositionVertexCube(frontLowerRightLarge, largeEdge, "blue");

PositionVertexCube(backUpperLeftLarge, largeEdge, "blue");
PositionVertexCube(backUpperRightLarge, largeEdge, "blue");
PositionVertexCube(backLowerLeftLarge, largeEdge, "blue");
PositionVertexCube(backLowerRightLarge, largeEdge, "blue");
}
else {
PositionVertexCube(vertex = frontUpperLeftLarge, length = largeEdge);
PositionVertexCube(frontUpperRightLarge, largeEdge);
PositionVertexCube(frontLowerLeftLarge, largeEdge);
PositionVertexCube(frontLowerRightLarge, largeEdge);

PositionVertexCube(backUpperLeftLarge, largeEdge);
PositionVertexCube(backUpperRightLarge, largeEdge);
PositionVertexCube(backLowerLeftLarge, largeEdge);
PositionVertexCube(backLowerRightLarge, largeEdge);
}

}

module PositionVertexCube(vertex, length, shade) {

translate(vertex) color(shade) cube(size = length, center = true);

}

module ExtrudeOuterFrame(withColor) {

// Vertex, rotation, strutLength, strutDiameter, shade

if (withColor) {
ExtrudeFrameStrut(frontUpperLeftLarge,[0, 90, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(frontLowerLeftLarge, [0, 90, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backUpperLeftLarge, [0, 90, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backLowerLeftLarge, [0, 90, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backUpperLeftLarge, [90, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backUpperRightLarge, [90, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backLowerLeftLarge, [90, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backLowerRightLarge, [90, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(frontLowerLeftLarge, [0, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(frontLowerRightLarge, [0, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backLowerLeftLarge, [0, 0, 0], largeWidth, largeEdge, "blue");
ExtrudeFrameStrut(backLowerRightLarge, [0, 0, 0], largeWidth, largeEdge, "blue");
}
else {
ExtrudeFrameStrut(frontUpperLeftLarge, [0, 90, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(frontLowerLeftLarge, [0, 90, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backUpperLeftLarge, [0, 90, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backLowerLeftLarge, [0, 90, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backUpperLeftLarge, [90, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backUpperRightLarge, [90, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backLowerLeftLarge, [90, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backLowerRightLarge, [90, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(frontLowerLeftLarge, [0, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(frontLowerRightLarge, [0, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backLowerLeftLarge, [0, 0, 0], largeWidth, largeEdge);
ExtrudeFrameStrut(backLowerRightLarge, [0, 0, 0], largeWidth, largeEdge);
}

}

module ExtrudeFrameStrut(vertex, rotation, strutLength, strutDiameter, shade) {

translate(vertex)
rotate(a = rotation)
color(shade)
linear_extrude(height = strutLength, center = false)
circle(diameter = strutDiameter);

}

module DrawInnerCube() {

PositionInnerVertexes(withColor);
ExtrudeInnerFrame(withColor);

}

module PositionInnerVertexes(withColor) {

if (withColor) {
PositionVertexCube(frontUpperLeftSmall, smallEdge, "red");
PositionVertexCube(frontUpperRightSmall, smallEdge, "red");
PositionVertexCube(frontLowerLeftSmall, smallEdge, "red");
PositionVertexCube(frontLowerRightSmall, smallEdge, "red");
PositionVertexCube(backUpperLeftSmall, smallEdge, "red");
PositionVertexCube(backUpperRightSmall, smallEdge, "red");
PositionVertexCube(backLowerLeftSmall, smallEdge, "red");
PositionVertexCube(backLowerRightSmall, smallEdge, "red");
}
else {
PositionVertexCube(frontUpperLeftSmall, smallEdge);
PositionVertexCube(frontUpperRightSmall, smallEdge);
PositionVertexCube(frontLowerLeftSmall, smallEdge);
PositionVertexCube(frontLowerRightSmall, smallEdge);
PositionVertexCube(backUpperLeftSmall, smallEdge);
PositionVertexCube(backUpperRightSmall, smallEdge);
PositionVertexCube(backLowerLeftSmall, smallEdge);
PositionVertexCube(backLowerRightSmall, smallEdge);
}

}

module ExtrudeInnerFrame(withColor) {

// Vertex, rotation, strutLength, strutDiameter, shade
if (withColor) {
ExtrudeFrameStrut(frontUpperLeftSmall, [0, 90, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(frontLowerLeftSmall, [0, 90, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backUpperLeftSmall, [0, 90, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backLowerLeftSmall, [0, 90, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backUpperLeftSmall, [90, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backUpperRightSmall, [90, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backLowerLeftSmall, [90, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backLowerRightSmall, [90, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(frontLowerLeftSmall, [0, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(frontLowerRightSmall, [0, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backLowerLeftSmall, [0, 0, 0], smallWidth, smallEdge, "red");
ExtrudeFrameStrut(backLowerRightSmall, [0, 0, 0], smallWidth, smallEdge, "red");
}
else {
ExtrudeFrameStrut(frontUpperLeftSmall, [0, 90, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(frontLowerLeftSmall, [0, 90, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backUpperLeftSmall, [0, 90, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backLowerLeftSmall, [0, 90, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backUpperLeftSmall, [90, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backUpperRightSmall, [90, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backLowerLeftSmall, [90, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backLowerRightSmall, [90, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(frontLowerLeftSmall, [0, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(frontLowerRightSmall, [0, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backLowerLeftSmall, [0, 0, 0], smallWidth, smallEdge);
ExtrudeFrameStrut(backLowerRightSmall, [0, 0, 0], smallWidth, smallEdge);
}

}

module ExtrudeStrut(start, end, rotation, strutDiameter, shade) {

strutDistanceX = end[0] - start[0];
strutDistanceY = end[1] - start[1];
strutDistanceZ = end[2] - start[2];

strutLength = sqrt(
strutDistanceX * strutDistanceX +
strutDistanceY * strutDistanceY +
strutDistanceZ * strutDistanceZ);

translate(start)
rotate(a = rotation)
color(shade)
linear_extrude(height = strutLength, center = false)
circle(diameter = strutDiameter);
}

module DrawStruts(withColor) {

if (withColor) {
ExtrudeStrut(frontUpperLeftLarge, frontUpperLeftSmall, [0, 125, 45], smallEdge, "green");
ExtrudeStrut(frontUpperRightLarge, frontUpperRightSmall, [0, 125, 135], smallEdge, "green");
ExtrudeStrut(frontLowerRightLarge, frontLowerRightSmall, [0, 55, 135], smallEdge, "green");
ExtrudeStrut(frontLowerLeftLarge, frontLowerLeftSmall, [0, 55, 45], smallEdge, "green");
ExtrudeStrut(backUpperLeftLarge, backUpperLeftSmall, [0, 125, 315], smallEdge, "green");
ExtrudeStrut(backUpperRightLarge, backUpperRightSmall, [0, 125, 225], smallEdge, "green");
ExtrudeStrut(backLowerRightLarge, backLowerRightSmall, [0, 55, 225], smallEdge, "green");
ExtrudeStrut(backLowerLeftLarge, backLowerLeftSmall, [0, 55, 315], smallEdge, "green");
}
else {
ExtrudeStrut(frontUpperLeftLarge, frontUpperLeftSmall, [0, 125, 45], smallEdge);
ExtrudeStrut(frontUpperRightLarge, frontUpperRightSmall, [0, 125, 135], smallEdge);
ExtrudeStrut(frontLowerRightLarge, frontLowerRightSmall, [0, 55, 135], smallEdge);
ExtrudeStrut(frontLowerLeftLarge, frontLowerLeftSmall, [0, 55, 45], smallEdge);
ExtrudeStrut(backUpperLeftLarge, backUpperLeftSmall, [0, 125, 315], smallEdge);
ExtrudeStrut(backUpperRightLarge, backUpperRightSmall, [0, 125, 225], smallEdge);
ExtrudeStrut(backLowerRightLarge, backLowerRightSmall, [0, 55, 225], smallEdge);
ExtrudeStrut(backLowerLeftLarge, backLowerLeftSmall, [0, 55, 315], smallEdge);
}

}

module ExtrudeStrut(start, end, rotation, strutDiameter, shade) {

strutDistanceX = end[0] - start[0];
strutDistanceY = end[1] - start[1];
strutDistanceZ = end[2] - start[2];

strutLength = sqrt(
strutDistanceX * strutDistanceX +
strutDistanceY * strutDistanceY +
strutDistanceZ * strutDistanceZ);

translate(start)
rotate(a = rotation)
color(shade)
linear_extrude(height = strutLength, center = false)
circle(diameter = strutDiameter);
}

There are a couple of things I’d like to work on before I upload it to Thingiverse.

  1. Experiment with making the struts rectangular instead of circular (I think those would print better)
  2. Investigate the possibility of printing the tesseract with support material in place to prevent sagging (there’s a Slic3r setting)
  3. Look into using the OpenSCAD Assign statement to see if it’s possible to change the value of a variable at run-time

{ Comments on this entry are closed }

The Tesseract – Part 2

by Bill Maya on December 24, 2013

It turns out constructing the hypercube from vertexes and extrusions was easier than subtracting cubic areas from the larger solid cube.

Snap1

Since I want the tesseract to be parametric, I first set up my variables for my larger and smaller cubes.

largeWidth = 20;
largeEdge = 3;

smallWidth = 10;
smallEdge = 2;

From these variables I create the large cube’s vertexes and position a cube at each vertex.

frontUpperLeftLarge = [-largeWidth / 2, -largeWidth / 2, largeWidth / 2];
frontUpperRightLarge = [largeWidth / 2, -largeWidth / 2, largeWidth /2];
frontLowerLeftLarge = [-largeWidth / 2, -largeWidth / 2, -largeWidth / 2];
frontLowerRightLarge = [largeWidth / 2, -largeWidth / 2, -largeWidth / 2];

backUpperLeftLarge = [-largeWidth / 2, largeWidth / 2, largeWidth / 2];
backUpperRightLarge = [largeWidth / 2, largeWidth / 2, largeWidth /2];
backLowerLeftLarge = [-largeWidth / 2, largeWidth / 2, -largeWidth / 2];
backLowerRightLarge = [largeWidth / 2, largeWidth / 2, -largeWidth / 2];

translate(frontUpperLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(frontUpperRightLarge) color("blue") cube(size = largeEdge, center = true);
translate(frontLowerLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(frontLowerRightLarge) color("blue") cube(size = largeEdge, center = true);

translate(backUpperLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(backUpperRightLarge) color("blue") cube(size = largeEdge, center = true);
translate(backLowerLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(backLowerRightLarge) color("blue") cube(size = largeEdge, center = true);

Snap2

I then extruded a circular strut between all the vertexes

translate(frontUpperLeftLarge)
rotate(a = [0, 90, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(frontLowerLeftLarge)
rotate(a = [0, 90, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backUpperLeftLarge)
rotate(a = [0, 90, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backLowerLeftLarge)
rotate(a = [0, 90, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backUpperLeftLarge)
rotate(a = [90, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backUpperRightLarge)
rotate(a = [90, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backLowerLeftLarge)
rotate(a = [90, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backLowerRightLarge)
rotate(a = [90, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(frontLowerLeftLarge)
rotate(a = [0, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(frontLowerRightLarge)
rotate(a = [0, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backLowerLeftLarge)
rotate(a = [0, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backLowerRightLarge)
rotate(a = [0, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

Snap3

When the vertex cubes and the struts are combined we have the outer cube.

Snap4

Using the smaller cube parameters I do the same thing for the inner cube.

Snap5

And for the structs that connect the outer cube to the inner cube.

Snap6

When everything is combined you have your complete tesseract.

Snap1

Which when it’s printed out looks like this.

IMG_0479

I still have some work to do with my print and slicer settings since there’s some sag when spanning larger gaps. I’m sure there’s a way to add support struts to hold the tesseract material in place while it’s printing (I can remove the struts after the object is printed). Also, the model is still not completely parametric – with some initial values it’s possible to create “broken” tesseracts. I’ll have to work on that today.

Snap8

Here’s the tesseract script as it stands right now.

largeWidth = 20;
largeEdge = 3;

smallWidth = 7;
smallEdge = 2;

$fn = 100;

// Outer cube

// Create vertexes
frontUpperLeftLarge = [-largeWidth / 2, -largeWidth / 2, largeWidth / 2];
frontUpperRightLarge = [largeWidth / 2, -largeWidth / 2, largeWidth /2];
frontLowerLeftLarge = [-largeWidth / 2, -largeWidth / 2, -largeWidth / 2];
frontLowerRightLarge = [largeWidth / 2, -largeWidth / 2, -largeWidth / 2];

backUpperLeftLarge = [-largeWidth / 2, largeWidth / 2, largeWidth / 2];
backUpperRightLarge = [largeWidth / 2, largeWidth / 2, largeWidth /2];
backLowerLeftLarge = [-largeWidth / 2, largeWidth / 2, -largeWidth / 2];
backLowerRightLarge = [largeWidth / 2, largeWidth / 2, -largeWidth / 2];

// Position vertex cubes
translate(frontUpperLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(frontUpperRightLarge) color("blue") cube(size = largeEdge, center = true);
translate(frontLowerLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(frontLowerRightLarge) color("blue") cube(size = largeEdge, center = true);

translate(backUpperLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(backUpperRightLarge) color("blue") cube(size = largeEdge, center = true);
translate(backLowerLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(backLowerRightLarge) color("blue") cube(size = largeEdge, center = true);

// Extrude frame
translate(frontUpperLeftLarge)
rotate(a = [0, 90, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(frontLowerLeftLarge)
rotate(a = [0, 90, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backUpperLeftLarge)
rotate(a = [0, 90, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backLowerLeftLarge)
rotate(a = [0, 90, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backUpperLeftLarge)
rotate(a = [90, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backUpperRightLarge)
rotate(a = [90, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backLowerLeftLarge)
rotate(a = [90, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backLowerRightLarge)
rotate(a = [90, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(frontLowerLeftLarge)
rotate(a = [0, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(frontLowerRightLarge)
rotate(a = [0, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backLowerLeftLarge)
rotate(a = [0, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

translate(backLowerRightLarge)
rotate(a = [0, 0, 0])
color("blue")
linear_extrude(height = largeWidth, center = false)
circle(diameter = largeEdge);

// Inner cube

// Create vertexes//
frontUpperLeftSmall = [-smallWidth / 2, -smallWidth / 2, smallWidth / 2];
frontUpperRightSmall = [smallWidth / 2, -smallWidth / 2, smallWidth /2];
frontLowerLeftSmall = [-smallWidth / 2, -smallWidth / 2, -smallWidth / 2];
frontLowerRightSmall = [smallWidth / 2, -smallWidth / 2, -smallWidth / 2];

backUpperLeftSmall = [-smallWidth / 2, smallWidth / 2, smallWidth / 2];
backUpperRightSmall = [smallWidth / 2, smallWidth / 2, smallWidth /2];
backLowerLeftSmall = [-smallWidth / 2, smallWidth / 2, -smallWidth / 2];
backLowerRightSmall = [smallWidth / 2, smallWidth / 2, -smallWidth / 2];

// Position vertex cubes
translate(frontUpperLeftSmall) color("red") cube(size = smallEdge, center = true);
translate(frontUpperRightSmall) color("red") cube(size = smallEdge, center = true);
translate(frontLowerLeftSmall) color("red") cube(size = smallEdge, center = true);
translate(frontLowerRightSmall) color("red") cube(size = smallEdge, center = true);

translate(backUpperLeftSmall) color("red") cube(size = smallEdge, center = true);
translate(backUpperRightSmall) color("red") cube(size = smallEdge, center = true);
translate(backLowerLeftSmall) color("red") cube(size = smallEdge, center = true);
translate(backLowerRightSmall) color("red") cube(size = smallEdge, center = true);

// Extrude frame
translate(frontUpperLeftSmall)
rotate(a = [0, 90, 0])
color("red")
linear_extrude(height = smallWidth, center = false)
circle(diameter = smallEdge);

translate(frontLowerLeftSmall)
rotate(a = [0, 90, 0])
color("red")
linear_extrude(height = smallWidth, center = false)
circle(diameter = smallEdge);

translate(backUpperLeftSmall)
rotate(a = [0, 90, 0])
color("red")
linear_extrude(height = smallWidth, center = false)
circle(diameter = smallEdge);

translate(backLowerLeftSmall)
rotate(a = [0, 90, 0])
color("red")
linear_extrude(height = smallWidth, center = false)
circle(diameter = smallEdge);

translate(backUpperLeftSmall)
rotate(a = [90, 0, 0])
color("red")
linear_extrude(height = smallWidth, center = false)
circle(diameter = smallEdge);

translate(backUpperRightSmall)
rotate(a = [90, 0, 0])
color("red")
linear_extrude(height = smallWidth, center = false)
circle(diameter = smallEdge);

translate(backLowerLeftSmall)
rotate(a = [90, 0, 0])
color("red")
linear_extrude(height = smallWidth, center = false)
circle(diameter = smallEdge);

translate(backLowerRightSmall)
rotate(a = [90, 0, 0])
color("red")
linear_extrude(height = smallWidth, center = false)
circle(diameter = smallEdge);

translate(frontLowerLeftSmall)
rotate(a = [0, 0, 0])
color("red")
linear_extrude(height = smallWidth, center = false)
circle(diameter = smallEdge);

translate(frontLowerRightSmall)
rotate(a = [0, 0, 0])
color("red")
linear_extrude(height = smallWidth, center = false)
circle(diameter = smallEdge);

translate(backLowerLeftSmall)
rotate(a = [0, 0, 0])
color("red")
linear_extrude(height = smallWidth, center = false)
circle(diameter = smallEdge);

translate(backLowerRightSmall)
rotate(a = [0, 0, 0])
color("red")
linear_extrude(height = smallWidth, center = false)
circle(diameter = smallEdge);

// Create struts to connect outer cube vertexes to inner cube vertexes
translate(frontUpperLeftLarge)
rotate(a = [0, 125, 45])
color("green")
linear_extrude(height = smallWidth - 1, center = false)
circle(diameter = smallEdge);

translate(frontUpperRightLarge)
rotate(a = [0, 125, 135])
color("green")
linear_extrude(height = smallWidth - 1, center = false)
circle(diameter = smallEdge);

translate(frontLowerRightLarge)
rotate(a = [0, 55, 135])
color("green")
linear_extrude(height = smallWidth - 1, center = false)
circle(diameter = smallEdge);

translate(frontLowerLeftLarge)
rotate(a = [0, 55, 45])
color("green")
linear_extrude(height = smallWidth - 1, center = false)
circle(diameter = smallEdge);

translate(backUpperLeftLarge)
rotate(a = [0, 125, 315])
color("green")
linear_extrude(height = smallWidth - 1, center = false)
circle(diameter = smallEdge);

translate(backUpperRightLarge)
rotate(a = [0, 125, 225])
color("green")
linear_extrude(height = smallWidth - 1, center = false)
circle(diameter = smallEdge);

translate(backLowerRightLarge)
rotate(a = [0, 55, 225])
color("green")
linear_extrude(height = smallWidth - 1, center = false)
circle(diameter = smallEdge);

translate(backLowerLeftLarge)
rotate(a = [0, 55, 315])
color("green")
linear_extrude(height = smallWidth - 1, center = false)
circle(diameter = smallEdge);

{ Comments on this entry are closed }

OpenSCAD and the Tesseract

by Bill Maya on December 23, 2013

I’ve been fooling around today with OpenSCAD, an open source program for creating 3D solid CAD objects that you can export as STL files for 3D printing. Unlike SketchUp Make or Tinkercad, where you create three dimensional models interactively by dragging primitives around the design surface, OpenSCAD renders your model from a script you create.

For example, this script.

width = 20;
edge = 5;

difference() {
cube(size = width, center = true);
cube(size = [width - edge, width - edge, width], center = true);
cube(size = [width, width - edge, width - edge], center = true);
cube(size = [width - edge, width, width - edge], center = true);
}

Creates this 3D model.

Snap1

Which can be exported and printed.

IMG_0477

The script is parametric, which mean the model is constructed using parameters. Different size cube frames can be printed by modifying the “width” and “edge” parameters in the script above.

IMG_0478

The cube on the left has a width of 10 and an edge of 3. The cube on the right has a width of 20 and an edge of 5.

So now I thought – what about putting the smaller cube frame inside the larger cube frame, creating a tesseract or hypercube.

600px-Schlegel_wireframe_8-cell

After working on it for a couple of hours I’ve got a partial script that creates the two cubes, one inside the other.

Snap2

But the script is a bit inelegant, subtracting rectangular cubes from the larger cube by “brute force.” I want to work on it a bit more, clean it up so it uses the parameters to derive the coordinates for the subtraction cubes (I also think I can reduce the number of subtraction cubes I currently use). After that I’ll have to figure out how to add the struts to connect the two cubes.

Here’s the script so far.

largeWidth = 20;
largeEdge = 5;

smallWidth = 10;
smallEdge = 3;

difference() {
cube(size = largeWidth, center = true);
cube(size = [smallWidth - smallEdge, smallWidth - smallEdge, largeWidth], center = true);
cube(size = [largeWidth, smallWidth - smallEdge, smallWidth - smallEdge], center = true);
cube(size = [smallWidth - smallEdge, largeWidth, smallWidth - smallEdge], center = true);

// Top
translate([4.5, -8.5, -10])
cube(size = [4.5, 17, largeWidth]);

translate([-largeWidth / 2 + 1, -8.5, -10])
cube(size = [4.5, 17, largeWidth]);

translate([-largeWidth / 2 + 1, -8.5, -10])
cube(size = [17, 4.5, largeWidth]);

translate([-largeWidth / 2 + 1, 4.5, -10])
cube(size = [18, 4.5, largeWidth]);

// Front
translate([4.5, -10, -8.5])
cube(size = [4.5, largeWidth, 17]);

translate([-largeWidth / 2 + 1, -10, -8.5]) // ; at end screws up
cube(size = [4.5, largeWidth, 17]);

translate([-largeWidth / 2 + 1, -10, -8.5])
cube(size = [18, largeWidth, 4]);

translate([-largeWidth / 2 + 1, -10, 5])
cube(size = [18, largeWidth, 4]);

// Side
translate([-largeWidth / 2, 4.5, -8.5])
cube(size = [largeWidth, 4.5, 17]);

translate([-largeWidth / 2, -9, -8.5])
cube(size = [largeWidth, 4.5, 17]);

translate([-largeWidth / 2, -9, 4.5])
cube(size = [largeWidth, 18, 4.5]);

translate([-largeWidth / 2, -9, -largeWidth / 2 + 1])
cube(size = [largeWidth, 18, 4.5]);

// Remove debris frames
translate([0, 0, 7])
cylinder(h = 3, r = largeWidth / 2 - 2);

translate([0, 0, -11])
cylinder(h = 3, r = largeWidth / 2 - 2);

translate([0, -8, 0])
rotate(a=[90, 0, 0])
cylinder(h = 3, r = largeWidth / 2 - 2);

translate([0, 10.5, 0])
rotate(a=[90, 0, 0])
cylinder(h = 4, r = largeWidth / 2 - 2);

translate([8.5, 0, 0])
rotate(a=[0, 90, 0])
cylinder(h = 3, r = largeWidth / 2 - 2);

translate([-10.5, 0, 0])
rotate(a=[0, 90, 0])
cylinder(h = 3, r = largeWidth / 2 - 2);
}

Here’s an updated script. I reduced the number of subtraction cubes from eighteen to six and the cube frame widths are more consistent but there’s still to many “magic numbers” for my liking (I feel I should be able to derive all numbers I need from the large and small widths and edges but it’s not working out right now).

Snap5

largeWidth = 20;
largeEdge = 5;

smallWidth = 10;
smallEdge = 3;

difference() {
cube(size = largeWidth, center = true);
cube(size = [smallWidth - smallEdge, smallWidth - smallEdge, largeWidth], center = true);
cube(size = [largeWidth, smallWidth - smallEdge, smallWidth - smallEdge], center = true);
cube(size = [smallWidth - smallEdge, largeWidth, smallWidth - smallEdge], center = true);

translate([smallWidth / 2, -11 + largeEdge / 2, -(largeWidth / 2) + 1.75])
cube(size = [largeEdge, largeWidth - 3.5, largeWidth - 3.5]);

translate([-largeWidth / 2, -11 + largeEdge /2, -(largeWidth / 2) + 1.75])
cube(size = [largeEdge, largeWidth - 3.5, largeWidth - 3.5]);

translate([-largeWidth / 2 + 1.75, -(largeWidth / 2) + largeEdge, -(largeWidth / 2) + 1.75])
rotate(a = [0, 0, 270])
cube(size = [largeEdge, largeWidth - 3.5, largeWidth - 3.5]);

translate([-largeWidth / 2 + 1.75, smallWidth + 2.5, -(largeWidth / 2) + 1.75])
rotate(a = [0, 0, 270])
cube(size = [largeEdge + 2.5, largeWidth - 3.5, largeWidth - 3.5]);

translate([-largeWidth / 2 + 1.75, -(largeWidth / 2) + 1.75, largeEdge])
rotate(a = [0, 0, 0])
cube(size = [largeWidth - 3.5, largeWidth - 3.5, largeWidth - 3.5]);

translate([-(largeWidth / 2) + 1.75, -(largeWidth / 2) + 1.75, -(largeWidth / 2) + 5])
rotate(a = [0, 90, 0])
cube(size = [largeWidth - 3.5, largeWidth - 3.5, largeWidth - 3.5]);
}

I’m also not sure how to create the struts that I need to attach the external corners of the smaller cube to the internal corners of the larger cube. At first I thought I’d modify the subtraction cubes into pyramids with their tops lopped off and then use six of these in different rotations to carve chunks out of the big cube. That’s 12 points and 16 triangles per “pyramid” for a total of 72 points and 96 triangles.

Snap3

Then I thought about using the entire pyramid with its tip at 0, 0, 0 and its base points at four of the larger cubes inner vertexes (again, I’d need six of these in various rotations to carve up the big cube. That’s 5 points and 6 triangles per pyramid for a total of 30 points and 36 triangles.

Snap4

Now I’m thinking that maybe I should calculate the sixteen vertexes of both cubes and construct the cubes and their connecting struts using those sixteen points and rectangular cubes.

Snap6

The larger square vertexes are blue; the smaller square vertexes are red. Here’s the script that created both sets of vertexes.

largeWidth = 20;
largeEdge = 3;

smallWidth = 10;
smallEdge = 2;

// Outer cube

frontUpperLeftLarge = [-largeWidth / 2, -largeWidth / 2, largeWidth / 2];
frontUpperRightLarge = [largeWidth / 2, -largeWidth / 2, largeWidth /2];
frontLowerLeftLarge = [-largeWidth / 2, -largeWidth / 2, -largeWidth / 2];
frontLowerRightLarge = [largeWidth / 2, -largeWidth / 2, -largeWidth / 2];

backUpperLeftLarge = [-largeWidth / 2, largeWidth / 2, largeWidth / 2];
backUpperRightLarge = [largeWidth / 2, largeWidth / 2, largeWidth /2];
backLowerLeftLarge = [-largeWidth / 2, largeWidth / 2, -largeWidth / 2];
backLowerRightLarge = [largeWidth / 2, largeWidth / 2, -largeWidth / 2];

translate(frontUpperLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(frontUpperRightLarge) color("blue") cube(size = largeEdge, center = true);
translate(frontLowerLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(frontLowerRightLarge) color("blue") cube(size = largeEdge, center = true);

translate(backUpperLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(backUpperRightLarge) color("blue") cube(size = largeEdge, center = true);
translate(backLowerLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(backLowerRightLarge) color("blue") cube(size = largeEdge, center = true);

// Inner cube

frontUpperLeftSmall = [-smallWidth / 2, -smallWidth / 2, smallWidth / 2];
frontUpperRightSmall = [smallWidth / 2, -smallWidth / 2, smallWidth /2];
frontLowerLeftSmall = [-smallWidth / 2, -smallWidth / 2, -smallWidth / 2];
frontLowerRightSmall = [smallWidth / 2, -smallWidth / 2, -smallWidth / 2];

backUpperLeftSmall = [-smallWidth / 2, smallWidth / 2, smallWidth / 2];
backUpperRightSmall = [smallWidth / 2, smallWidth / 2, smallWidth /2];
backLowerLeftSmall = [-smallWidth / 2, smallWidth / 2, -smallWidth / 2];
backLowerRightSmall = [smallWidth / 2, smallWidth / 2, -smallWidth / 2];

translate(frontUpperLeftSmall) color("red") cube(size = smallEdge, center = true);
translate(frontUpperRightSmall) color("red") cube(size = smallEdge, center = true);
translate(frontLowerLeftSmall) color("red") cube(size = smallEdge, center = true);
translate(frontLowerRightSmall) color("red") cube(size = smallEdge, center = true);

translate(backUpperLeftSmall) color("red") cube(size = smallEdge, center = true);
translate(backUpperRightSmall) color("red") cube(size = smallEdge, center = true);
translate(backLowerLeftSmall) color("red") cube(size = smallEdge, center = true);
translate(backLowerRightSmall) color("red") cube(size = smallEdge, center = true);

{ Comments on this entry are closed }

My Printrbot Simple

by Bill Maya on December 22, 2013

My new 3D printer arrived on Friday, 12/13, and I’ve been printing stuff with it ever since. The idea that I can have a device sitting on my desk that will print out three dimensional objects that I design or download from Thingiverse is simply amazing. I sit here and watch it while it prints stuff and the possibilities blow my mind.

IMG_0474

IMG_0449

I’ve been thinking about buying a 3D printer for quite a while, ever since I took that 3D printing class at AS220, and several times I got really close to buying one the MakerBot Replicators but something always held me back (maybe it was the fact that if I spent $2000+ on a piece of hardware I felt I’d absolutely have to have a good reason for purchasing one). But when I read about the Printrbot Simple in Make’s Ultimate Guide to 3D Printing 2014 I knew that this was the first printer for me. At $399 it’s not such a big outlay of cash that I feel I have to be using it every day and, based on talking to people at the monthly Providence 3D printer meeting, its quality and build size are adequate for experimentation.

I know very little about the current 3D consumer printer industry right now but I can’t help shake the feeling that at this point it resembles the microcomputer industry of the 70s and early 80s. Back then you had ten, twenty, maybe thirty companies offering their own version of the personal computer, each jockeying for market share and acceptance. A lot of them fell by the wayside as the industry in the US consolidated on the machines offered by Apple, Commodore, Atari, and the IBM PC. Further consolidation led us to the the Windows/Macintosh hegemony that prevailed in the 90s.

Slide12B

Whether or not the 3D printer will follow the same path remains to be seen. I don’t know if there’s a killer app for 3D printing (there might be several for all I know) but I felt I had to take the plunge now while the industry is in its early stages so I can learn more and possibly be a part of it.

easy_bake_oven

{ Comments on this entry are closed }

Balance of the Planet – Real Time

by Bill Maya on November 3, 2013

I wrote earlier that Balance of the Planet for the iPad would be played in real time instead of being turn based. What this means is that once the game is started it can proceed with its initial settings from beginning to end without user intervention. That wouldn’t be much of a game so at any time the user can make changes to the game parameters to achieve their desired outcome.

The controls at the top of the screen are used to control the game’s real time progress

BotP_iPad_GameSpeedControls1

The individual controls themselves are pretty familiar for those who’ve played real-time-strategy (RTS) games in the past, games like Dune II, Warcraft: Orcs & Humans, StarCraft, and Age of Empires. If you’re not a aficionado of the genre here’s how tapping on the various icons would affect the game’s real time progress.

BotP_iPad_GameSpeedControls2

The dateline to the right of the controls shows the start and end dates of the game. In the free version of the game the dates would be fixed but in-app purchasing one of the add-in scenarios could give the gamer the option of setting the start and end dates.

The progress bar timeline between the start and end dates shows where you are in the game. As the game progresses the indicator moves from left to right. Once the game ends you can “scrub” the indicator to the left, from Jan 2114 to Jan 2014, to review the games history and possibly learn things you did right or wrong, information you could apply to future games.

{ Comments on this entry are closed }

Balance of the Planet – Tax Histograms

by Bill Maya on October 30, 2013

Chris is worried that I won’t be able to implement the tax histogram charts I’ve designed in the space available.

As to the layouts themselves, I am dubious that you’ll be able to make those histograms workable. The absolute minimum width is one pixel per year, which would require only a hundred pixels of width, but with margins and such, it could bite into the other areas.

On the left is my initial design which mirrors Chris’ original 1990 design on the right (I’ve moved the controls for changing the taxable amount underneath the chart, Chris had them elsewhere on the screen).

BotP_Histogram1

What’s not immediately apparent in my design is that the square window that contains the histogram data is merely a view into a small slice of all the data collected so far. Once the game starts each chart is built up column by column, left to right. Once the initial view is filled up, the older columns disappear off to the left.

BotP_iPad_Histogram1

By tapping and holding on the chart you can “scrub” left or right to display the entire data set.

BotP_iPad_Histogram2

{ Comments on this entry are closed }

Balance of the Planet for the iPad

by Bill Maya on October 28, 2013

I’m talking with Chris Crawford about bringing Balance of the Planet to the iPad.

BotPlanet_disks

BotP_Mac0

For those of you who aren’t familiar with Chris’ work, the original Balance of the Planet was an environmental management simulation released in 1990. The goal of the “game” was to influence society towards a more sustainable ecological footprint by funding various subsidies with money raised by taxing polluters.

BotP_Mac1

BotP_Mac2

While trying to make things right, the player can also explore the causes and effects of various environmental problems through a point-and-click hypertext network of 154 factors.

BotP_Mac3

BotP_Mac4

Overall very advanced for its time with the ability to change the formulas behind the calculations and save your modifications as a bias – pro-nuclear, pro-environmentalist, pro-industry, etc.

In 2012 Chris launched a Kickstarter campaign to update Balance of the Planet. It failed to get funded.

You can download his prototype here (though it doesn’t have all the features shown in the video).

My iPad design follows Chris’ redesign – reducing the taxes from ten to six and the subsidies from thirteen to five.

BotPlanet_mockup_1a

BotPlanet_mockup_1b

 Couple of highlights about this design.

  • iPad only (maybe iPhone later)
  • Real time instead of turn-based (pause; speed increase/decrease controls at top)
  • Taxes/subsidies window touch scrolls (the charts flip 90 degrees in horizontal orientation)
  • Filterable chart built form top-to-bottom (vertical orientation) or left-to-right (horizontal orientation)
  • Cause/effect area to explore the hypertext network of causes and effects (displayed in chart area; pauses program)

I’ll post more about my design as it evolves.

{ Comments on this entry are closed }

Man Plus

by Bill Maya on September 3, 2013

I heard yesterday that Frederick Pohl died.

I’ve only read a couple of Pohl’s books but happliy found two of them still on my shelf (hopefully I can pass them on to my daughter if she develops an interest in sci-fi).

Frederic-Pohl_1976_ManPlus_Gateway

I haven’t read either book in years but have kept them because they were great books. I still remember the gist of each.

Roger Torraway of Man Plus is a retired astronaut involved in a government program to re-engineer a human being so they can survive unprotected on the surface of Mars. When the current candidate dies unexpectedly, Torraway must step up to the plate and allow the scientists and engineers to turn him into something more than human. His personal journey to retain his human feelings, hopes, and desires as his humanity is stripped away piece by piece in order to insure humanity’s survival is fascinating and imaginative (there’s also a nice twist at the end revealing who’s actually behind the Mars Man Plus project).

Bob Broadhead of Gateway is on a different sort of journey. A food miner on Earth just scraping by, he wins a lottery to Gateway, a space station built into a hollow asteroid by a vanished race known as the Heechee. Inside the asteroid are thousands of starships pre-programmed for destinations throughout the galaxy. The kicker is that no one knows which ship goes to which destination – a trip out could result in returning with a piece of alien technology that could make a prospector incredibly wealth or returning dead. The entire book, with chapters alternating between Roger’s time on Gateway and future conversations with his robotic therapist, leads up to the Roger’s last trip, a culmination of all his dreams and all his horrors.

Both books were written in the late ’70s (Man Plus in 1976; Gateway in 1977) so they’re probably a bit dated but I’m sure the ideas and the drama hold up. I should read them again when I’ve got the time

{ Comments on this entry are closed }