Forum Update - Announcement about May 10th, 2018 update and your password.

[UPDATE] Solar tracking with Photosensors

Nomadic0Nomadic0 Posts: 19
edited February 21 in Propeller 1 Vote Up0Vote Down
Good evening!

In the execution of this program, the servos execute well when I block light from 1 section (2 photo-sensors) (4 sensors in total). However, when I block one of those same sensors as well as one adjacent to it, BOTH servos move, and then continue to move together no matter which sections I block afterward.

It's executing well (according to the terminal), but it's like the servos are storing energy(?) for the next execution of the while loop.

I am using RCTIME to measure the 'darkness' in these 4 sensors.

Any help would be appreciated. Apologies for the novice code.

Nomad
#include "simpletools.h"                      // Include simple tools
#include "servo.h"    

int main()                                    // main function
{
    
   int rf,lf,rb,lb,tilt,spin,frontsum,backsum,leftsum,rightsum=0;
  
  while(1)                                    // Endless loop
  {
    
    
    
    high(4);                                  // Set P4 high
    pause(1);                                 // Wait for circuit to charge
    rf = rc_time(4, 1);                    // Measure decay time on P4
    print("rf = %d\n", rf);                     // Display decay time
    //pause(100); 
    
           
    high(5);                                  // Set P5 high
    pause(1);                                 // Wait for circuit to charge
    lf = rc_time(5, 1);                    // Measure decay time on P5
    print("lf = %d\n", lf);                     // Display decay time
    //pause(100);  
    
    high(8);                                  // Set P8 high
    pause(1);                                 // Wait for circuit to charge
    rb = rc_time(8, 1);                    // Measure decay time on P8
    print("rb = %d\n", rb);                     // Display decay time
    //pause(100); 
    
           
    high(9);                                  // Set P9 high
    pause(1);                                 // Wait for circuit to charge
    lb = rc_time(9, 1);                    // Measure decay time on P9
    print("lb = %d\n", lb);                     // Display decay time
    //pause(100);  
    
    frontsum=lf+rf;
 
  printf("FRONTSUM %d\n", frontsum);
  
   backsum=rb+lb;
    
  printf("BACKSUM %d\n", backsum);
  
   leftsum=lf+lb;
  printf("LEFTSUM %d\n", leftsum);
  
  rightsum=rf+rb;
  printf("RIGHTSUM %d\n", rightsum);
 
  spin=leftsum-rightsum;
  printf("SPIN %d\n", spin);
 
 tilt=frontsum-backsum; 
  printf("TILT %d\n", tilt);
  
  //I then compare each labeled section to determine where the servos should move the panels (X and Y axis)
  
  
if(tilt<-30000)
  {           
                       
   servo_angle(25, 900);                       // P25 servo to 90 degrees
 pause(20);                              
  servo_stop();    
  printf("Clockwise tilt\n");                                      
  }
    else if (tilt>30000)
    {               
                    
   servo_angle(25, 1800);                       // P25 servo to 180 degrees
    pause(20);                              
    servo_stop();
     printf("CounterClockwise tilt\n");                                           
      }
  
 
  if(spin<-30000)
  {       
                         
   servo_angle(26, 900);                       // P26 servo to 90 degrees
  pause(20);                              
  servo_stop(); 
   printf("Clockwise\n");                                          
  
  }  else if (spin>30000)
    {                
          
   servo_angle(26, 1800);                       // P26 servo to 180 degrees
    pause(20);                              
    servo_stop(); 
   
     printf("CounterClockwise\n");                                          
      }
 
  pause(5000);     //Long pause to examine the results
      
}

Comments

  • 23 Comments sorted by Date Added Votes
  • For two servos you will get a much simpler reading if you use four photo-sensors instead of two.
    Make the right two read as positive for the LeftRight servo and the left two negative, then sum for LR motion.
    Make the top two read as positive for the UpDown axis and the bottom two negative, then sum for UD motion.

    There was a user who did something like this with visible lasers recently if anyone can link the post, please.
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • For two servos you will get a much simpler reading if you use four photo-sensors instead of two.
    Make the right two read as positive for the LeftRight servo and the left two negative, then sum for LR motion.
    Make the top two read as positive for the UpDown axis and the bottom two negative, then sum for UD motion.

    There was a user who did something like this with visible lasers recently if anyone can link the post, please.

    That did need clarification! I am using 4 (1 on each corner)

    Thank you
  • More meaningful variable names might help with understanding the code.

    We have to assume that P4, P5, P8, & P9 are the photo-sensors but which is which?

    Assumptions I'm making:

    P4 Front Left
    P5 Rear Left
    P8 Front Right
    P9 Rear Right

    This allows variable name transformations of:
    s becomes fl
    t becomes rl
    u becomes fr
    v becomes rr

    a becomes leftsum
    b becomes rightsum
    c becomes frontsum
    d becomes rearsum

    x becomes leftright
    y becomes frontrear

    It also helps to identify what range of values are expected, and in your test case what values you are measuring.

    That alone may help you understand what is happening.
  • AJL wrote: »
    More meaningful variable names might help with understanding the code.

    We have to assume that P4, P5, P8, & P9 are the photo-sensors but which is which?

    Assumptions I'm making:

    P4 Front Left
    P5 Rear Left
    P8 Front Right
    P9 Rear Right

    This allows variable name transformations of:
    s becomes fl
    t becomes rl
    u becomes fr
    v becomes rr

    a becomes leftsum
    b becomes rightsum
    c becomes frontsum
    d becomes rearsum

    x becomes leftright
    y becomes frontrear

    It also helps to identify what range of values are expected, and in your test case what values you are measuring.

    That alone may help you understand what is happening.

    I've updated this, and the results are clearer; that the program runs correctly, but the servos are still misbehaving
  • Nomadic0 wrote: »

    I've updated this, and the results are clearer; that the program runs correctly, but the servos are still misbehaving

    Can you post some pictures so others can help examine the configuration? :smile:
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • I updated your code to use a cog for the sensors.

    I noticed that you are doing a servo_stop which kills the servos. so you want them to go lifeless.

    If the sensors are on the board that the servo is moving isn't going to change the readings and cause the servos to continue to move?

    I would shut the servos off and then record reading as you move the sensor board around to get a list of values returned by the sensors. The rc_time function has a time limit that may be expiring.

    Anyway here is the updated code:
    #include "simpletools.h" // Include simple tools
    #include "servo.h"
    
    void doSensors(void *par);
    
    
    int volatile rf, lf, rb, lb;
    int *cog;
    
    
    int main() // main function
    {
    
      *cog = cognew(&doSensors, 40);
      
      while(1) // Endless loop
      {
    
        int tilt,spin,frontsum,backsum,leftsum,rightsum=0;
    
    
        print("rf = %d\n", rf); // Display decay time
    
        print("lf = %d\n", lf); // Display decay time
      
        print("rb = %d\n", rb); // Display decay time
    
        print("lb = %d\n", lb); // Display decay time
      
        frontsum=lf+rf;
        
        printf("FRONTSUM %d\n", frontsum);
        
        backsum=rb+lb;
        
        printf("BACKSUM %d\n", backsum);
        
        leftsum=lf+lb;
        printf("LEFTSUM %d\n", leftsum);
        
        rightsum=rf+rb;
        printf("RIGHTSUM %d\n", rightsum);
        
        spin=leftsum-rightsum;
        printf("SPIN %d\n", spin);
      
        tilt=frontsum-backsum;
        printf("TILT %d\n", tilt);
      
        //I compare each labeled section to determine where the servose should move the panels (X and Y axis)
      
        if(tilt<-30000)
        {
        
          servo_angle(25, 900); // P26 servo to 90 degrees
          pause(20);
          servo_stop();
          printf("Clockwise tilt\n");
        }
        else if (tilt>30000)
        {
        
          servo_angle(25, 1800); // P26 servo to 180 degrees
          pause(20);
          servo_stop();
          printf("CounterClockwise tilt\n");
        }
      
      
        if(spin<-30000)
        {
        
          servo_angle(26, 900); // P26 servo to 90 degrees
          pause(20);
          servo_stop();
          printf("Clockwise\n");
      
        } else if (spin>30000)
        {
      
          servo_angle(26, 1800); // P26 servo to 180 degrees
          pause(20);
          servo_stop();
          printf("CounterClockwise\n");
        }
    
        pause(5000);
    
      }
    }
    
    void doSensors(void *par)
    {
      
      while (1)
      {
        high(4); // Set P4 high
        pause(1); // Wait for circuit to charge
        rf = rc_time(4, 1); // Measure decay time on P4
    
        high(5); // Set P5 high
        pause(1); // Wait for circuit to charge
        lf = rc_time(5, 1); // Measure decay time on P5
    
        high(8); // Set P8 high
        pause(1); // Wait for circuit to charge
        rb = rc_time(8, 1); // Measure decay time on P8
    
        high(9); // Set P9 high
        pause(1); // Wait for circuit to charge
        lb = rc_time(9, 1); // Measure decay time on P9
    
        pause(100);
      }
    }
    
  • iseries wrote: »
    I updated your code to use a cog for the sensors.

    I noticed that you are doing a servo_stop which kills the servos. so you want them to go lifeless.

    If the sensors are on the board that the servo is moving isn't going to change the readings and cause the servos to continue to move?

    I would shut the servos off and then record reading as you move the sensor board around to get a list of values returned by the sensors. The rc_time function has a time limit that may be expiring.

    Anyway here is the updated code:

    I really appreciate your input to help me out! I have the servos just off to the side for now (for testing the sensors with shadows).

    Setup aside, I am not completely sure I understand the cog function.

    The rl,fl,rb,lb in the new code are returned as 0 when I tried to execute it. (I took away the int = 0 also, same thing showed.)
  • One of the best features of the propeller chip is it's multiple processors feature so you can run multiple functions at the same time.

    By placing the input function in a cog it runs all the time no mater what other functions your doing so you can always have fresh values from the sensors. In order to get values from that cog you need to tell the compiler that the variables in that cog are changing outside the normal process by using the "volatile" key word. They also have to be declared outside the main function where I have them so that all of the code has access to those variables.

    Also if you want to read your sensors at an exact time frame such as every 20 milliseconds you can adjust the cog functions to have that timing even though the reset of the program is stopped waiting for input.

    I don't have your sensors or what R/C time function your using so I'm not able to test the code.

    Mike

  • May be that this is just bad form and the compiler will do the right thing, but defining your variables within the while loop seems problematic, to me...
    ...
    while(1) // Endless loop
    {
    
    int rf,lf,rb,lb,tilt,spin,frontsum,backsum,leftsum,rightsum=0;
    ...
    

    It might just be my thinking, as the compiler might optimize and only create the variable space once, but I avoid creating vars other than simple indexes in for-loops, within while/until loops.

    Maybe, this would help:
    ...
    int rf,lf,rb,lb,tilt,spin,frontsum,backsum,leftsum,rightsum;
    
    while(1) // Endless loop
      rightsum=0;
    ...
    {
    
    
    

    dgately
    Livermore, CA (50 miles SE of San Francisco)
  • iseries wrote: »
    One of the best features of the propeller chip is it's multiple processors feature so you can run multiple functions at the same time.

    By placing the input function in a cog it runs all the time no mater what other functions your doing so you can always have fresh values from the sensors. In order to get values from that cog you need to tell the compiler that the variables in that cog are changing outside the normal process by using the "volatile" key word. They also have to be declared outside the main function where I have them so that all of the code has access to those variables.

    Also if you want to read your sensors at an exact time frame such as every 20 milliseconds you can adjust the cog functions to have that timing even though the reset of the program is stopped waiting for input.

    I don't have your sensors or what R/C time function your using so I'm not able to test the code.

    Mike

    Shouldn't what I'm trying to do still be possible with my code? I'm just not seeing why it doesn't clear the values.

    I would code it using the cog function if I understood how to troubleshoot it.

  • Yes, your code should work and you should get updated values as it goes through the loop.

    So what you are saying is that the values don't change each time it goes through the loop.

    I also don't understand your servo code. The servos move from 0 degrees to 180 degrees in tenths.

    So you need to come up with an angle that you want the board at and then tell the servos that is the angle to be at.

    If the sun is directly overhead then all four sensors will be on and the servos should go to 90 degrees.

    You can not use the servo_stop function as this shuts down the servo control code and all the servos will stop working.

    The servo function starts a cog in the background that feeds a signal to the servos that tell them where to be. This process is started automatically once it sees the first servo_angle call. Once you do a servo_stop this background function is stopped and all the servos go dead.

    You need to tell each servo what angle to be at and let them go there. They will stay there until you tell them a new angle.

    Mike
  • iseries wrote: »
    Yes, your code should work and you should get updated values as it goes through the loop.

    So what you are saying is that the values don't change each time it goes through the loop.

    I also don't understand your servo code. The servos move from 0 degrees to 180 degrees in tenths.

    So you need to come up with an angle that you want the board at and then tell the servos that is the angle to be at.

    If the sun is directly overhead then all four sensors will be on and the servos should go to 90 degrees.

    You can not use the servo_stop function as this shuts down the servo control code and all the servos will stop working.

    The servo function starts a cog in the background that feeds a signal to the servos that tell them where to be. This process is started automatically once it sees the first servo_angle call. Once you do a servo_stop this background function is stopped and all the servos go dead.

    You need to tell each servo what angle to be at and let them go there. They will stay there until you tell them a new angle.

    Mike


    Mike, i appreciate it! Right now my servos are moving a rod. One is connected which tilts it. The other servo is under that setup, spinning it.

    As of yet, (coming from PBASIC), I'm not sure how to just give small pulses to the servos. I was using the servo_angle only because that's the only command I've seen to control them.

    That poriton is based off of a Parallax example.

    When the sun is overhead, I'd like the servos to track it (using the sensors on a board) and then stay put unless the sun moves.

    Nomad
  • One characteristic of the servo library is that when the system is started, the position of the servo is unknown. (The 360 feedback servos are different, they are at 0 degrees in whatever position they are in when powered up). When ending the program, the servo should be in a known position or it should b moved manually to an approximate known position before starting the program, otherwise it can move significantly when the program is restarted (if that is of concern).

    Once everything is in a known position, to make small adjustments just keep track of the current position (as an integer in tenths of a degree) and add or subtract a few tenths (or whatever resolution you want), send that to the servo, measure the light and either add or subtract a few more, again measure the light, etc until you reach a max.

    Do this in small increments. If you send large angle changes you have to add delays to allow the servo to reach the commanded position before sending a new command, or the servo motion will not make any sense as it starts executing the next position change before the first is done. (Surprisingly large delays are needed compared with those expected).

    Tom

  • It would help to know what setup you have. Servo models and photo detectors to determine the best way to control your setup.

    C is a little different than PBASIC is so it will take a little to get use to the functions.

    If your using the Parallax standard servos your going to need to track the servo angles as a way to determine where you are.

    At sun rise you might be at 0 and 90 degrees. At noon you might be at 90 and 90 and at sun set 180 and 90. This is assuming that the sun is directly over head. Since the servos move based on the angle fed to them you only need to tell them what angle they should be at and they will take care of the rest.

    If on the other hand you are using motors, then things get a little more interesting in that you need to pulse them so they move in the correct direction and then stop them when they reach the correct angle. Your code will need to figure out how much to pulse them and then stop.

    Mike

  • iseries wrote: »
    It would help to know what setup you have. Servo models and photo detectors to determine the best way to control your setup.

    C is a little different than PBASIC is so it will take a little to get use to the functions.

    If your using the Parallax standard servos your going to need to track the servo angles as a way to determine where you are.

    At sun rise you might be at 0 and 90 degrees. At noon you might be at 90 and 90 and at sun set 180 and 90. This is assuming that the sun is directly over head. Since the servos move based on the angle fed to them you only need to tell them what angle they should be at and they will take care of the rest.

    If on the other hand you are using motors, then things get a little more interesting in that you need to pulse them so they move in the correct direction and then stop them when they reach the correct angle. Your code will need to figure out how much to pulse them and then stop.

    Mike

    This is all becoming clearer. I was using the 90 / 180 degrees as a way to go one direction, then reverse.

    Also, I am using the standard Parallax servos and photosensors (from the Boe-Bot)

    I'll need to define exactly what angle I want (?) by adding/subtracting from a variable, correct?
  • Right, so if the board is flat then you would start with 90 degrees.

    If the Left sensor is off then you might add 10 degrees to move it in that direction until it is on fully and stop.

    As the sun moves the sensor will indicate what direction it moved in and you would add or subtract a few degrees and check your results.

    You could also use a real time clock and just calculate the angle based on what time it is.

    Mike

  • Nomadic0Nomadic0 Posts: 19
    edited February 21 Vote Up0Vote Down
    So if i want these servos to just move the most minimum amount (in either direction), how would I code it? I'm not sure how long I want the pause either.

    Would I still want to use this?

    servo_angle(PIN , VAR);
    pause (??);
    servo_stop():

    not sure how else the motors will stop also

    I understand our approach to add/sub from the angle variable. Just not sure how it'd look

  • You don't want to use servo_stop as this shutdown the servo process.

    The servos move from 0 to 180 degrees in tenths of an increment. Don't know how you have the servo attached to your board but movements of 1 degree is not noticeable. You will have to play with it and see how the board reacts to small movements.

    So if the board is flat and the servo is at say 90 degrees to move it a small amount you would add or subtract a few degrees from your current angle. So you might try 95 or 85 to start and see how it reacts.

    Here is some sample code that will allow you to enter an angle and have the servo move to that angle.
    #include "servo.h"
    
    #include "simpletools.h"
    
    #define ServoX 25
    #define ServoY 26
    
    int Angle;
    
    int main()
    {
      servo_angle(ServoX, 900); // move servo to middle of range
      servo_angle(ServoY, 900);
      
     
      while(1)                              // Main loop
      {
        print("Enter angle: ");             // Prompt user for angle
        scan("%d", &Angle);                 // Get entered angle
        print("\r");                        // New line
        servo_angle(ServoX, Angle*10);      // Move servo to angle in tenths
      }    
    }
    

    Mike
  • Nomadic0Nomadic0 Posts: 19
    edited February 22 Vote Up0Vote Down
    Mike,

    When I run this code, the servos continually move from the beginning of execution. (Even if i change 900 to 0) Although, if I enter the angle '180', one on the servos changes direction.

    I am using the schematic on the left in the attached pic. (Not sure if this is intended for use with the Propeller and 9V battery).

    Thanks
    Nomad
  • Try adding
    pause(500); 
    
    after the
    servo_angle(ServoY, 900);
    

    Depending where the servo was before this it might require a longer pause.

    After
        servo_angle(ServoX, Angle*10); 
    
    add
    pause(100);
    
    again if the servo doesn't stop make the pause longer. If it stops and waits too long before moving make the pause shorter.

    An alternative is to try this (after the includes, defines & global declarations):
    int main()
    {
      servo_angle(ServoX, 900); // move servo to middle of range
      servo_angle(ServoY, 900);
      
    pause(1000);                      // give the servos time to move & stop
     
     for(int i =920; i<=1700; i+=20)     // Main loop from92 deg to 170 deg
      {                          // try different increments of i. 2 deg may be too small
        print("angle = %d\n", i);             
        servo_angle(ServoX, i);      // Move servo to angle in tenths
        pause(100);                      // give it time to move & stop
      }    
    }
    
    
  • Ok, if you have the Boe-Bot robot, the servos for that unit are Parallax continuous rotation servos.

    The servos I was think off are these: Parallax Standard Servo 900-00005. These servo move to a given angle and stop.

    The Boe-Bot servos are continues servos and don't stop, but continue to move based on signal applied. This is going to make your project much harder to code. Also the Boe-Bot uses PBASIC. So how are you coding in C ?

    To work with the continues servos you will need to use the servo_speed function.

    servo_speed(ServoX, 0); //Stay still
    servo_speed(ServoX, -100); //Full speed clockwise
    servo_speed(ServoX, 100); //Full speed clockwise

    since you can only turn the servo on or off you won't know what position your at. You can only move the servo in a direction and hope it moves and then check the results. You will also have to pulse the motor to get them to move just a little and hope it was enough to get the desired movement.

    For example:

    servo_speed(ServoX, 50);
    pause(30);
    servo_speed(ServoX, 0);

    This short pulse will move the servo counter clockwise for 30 milliseconds and then stop.

    If the board is to heavy it will not move very much if at all.

    Mike

  • Nomadic0Nomadic0 Posts: 19
    edited February 22 Vote Up0Vote Down
    Mike

    I think this is what was definitely holding me back here.

    I have used the servo_speed function and it works like I had originally planned (aside from some buzzing(?) sounds when they stop).

    Also, I am using the Prop Education Kit board with the BoeBot servos. (Allowing for C)

    I really appreciate the helping hand.

    Nomad
  • Always willing to help a fellow C coder.

    This servo is 4 - 6 volt only servo and the center maybe off a little requiring the POT on the servo to be turned a little to find the center frequency and stop.

    Don't know how your going to control the servos as the only feed back you have is the light sensors so you will not know if the board is tipped to far.

    Mike
Sign In or Register to comment.