The emperor’s new clothes

The Dremel is one of my favorite tools.  You can basically accomplish any cutting task with one if you’re patient enough or whatever.  Having recently upgraded to a much more powerful model I had the battery-powered model seen here kicking around.  Needing something capable of milling and etching for the CNC machine and not wanting to waste the expense to both my wallet and the environmental factors involved in shipping a DC motor overseas I decided to sacrifice the old model.

After disassembling, here’s what there is under the hood:

 

A hobby-grade DC motor with a chuck attached to it and rechargeable batteries.  Interestingly the batteries were advertised to have “Lithium Ion Technology” but they’re actually standard Ni-Cd batteries… the original rechargeables that have been around for about 30 years.  And suck.

The unit retailed for about $60… and the parts seen above can be purchased for about $8 total individually.  The rest is just injection-molded plastic.

So yeah, fisted.

Still love Dremel though…

Advertisements

Blues for a solar panel

Oh noes!

One of the cells has split somewhat.  Apparently the strain of panels against plexiglass, which I have learned tends to expand and contract more than I would have expected due to temperature, has cracked it.  Being made of glass and <0.2mm thick, it’s not difficult to do.

The problem is that this single crack is limiting the output of this cell by ~30% of its output wattage.  That’s causing the entire panel to lose 30%.  Butts.

I’ll be repairing this.

In the meantime, I noticed this at 11pm:

I stuck the above LEDs into the circuit to see what they were doing and to my surprise they were flickering right along.  But why flickering?  I started trying to figure out if there was any way there was an odd capacitance in the circuit that I wasn’t understanding.  But no, nothing.  Even with the MCU entirely powered down it was still happening.  And four LEDs drawing at least 20mA a piece wouldn’t be sustained by any capacitance.

What I did notice, however, was that the flickering matched the dancing of the flame of a tiki torch lit in the backyard that was near the panel.  3v and at least 80mA coming from a single torch in what would otherwise be pitch black.  Surprising…

More interesting to come, tomorrow though.

Things to look for soon:  Stirling engines, Peltier cell phone charger, my take on Mr Fusion.

Sidebar poll:

Shave and a haircut (and native floating point support): 32 bits

Since the voting regarding which angle of attack to use on tackling the out of memory problem resulted in a tie I decided to take a half-of-each approach.  The code would be optimized as much as possible, but instead of dumping more RAM into the mix, I would set up a second microcontroller as a math co-processor.

I had a few right here to chose from.  Two PIC chips, two ATMega644P’s, a Sanguinololu (which another project already had dibs on unless I was guaranteed it could do the job, and two Parallax Propeller P8X32A QuickStart boards.

The Parallax Propeller is an interesting board.  It’s a 32-bit 8-core processor that supports development in C, C++, SPIN, and ASM.  Each core operates at a user-defined speed ranging from 20kHz to 80MHz (the k in kHz wasn’t a typo).  The 32-bit architecture also lent itself nicely to the floating-point arithmetic needed by the solar position calculations.  It also has 32kb of program memory and 32kb of RAM.

Here’s a picture of it as if that helps at all:

So I programmed it up and TADA! It was out of memory.  Because the fucker only allocates 4k per core and there’s nothing you can do to get at the rest.

Fuck.  So I bought a RAM upgrade for the original microcontroller.

$20 lighter.

This is the pre-optimized code in C++ for a 32 bit compiler if anyone has any ideas:

#include <Arduino.h>
#include "SolarPosition.h"
#include <Time.h>
#include <HardwareSerial.h>
int inputMonth;
 int inputDate;
 int inputYear;
 int inputHour;
 int inputMinute;
 int inputAMPM;
 double degreesToRadians = 3.1416 / 180.0;
 double radiansToDegrees = 180.0 / 3.1416;
 double feetToMeters = 1.0 / 3.28;
 double solarMinutesAfterMidnight;
SolarPosition::SolarPosition(){
 degreesToRadians = 3.1416 / 180.0000;
 radiansToDegrees = 180.0000 / 3.1416;
 feetToMeters = 1.0000 / 3.2800;
}
 double SolarPosition::getOutputEOT(){
 return outputEOT;
 }
 double SolarPosition::getSolarMinutesAfterMidnight(){
 return solarMinutesAfterMidnight;
 }
String SolarPosition::getOutputLSOT(){
 return outputLSOT;
 }
 String SolarPosition::getOutputClockTime(){
 return outputClockTime;
 }
 double SolarPosition::getOutputHourAngle(){
 return outputHourAngle;
 }
 double SolarPosition::getOutputAltitude(){
 return outputAltitude;
 }
 double SolarPosition::getOutputDeclination(){
 return outputDeclination;
 }
 String SolarPosition::getOutputSunrise(){
 return outputSunrise;
 }
 String SolarPosition::getOutputSunset(){
 return outputSunset;
 }
 double SolarPosition::getOutputAzimuth(){
 return outputAzimuth;
 }
 void SolarPosition::setTime(int Year, int Month, int Date, int Hour, int Minute, int AMPM){
 inputYear = Year;
 inputDate = Date;
 inputMonth = Month;
 inputHour = Hour;
 inputMinute = Minute;
 inputAMPM = AMPM;
 }
void SolarPosition::Calculate(int Year, int Month, int Date, int Hour, int Minute, int AMPM) {
 inputYear = Year;
 inputDate = Date;
 inputMonth = Month;
 inputHour = Hour;
 inputMinute = Minute;
 inputAMPM = AMPM;
 
 inputLongitude = 77.45;
 inputEastWest = 0; // West = 0, East = 1
 inputLatitude = 43.22;
 inputNorthSouth = 0; // North = 0, South = 1;
 inputElevation = 465;
 inputFeetMeters = 0; // Feet = 0, Meters = 1
 inputTimeZone = -5;
 inputDaylight = 1;
 inputZeroAzimuth = 0;// 0 = North, 1 = South

 if (inputEastWest == 1) inputLongitude *= -1; // [0] = east, [1] = west
 if (inputNorthSouth == 1) inputLatitude *= -1; // [0] = north, [1] = south

 if (inputMonth > 2) {
 inputMonth = inputMonth - 3;
 }
 else {
 inputYear = inputYear - 1;
 inputMonth = inputMonth + 9;
 }
 if (inputLongitude > 180) inputLongitude = inputLongitude - 360;
 if (inputLongitude < -180) inputLongitude = inputLongitude + 360;
 if (inputFeetMeters == 0) inputElevation *= feetToMeters;
int meridian = inputTimeZone * -15;
if (inputAMPM == 0 && inputHour == 12) inputHour = 0;
 if (inputAMPM == 1) { if (inputHour != 12) inputHour += 12; }
double inputHoursAfterMidnight = inputHour + (float)inputMinute / 60;
 double inputMinutesAfterMidnight = inputHour * 60 + inputMinute;
 double UT = inputHoursAfterMidnight - inputTimeZone - inputDaylight;
 double t = ((UT / 24) + inputDate + floor(30.6 * double(inputMonth) + 0.5) + floor(365.25 * double(inputYear - 1976)) - 8707.5) / 36525;
 double G = NormalizeTo360(357.528 + 35999.05 * t);
 double C = (1.915 * sin(G * degreesToRadians)) + (0.020 * sin(2.0 * G * degreesToRadians));
 double L = NormalizeTo360(280.460 + (36000.77 * t) + C);
 double alpha = L - 2.466 * sin(2.0 * L * degreesToRadians) + 0.053 * sin(4.0 * L * degreesToRadians);
 double GHA = NormalizeTo360(UT * 15 - 180 - C + L - alpha);
outputDeclination = atan(tan((23.4393 - 0.013 * t) * degreesToRadians) * sin(alpha * degreesToRadians)) * radiansToDegrees;
outputEOT = (L - C - alpha) / 15;
double clockTimeToLSOTAdjustment = ((inputLongitude - double(meridian)) / 15.0) - outputEOT + double(inputDaylight); // in hours
double solarHourAngle = NormalizeTo180(GHA - inputLongitude);
double apparentSolarTime = NormalizeTo24(12 + solarHourAngle / 15.0);
 
 solarMinutesAfterMidnight = inputMinutesAfterMidnight - (clockTimeToLSOTAdjustment * 60.0);
double whichDay = 0;
 
 if (solarMinutesAfterMidnight < 0)
 { 
 solarMinutesAfterMidnight += 24 * 60;
 whichDay = -1;
 }
if (solarMinutesAfterMidnight >= 24 * 60)
 { 
 solarMinutesAfterMidnight -= 24 * 60;
 whichDay = 1;
 }
 
 String solarTime = MinutesToClockTime(int(solarMinutesAfterMidnight));
if (whichDay == -1) outputLSOT = solarTime + "-";
 if (whichDay == 0) outputLSOT = solarTime;
 if (whichDay == 1) outputLSOT = solarTime + "+";
whichDay = 0;
if (inputMinutesAfterMidnight < 0)
 { // it's the day before
 inputMinutesAfterMidnight += 24 * 60;
 whichDay = -1;
 }
if (inputMinutesAfterMidnight >= 24 * 60)
 { // it's the next day
 inputMinutesAfterMidnight -= 24 * 60;
 whichDay = 1;
 }
String clockTime = MinutesToClockTime((int)inputMinutesAfterMidnight);
 
 if (whichDay == -1) outputClockTime = clockTime + "-";
 if (whichDay == 0) outputClockTime = clockTime;
 if (whichDay == 1) outputClockTime = clockTime + "+";*/
 
 outputHourAngle = (solarMinutesAfterMidnight - (12 * 60)) / 4;
 
 double altitudeAngle = radiansToDegrees * asin(
 (sin(inputLatitude * degreesToRadians) *
 sin(outputDeclination * degreesToRadians)) -
 (cos(inputLatitude * degreesToRadians) *
 cos(outputDeclination * degreesToRadians) *
 cos((solarHourAngle + 180) * degreesToRadians)));
outputAltitude = altitudeAngle;
 
 double preAzimuthAngle = radiansToDegrees * acos(
 (cos(outputDeclination * degreesToRadians) *
 ((cos(inputLatitude * degreesToRadians) *
 tan(outputDeclination * degreesToRadians)) +
 (sin(inputLatitude * degreesToRadians) *
 cos((solarHourAngle + 180) * degreesToRadians)))) /
 cos(altitudeAngle * degreesToRadians));
 
 outputAzimuth = preAzimuthAngle + (inputZeroAzimuth - 180);
 if (inputZeroAzimuth == 0)
 outputAzimuth = ChangeSign(outputAzimuth, 0, outputHourAngle);
 else
 outputAzimuth = ChangeSign(outputAzimuth, 1, outputHourAngle);
double sunRiseSetLSoTMinutes = radiansToDegrees * acos(-1 *
 (sin(inputLatitude * degreesToRadians) *
 sin(outputDeclination * degreesToRadians) -
 sin((-0.8333 - 0.0347 * sqrt(inputElevation)) * degreesToRadians)) /
 cos(inputLongitude * degreesToRadians) /
 cos(outputDeclination * degreesToRadians)) * 4;
 
 outputSunrise = MinutesToClockTime((int)(12 * 60 - sunRiseSetLSoTMinutes + (clockTimeToLSOTAdjustment * 60)));
 outputSunset = MinutesToClockTime((int)(12 * 60 + sunRiseSetLSoTMinutes + (clockTimeToLSOTAdjustment * 60)));
 
 }
double SolarPosition::ChangeSign (double input, int mode, double basis) {
if (mode == 0) {
 if ((input * basis) < 0) {
 input *= -1;
 }
 }
 
 else {
 if ((input * basis) > 0) {
 input *= -1;
 }
 }
 
 return input;
 }
String SolarPosition::doubleToString(double input,int decimalPlaces){
 if(decimalPlaces!=0){
 String string = String((int)(input*pow(10,decimalPlaces)));
 if(abs(input)<1){
 if(input>0)
 string = "0"+string;
 else if(input<0)
 string = string.substring(0,1)+"0"+string.substring(1);
 }
 return string.substring(0,string.length()-decimalPlaces)+"."+string.substring(string.length()-decimalPlaces);
 } else {
 return String((int)input);
 }
 }
String SolarPosition::MinutesToClockTime (int totalMinutes) {
 String output;
 int theHours = floor(totalMinutes / 60);
 int theMinutes = (totalMinutes % 60);
if (theMinutes < 10) output = "0" + String(theMinutes); // add leading "0" if necessary
 else output = String(theMinutes);
if (theHours < 12) {
 if (theHours == 0) theHours = 12;
 output = String(theHours) + ":" + output + "am";
 }
 else {
 if (theHours == 12) theHours = 24;
 output = (String(theHours - 12)) + ":" + output + "pm";
 }
 
 return output;
 }

 double SolarPosition::NormalizeTo360 (double theThing) {
 return (theThing - floor(theThing / 360.0) * 360);
 }

 double SolarPosition::NormalizeTo180 (double theThing) {
 theThing = NormalizeTo360(theThing);
 if (theThing > 180) { theThing = theThing - 360; }
return (theThing);
 }

 double SolarPosition::NormalizeTo24 (double theThing) {
 return (theThing - floor (theThing / 24.0) * 24);
 }

Green machine

One of the nicest things about not having a woman around when you’re trying to get stuff done is not having a woman around when you’re trying to get stuff done.

With that in mind I started tossing together a CNC machine that will be able to mill wood, plastics, and PCBs using the RepStrap idea of tossing something together to make the parts for a more permanent machine.  This will be used mainly to create parts for a 3D printer and to properly mill a replica of itself that will be perfectly machined.  Once complete it will be dismantled and its parts will be recycled to make something that runs much more efficiently and looks a fuck of a lot prettier.

Also I’m doing it entirely with hand tools.  Just a hand saw, power drill, and battery-powered Dremel.  With batteries charged off of the solar panel.  Hence the title.  Fuck it.

Here’s a quick pic of what I have so far.  More later, maybe with plans or something:

Yes, that’s a first aid kit in the background. Yes, I cut my thumb open. Yes, it was a hand saw. Yep, that’s pretty sad.