Saturday, June 22, 2019

Bangle - Next Steps

I haven’t solved the bridging issue yet, so I’ve started printing the first of two cut-down halves to see if I can glue them together seamlessly. (CA/Superglue is said to be good for this).

Here's the filament I chose. It's non-metalic PLA but looks a lot like copper:

If the result of gluing the two cut-down halves is good, I'll sand the inner diameter to make it a comfortable thing bangle, then print two full halves in copper and try gluing them. If gluing doesn't end up being a good solution, I'll have to solve the bridging issue, perhaps with supports, or with tweaking print/extrusion/fan speeds.

Saturday, June 15, 2019

Designing and 3D Printing a Chunky Bangle

Initial Concept

My wife likes big, chunky jewelry, so I thought I would try and 3D print something for her. I started with this as a basic idea:

This bangle looks to be in 3 pieces. My wife has similar multiple-part bangles. The pieces are held together with elastic. It allows for a smaller inner diameter, but the elastic is a potential point of failure. My wife also has one-piece bangles that she can slide her hand into, so I figure I can make a one-piece for her.


Printer: I have access to a Prusa i3 MK3, the predecessor to the MK3S.

Modeling: OpenSCAD - open source, "The Programmers Solid 3D CAD Modeller". Unlike traditional CAD apps that rely on drawing and/or moving around shapes, in OpenSCAD, you build designs by writing lines of OpenSCAD language code (some examples) Once you have a design in OpenScad, you have the software render it and export it in STL format.

Slicing / exporting gcode: Prusa has their own version of the popular open source app, Slic3r. Slicing is the process of taking a 3D model (usually an STL file) and converting it to a stack of slices that a printer can print, one on top of the other, to create the object. Gcode is the low-level instruction language used by printers to control the motions of the bed, the extruder, the arms and so on. Exporting gcode is the process of taking slices and converting them into those low-level instructions

Iteration 1:

Design a basic ring-ish shape. The easiest way I found was to design a disk and subtract from it a disk of same thickness but smaller diameter, centering the disks on each other. It looked like this:

Iteration 2:

I wanted to improve the ring design from a harsh geometric shape into the first inkling of a bracelet design. This involved learning to rotate a 2-D circle in 3-space around an axis, using the rotate_extrude() function. The result looked like this:

Iteration 3:

To create the first printed prototype, I reduced the thickness of the bracelet design, keeping the diameter. Thinness causes a quicker print and uses less plastic. Took about 40 minutes to print. (No pic)

Iteration 4:

Discover that diameter of first physical prototype is about 1/3 of useful bracelet diameter. Scale design to 300% and print again. When my wife put it on, it was a little too big, I decided to measure a favorite bracelet of hers and use its inner diameter (ID), 65 mm, for my design. Going back to the Iteration 1 design, I quick-printed something with the 65 mm ID. Holding it up against the favorite bangle, the ID matched. My wife put it on and called the fit perfect.  So, I had confirmed the final ID. (No pics)

Iteration 5:

Learn to go from circular cross-section to something more complex.
First, I set out to relearn parabolas:

I created a curve that I liked. It turned out to be Y = 0.3*(x-6.1)^2 + c.

Then I enclosed the curve into a shape with a perimeter and area:

Then I plugged some points into the equation and added 3 corners. It was simple to turn those points into a polygon call in OpenSCAD (in a future iteration, I would calculate and add more points in between these points, to smooth out what was a faceted curve:

            polygon(points=[[6.0, 0.000],
                            [5.5, 0.108],
                            [5.0, 0.363],
                            [4.5, 0.768],
                            [4.0, 1.323],
                            [3.5, 2.028],
                            [3.25, 2.773],
                            [3.0, 3.518],
                            [3.0, 0.000]

The rotate_extrude() call stands up a shape and rotates it around the z axis. Applying this to my polygon resulted in a shape like a volcano:

In OpenSCAD, I duplicated the "volcano", fliped it 180 degrees, and lined the duplicate up with the base of the original:

I showed the double-volcano model to my wife for her blessing, which I received. A first real physical prototype is in sight.

Iteration 6:

I decided to test-print only one volcano, just to have something to handle before committing to the whole print (which the slicing software projected would take 13 hours at 7% infill). It turned out that because of the nature of the curve I chose, the edges taper to a very thin edge are are not comfortable to wear:

Iteration 7:

I decided I needed to find some way to smooth the sharp edges and reduce/eliminate the faceting artifacts shown above. I had already figured out how to reduce the faceting down the face of the "volcano" by using more points to express the curve that became the polygon that was rotated through space. The faceting around the perimeter turned out to be easy - I had to add an extra argument, $fn=360, (number of fragments) to the rotate_exclude() call. Of course, the extra computation changed the rendering and slicing time from seconds to several minutes. I smoothed the lips edges of the volcano by smoothing the polygon itself using the offset() function before the rotate_extrude() call. The resulting model looked like this:

I started to print, but not long after it started, the print separated from the bed. I suspected that there was not enough surface area on the bed, so I stopped the print and restarted it with a 15mm brim (seen below) After 13.5 hours, the first "real" prototype print looked like this:

But the print had some issues:

It might be because the sharp angle of the base of the upside-down volcano extends out too far for support good bridging. There are lots of ways to address bridging issues. But before I tried any of those, I noticed that the model had a weird asymmetry. Displaying each volcano in a different color: 

and shifting one of the volcanos along the x-axis make the asymmetry more obvious:

It turns out that before I used the offset(), the two halves would remain on the z plane when one was turned upside-down. But adding the call resulted in one of the volcanos impinging across the z-plane. Could the impingement be responsible for the defect?

Iteration 8:

I moved the offset()'ed volcanos so their bases both sit on the the z-plane, but that resulted in a "bumpy" circumference, so I didn't print it - it needed more adjustment:

Iteration 9:

By making each volcano cross the z-axis an equal amount, I got to  this:

To determine whether there is a bridging issue, but not have to print the entire 13.5 hours, I "chopped off" some of the top and bottom of the model (by intersecting it with a box)

I printed iteration 9 and the bridging issue remains:

 So, next is figuring out how to fix it.

Tuesday, December 13, 2016

Things an "Expert" C Developer Knows: Undefined Behavior

This is the first post in my series: Things an "Expert" C Developer Knows

The 2016 SEI CERT C Coding Standard [free download] gives  this definition of Undefined Behavior:
Behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which the C Standard imposes no requirements.
An example of an action that causes undefined behavior is signed integer overflow. Professor John Regehr at U of Utah has a blog post that gives several possible examples of what C compilers *could* do with this C statement in a program:
printf ("%d\n", (INT_MAX+1) < 0);
The possibilities Regehr lists include printing 0, 1, 42 or formatting your hard drive. While the latter won't actually happen, undefined behavior can cause data corruption and/or security vulnerabilities.

The CERT C Coding Standard lists. in Appendix C, all undefined behaviors in the current C standard: C11 (more formally known as: ISO/IEC 9899:2011) There are 203.

Since I've mentioned the C11 standard here, I should probably have a Things an "Expert" C Developer Knows post about C standards.

Things an "Expert" C Developer Knows...

In January, my engagement with my current client will be taking a real change in direction. Rather than being a software craftsmanship coach, I will be joining a large team as an embedded C developer.

In that vein, I submitted a talk to my employer's internal conference in February about things that developers need to know if they are going to say they *really* know C.

In preparation for that, watch for a series of posts from me on: "Things an "Expert" C Developer Knows"

Tuesday, November 15, 2016

Always TDD? But Certainly Not for Startups, Right?

I just read "Uncle Bob is Smoking His Socks", in which the author, Joe Rounceville, starts by taking issue with Uncle Bob's statement that you are not a professional software developer if you don't TDD. I understand how that statement makes people bristle. Rounceville goes on to suggest that there are contexts (in particular lean startup) that don't merit TDD. He goes as far as to suggest that TDD in that context might be "gold plating."

Of course, startups need to be ultra-agile and able to get fast feedback on experiments by getting work out in front of customers rapidly. There's an element of racing against time when a company has to achieve success with only a certain amount of capital to burn through. Startups need to be able to pivot quickly in response to what they learn in their experiments.

But people who argue against "always TDD" seem to think that they save time up front by not using TDD. Among experienced TDD developers, I have not found that to be the case. And well test-driven code allows for rapid pivots because it's easy to understand and different concerns in the code are not tangled-up among each other.

Another risk for startups that decide not to TDD is that prototypes tend to be pushed into production as-is. Many young companies have met serious pains when their initial rushed-to-market release could not handle the load that came with the product's rapid success. And there's the old saw that if you don't have the time to write it correctly the first time, you are not going to have the time to re-write it later.

The relationship between TDD and startups is tricky. Learning TDD takes time. It's not a simple matter to start using TDD if you aren't good at it. Developing software with TDD when you are new to it is slower than developing without TDD. There is a non-trivial learning curve. As a developer, I would not want to try to get good at TDD while working for a startup. And I personally would not want to join a startup if I wasn't already strong in TDD. And because of the ever-changing nature of the market, if I have a startup idea and I want to get good at TDD before starting on it, I'm likely to miss my window of opportunity. And if I develop my startup without TDD, I'm likely to end up with a hard to change and hard to maintain project that's prone to defects. So while Uncle Bob's statement about "always TDD" may sound dogmatic, I find the statement that "startups don't need / can't afford TDD" to be false.