Welcome to my build log for my Rotating Lithophane Lamp! This was a project I built for Valentines day, 2018. Over a year later, I'm finally getting around to compiling the documentation for it. This was my first time using Fusion 360 to integrate electronics and 3D printed parts. The wiring and code is cringe worthy, but you would not be able to tell when seeing the final product!Features
- Secret activation key
- 3 different light modes
- Toggle rotation ON/OFF
Use only salvaged or leftover parts on hand.Components
The list of components is more accurate than the picture of components. It's a common occurrence to add parts as the project progresses.
- 1x Arduino Nano
- 1x Geared DC Motor
- 1x RGBW LED Strip 12V
- 1x Power Adapter 12V
- 1x Barrel Jack
- 1x Rocker Switch [SPDT 125V/10A]
- 1x Slide Switch [SPDT 5V/0.3A]
- 1x Push Button [6x6x8mm]
- 1x Reed Switch [N/O 2x14mm]
- 1x Rare Earth/Neodymium Magnet [8x2mm]
- 1x Perfboard/Veroboard
- 3x Blue LED [3mm]
- 1x Green LED [3mm]
- 8x 1K Ohm Resistor [at least ~400 Ohm]
- 2x M3 Bolt [at least 16mm]
- 2x M3 Bolt [at least 10mm]
- 4x M3 Nut
- 1x M8 or 5/16" Threaded Rod [123mm]
- 3x M8 or 5/16" Nut
- 2x 608zz Bearing
- 1x Spring Coupler [5x8x25mm]
- 4x ZTX458 NPN BJTs (for RGBW strip)
- 1x RFP40N10 N-channel MOSFET
- 1x 220 Ohm Resistor (Series with motor)
- 1x 330 Ohm Resistor
- 1x 1N4001 Diode (Flyback protection)
- 4x Rubber Feet
- 2.54mm Male & Female Pin Headers
- Heatshrink Tubing
- Zip Ties
- Jumper Cables
- 3D Printed Parts
Here are the equipment and tools that I used, but only the ones with an asterisk (*) are absolutely mandatory.
- 3D Printer *
- Digital Calipers *
- Soldering Iron *
- Hot glue gun *
- Heat gun
- Wire Cutter & Wire Stripper
- Hand Files
- 100 Grit Sandpaper
- Super Glue
Since this was a Valentines day gift, I wanted to make a unique, personalized gift. I discovered lithophanes very shortly after getting my 3D printer, and I made a few since. I had not seen one that wrapped around itself yet, and that's where it began. At the same time, I wanted to add something fun using electronics, which gave me the magnetic key idea. Without the second heart piece, the lamp will not work.
Once the vision was born, I took my time measuring, planning, and testing ideas of how each component would interact. At this stage, I was also figuring out what components were available for my design. My logic was to spend some time going through iterations on paper so that I could print it once, as a unit of this scale demands much filament.
I had leftover 5/16" (8mm) threaded rod and nuts from a structural upgrade for my printer.
The motor I salvaged came with a gearbox, which mechanically converts speed into torque. The increased toque was beneficial as I was bound to have losses in the system due to misalignment or slop in my parts. The alternative to using a gear reduction to drop the speed is through PWM; however, it simply drops the speed as opposed to converting it, so no additional torque is obtained with PWM.
The motor conveniently had a 5mm shaft, which allowed me to use a spare spring coupler I had leftover to join it with the 8mm rod. I did need to trim down the motor's shaft with a hacksaw because it was too long.Making the Lithophane
I selected 3 photos to stitch together in GIMP. They were each cropped to 4:3 and placed side by side. The aspect ratio has no scientific origin other than I had a feeling it would look good when wrapped around. The final canvas size was 5751 x 1438 pixels.
The stitched image was converted into a lamp shade using 3DPRock's online tool. It's crucial to go to the "Image Settings" tab and change the mode from negative to positive image.
Using Simplify3D, I obtained the gcode for the lampshade. For Lithophanes, I make sure to have 0% infill with >10 walls/shells/perimeters. I used a 0.16mm layer height. My lithophane took 22 hours to print on a direct extruder.
This was my first design project using Fusion 360. Before this, the most I did was extrude some holes into blocks, so this was a difficult self imposed challenge. I measured and modeled each part I used to get the proper dimensions for my clearances.
The motor's rotation was transferred to the top piece (lid) via an axle using M8 hardware. The top piece mounts onto the center axle with a hex cavity that press fits onto a hex nut.
The mid piece provided a shaft for the LEDs to wrap around, while covering the internals of the base. The LEDs remain stationary when the top rotates.
The base had to be split into two pieces because I needed to have access to the set screws on the coupler when the base and mid section were stacked. This was necessary to do, but it also omitted my original plan to super glue the middle to the top. At this point, I already had the middle printed and needed a way of attaching it to the base. This is where the dovetails come in. I designed dovetails to be glued onto the bottom of the mid section so they could slide into respective mating pieces on the base. It would have been better to use a screw/bolt to attach the mid to the base, but would mean redesigning the mid.
The heart holds on using a friction fit. I sketched out multiple attachment methods that involved the use of more magnets. In retrospect, I should have spent more time and implemented this, but the lack of time will be a common theme throughout this log.
The entire assembly came together just as planned!
Total Print Time: ~37 hours
- Lithophane: 22 hours
- Base A: 6 hours
- Middle: 3 hours 20 minutes
- Base B: 2 hours
- Top: 2 hours
- 3 Heart pieces: 30+20+20 = 1 hour 10 minutes
- Dovetails: 15 minutes
This did not include post processing and filament changes for multicolor prints.
Making 2 colored prints isn't just a gimmick. Any color inside the lithophane will bleed through; additionally, the light from the LEDs bounces and accentuates the internal color as well. This is why I strategically made everything contained inside the lithophane white.
I don't own a dual extruder nor a tool changer, so I had to do some gcode gymnastics to swap filament mid print at predetermined layers. Simplify3D allows me to analyze the gcode layer by layer, which helps me determine when to do a palette swap.
Once I knew the layer, I opened the gcode file in Nodepad++ and found the beginning of my desired layer(s). Next, I inserted this portion of code.
G91 ; Set coordinates to relative mode G1 Z10 ; Raise nozzle 10mm G90 ; Set coordinates to absolute mode G1 X0 ; Home X axis M0 Click To Restart ; Pause and wait for the user G91 ; Set coordinates to relative mode G1 Z-10 ; Return nozzle down 10mm G90 ; Set coordinates to absolute mode
Using this code, I had to retract and prime the nozzle by hand. Some time later, I learned about Marlin's advanced pause feature, which allows me to replace all that code with just:
It takes care of parking the nozzle, retracting the first filament, and priming the nozzle with new filament.Code
There's not much to the code. I'm primarily checking to see if the reed switch is shorted to ground by the magnet hidden in the heart piece. The bulk of the code is conditional logic that observes the user input (i.e. which light preset or whether the motor should be on or off).
There are 3 light modes I implemented:
- Mode 1: Warm White
- Mode 2: Cool White
- Mode 3: Mood Lights
The user can switch between these modes using the "Mode" button to the right. The mood lights tend to be the most favorable. I made a global variable that can be changed to modify the speed of the fade. The RGB strip without any white was far too intense for my liking, so I diluted it with white set to about half brightness. The function for mode 3 fades between different PWM values for each pin, which seamlessly transitions if coded properly.
I did not realize the function for Mode 3 was not optimized until the device was complete. Since I used the
delay() function, it halts the MCU from performing any processes until the delay is complete. Even interrupts are ineffective as they both utilize Timer 1. The result is that anytime the user wants to go from Mode 3 to Mode 1, or if they turn on/off the motor, the request will not be executed until after the final loop in the fade completes. This is can be solved using the
millis() function instead of delays, OR you can use a timer, but the code is done for me. It works; you just need to wait for the loop to end.
Once I got to this point, I was incredibly tight on time, so this section was atrocious. Be warned.
This is the schematic diagram I designed and tested block by block before doing any soldering.
I had an RGBW LED strip, which required a way to drive each color. This meant that I needed 4 transistors just for the LED strip, and a 5th transistor to drive the motor. I quickly threw together some transistors and their passives onto a stripboard.
To drive the LEDs, I used 4 ZTX458 NPN BJTs. For the motor, I used an RFP40N10 N channel MOSFET. These transistors are exotic and certainly overkill for their task, but that was what I had on hand.
I originally planned on using an Arduino Nano given it's small form, but I burned the only one I had. This forced me to resort to using my Arduino UNO. I got lucky that the extra space inside accommodated the much larger UNO quite nicely.
I'm not proud of the wiring, but it had to be done fast. Stripping and tinning wires took up more time than I could afford, so jumper wires made it into the final result. Again, nobody sees the inside.Assembly
Above is solely the CAD assembly animation if you missed it in the first video.
The lithophane is glued to the top, which press fits onto the axle. The heart is also glued. The electronics are secured with copious amounts of hot glue, which is entirely unnecessary given how tightly fit the components are.
Not shown is that I added 4 thin rubber feet to keep the lamp from sliding.Conclusion
I'm beyond happy with how it turned out. The entire project took me 3 weeks from the inception to the handover. Some improvements I would make include:
- replacing the dovetails (joining the base to the mid section) with screws
- attaching the top to the axle with screws instead of friction
- adding another magnet to the heart for stability
- optimizing the code for the mood light function to omit the use of delays
Since I'm writing this a year after its creation, I've certainly gained more experience working on electronics projects. If I were to redo it, I'd use my favorite ESP32 to allow me to not lock myself into a finite number of light modes. Those ESPs have become my default MCUs.
Since this was a Valentine's gift, I won't be releasing the STL or STEP files because I want this specific one to be unique. I've released everything else because I do believe in open source and I hope that my documentation can inspire others to create something of their own. Thanks for getting this far!