Author Topic: Dual-axis tracker using hall sensors and DC motors  (Read 15977 times)

Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #15 on: November 27, 2012, 03:15:57 AM »
Glad you are enjoying the progress!

I will keep the updates coming. This week I have more coding to do then at the weekend if I get time I want to give a bit more of a push to the physical set up so I can have it tracking according to the GPS coordinates and the compass direction. I still need to alter the wiring to the switches, build the motor read and switch read circuits on perfboard, box up the electronics and fit water tight cabling to the external unit. I have some way to go but mostly aesthetic stuff.

I did some more coding but I'm not happy with the results at all, I think I will revert. I am having some trouble deciding on the conceptual organisation of the code. I think it would probably be helpful if I write it in a way that can one day (if wanted) be integrated back into the main program to add GPS and Compass functionality in a fairly seamless way. This ties in with my idea for the Plug'n'Play Solar Tracker.

I find it quite remarkable that Gabriel has managed to write a program that can be so versatile, just by altering some parameters in the flash array it is able to drive all kinds of machinery. As cool as this is I had to completely gut all but the sun calculation code to regain precise control of the motors, for example, to deal with the worm drive correction and to ensure the machine behaves in my desired manner at night and near sun up and sun down. My hope is that the rest of my code can be a bit more compatible with Gabriel's. I think I have helped the "main branch" of this project a bit by writing the BigNumberMath library and optimising the sun calculation bit. I'd like to help that a bit more by adding (optional) GPS and Compass modules for the Arduino Mega. I guess I need to speak to Gabriel a bit once my code is written up about how he sees this as an option.

More to come (hopefully in the next few days  ;D).


Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #16 on: November 27, 2012, 04:28:45 PM »
This is a complete mess but should outline my ideas for the code structure.

Essentially I have created a class (library) called Spacetime it contains fields to store information about the current time and the position and orientation of the machine (relative to true north).

Spacetime also contains a TinyGPS object and methods to populate the Spacetime fields using any gps capable of passing $GPRMC to a serial port.

Additionally Spacetime contains a LSM303 object and methods to populate the Spacetime true heading fields for any I2C compass compatible with the pololu LSM303 library. The methods use AP_Declination to automatically correct for the declination when doing this.

The net result is something like this:
Code: [Select]
#include <Spacetime.h> // include the Spacetime library

Spacetime mySpacetime = Spacetime(); // declare an instance of spacetime to store your current time, location and orientation

void setup() {
  mySpacetime.update(); // use a GPS and LSM303 compass to populate all fields of Spacetime
}

My idea is to also wrap SunCalculations into a library that has fields for Altitude and Azimuth. One could then do something like:
Code: [Select]
#include <Spacetime.h>
#include <SunCalculations.h>

Spacetime mySpacetime = Spacetime();
SunCalculations mySunAngles = new SunCalculations(); // instance to store (and calculate) altitude and azimuth

void setup() {
  mySpacetime.update(); // use a GPS and LSM303 compass to populate all fields of Spacetime
  mySunAngles.update(mySpacetime); // calculate the sun's altitude and azimuth at the current spacetime point
  mySunAngles.getAltitude(); // returns sun's altitude as float
  mySunAngles.getAzimuth(); // returns sun's azimuth as float
}

I will also wrap up my motor control as a library.

This effort will help to keep the global namespace clear and should make the control flow of the main program much clearer.

Code attached (for Spacetime) but it is very messy and completely untested, I am certain many bugs exist in it at this point as it is very sketchy.
« Last Edit: November 27, 2012, 04:34:05 PM by Bob101 »


Gabriel

  • Administrator
  • Hero Member
  • *****
  • Posts: 654
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #17 on: November 27, 2012, 04:45:51 PM »
Having access to the calculated declination and hour angle values could also come in handy if someone wanted to use this with a single axis tracker.

I actually wanted to put all of this in a library myself, but haven't had the time yet.

It is quite a bit of work making a program as universal as possible isn't it. :)

Thanks!
Gabriel

Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #18 on: November 30, 2012, 07:12:12 PM »
Just finished wrapping SunCalculations, MotorControl and all the gps/compass stuff inside Spacetime.

I did this at very high speed (for me) so I will check it out on my machine tomorrow before inflicting it on you. I should probably improve the code quality a bit too.

More coming soon...

Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #19 on: December 05, 2012, 04:31:36 PM »
Since it has been a bit quiet on the forum of late I thought I'd post an update.

I have made considerable progress on my version of the program and I thought I'd explain some of the design principles.

There are two main Libraries in use:
- Spacetime which itself uses Arduino, Wire, TinyGPS, AP_Declination, LSM303. It can interface with any GPS compatible with TinyGPS and any compass compatible with the Pololu LSM303 library. It uses the compass and GPS device to determine the current true heading (i.e heading after correcting for declination), latitude, longitude, year, month, day, hour, minute and second (it assumes timezone = 0 since GPS devices return time in UTC). In principle any code regarding specific types of clocks could be moved in here. There is also a debug_ function in place to manually override any of these values making testing very easy.
- SunCalculations which itself uses Arduino, MemoryFree (for debugging), BigNumber, BigNumberMath, Spacetime. It must be passed a spacetime object which it will store a pointer to. It can determine the sun's altitude, apparent altitude (using Gabriel's atmospheric refraction code), azimuth. There is commented out code in place for returning the sun's declination and local hour angle but I am not confident I understand these numbers and so can not test the validity. Gabriel, do you mind explaining exactly which values in SunCalculations you want access to?

With these two libraries in place a typical sketch becomes extremely simple.
Code: [Select]
// Must include all libraries used inside any libraries (due to bug in Arduino 1.0.1)
# include <Wire.h>
...

// note: compass must be on I2C = 20 (SDA) and 21 (SCL) on Arduino Mega 2560
// note: gps must be on Serial2 = 17 (RX) and 16 (TX) on Arduino Mega 2560
#include <Spacetime.h> // uses compass and gps to determine machine location, orientation and the current time
//#include <OysterMotors.h>
#include <SunCalculations.h> // uses spacetime to determine sun's altitude, apparent altitude and azimuth


Spacetime mySpacetime; // computes and stores the current true heading, latitude, longitude, year, month, day, hour, minute, second
SunCalculations mySun = SunCalculations(mySpacetime); // give SunCalculations our spacetime (it will store a pointer)

void setup() {
  Serial.begin(9600);
  if(mySun.update()) // calling update on mySun automatically calls update on its spacetime point mySpacetime
  {   
    mySpacetime.printSpacetime(); // print result of updated spacetime
    Serial.print("Sun's Altitude: "); Serial.println(mySun.getSunsAltitude());
    Serial.print("Sun's Apparent Altitude: "); Serial.println(mySun.getSunsApparentAltitude()); // Gabriel's new function to correct for atmospheric effects
    Serial.print("Sun's Azimuth: "); Serial.println(mySun.getSunsAzimuth());
   
  } else {
      Serial.println("Update failed - no gps lock");
  }
}

This would output all details known about our where we are and where we are facing and the sun's altitude, apparent altitude and azimuth. The GPS will try for 10 minutes to obtain a lock after which it will cause mySun.update() to return false, if this happens the machine could be moved home and then we could try again to obtain a GPS lock.

Simple!

Probably the most major challenge in getting this all working was the severely restricted memory on the Arduino and I think there is a very important lesson to be learnt from this. Pass BigNumbers by const reference not by value! When you pass a BigNumber by value a copy must be made this eats memory and slows things down.
Pass by value:
Code: [Select]
BigNumber myFunction(){
    BigNumber a = "5";
    BigNumber b = "10";
    return addBigNumbers(a,b);
}

// a and b are copied here
BigNumber addBigNumbers(BigNumber a, BigNumber b){
    return (a+b);
}
Pass by const reference:
Code: [Select]
BigNumber myFunction(){
    BigNumber a = "5";
    BigNumber b = "10";
    return addBigNumbers(a,b);
}

// constant references to a and b (actually we just pass their addresses), no copy is made
BigNumber addBigNumbers(const BigNumber &a, const BigNumber &b){
    return (a+b);
}

This hugely reduces the memory used in functions like findSunsAltAndAzOne which call function after function and really rack up the copies in memory. I have updated BigNumberMath to use const references, I will post it in the coming days but an early version is attached in the libraries folder of this post.

I also found that my Arduino was crashing (memory issues?) when using bigNumberToFloat I am guessing this is due to the large number of casts. I rewrote it and now it should be a bit faster and less memory hungry. Does anybody have any objections to the new version? As a bonus the new version also rounds correctly.
Old Version:
Code: [Select]
float bigNumberToFloat(BigNumber number){
  char buf1[15];
  BigNumber num1,num5;
  long num3, num4;
  num3 = (long)(number);
  num5 = dtostrf(num3,5,5,buf1);
  num1= (number - num5)*BigNumber(10000.0);
  num4 = (long)num1;
  return (float)num3+(((float)(num4))/10000.0);
}
New Version:
Code: [Select]
float bigNumberToFloat(const BigNumber &number){
  //Serial.print("bignumber "); printBignum(number);
  char * s = number.toString();
  float fnumber = atof(s);
  free (s);
  //Serial.print("fnumber "); Serial.println(fnumber);
  return fnumber;
}

In summary. Things are going well and I think the Arduino has enough memory to do what I want it to. I have modified SunCalculations and BigNumberMath to improve memory usage and speed and I have written the two new libraries in a fairly memory efficient manner. There is quite a lot of fancy pointer usage for the purposes of keeping the number of copies in memory very low for all variables. However, from a user perspective a sketch to control a machine looks considerably simpler. It is a matter of declaring a few default objects and writing what you want them to do in what order, rather than worrying about making a gps update or correcting the declination of a compass etc, anything that can be made transparent has been (I think).

I think a very, very similar spacetime class could be written for a non-gps & compass machine and the SunCalculations library could be used without modification.

No motor code has been tested as of yet (machine is apart again).

Let me know any thoughts! All comments welcome.

Code: [Select]
// TO DO
// implement useNorthAsZero
// implement check if in southern hemisphere and correct angles
// implement getSunriseUTC() & getSunsetUTC() see: http://souptonuts.sourceforge.net/code/sunrise.c.html
// OysterMotors library - horrible nightmare regarding use of interrupts in libraries (workaround?)


Gabriel

  • Administrator
  • Hero Member
  • *****
  • Posts: 654
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #20 on: December 06, 2012, 03:05:24 PM »
Hi Bob,

Wow you've been busy!

Aside from the obvious sun's altitude and azimuth values, I think it might be useful to have access to the sun's declination (delta) and hour angle (h) values. I'm not sure if I'll ever get around to trying it, but I think that it would be possible for someone to control a single axis tracker with minimal modification to the Sun Tracking / Heliostat Program using these values. I'm not in any rush to start working / testing this right now though, but it would probably be easier to add access to those values now so that everyone doesn't have to worry about updating the library later down the road.


The new bigNumberToFloat function is cool with me. I'm amazed that you are still finding ways to speed up the program. I can run the MatLab test again sometime if you want.

Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #21 on: December 06, 2012, 04:48:54 PM »
Would be very, very happy for you to test out the new library using the debug_ function of the Spacetime object. I can write a matlab test program to do this for you when I am reasonably happy with the set up.

Can I tempt you to buy a GPS and LSM303? :D

Glad you are ok with the changes to bigNumberToFloat. Of course this slightly changes the output due to correctly rounding it rather than truncating it like the old function but if anything this should improve things (though maybe not in the comparison to MatLab).

My changes have not been so much related to speed as saving memory (SRAM). I initially just threw everything together and the added baggage of the objects and GPS and compass classes just caused the Arduino to immediately crash. Now things seem to be running very smoothly. I thought about using PROGMEM for the internal variables of BigNumberMath (and maybe even SunCalculations) but this is not easy to implement and once the BigNumber is loaded into memory using the string constructor it would take up as much SRAM anyway. If I really needed more memory I could use the preprocessor to free some up, my idea is: rather than having public constants in BigNumberMath instead let the compiler explicitly insert BigNumber(PI) and PI=3.14..... everywhere I want it inside BigNumber math, this would mean that they only eat memory when you are using a function inside BigNumberMath and not when you declare BigNumberMath. This would slow things down though as it would have to create them each time they are needed. Not a big fan of this if I can avoid it.

At the end of the day waiting for a GPS lock and spending several seconds averaging over the compass values (reduces the random error) takes far longer than the calculation so I can't tell you if my changes speed things up... my guess is "a bit" but the overhead of using objects could more than counteract this. We will see when using the matlab test I guess.

I have already added commented out code to give access to delta and h but since they are BigNumbers and in general we don't want to have BigNumber in memory outside the SunCalculations class I cast them to floats. This might cause a problem for h since it seemed to be a very large number and I am not sure how much significance is required. My suggestion is to leave them commented out for now and think about how to use them before I just add methods for returning more and more internal variables. This is a very small change to the library and would not break any code... so don't worry about having to update it... it would literally just add methods getLocalHourAngle() etc. If somebody else using the library didn't use this function then they would see no difference in behaviour after the update so no harm done.

Gabriel

  • Administrator
  • Hero Member
  • *****
  • Posts: 654
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #22 on: December 08, 2012, 01:35:49 PM »
Can I tempt you to buy a GPS and LSM303? :D

One day I will definitely have get one of each. I have lots of other things that I want to do first though. Mostly just getting everything documented is sucking up all of my free time. The official documentation for the Sun Tracking / Heliostat Program and Electronics is far behind the current developments, which I'm sure is confusing everybody. I'm chipping away at it though.

Incidentally, the large hour angle value is to be expected. Basically it just has to be brought down to an angle value between -180 and 180 by adding a k*2*pi value.