/* EQ platform driver - by Nils Olof Carlin ************* this version mar 10, 2011 with bugfix in battcheck routine 101112 * *Addendum 2014-04-16 *For duemilanove, the startport and stopport inputs are correctly initialized with *pullup resistors: * pinMode (port,INPUT); * digitalWrite(port,HIGH); *For newer models, instead the programming for pullup is: * pinMode (port,INPUT_PULLUP); * * Tangent arm driver, with rate compensation for arcsine. * This compensation may appear ever so small (and it is indeed): * 5 sec for a 30 minute excursion either side of "neutral" position * but since this is done in software and as an exercise, all right - no harm done * Desired RA angle: (2*pi/86164.1)*time (seconds), in radians: natural constant * Arcsin(x) equals x + x^3/6 (higher order terms are totally negligible) * Given mv=the angle of the latest step, the time to perform next step: * (86164.1/2*pi)*mv*(1+mv^2/6) or to avoid one slow float division by 6. * break out and rewrite * (86164.1/12*pi)*mv*(6+mv*mv) ** an even closer approximation would be x + x^3/6 + 3x^5/40: ** make the last term 1/12 instead - this would overshoot ** at most 2 arcsec, but is easier to compute: ** (86164.1/24*pi)*mv*(11+mv2*mv2) where mv2=(1+mv*mv) ** involving 4 multiplications and 2 additions, compared to 3 and 1 as here. ** This would be good to at least 3 hours start-to-end within some 2 arcsec, ** but polar alignment, mechanical tolerances and not least the need for ** compensating for other mechanical factors makes this less than meaningful * Microstepping routine for analog outputs: * choose number of microsteps/step (minr: here= 12) * The present ouput will ramp down successively * while the next output is ramped up * Using a microstepping driver would be possible, redesigning the functions * and connecting and initializing the control lines as appropriate * Doing a small sketch, to see the current to one winding as a function of analog * output value, yielded a rather non-linear function. I plotted it, and read the * analog numbers for each 1/minr of total, this is what I put in the matrix. This means * essentially constant current to the motors during the microstepping. * (experimenting with a sine-shaped pulse width sequence gave a very jerky * motion - if you get that, I don't know what to do) * added: battery monitoring: battery voltage divided by 27k and 10k divider, compared * to 5V as reference: empirically 53.4 per volt. * analogRead(battport): 560 for 10.5 V, 587 for 11V, 614 for 11.5V * Operation: at power on, rewind is done until the start switch is hit. * Then it starts tracking until EITHER the maximum number of steps are done, * after which it rewinds to beginning and starts another run, * OR the end switch is hit (manually, or at the end of travel) * in which case it will wind/rewind to neutral position (n=0) and wait there * for you to shut off the power, pack up and go home - or change your mind, * press the end switch again to do a rewind and start another run. * A short beep tells you neutral position is reached. * (pressing the Arduino reset button would do so, too, but you may not reach it, * and of corse turning off the power and turning it on again) * 1700 steps before end of tracking (approx 30 sec), beeper warns of impending stop. * */ /////////////////////// Global variables or constants: /////////////////////// int portar[4]={3,9,10,11}; // These 4 PWM-ports are used // for my unit: yellow, red, green, black for ccw) int mistep[13]={255,244,230,216,200,182,164,144,122,98,66,36,0}; // analog values for microsteps 0-255 determined //empirically - equal current intervals int battlevel[3]={560,587,614};// battery voltage warning levels, see above float timecons=2285573.74; // number of milliseconds for 1/6 radians //=86164.1/(12*pi)*1000 - a "natural" constant // to be used in the setup routine below int startport=7; // switch at the start - rewind to close it int stopport=8; // switch at the end of the motion - safety only int beepport=5; // acoustic beeper int battport=4; // analog port for battery monitoring int beeplen=16; // length 0 - 255 for beeper pulse length, try //int potinput=1; // ***for analog speed adjustment - skip when done /////////// hardware constants, in mm where applicable: long beginstep=-10400;// total number of steps from start position to mid position, // usually negative: if start before reaching mid position long endstep =10200; // ditto from mid to end position - maybe equal to beginstep // here calculated for 1/2 hr, or from the actual platform float pitch = 1.0; // pitch of thread float radius = 386.0 ; // radius of sector, axis to driving pin // You will likely have to fine tune this, to get exact speed int motorsteps = 200; // steps per full turn of stepper motor axis - includes // gearbox if one int rewind = 2500; //step interval microsec (!) during rewinding (if applicable) // You will have to determine this constant empirically // 1500 is minimum for my stepper, no load and room temp // Variables, to be computed during setup or during stepping float stepangle; // angle per step, in radians (at mid position) // depends on hardware unsigned long startofrun; // timer setting after rewind, at start of forward stepping float goaltime; // calculated time for next step float begintime; // calculated time ms of start position = negative if beginstep is int steptime; // calculated time from latest to next step: millisec (at mid pos) float donetime; // read the timer in microsecs since program start, // convert to float long n; // number of steps from midpos - starts negative if beginstep is int minr = 12; // number of microsteps per fullstep float mv; // Intermediate value for time calculation: see below /////////////////////// Functions to be adapted or modified as appropriate void beep() // small function to sound beeper - 0 for no pulse {analogWrite(beepport,beeplen); } void unbeep() // ditto to silence beeper {analogWrite(beepport,0); } ////////////////////////////////////////////// void dostep() // analog (PWM) one fullstep in microsteps // the array mistep implements the relative currents to the //windings. Any number of microsteps possible, not only powers of 2 { int m; int k; // port number = n modulo 4 (must not be negative!!) unsigned long now; // read global timer at start unsigned long goal; // calculated time for next microstep m=(n-beginstep)%4; // latest step to this port k=(n+1-beginstep)%4; // step to do now, to next port now=millis(); // read global timer for (int ctr=0; ctr=11.5 V if (n>(endstep-245)) // start beeping 245 steps from end of range, about 30 sec { if ((cntr%8)==0) beep(); else unbeep(); } // every 4th step //***************************** the previous 2 lines were corrected 101112 //Serial.println(voltage); } /////////// setup() this is the initializing routine - part of any Arduino sketch void setup() // { // Serial.begin(9600); // initialize communication if needed for debug // If you wish: tie a potentiometer to gnd and +5v, and wiper to port 0 // and calculate a modified radius before a test run, something like: // potinput = analogRead(0); // radius=radius + (potinput*0.01); //Radius varied 375 - 385 mm // Serial.println (potinput); // print to know, then program for (int i=0; i<4; i++) // First initialize the 4 analog output ports for { pinMode(portar[i],OUTPUT); } //driving the stepper interface citcuits pinMode (startport,INPUT); // Initialize endswitches - at start pos digitalWrite(startport,HIGH); // set the port with pullup resistor pinMode(stopport,INPUT); // and do the same with stop pos digitalWrite(stopport,HIGH); pinMode(beepport,OUTPUT); // to give a beep = warning of imminent stopping stepangle = pitch/(radius*motorsteps); // angular motion per fullstep, // in radians, not corrected for arcsin steptime = int(6.0*timecons*stepangle); // estimated time between fullsteps; gives // the minimum timeframe for the step routine mv=n*stepangle; // intermediate "uncorrected" angle begintime = timecons*mv*(6.0+mv*mv); // true begin time at beginstep position (neg) // // Serial.println(steptime); //print any value desired for debug // Serial.println(steptime/minr); //print any value desired for debug } ////////////////////////// loop() is the main routine, iterated until reset/pwr off void loop() { // First: reset to start pos, to know the position n=endstep-beginstep+100; // set n large enough not to reach 0 during rewind while (digitalRead(startport)==HIGH) // to start, or n if failed quickstep(false); //rewind false=backward n=beginstep; startofrun=millis(); // now that rewind is done, read timer for a starting value do // main loop, do a step of many microsteps at the right time // and repeat until stop switch is pressed, or { // n+=1; //increment n mv=n*stepangle; // angle to be corrected for arcsin goaltime=timecons*mv*(6.0+mv*mv) - begintime; // right time to do the step do // repeat reading the time donetime=float(millis()- startofrun); // how long actual time since start of this run? while(donetime