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

Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Dual-axis tracker using hall sensors and DC motors
« on: August 15, 2012, 02:57:59 AM »
Saw some discussion on the forum regarding using DC motors in place of stepper motors and thought I should mention that I am working on such a project.

I am currently building a solar tracker using DC motors with built in hall sensors. It uses a simple gearing system for azimuth and a worm drive for altitude. The mechanical part of the project I found in an old device designed to track analog satellites so I am repurposing it to track the sun.

I have two working hall sensor read circuits (thanks to the guys on Arduino IRC), dual H-Bridge control (Pololu Dual VNH5019 Motor Driver Shield for Arduino) and both limit switches are in place. I have written code that gives quite precise control of the motors via counting pulses from the hall sensors. It uses PWM to gently ramp up and down the motor speed and can move both motors (one at a time) a given number of pulses in either direction. Pulses are linearly proportional to the angle moved so once calibrated I should have a system that can move a panel quite accurately using hall sensors and DC motors.

I will soon/eventually start work on adapting Gabriel's excellent sun tracker program to tell me which angles I should move to. Once done I can put this code up here along with some video of the unit in action, it might help with anybody else trying to use hall sensors and DC motors.

It may be a bit more complicated than the current program though as I intend to use the BigNumberMath library on an Arduino Mega and since the solar tracker will be mounted on a vehicle (RV/Motor home) it will get its GPS location in real time from a GPS chip (already working) and orientation from a magnetometer (already working - up to a bit of calibration) then plug this into Gabriel's program to get angles.


cheese

  • New Member
  • *
  • Posts: 6
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #1 on: August 15, 2012, 03:31:22 AM »
Share a code. Yours faithfully Sergey.


GeorgeC

  • New Member
  • *
  • Posts: 6
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #2 on: September 02, 2012, 02:06:18 AM »
Hi, can I´see your programm?

Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #3 on: September 04, 2012, 03:29:50 AM »
Hi GeorgeC.

At the moment nothing like "a program" really exists for my machine. When I am finished and happy with the final result I will upload it but please be aware that it will be nothing like as general as Gabriel's code. It will be specifically designed for the machine I am building, the motor driver I am using, the compass and gps I am using so you will not be able to utilise it directly.

I have many small snippets that have been tested and perform specific functions but there are still many issues to solve before I can proceed. Specifically, the machine itself is missing a limit switch on one axis at the moment, I know how to rectify this but haven't had time.

You can see some bits of the code in various places.

 - BigNumberMath library: http://cerebralmeltdown.com/forum/index.php?topic=342.0

 - BigNumberMath library implemented in Gabriel's code (COMPLETELY UNTESTED): http://cerebralmeltdown.com/forum/index.php?topic=325.30

 - Compass & GPS wiring diagrams and test code (Note that these codes are only for testing the devices and will be rewritten for implementing into an actual solar tracker... specifically the GPS will make use of the TinyGPS library): http://www.motorhomefun.co.uk/solar-power/40301-homebrew-solar-tracker-7.html#post614953

 - Further compass test: http://www.motorhomefun.co.uk/solar-power/40301-homebrew-solar-tracker-8.html#post615137

 - Hall sensor wiring diagram and test program: http://www.motorhomefun.co.uk/solar-power/40301-homebrew-solar-tracker-9.html#post618093

 - A video showing the Pololu Motor Driver (controlled by thumb joystick):
Arduino & Pololu Motor Driver Shield


You can read more in general about the project at: http://www.motorhomefun.co.uk/solar-power/40301-homebrew-solar-tracker.html
I post with an older friend under the name "Snowbird".

I also have a code that allows PWM ramping of the motors for smooth movement and stopping at limit switches along with controlling the motors precisely by counting the hall sensor pulses. I can post this up later if there is interest but of course at the moment it is just a tested snippet of code not a solar tracking program!
« Last Edit: September 04, 2012, 11:44:01 AM by Bob101 »

Gabriel

  • Administrator
  • Hero Member
  • *****
  • Posts: 651
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #4 on: September 07, 2012, 04:20:41 AM »
Looking good Bob! It will be very cool to see it up and running when it is finished. It's certainly one of the most sophisticated Arduino projects I've seen.


Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #5 on: September 09, 2012, 11:08:48 AM »
I have just made a little video explaining the mechanical set-up and an overview of the electronics involved in using DC motors with built-in hall sensors to track the sun. The machine I show is the "Oyster" unit which was salvaged, it is a beautiful creation and unfortunately I can not claim any credit for it! I explain how it is built as this might inspire somebody with more mechanical experience to design something awesome! Or, maybe it will just help you guys understand what I am trying to do.

At the moment the project is still very much in the design phase. Here's a short list of the things I still need to address:
- Attach all limit switches
- Build the motor read circut on perfboard (AGAIN... actually I can alter the first version)
- Build a small circuit for neatly attaching the limit switches to the Arduino (pull up resistors etc)
- Alter the Pololu motor driver library to drive the motors in the ultrasonic range when using the Arduino Mega (this has already been done by a 3rd party on the Pololu forums)
- Program the GPS to output $GPRMC only so that TinyGPS always gets the correct date and time and attach to the Arduino
- Attach and calibrate the compass
- Calculate the angle moved with each hall pulse and write code to correctly convert from angle to hall pulses and avoid moving the machine beyond its limits (this also includes a correction to the vertical angle for each degree horizontal angle moved as the vertical position is controlled via a worm drive)
- Integrate the GPS/Compass/Motor control with Gabriel's solar angle calculations
- Fully assemble the machine and mount the solar panel
- TEST LIKE CRAZY

Video:


Code:
This is the code used in the video. It is not even close to being complete. I just post it here as it may help somebody who is coding something similar. It will absolutely not work if you just upload it to your Arduino!
Code: [Select]
volatile boolean limit1;
volatile boolean limit2;

#include "DualVNH5019MotorShield.h"

#define M1INA 4 // Remapped
#define M1INB 5 // Remapped
#define M1EN 6
#define M1CS A0
#define M2INA 7
#define M2INB 8
#define M2EN 12
#define M2CS A1
//#define M1PWM "9" // Can not be remapped
//#define M2PWM "10" // Can not be remapped

DualVNH5019MotorShield md;

volatile int rotate1;
volatile int rotate2;

volatile boolean m1forward;
volatile boolean m2forward;

void setup()
{
  Serial.begin(115200);
 
  md = DualVNH5019MotorShield(M1INA,M1INB,M1EN,M1CS,M2INA,M2INB,M2EN,M2CS);
  md.init();
 
  attachInterrupt(4, limit1_true, RISING); // Horizontal Limit Switch
  attachInterrupt(5, limit2_true, RISING); // Vertical Limit Switch
 
  // TO DO - Do not assume limits are reached, measure with digitalRead, if not reached then call recalibrate
  limit1 = true;
  limit2 = true;
 
  Serial.println("Motor Control Initialised");
 
  m1forward = true;
  m2forward = true;
  attachInterrupt(0, rotate1_inc, RISING); // Horizontal Motor Hall Sensor
  attachInterrupt(1, rotate2_inc, RISING); // Vertical Motor Hall Sensor
  rotate1 = 0;
  rotate2 = 0;
 
  md.setM1Brake(400);
  md.setM2Brake(400);
 
  // Prototyping Delay
  delay(10000);
 
  // HACK - remove this
  limit1 = false;
  limit2 = false;
 
  moveM1(200);
  delay(1000);
  moveM1(-150);
  delay(1000);
  moveM1(-40);
  delay(1000);
  recalibrate();
 
  delay(5000);
}

void loop()
{
  //moveM1(-100);
  //print_rotate();
  //print_limit();
  //delay(1000);
  //moveM1(100);
  //print_rotate();
  //print_limit();
}

void recalibrate()
{
  // TO DO - Save this offset for debugging
  while(!limit1)
  {
   moveM1(-1);
   delay(1000);
  } 
  Serial.print("Limit1 offset: ");
  Serial.println(rotate1);
  rotate1 = 0;
  Serial.println("Limit1 Recalibrated");
 
  while(!limit2)
  {
    moveM2(-1);
    delay(1000);
  }
  Serial.print("Limit2 offset: ");
  Serial.println(rotate2);
  rotate2 = 0;
  Serial.println("Limit2 Recalibrated");
}

void print_limit()
{
  Serial.print("Limit1: ");
  Serial.println(limit1);
  Serial.print("Limit2: ");
  Serial.println(limit2);
}

void print_rotate()
{
  delay(200);
  Serial.print("Rotate1: ");
  Serial.println(rotate1,DEC);
  Serial.print("Rotate2: ");
  Serial.println(rotate2,DEC);
  delay(200);
}

void moveM1(int pulses) {
  if (pulses== 0) return;
  int target = rotate1 + pulses;
  int gain = 8;
  if (pulses > 0) {
    // RAMP FORWARD
    m1forward = true;
    while (target > rotate1) {
      // target - pulses = initial rotate1
      // rotate1 - (target-pulses) = pulses moved
      // target - rotate1 = pulses remaining
      md.setM1Speed(constrain(max(80,gain*min(rotate1-(target-pulses),target-rotate1)),0,400));
           
      // TO DO - if rotate1 is greater than limit perform emergency actions (obviously this should never run)
     
      delay(2);
    }
    md.setM1Speed(0);
    md.setM1Brake(400);
   
    // TO DO - reset limit1 if digitalRead(19) is low
   
  } else {
    // RAMP BACKWARD
    m1forward = false;
    while (target < rotate1) {
      // target - pulses = initial rotate 1
      // (target-pulses) - rotate1 = pulses moved (positive)
      // rotate1 - target = pulses remaining (positive)
      md.setM1Speed(constrain(min(-80,-1*gain*min(target-pulses-rotate1,rotate1-target)),-400,0));     
      // check limits not reached
      if (digitalRead(19) == HIGH || limit1)
      {
        md.setM1Speed(0);
        md.setM1Brake(400);
        limit1 = true;
        break;
      }
      delay(1);
    }
    md.setM1Speed(0);
    md.setM1Brake(400);
  }
}

void moveM2(int pulses) {
  if (pulses== 0) return;
  int target = rotate2 + pulses;
  int gain = 8;
  if (pulses > 0) {
    // RAMP FORWARD
    m2forward = true;
    while (target > rotate2) {
      // target - pulses = initial rotate2
      // rotate2 - (target-pulses) = pulses moved
      // target - rotate2 = pulses remaining
      md.setM2Speed(constrain(max(80,gain*min(rotate2-(target-pulses),target-rotate2)),0,400));
     
      // TO DO - if rotate2 is greater than other limit perform emergency actions (obviously this should never run)
     
      delay(2);
    }
    md.setM2Speed(0);
    md.setM2Brake(400);
   
    // TO DO - reset limit2 if digitalRead(18) is low
   
  } else {
    // RAMP BACKWARD
    m2forward = false;
    while (target < rotate2) {
      // target - pulses = initial rotate2
      // (target-pulses) - rotate2 = pulses moved (positive)
      // rotate2 - target = pulses remaining (positive)
      md.setM2Speed(constrain(min(-80,-1*gain*min(target-pulses-rotate2,rotate2-target)),-400,0));
      // check limits not reached
      if (digitalRead(18) == HIGH || limit2)
      {
        md.setM2Speed(0);
        md.setM2Brake(400);
        limit2 = true;
        break;
      }
      delay(1);
    }
    md.setM2Speed(0);
    md.setM2Brake(400);
  }
}

// Interrupt Functions
void limit1_true()
{
  limit1 = true;
}

void limit2_true()
{
  limit2 = true;
}

void rotate1_inc()
{
  if(m1forward) {
    rotate1++;
  } else {
    rotate1--;
  }
}
 
void rotate2_inc()
{
  if(m2forward) {
    rotate2++;
  } else {
    rotate2--;
  }
}

Notice that I attach an interrupt to count the hall sensors pulses:
Code: [Select]
  attachInterrupt(0, rotate1_inc, RISING); // Horizontal Motor Hall Sensor
  attachInterrupt(1, rotate2_inc, RISING); // Vertical Motor Hall Sensor
Code: [Select]
void rotate1_inc()
{
  if(m1forward) {
    rotate1++;
  } else {
    rotate1--;
  }
}
 
void rotate2_inc()
{
  if(m2forward) {
    rotate2++;
  } else {
    rotate2--;
  }
}

Another interesting line is the code that actually moves the motors:
Code: [Select]
    while (target > rotate1) {
      // target - pulses = initial rotate1
      // rotate1 - (target-pulses) = pulses moved
      // target - rotate1 = pulses remaining
      md.setM1Speed(constrain(max(80,gain*min(rotate1-(target-pulses),target-rotate1)),0,400));     
      delay(2);
    }

The slightly complicated "constrain(max(....))" calculates the speed that the motor should move so that it smoothly ramps up from 80 to its maximum speed of 400 and then smoothly ramps down to 80 before stopping. This allows more precise movement of the motor as when the correct number of hall pulses is reached the motor is moving very slowly and can immediately be stopped without moving further pulses. You can see this ramping movement in the video when the machine initially moves 200 pulses.

I know this is not of great help for you guys but hopefully it gives you some idea of how I am approaching this and maybe that will help you.

Let me know your thoughts. I will post some more as I complete more of the project. It's very fun to be doing this.

Best of luck!

Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #6 on: October 02, 2012, 03:57:14 PM »
Using Gabriel's solar tracking algorithm and my own movement code I have just ran a small test.

An Arduino Mega 2560 R3 is used to control a solar tracker made from two DC motors with integrated hall sensors.

In a 5 minute period the machine demonstrates tracking the sun over 11 hours (from sunrise to sunset).

A solar panel will be mounted on the back of the arm where "OYSTER" is written and will be used to charge a battery bank.

See it in action:
Arduino Solar Tracker (Alpha 1)

Gabriel

  • Administrator
  • Hero Member
  • *****
  • Posts: 651
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #7 on: October 02, 2012, 05:20:15 PM »
Ha ha,  that's awesome! It looks like you have it pretty well figured out. It's going to be epic once you have it mounted on your RV with the panels on it.

Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #8 on: October 05, 2012, 03:08:45 PM »
Here is the code used in the video (attached).

At this stage the code is just telling the machine to simulate a single day at a single location, the GPS and compass code are not yet integrated. Please note that if you are building your own machine you should not just upload this code and expect it to work, this code is very specifically designed for our unit, but do feel free to modify or borrow our code for your own projects.

This code of course uses the excellent arbitrary accuracy Arduino Mega code written by Gabriel.

To use our code you will also need a few libraries:
- Pololu motor driver library (written by Pololu): https://github.com/pololu/Dual-VNH5019-Motor-Shield
- Arbitrary precision (BigNumber) library (written by Nick Gammon): http://arduino.cc/forum/index.php/topic,85692.0.html
- The BigNumberMath library: http://cerebralmeltdown.com/forum/index.php?topic=342.0

Just drop each of these in the /libraries/ folder in your Arduino IDE.

Hope you find this useful. Please let us know what you're upto with our code... it'd be great to see it used in another project.

Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #9 on: November 18, 2012, 09:17:15 AM »
(Note: This post is a cross post of that on motorhomefun but I thought some of you might be interested)

Well we finally got round to mounting the panel on our Oyster arm and we're pretty pleased with the results.

First we added some aluminium cross beams to the back of the solar panel spaced so that arm of the Oyster would fit comfortably between them.



We doubled up on the locknuts here.



As you can see the arm fits nicely between these cross beams with the top wings resting on the beams and the two lugs near the bottom supporting the arm. The very bottom of the arm also sits nicely onto the edge of the solar panel.



We added aluminium straps across the arm and bolted them until they bowed, firmly holding the arm in place. With just one of these straps in place we could easily lift the panel up by the arm without it moving an inch.





We mounted the whole lot back on the Oyster making sure that the panel was level when the arm was in the home position. This means that when the unit is turned off it should perform no worse than a panel mounted on the roof. The clearance between the arm/staps/beams and the fibre glass Oyster base when the solar panel is levelled is pretty decent, we're not anticipating any problems here but of course we'll have to carefully watch the full range of motion to be sure.



The final product actually looks a bit like a solar tracker! We used a level to check that in the "home" position the panel is pretty level.





There is some play in the panel and arm but the Oyster seems quite comfortable supporting the weight. The whole arrangement does not feel considerably heavier than the original satellite dish and LMB. The Oyster is designed to battle pretty high winds without too much trouble and our guess is that it will perform ok with the panel on it.

Unfortunately, our little control circuit is not in one piece at the moment as we had to dismantle it for testing the compass and GPS code properly. Hopefully in the next few days I can put this back together, tweak the PWM duty cycle to ensure we've got enough umpf to lift the panel comfortably and test out our tracker! I'm interested to see how it performs with the full weight on it, let's hope that gearing saves us.
« Last Edit: November 18, 2012, 01:27:06 PM by Bob101 »

Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #10 on: November 19, 2012, 05:25:43 PM »
(Note: This post is a cross post of that on motorhomefun but I thought some of you might be interested)

I rebuilt the control circuit and we decided to test the unit out with the panels mounted. It is a little top heavy so at first since it is not secured down it nearly threw itself across the room, fortunately, Dave managed to grab the thing before it fell and we can report no damage  ;D. He has quick wits for an old man!

Here's a video of it in action, it is running the same program as the last video we showed but we had to up the vertical motor power to just over 50% (rather than just over 25% as in the previous video). It returns home just a little bit hot but we think the behaviour is ok  ;).

Let us know your thoughts... time for me to get some sleep...

Arduino Solar Tracker (Alpha 2)

Gabriel

  • Administrator
  • Hero Member
  • *****
  • Posts: 651
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #11 on: November 19, 2012, 06:52:38 PM »
Awesome! It looks like you have it pretty well figured out. It's going to be really cool to see it out in the sun! I'm sure that it is going to be quite the conversation starter once you get it out on the road.

Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #12 on: November 21, 2012, 03:27:34 PM »
Edging towards the finish line now...

I just wrote some more code combining up the GPS/COMPASS/DECLINATION/SUN CALCULATION/MOTOR MOVE code with all the latest libraries. I've still not quite caught up to the latest version of the Mega program, specifically, I need to think about how this machine will behave when below the equator and at night.

I am also considering defining a new class that can store my location, time and true orientation (relative to true north) in the current frame (I could call the class "spacetime"). This might help keeping my code a bit cleaner as I should never need to alter these variables, they are set automatically by the GPS and compass.

None of this is tested yet but I'm uploading it for safe keeping and because it may be of interest to anybody else trying to combine these things up.


Bob101

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #13 on: November 22, 2012, 05:23:22 PM »
- Fixed a bug in the compass routine where get_true_heading() could return values not in the range [0,360).
- Added compass heading averaging to reduce the effect of noise on the magnetometer.
- Added lock_time_limit to limit the amount of time spent trying to obtain a gps lock before giving up and returning home (default 10 minutes = 600000 milliseconds)
- Changed type of functions relating to gps so they can report success or failure
- Tidied solar tracking variables (removed default values)

Still untested.

Paul L

  • Jr. Member
  • **
  • Posts: 99
    • View Profile
Re: Dual-axis tracker using hall sensors and DC motors
« Reply #14 on: November 23, 2012, 08:03:59 PM »
Hey Bob,

   Enjoying seeing the progress - nice work (is this what jealously tastes like???)! Thanks for keeping us updated on the project,

Paul