|
|
View previous topic :: View next topic |
Author |
Message |
quium
Joined: 19 Jan 2007 Posts: 27
|
Solar tracking problem with codes |
Posted: Tue Mar 27, 2007 6:26 pm |
|
|
Hi
I am using LDR,S FOR TRACKING THE SUN, The motor i am using is a bipolar stepper motor, I am using pic to read the values of three ldr.and since i have caliberated my ldr,s The first two i am using for rotating my motor. If the difference between the voltages read from these ldr's is greater than 0.5v. I am giving the signal to rotate the motor by one step(1.8). I have written down the codes but I am not getting the required results. Can some one please check my codes and help me out with any problem with it.
The first two ldrs are on the either sides of a thin sheet as the sun moves one of the ldr comes in shade there by increasing the resistance. The third ldr is used for detecting the night condition. It is always in light . Below are my codes
#include <16f876.h>
#use delay(Clock=4000000)
#fuses XT, NOWDT, NOPROTECT, NOPUT, NOBROWNOUT
float mean_adc(byte channel) // Reads the adc port 30 times and gives the mean value
{
int i,mean_total = 30;
float mean = 0,mean1 = 0;
set_adc_channel(channel);
delay_us(100);
for (i=1; i<=mean_total; i++)
{
mean =mean + read_adc();
delay_us(100);
mean1=(mean/mean_total);
}
return(mean1);
}
void stepper_motor_sequence(count)
{
byte const step_motor_state[4]={0b00001001,0b00001010,0b00000110,0b00000101};// stepper motor bipolar states
int j;
int current_step;
int current_step1;
current_step=count+1;
for (j=count;j<current_step;j++)
{
current_step1 = j%4;
output_b(step_motor_state[current_step1]);
}
}
void stepper_motor_sequence_reverse(count)
{
int k;
byte const step_motor_state[4]={0b00000101,0b00000110,0b00001010,0b00001001};
for (k=count;k<=1;k--)
{
int current_step1_reverse;
current_step1_reverse=k%4;
output_b(step_motor_state[current_step1_reverse]);
delay_ms(250);
}
}
main()
{
int ldr_low=51; // voltage equivalent to 0.5v
float diff;
int count=0;
float ldr_1,ldr_2,ldr;
const byte ldr_1_chanel=0,ldr_2_chanel=2,ldr_chan=1;
set_tris_b(0xf0);
while(true)
{
ldr_1=mean_adc(ldr_1_chanel);
ldr_2=mean_adc(ldr_2_chanel);
ldr=mean_adc(ldr);
diff = ldr_1-ldr_2;// difference of ldr1 and ldr2
if(diff<ldr_low>=153 && diff<=26)// this is to check the night conditon and rotate the motor in reverse direction at the end of day
{
stepper_motor_sequence_reverse(count);
}
}
} |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
quium
Joined: 19 Jan 2007 Posts: 27
|
|
Posted: Tue Mar 27, 2007 7:11 pm |
|
|
Hi
As u said I have updated my profile and posting the codes again
#include <16f876.h>
#use delay(Clock=4000000)
#fuses XT, NOWDT, NOPROTECT, NOPUT, NOBROWNOUT
float mean_adc(byte channel) // Reads the adc port 30 times and gives the mean value
{
int i,mean_total = 30;
float mean = 0,mean1 = 0;
set_adc_channel(channel);
delay_ms(100);
for (i=1; i<=mean_total; i++)
{
mean =mean + read_adc();
delay_us(100);
mean1=(mean/mean_total);
}
return(mean1);
}
void stepper_motor_sequence(count)
{
byte const step_motor_state[4]={0b00001001,0b00001010,0b00000110,0b00000101};// stepper motor bipolar states
int j;
int current_step;
int current_step1;
current_step=count+1;
for (j=count;j<current_step;j++)
{
current_step1 = j%4;
output_b(step_motor_state[current_step1]);
}
}
void stepper_motor_sequence_reverse(count)
{
int k;
byte const step_motor_state[4]={0b00000101,0b00000110,0b00001010,0b00001001};
for (k=count;k<=1;k--)
{
int current_step1_reverse;
current_step1_reverse=k%4;
output_b(step_motor_state[current_step1_reverse]);
delay_ms(250);
}
}
main()
{
int ldr_low=51; // voltage equivalent to 0.5v
float diff;
int count=0;
float ldr_1,ldr_2,ldr;
const byte ldr_1_chanel=0,ldr_2_chanel=2,ldr_chan=1;
set_tris_b(0xf0);
while(true)
{
ldr_1=mean_adc(ldr_1_chanel);
ldr_2=mean_adc(ldr_2_chanel);
ldr=mean_adc(ldr);
diff = ldr_1-ldr_2;// difference of ldr1 and ldr2
if(diff<=ldr_low)
{
count=count+1;
stepper_motor_sequence(count);
delay_ms(250);
output_b(0xf0);
}
else if (ldr>=153 && diff<=26)// this is to check the night conditon and rotate the motor in reverse direction at the end of day
{
stepper_motor_sequence_reverse(count);
}
}
} |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 27, 2007 8:50 pm |
|
|
Quote: | I have written down the codes but I am not getting the required results |
1. What results are you getting ?
2. What results do you want to get ?
Also, your #fuses statement doesn't have NOLVP in it. Are you using
an LVP programmer ? Less than 1% of all people use one. If not, then
add the NOLVP fuse as shown below. This alone, could be the reason
why your program doesn't work properly.
Quote: | #include <16f876.h>
#use delay(Clock=4000000)
#fuses XT, NOWDT, NOPROTECT, NOPUT, NOBROWNOUT, NOLVP |
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Mar 28, 2007 1:51 am |
|
|
When posting code please use the 'code' buttons to preserve the layout of your code.
Code: | void stepper_motor_sequence(count) | Specify the type for the function parameters. It might be true that the CCS compiler defaults to int8 (as in K&R C) but try to use the ANSII C syntax where possible as it is allows for type checking. Code: | void stepper_motor_sequence(int8 count) |
Passing a calculated float value as the channel number??? I'm sure this is not what you intended to do.
With the above mentioned ANSII C syntax for function parameters a good compiler would have warned you here.
Code: | void stepper_motor_sequence(count)
{
byte const step_motor_state[4]={0b00001001,0b00001010,0b00000110,0b00000101};// stepper motor bipolar states
int j;
int current_step;
int current_step1;
current_step=count+1;
for (j=count;j<current_step;j++)
{
current_step1 = j%4;
output_b(step_motor_state[current_step1]);
}
} | Sometimes introducing a new variable can make code easier to read but in your case you are introducing unneeded new variables with confusing names making your code harder to read.
I rewrote your code to show what it is doing: Code: | void stepper_motor_sequence(int8 count)
{
byte const step_motor_state[4]={0b00001001,0b00001010,0b00000110,0b00000101};// stepper motor bipolar states
int current_step;
current_step = count%4;
output_b(step_motor_state[current_step]);
} | I guess this is not what you had in mind... Up to you to fix it.
Code: | for (k=count;k<=1;k--) | change to Code: | for (k=count;k>=1;k--) |
After calling stepper_motor_sequence_reverse() you don't reset count to zero. |
|
|
quium
Joined: 19 Jan 2007 Posts: 27
|
|
Posted: Wed Mar 28, 2007 5:58 am |
|
|
Hi
Thanks I have made alterations as you have said, but I could not get what you meant by
"After calling stepper_motor_sequence_reverse() you don't reset count to zero"
As when the night conditon is detected I have to rotate the motor back to its original positon ie facing towards the east. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Mar 28, 2007 8:36 am |
|
|
quium wrote: | Thanks I have made alterations as you have said, but I could not get what you meant by
"After calling stepper_motor_sequence_reverse() you don't reset count to zero" |
Change Code: | {
stepper_motor_sequence_reverse(count);
} | to Code: | {
stepper_motor_sequence_reverse(count);
count = 0;
} |
|
|
|
quium
Joined: 19 Jan 2007 Posts: 27
|
|
Posted: Wed Mar 28, 2007 9:33 am |
|
|
Thanks, I have changed it.
I will check the codes tomorrow hopefully they should be working.
Thanks |
|
|
Ttelmah Guest
|
|
Posted: Wed Mar 28, 2007 10:01 am |
|
|
Let me make some other comments. You only need one table of stepper 'states'. Is your motor powerful enough to make the movement with no reduction?. Typically, reduction ratios of thouands to one are used on steppers trying to do this sort of job, unless a very high torque motor is used...
Take this:
mean1=(mean/mean_total);
outside the sample loop. At present, you recalculate the average 30 times, and only return with the last value. A lot of wasted work.
Your 'end of day' test is screwy. '<', and '>=', have the same precedence, so evaluate left to right. So diff is compared with ldr_low, and this returns a logical value, which is then compared with 153. You need to use brackets to force the evaluation to be in the required order. Then move 'to' the overnight position (probably a count like '0'), and stay in this position, till the light rises to a suitable level to start moving again.
This is part cut out of some code used in another astronomical application, to move a stepper - you will have to put your own data definitions, and select the port etc., to suit your application. It is cut down to only use an 8bit 'position' value - originally the position was an int32, to handle many hundreds of thousands of steps/rev:
[code]
int8 position; //curent motor position
//Motor drive patterns
const int drivebits[]= { 0x03,0x06,0x0C,0x09 };
//Change to suit your stepper hardware
//Output the required drive pattern to the motor
#define drive(position) output_b(drivebits[position & 3])
//Change to suit required port
void move_to(int8 required) {
if (position<required) {
while (position<required) {
position++'
drive(position);
delay_ms(1);
}
else {
while (position>required) {
position--;
drive(position);
delay_ms(1);
}
}
} |
|
|
quium
Joined: 19 Jan 2007 Posts: 27
|
|
Posted: Wed Mar 28, 2007 10:08 am |
|
|
Quote: | //Output the required drive pattern to the motor
#define drive(position) output_b(drivebits[position & 3])
//Change to suit required port
Can you please explain this a bit in detail |
|
|
|
quium
Joined: 19 Jan 2007 Posts: 27
|
|
Posted: Wed Mar 28, 2007 10:15 am |
|
|
I am having a small solar panel with 1.5kg weight and I am using 1200mNm stepper motor, The panel is mounted on a disc which is rotating on motor shaft. |
|
|
Ttelmah Guest
|
|
Posted: Wed Mar 28, 2007 12:12 pm |
|
|
#define drive(position) output_b(drivebits[position & 3])
Imagine you have 'positions' called 0,1,2,3,4.... etc..
You have stepper code 'patterns' of:
0b00000101,0b00000110,0b00001010,0b00001001
You need to output the first pattern for the first position, the second pattern for the second, third for third, fourth for fourth, then go back to the first for the fifth position. To 'step' the motor from position 5, to position 3, the patterns would be the first, then the fourth, then then third. The operation '&', performs a bitwise '&' on the 'position' value.
For values of:
Code: |
value value & 3
0 0
1 1
2 2
3 3
4 0
5 1
6 2
...
|
This then gives the right number to select the motor drive required for a given position.
It is impossible to know whether the motor will do what is needed on it's own, without knowing the drag of the bearings, how far the mass is from the axis etc. etc.. You should be testing a simple movement on it's own first, without trying to track the light. Only once you have the movement working, start to build the second 'tracking' component.
You should also think about how the system will handle wind for example.
As it stands, to 'hold' the panel, requires current to be permanently supplied to the motor. A worm drive, will remove this need, and instead the sequence could be:
Apply last power pattern,
Wait a moment.
Step to next position.
Turn off power.
Which will waste a lot less power.
Best Wishes |
|
|
quium
Joined: 19 Jan 2007 Posts: 27
|
|
Posted: Wed Mar 28, 2007 12:34 pm |
|
|
Yeah I have got it, But one more thing, If i want to rotate it by one step and then wait for my ldr values to show some difference, In that case between these two intervals the time might be half an hour or more In that case as per my codes do I have to set the output to zero every time i rotate by one step
Many Thanks |
|
|
quium
Joined: 19 Jan 2007 Posts: 27
|
|
Posted: Wed Mar 28, 2007 1:15 pm |
|
|
The dimensions of my solar panel are 416mmx235mm. I am keeping the tilt angle fixed to 33.23 degree. And I am having a base unit that is attached or mounted on to the motor The circular disc which is rotating on the shaft of the motor is having wheels that rotate on the base unit. The radius of the circular disc is 168mm which gives me an angle of 66.23. The centre of mass of the panel comes exactly on the axis of motor rotation. This design is based on the uk geographical location |
|
|
Ttelmah Guest
|
|
Posted: Wed Mar 28, 2007 2:38 pm |
|
|
The only way to find out what will happen, without a _lot_ of maths (how much drag do your wheels involve, will this change with temperature etc. etc.), is to actually try moving the device. A simple test program that moves it, is a good place to start.
You leave the 'count' at the last position, and turn off the actual drive. Then before moving, turn the drive back on, at the same 'count'. However on a direct drive, _beware_ of doing this. The stepper will display residual magnetism, and is pretty sure to move when you do this. It is really only practical on a worm driven system. Remember also that wind is almost certain to give an assymetric load on the system (wind speeds higher up the panel will tend to be higher).
Since th system should only ever need to turn forwards (except for the 'night' triggered reverse, the algorithm need only look for a forward movement, and when it is required, turn on the drive, move the mount forwards, then switch off till a forward movement is requred. I'd really suggest having a detector, at due east, and moving the system back to this overnight, which will correct for any errors in the stepping.
Best Wishes |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|