additional mechanical parts for housing
This commit is contained in:
@ -0,0 +1,544 @@
|
||||
/*
|
||||
=============================================================================
|
||||
FireFly Morse Throwie
|
||||
- a light controled (LED as Sensor) morseblinker throwie with ATTiny45/85
|
||||
=============================================================================
|
||||
|
||||
Project definitions, sources
|
||||
-----------------------------------------------------------------------------
|
||||
Version: 0.1 - Attiny85 Version
|
||||
Date : 25.05.2026
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Inspired by Karl Lunt's FireFly project I wrote some code to make this
|
||||
Throwie lasting longer, blinking only at low light levels and morse also
|
||||
some text.
|
||||
http://www.seanet.com/~karllunt/fireflyLED.html
|
||||
|
||||
How it works (only the Morsethrowy part):
|
||||
LED detects light level, using bleeding out time of LED pn-capacitor.
|
||||
If dark enough blink a text in morsecode (ATTiny45 = 22 Chars, text will
|
||||
be defined in line 191/192 of this file)
|
||||
To save energy go to powersave mode after blinking or light level is
|
||||
over threshold. Tests this every 8s (maximum time for watchdog timer
|
||||
possible for ATTiny). Repeat this endless
|
||||
|
||||
|
||||
The wiring, it's very simple, see also HW part of the Project.
|
||||
|
||||
+---+ +------\/------+
|
||||
| | ATTINY45 /85 |
|
||||
> | -+1=PB5 VCC=8+-> to SuperCap / DC-DC 3V/5V
|
||||
xxx Ohm < | | |
|
||||
> +------+2=PB3 PB2=7+-
|
||||
| | |
|
||||
----- +------+3=PB4 PB1=6+-
|
||||
LED / \ | | |
|
||||
----- | +--+4=GND PB0=5+-
|
||||
| | | | |
|
||||
+---+ | +--------------+
|
||||
|
|
||||
+---------------------> to battery GND
|
||||
|
||||
You can use other pins if necessary, theoretical up to 3 LEDs, as example I
|
||||
tried out to connect another one at PB2&PB1. working fine. Basic wiring:
|
||||
|
||||
+ LED_N_Side), wired to a digital pin, NOT Vcc
|
||||
|
|
||||
<
|
||||
> 100 - 460 ohm resistor depending Voltage
|
||||
<
|
||||
|
|
||||
|
|
||||
-----
|
||||
/ \ LED, maybe a 5mm, clear plastic is good
|
||||
-----
|
||||
|
|
||||
|
|
||||
+ LED_P_Side), wired to a digital pin, NOT Gnd
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
Im just a newbe in ATTiny / Arduino programming, so many thanks to:
|
||||
|
||||
Programming ATTiny with Arduino IDE:
|
||||
http://highlowtech.org/?p=1695
|
||||
|
||||
LED Lightsensor, Arduino Playground:
|
||||
http://playground.arduino.cc/Learning/LEDSensor
|
||||
|
||||
Powersaving Mode for Attiny45/85:
|
||||
A good description by Martin Nawrath nawrath@khm.de and the folks at
|
||||
http://www.insidegadgets.com/2011/02/05/reduce-attiny-power-consumption-by-sleeping-with-the-watchdog-timer/
|
||||
|
||||
With this description I got ~5uA during sleep mode.
|
||||
in Morse-Mode with LED OFF: 1.7mA
|
||||
LED ON: 6.9mA
|
||||
--> I hope to run this throwies ~40days with one CR2032.
|
||||
|
||||
Morsecode
|
||||
To translate a text into morsecode, there are several ways. You can use
|
||||
this fine online translator:
|
||||
http://morsecode.scphillips.com/jtranslator.html
|
||||
|
||||
There is also a great morse coder / encoder from Matthias Esterl aka madc.
|
||||
Works fine for Arduino, but not for ATTiny because of RAM limitations. But
|
||||
maybe this is helpful if your project works with an Arduino.
|
||||
https://gist.github.com/madc/4474559
|
||||
|
||||
For this project I use a simple case structur. Looks arkward, but the
|
||||
ATTiny45 has only 256byte RAM but 4kFlash. A data structure is better programming
|
||||
but needs a lot of RAM we not have. Therefore this ugly case structure.
|
||||
This will waste the flash memory but we have enough and saving RAM for
|
||||
our payload - the ASCII-string with the morsetext.
|
||||
|
||||
BTW - Morsecode itself:
|
||||
|
||||
'A', ".-" 'B', "-..." 'C', "-.-."
|
||||
'D', "-.." 'E', "." 'F', "..-."
|
||||
'G', "--." 'H', "...." 'I', ".."
|
||||
'J', ".---" 'K', ".-.-" 'L', ".-.."
|
||||
'M', "--" 'N', "-." 'O', "---"
|
||||
'P', ".--." 'Q', "--.-" 'R', ".-."
|
||||
'S', "..." 'T', "-" 'U', "..-"
|
||||
'V', "...-" 'W', ".--" 'X', "-..-"
|
||||
'Y', "-.--" 'Z', "--.."
|
||||
|
||||
'1', ".----" '2', "..---" '3', "...--"
|
||||
'4', "....-" '5', "....." '6', "-...."
|
||||
'7', "--..." '8', "---.." '9', "----."
|
||||
'0', "-----"
|
||||
|
||||
'.', ".-.-.-" ',', "--..--" '?', "..--.."
|
||||
'!', "-.-.--" ':', "---..." ';', "-.-.-."
|
||||
'(', "-.--." ')', "-.--.-" '"', ".-..-."
|
||||
'@', ".--.-." '&', ".-..."
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
Legal stuff / Copyright:
|
||||
Creative Commons Attribution ShareAlike 3.0.:
|
||||
http://creativecommons.org/licenses/by-sa/3.0/legalcode
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
// ===========================================================================
|
||||
// Ok folks, let's start
|
||||
// ===========================================================================
|
||||
// for sleep Mode / Powersave we need some additional stuff. Its alredy there,
|
||||
// if you installed the Attiny extension for Arduino IDE, no additional
|
||||
// installing needed.
|
||||
#include <avr/sleep.h>
|
||||
#include <avr/wdt.h>
|
||||
|
||||
// ===========================================================================
|
||||
// Some definitions for powersave depending of ATTiny type.
|
||||
#ifndef cbi
|
||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
||||
#endif
|
||||
#ifndef sbi
|
||||
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
||||
#endif
|
||||
|
||||
// ===========================================================================
|
||||
// for ATTiny85
|
||||
// Unit length < 150 will hard to be read for optical morse code
|
||||
// > 300 are too slow in my feeling for longer text
|
||||
//
|
||||
// for ATTiny85 at 8MHz (for 1MHz see ATTiny45)
|
||||
// Unit length < 5 will hard to be read for optical morse code
|
||||
// > 10 are too slow in my feeling for longer text
|
||||
//
|
||||
//
|
||||
|
||||
#define unitLength 100
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// LED Pin definitions,
|
||||
// theoretical you can use up to 3 LED. For example you can use it for a
|
||||
// landmark beacon. So if you point this LEDs to different directions you can
|
||||
// detect the position in dependence of your location to the bacon.
|
||||
#define LED1_N_SIDE 3
|
||||
#define LED1_P_SIDE 4
|
||||
|
||||
// ===========================================================================
|
||||
// Variables
|
||||
// ===========================================================================
|
||||
// ###########################################################################
|
||||
// # and now the text, but be aware, only 256Byte RAM for Attiny45 #
|
||||
// # so there are only 22 Chars left for your message. #
|
||||
// # BTW with an Attiny85 you will have additional 256byte #
|
||||
// # => more than for twitter :-) #
|
||||
// # => for FireFly with SuperCap: less ist better, charge last longer #
|
||||
|
||||
String morseText =
|
||||
"TOGO LAB";
|
||||
// # "....5....1....5....2.."; just a ruler, remember 22 Chars for ATTiny #
|
||||
// IT IS USELESS
|
||||
// HAIL GLOW CLOUD
|
||||
// ###########################################################################
|
||||
|
||||
// Define light trigger threshold. best way to set it on dusk / dawn level
|
||||
// diffuse red ones are less sensitive than clear green ones...
|
||||
int darknessThreshold = 17000;
|
||||
|
||||
// Interrupt Flag, should be volatile, means: read from RAM, not register
|
||||
// because registers are used for interrupt handling, it have to be volatile.
|
||||
volatile boolean f_wdt = 1;
|
||||
|
||||
// ===========================================================================
|
||||
// Setup watchdog
|
||||
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
|
||||
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
|
||||
// ===========================================================================
|
||||
void setup()
|
||||
{
|
||||
setup_watchdog(9);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Main
|
||||
// ===========================================================================
|
||||
|
||||
void loop(){
|
||||
|
||||
if (f_wdt==1) { // wait for timed out watchdog
|
||||
// flag is set when a watchdog timeout occurs
|
||||
f_wdt=0; // reset flag
|
||||
|
||||
// if it's dark enough [>darknesThreshold] morse
|
||||
if (sensDarkness(LED1_N_SIDE, LED1_P_SIDE) > darknessThreshold){
|
||||
// looks like it's dark, so do your job
|
||||
morse(LED1_N_SIDE, LED1_P_SIDE);
|
||||
}
|
||||
}
|
||||
// set all used port to intput to save power
|
||||
pinMode(LED1_N_SIDE,INPUT);
|
||||
pinMode(LED1_P_SIDE,INPUT);
|
||||
system_sleep();
|
||||
f_wdt=0; // 2nd time sleep
|
||||
system_sleep();
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Subroutines for Sleeping
|
||||
// ===========================================================================
|
||||
// set system into the sleep state
|
||||
// system wakes up when wtchdog is timed out
|
||||
void system_sleep() {
|
||||
cbi(ADCSRA,ADEN); // switch Analog to
|
||||
// Digitalconverter OFF
|
||||
|
||||
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
|
||||
sleep_enable();
|
||||
|
||||
sleep_mode(); // System sleeps here
|
||||
|
||||
sleep_disable(); // System continues execution here when
|
||||
// watchdog timed out
|
||||
sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Setup for watchdog. Parameter ii for sleeping time:
|
||||
// 0 = 16ms, 1 = 32ms, 2 = 64ms,
|
||||
// 3 = 128ms, 4 = 250ms, 5 = 500ms
|
||||
// 6 = 1 sec, 7 = 2 sec, 8 = 4 sec,
|
||||
// 9 = 8 sec
|
||||
void setup_watchdog(int ii) {
|
||||
|
||||
byte bb;
|
||||
int ww;
|
||||
if (ii > 9 ) ii=9;
|
||||
bb=ii & 7;
|
||||
if (ii > 7) bb|= (1<<5);
|
||||
bb|= (1<<WDCE);
|
||||
ww=bb;
|
||||
|
||||
MCUSR &= ~(1<<WDRF);
|
||||
|
||||
WDTCR |= (1<<WDCE) | (1<<WDE); // start timed sequence
|
||||
|
||||
WDTCR = bb; // set new watchdog timeout value
|
||||
WDTCR |= _BV(WDIE);
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
// Watchdog Interrupt Service / is executed when watchdog timed out
|
||||
ISR(WDT_vect) {
|
||||
f_wdt=1; // set global flag
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Subroutines for light sensor
|
||||
// =============================================================================
|
||||
// Function sensDarkness
|
||||
// Usage: sensDarkness(Pin-No. N-Side of LED, Pin-No. P-Side of LED):
|
||||
// will result "darkness-level" - the higher the darker:
|
||||
// 30000 = pitch black
|
||||
// 0 = sunshine
|
||||
int sensDarkness(int LED_N, int LED_P){
|
||||
|
||||
unsigned int i; //Parameter bleed-out LED capacitor
|
||||
|
||||
// charge the capacitor of LED
|
||||
pinMode(LED_N,OUTPUT);
|
||||
pinMode(LED_P,OUTPUT);
|
||||
digitalWrite(LED_N,HIGH);
|
||||
digitalWrite(LED_P,LOW);
|
||||
|
||||
// Isolate the N end of the diode and turn off internal pull-up resistor
|
||||
pinMode(LED_N,INPUT);
|
||||
digitalWrite(LED_N,LOW);
|
||||
|
||||
// Count how long it takes the diode to bleed back down to a logic zero
|
||||
for ( i = 0; i < 30000; i++) {
|
||||
if ( digitalRead(LED_N)==0) break;
|
||||
}
|
||||
// thats it, return result
|
||||
return i;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Subroutines for morse text
|
||||
// =============================================================================
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function dit = ".", a dit is as long as a unitLength, used in morse()
|
||||
//
|
||||
void dit(int LED_P){
|
||||
digitalWrite( LED_P, HIGH ); delay( unitLength );
|
||||
digitalWrite( LED_P, LOW ); delay( unitLength );
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function dah = "-", a dah is as long as a 3*unitLength
|
||||
//
|
||||
void dah(int LED_P){
|
||||
digitalWrite( LED_P, HIGH ); delay( unitLength*3 );
|
||||
digitalWrite( LED_P, LOW ); delay( unitLength );
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function morse:
|
||||
// hand over text and LED Pins
|
||||
// because you want to use more than one LED hand over also LED Pins
|
||||
|
||||
void morse(int LED_N, int LED_P){
|
||||
|
||||
// Because I have more Flash than RAM I decided to use a case structure.
|
||||
// Its not so pretty, but I can use the RAM to hold my morseText.
|
||||
//
|
||||
// set N-Side of LED Low, so you can set P-side high to let them flash
|
||||
|
||||
pinMode( LED_N, OUTPUT);
|
||||
pinMode( LED_P, OUTPUT);
|
||||
|
||||
digitalWrite( LED_N, LOW);
|
||||
|
||||
// send it to defined LED
|
||||
for(int i=0; i<=morseText.length(); i++)
|
||||
{
|
||||
switch( morseText[i] )
|
||||
{
|
||||
|
||||
// Chars A-Z
|
||||
case 'A': // .-
|
||||
dit(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case 'B': // -...
|
||||
dah(LED_P); dit(LED_P); dit(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case 'C': // -.-.
|
||||
dah(LED_P); dit(LED_P); dah(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case 'D': // -..
|
||||
dah(LED_P); dit(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case 'E': // .
|
||||
dit(LED_P);
|
||||
break;
|
||||
|
||||
case 'F': // ..-.
|
||||
dit(LED_P); dit(LED_P); dah(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case 'G': // --.
|
||||
dah(LED_P); dah(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case 'H': // ....
|
||||
dit(LED_P); dit(LED_P); dit(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case 'I': // ..
|
||||
dit(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case 'J': // .---
|
||||
dit(LED_P); dah(LED_P); dah(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case 'K': // .-.-
|
||||
dit(LED_P); dah(LED_P); dit(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case 'L': // .-..
|
||||
dit(LED_P); dah(LED_P); dit(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case 'M': // --
|
||||
dah(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case 'N': // -.
|
||||
dah(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case 'O': // ---
|
||||
dah(LED_P); dah(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case 'P': // .--.
|
||||
dit(LED_P); dah(LED_P); dah(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case 'Q': // --.-
|
||||
dah(LED_P); dah(LED_P); dit(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case 'R': // .-.
|
||||
dit(LED_P); dah(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case 'S': // ...
|
||||
dit(LED_P); dit(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case 'T': // -
|
||||
dah(LED_P);
|
||||
break;
|
||||
|
||||
case 'U': // ..-
|
||||
dit(LED_P); dit(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case 'V': // ...-
|
||||
dit(LED_P); dit(LED_P); dit(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case 'W': // .--
|
||||
dit(LED_P); dah(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case 'X': // -..-
|
||||
dah(LED_P); dit(LED_P); dit(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case 'Y': // -.--
|
||||
dah(LED_P); dit(LED_P); dah(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case 'Z': // --..
|
||||
dah(LED_P);dah(LED_P); dit(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
// Numbers
|
||||
case '1': // .----
|
||||
dit(LED_P); dah(LED_P); dah(LED_P); dah(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case '2': // ..---
|
||||
dit(LED_P); dit(LED_P); dah(LED_P); dah(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case '3': // ...--
|
||||
dit(LED_P); dit(LED_P); dit(LED_P); dah(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case '4': // ....-
|
||||
dit(LED_P); dit(LED_P); dit(LED_P); dit(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case '5': // .....
|
||||
dit(LED_P); dit(LED_P); dit(LED_P); dit(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case '6': // -....
|
||||
dah(LED_P); dit(LED_P); dit(LED_P); dit(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case '7': // --...
|
||||
dah(LED_P); dah(LED_P); dit(LED_P); dit(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case '8': // ---..
|
||||
dah(LED_P); dah(LED_P); dah(LED_P); dit(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case '9': // ----.
|
||||
dah(LED_P); dah(LED_P); dah(LED_P); dah(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case '0': // -----
|
||||
dah(LED_P); dah(LED_P); dah(LED_P); dah(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
// Special Signs
|
||||
case ' ': // Gap
|
||||
delay( unitLength*5 );
|
||||
break;
|
||||
|
||||
case '.': // .-.-.-
|
||||
dit(LED_P); dah(LED_P); dit(LED_P); dah(LED_P); dit(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case ',': // --..--
|
||||
dah(LED_P); dah(LED_P); dit(LED_P); dit(LED_P); dah(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case '?': // ..--..
|
||||
dit(LED_P); dit(LED_P); dah(LED_P); dah(LED_P); dit(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case '!': // -.-.--
|
||||
dah(LED_P); dit(LED_P); dah(LED_P); dit(LED_P); dah(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case ':': // ---...
|
||||
dah(LED_P); dah(LED_P); dah(LED_P); dit(LED_P); dit(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case ';': // -.-.-.
|
||||
dah(LED_P); dit(LED_P); dah(LED_P); dit(LED_P); dah(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case '(': // -.--.
|
||||
dah(LED_P); dit(LED_P); dah(LED_P); dah(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case ')': // -.--.-
|
||||
dah(LED_P); dit(LED_P); dah(LED_P); dah(LED_P); dit(LED_P); dah(LED_P);
|
||||
break;
|
||||
|
||||
case '"': // .-..-.
|
||||
dit(LED_P); dah(LED_P); dit(LED_P); dit(LED_P); dah(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case '@': // .--.-.
|
||||
dit(LED_P); dah(LED_P); dah(LED_P); dit(LED_P); dah(LED_P); dit(LED_P);
|
||||
break;
|
||||
|
||||
case '&': // .-...
|
||||
dit(LED_P); dah(LED_P); dit(LED_P); dit(LED_P); dit(LED_P);
|
||||
}
|
||||
// wait at end of sign
|
||||
delay( unitLength*3 );
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// That's all, folks :-)
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -183,8 +183,8 @@
|
||||
// theoretical you can use up to 3 LED. For example you can use it for a
|
||||
// landmark beacon. So if you point this LEDs to different directions you can
|
||||
// detect the position in dependence of your location to the bacon.
|
||||
#define LED1_N_SIDE 4
|
||||
#define LED1_P_SIDE 3
|
||||
#define LED1_N_SIDE 3
|
||||
#define LED1_P_SIDE 4
|
||||
|
||||
// ===========================================================================
|
||||
// Variables
|
||||
|
||||
Binary file not shown.
@ -1,288 +0,0 @@
|
||||
/*
|
||||
FireFly tetrahedron adapter
|
||||
Base STL: tetrahedron40mmC.stl
|
||||
|
||||
Purpose:
|
||||
- Import original 40 mm foldable tetrahedron STL
|
||||
- Scale it to 60 mm base geometry
|
||||
- Add cable holes, vent/drain holes, and optional PCB mounting holes
|
||||
|
||||
Workflow:
|
||||
1. Set PART = "upper"
|
||||
2. Render with F6
|
||||
3. Export STL
|
||||
4. Set PART = "lower"
|
||||
5. Render with F6
|
||||
6. Export STL
|
||||
|
||||
Notes:
|
||||
- Hole coordinates are defined on the original 40 mm STL coordinate system.
|
||||
- The script scales them automatically to 60 mm.
|
||||
- First export should be treated as v0.1 prototype.
|
||||
*/
|
||||
|
||||
|
||||
/* =========================
|
||||
Main selection
|
||||
========================= */
|
||||
|
||||
PART = "upper"; // "upper", "lower", or "both_preview"
|
||||
|
||||
|
||||
/* =========================
|
||||
Input file
|
||||
========================= */
|
||||
|
||||
input_stl = "tetrahedron40mmC.stl";
|
||||
|
||||
|
||||
/* =========================
|
||||
Scaling
|
||||
========================= */
|
||||
|
||||
// Original tetrahedron edge length
|
||||
original_edge_mm = 40;
|
||||
|
||||
// Target mechanical base size
|
||||
target_edge_mm = 60;
|
||||
|
||||
// XY scale from 40 mm to 60 mm
|
||||
scale_xy = target_edge_mm / original_edge_mm; // 1.5
|
||||
|
||||
// Keep original thickness.
|
||||
// Set to 1.2 or 1.3 if you want a slightly thicker part.
|
||||
scale_z = 1.0;
|
||||
|
||||
|
||||
/* =========================
|
||||
General hole settings
|
||||
========================= */
|
||||
|
||||
hole_fn = 40;
|
||||
cut_height = 20;
|
||||
|
||||
|
||||
/* =========================
|
||||
Feature switches
|
||||
========================= */
|
||||
|
||||
add_upper_cable_holes = true;
|
||||
add_upper_hanger_hole = true;
|
||||
|
||||
add_lower_vent_holes = true;
|
||||
add_lower_cable_holes = true;
|
||||
add_lower_pcb_mount_holes = true;
|
||||
|
||||
// Keep this false for the first prototype.
|
||||
// Standoffs may interfere with folding depending on print orientation.
|
||||
add_lower_pcb_standoffs = false;
|
||||
|
||||
|
||||
/* =========================
|
||||
Hole sizes
|
||||
========================= */
|
||||
|
||||
cable_hole_d = 3.2; // for small solar-panel wires
|
||||
hanger_hole_d = 3.5; // for small ring / wire / eyelet
|
||||
vent_hole_d = 2.0; // condensation vent / drain holes
|
||||
pcb_screw_hole_d = 2.2; // M2 clearance-ish
|
||||
pcb_standoff_d = 6.0;
|
||||
pcb_standoff_h = 3.0;
|
||||
|
||||
|
||||
/* =========================
|
||||
Coordinate reference
|
||||
=========================
|
||||
|
||||
The uploaded STL is approximately:
|
||||
|
||||
X: -34.64 to +34.64
|
||||
Y: -20.00 to +60.00
|
||||
Z: -0.10 to +2.00
|
||||
|
||||
The original model is a flat foldable tetrahedron net.
|
||||
Coordinates below are before scaling.
|
||||
*/
|
||||
|
||||
|
||||
/* =========================
|
||||
Upper part hole positions
|
||||
========================= */
|
||||
|
||||
// Cable holes for three solar panels.
|
||||
// Adjust after checking where your real panel wires exit.
|
||||
upper_cable_points = [
|
||||
[-18, 20],
|
||||
[ 24, 7],
|
||||
[ 24, 33]
|
||||
];
|
||||
|
||||
// Optional hanger hole close to one upper fold/vertex area.
|
||||
// If this weakens the corner too much, disable it and use an external loop instead.
|
||||
upper_hanger_points = [
|
||||
[0, 38]
|
||||
];
|
||||
|
||||
|
||||
/* =========================
|
||||
Lower part hole positions
|
||||
========================= */
|
||||
|
||||
// Cable transfer holes between upper solar section and lower electronics bay.
|
||||
lower_cable_points = [
|
||||
[-10, 20],
|
||||
[ 12, 13],
|
||||
[ 12, 27]
|
||||
];
|
||||
|
||||
// Small vent/drain hole clusters near likely lower/edge areas.
|
||||
// These are deliberately small.
|
||||
lower_vent_centres = [
|
||||
[ 0, 3],
|
||||
[ 0, 37],
|
||||
[-30, 20],
|
||||
[ 31, 20]
|
||||
];
|
||||
|
||||
// Approximate triangular PCB mounting pattern.
|
||||
// Tune this after measuring your actual red triangle PCB.
|
||||
lower_pcb_mount_points = [
|
||||
[ 0, 8],
|
||||
[ 25, 20],
|
||||
[ 0, 32]
|
||||
];
|
||||
|
||||
|
||||
/* =========================
|
||||
Basic modules
|
||||
========================= */
|
||||
|
||||
module base_import_scaled()
|
||||
{
|
||||
scale([scale_xy, scale_xy, scale_z])
|
||||
import(input_stl, convexity = 10);
|
||||
}
|
||||
|
||||
|
||||
module vertical_hole(p, d)
|
||||
{
|
||||
translate([p[0] * scale_xy, p[1] * scale_xy, 1])
|
||||
cylinder(h = cut_height, d = d, center = true, $fn = hole_fn);
|
||||
}
|
||||
|
||||
|
||||
module vent_cluster(p)
|
||||
{
|
||||
// Small 2 x 3 vent/drain pattern.
|
||||
// Pitch is in final millimetres, not original model coordinates.
|
||||
pitch = 3.0;
|
||||
|
||||
for (ix = [-1, 0, 1])
|
||||
for (iy = [0, 1])
|
||||
translate([
|
||||
p[0] * scale_xy + ix * pitch,
|
||||
p[1] * scale_xy + iy * pitch,
|
||||
1
|
||||
])
|
||||
cylinder(h = cut_height, d = vent_hole_d, center = true, $fn = hole_fn);
|
||||
}
|
||||
|
||||
|
||||
module pcb_standoff(p)
|
||||
{
|
||||
// Standoff added on top of the flat STL.
|
||||
// Use only if you confirm it does not block folding.
|
||||
translate([p[0] * scale_xy, p[1] * scale_xy, 2.1 * scale_z])
|
||||
cylinder(h = pcb_standoff_h, d = pcb_standoff_d, center = false, $fn = hole_fn);
|
||||
}
|
||||
|
||||
|
||||
/* =========================
|
||||
Upper tetrahedron
|
||||
========================= */
|
||||
|
||||
module upper_part()
|
||||
{
|
||||
difference()
|
||||
{
|
||||
base_import_scaled();
|
||||
|
||||
if (add_upper_cable_holes)
|
||||
{
|
||||
for (p = upper_cable_points)
|
||||
vertical_hole(p, cable_hole_d);
|
||||
}
|
||||
|
||||
if (add_upper_hanger_hole)
|
||||
{
|
||||
for (p = upper_hanger_points)
|
||||
vertical_hole(p, hanger_hole_d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* =========================
|
||||
Lower tetrahedron
|
||||
========================= */
|
||||
|
||||
module lower_part()
|
||||
{
|
||||
difference()
|
||||
{
|
||||
union()
|
||||
{
|
||||
base_import_scaled();
|
||||
|
||||
if (add_lower_pcb_standoffs)
|
||||
{
|
||||
for (p = lower_pcb_mount_points)
|
||||
pcb_standoff(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (add_lower_cable_holes)
|
||||
{
|
||||
for (p = lower_cable_points)
|
||||
vertical_hole(p, cable_hole_d);
|
||||
}
|
||||
|
||||
if (add_lower_vent_holes)
|
||||
{
|
||||
for (p = lower_vent_centres)
|
||||
vent_cluster(p);
|
||||
}
|
||||
|
||||
if (add_lower_pcb_mount_holes)
|
||||
{
|
||||
for (p = lower_pcb_mount_points)
|
||||
vertical_hole(p, pcb_screw_hole_d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* =========================
|
||||
Output
|
||||
========================= */
|
||||
|
||||
if (PART == "upper")
|
||||
{
|
||||
upper_part();
|
||||
}
|
||||
else if (PART == "lower")
|
||||
{
|
||||
lower_part();
|
||||
}
|
||||
else if (PART == "both_preview")
|
||||
{
|
||||
translate([-80, 0, 0])
|
||||
upper_part();
|
||||
|
||||
translate([80, 0, 0])
|
||||
lower_part();
|
||||
}
|
||||
else
|
||||
{
|
||||
echo("Invalid PART setting. Use upper, lower, or both_preview.");
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
7960
hardware/CAD/ToGo-Lab_FireFly_MorseThrowie - LaserCut.dxf
Normal file
7960
hardware/CAD/ToGo-Lab_FireFly_MorseThrowie - LaserCut.dxf
Normal file
File diff suppressed because it is too large
Load Diff
7410
hardware/CAD/ToGo-Lab_FireFly_MorseThrowie - LaserCut_Upload.dxf
Normal file
7410
hardware/CAD/ToGo-Lab_FireFly_MorseThrowie - LaserCut_Upload.dxf
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user