Read Servo Position based on light level?

Hi there :slight_smile: I am fiddling with my second light follower robot on my 2WD chassis
the first one was the classic “3 photo resistors” model.
Now iI have fitted a servo onto the chassis, and have mounted a single photo resistor onto the servo.

https://fbcdn-sphotos-e-a.akamaihd.net/hphotos-ak-ash3/178416_637341408647_239375050_o.jpg

The servo scans from 40 degrees, to 130 degrees (90 is the centre, both of these values are the extents possible without fouling the photo resistor on the bodywork)

I want the photo resistor to take a reading for each increment of servo movement, compare it to the previous reading, and once the light level starts to drop down again (as in once the photo resistor has scanned past the light, and starts to scan away from the light source), it notes the position of the servo, and logs it as a “direction” to the light source.

currently 130 is left, 90 is straight forward, and 40 is right. I would build “windows” into the factors, as in "if the light is between 80 and 100, straight forward, else steer, depending on value)

here is my voidloop. I think im along the right lines, I know it is incomplete to do what i want, but im not sure what to focus on to do what i need to do. any advice would be top

//Sense Light direction
  int LightLevel = analogRead(PR);   

      if (LightLevel < PrevLightLevel) {
        PrevLightLevel = LightLevel;
      }  
  else if (LightLevel > PrevLightLevel) {
        Direction = HoriPos;
      }  
      
  Serial.print(Direction);
  Serial.print(", ");
  Serial.println(LightLevel);   

  
  { 
  for(HoriPos = 40; HoriPos < 130; HoriPos += 1) 
  {    
    Hori.write(HoriPos);             
    delay(15);                      
  } 
  for(HoriPos = 130; HoriPos>=40; HoriPos-=1)    
  { 
    Hori.write(HoriPos);             
    delay(15);                      




  } 
}
  int LightLevel = analogRead(PR);   

      if (LightLevel < PrevLightLevel)
      {
        PrevLightLevel = LightLevel;
      }  
      else if (LightLevel > PrevLightLevel)
      {
        Direction = HoriPos;
      }

Properly indented code is easier to read.

I’m not sure why you are reading the light level and then waving the servo around, doing nothing. It seems to me like you want to move the servo a little (or all the way to one end), take a reading, move the servo, take a reading, etc., until you have all the readings you want, and then decide on a way to go.

I think this is properly indented now.

I realised already that i needed to move the calcs into the “for” sections. Although whether or not “for” is the best instruction to use in this scenario, i don’t know.
I have got so far, I want it to update once per sweep. I have added a count function, and have put a “print” request within this, so that it should only print once per sweep too.

I am currently getting the prints at the end of each sweep, and it is printing the value of the extremes only. (40, 130, 40, 130 etc…)

(once i have got a simple sweep back and forth going, i will be able to include the vertical axis, and identify a position, before making a movement decision based on the information.)

I think it is the voidloop where i have fallen down, but here is everything:

#include <AFMotor.h>
#include <VarSpeedServo.h> 

AF_DCMotor motorL(3, MOTOR12_1KHZ);  
AF_DCMotor motorR(2, MOTOR12_1KHZ);
VarSpeedServo Hori;
VarSpeedServo Vert;

const int PR = A1; // connect PR to A1
const int RLED = 13; // indicator LED: 13 and 2 are the only properly pins on the motorshield.
const int LLED = 2; // indicator LED

int HoriPos = 90;      // straight forward, 
int VertPos = 90;      // 30 degrees up from horizontal

int LightLevel;
int PrevLightLevel;
int Direction;
byte count =1;

void setup() {

  Serial.begin(9600);  // Serial at 9600 bps

  Hori.attach(9);  // Hori Servo on Pin 9 (Servo2 on the Motorshield)
  Vert.attach(10); // Vert Servo on Pin 10 (Ser1 on the Motorshield)

  constrain(HoriPos, 40, 130); // 90 is center, straightforward, 40 is Left, 130 is full right. Doesnt foul when vert is = 120, would foul if vert is < 120
  constrain(VertPos, 1, 170); // 0 is tilted back approx 30,  170 is max down without fouling on body. 30 is vertical, 120 is horizontal

  motorL.setSpeed(150);      // set the speed of motors: 0 is stop, 255 is full speed:
  motorR.setSpeed(150);

  pinMode (RLED,OUTPUT);
  pinMode (LLED,OUTPUT);

}

void loop() {


   
  for(HoriPos = 40; HoriPos <= 130; HoriPos += 1) 
  {    

    Hori.write(HoriPos);
    PrevLightLevel = LightLevel;
    LightLevel = analogRead(PR);    

    if (LightLevel > PrevLightLevel && count == 1) {
      Direction = HoriPos;
      Serial.println(Direction); 
      count = 0;
    }

    if (LightLevel > PrevLightLevel && count == 0) {
    }

    if (LightLevel < PrevLightLevel) {
    }
    
    if (HoriPos == 130){
      count = 1;
    }
    delay(50);                         


  }


  for(HoriPos = 130; HoriPos >= 40; HoriPos-=1)    
  { 

    Hori.write(HoriPos);

    LightLevel = analogRead(PR);    
    PrevLightLevel = LightLevel;
    if (LightLevel > PrevLightLevel && count == 1) {
      Direction = HoriPos;
      Serial.println(Direction); 
      count = 0;
    }

    if (LightLevel > PrevLightLevel && count == 0) {
    }

    if (LightLevel < PrevLightLevel) {
    }

    if (HoriPos == 40){  
      count = 1;
    }
    delay(50);                         


  }
}

Thanks for looking.

It doesn’t seem that difficult to look at the reference documentation, and read about how a function works. For instance:
http://arduino.cc/en/Reference/Constrain
Specifically, note this part:

Returns

x: if x is between a and b

a: if x is less than a

b: if x is greater than b

Note that the function computes a new value based on the input arguments. It does NOT modify any of them.

  constrain(HoriPos, 40, 130); // 90 is center, straightforward, 40 is Left, 130 is full right. Doesnt foul when vert is = 120, would foul if vert is < 120
  constrain(VertPos, 1, 170); // 0 is tilted back approx 30,  170 is max down without fouling on body. 30 is vertical, 120 is horizontal

If you are going to discard the return value, why bother calling the function?

  pinMode (RLED,OUTPUT);
  pinMode (LLED,OUTPUT);

}

void loop() {





  for(HoriPos = 40; HoriPos <= 130; HoriPos += 1)

If vertical spacing is good, why isn’t horizontal spacing?

    if (LightLevel > PrevLightLevel && count == 1) {
    }

If you aren’t going to do anything, does the conditional matter? If you aren’t sure yet what to do, put a comment to that effect in the body.

If you are going to discard the return value, why bother calling the function?

I don’t recall discarding the information. As i understand it, by placing this in the setup part of the sketch, it applies the restriction to the entire Code. I have put it in here, to prevent my servos from clashing on physical objects and trashing themselves due to a balls up in the loop section. If it doesnt work like this then i have made a mistake. I refer to you the "Newbie" part of my stats.

If you aren't going to do anything, does the conditional matter? If you aren't sure yet what to do, put a comment to that effect in the body.

I don't know, you tell me. It makes the sketch works in a different way to how it works without it, a way that is closer to what I want/expect it to do. So it seems to be a good idea. I specifically want it to do nothing here. Again, I refer to you the "Newbie" part of my stats.

If vertical spacing is good, why isn't horizontal spacing?

maybe because I have been working on this simple silly little code (which appears to be below you) for some time, and things have been chopped and changed more times than I care to count. maybe just because it annoys you. Evidently

OllyR: As i understand it, by placing this in the setup part of the sketch, it applies the restriction to the entire Code.

You have completely and fundamentally misunderstood how 'C' and C++ code works.

The setup() function is called once when the sketch starts. If you put a call to constrain() here, the function is called once. During that call, it calculates a value from the arguments you passed in. That is all it does - it doesn't make anything happen or not happen in future. If you don't do anything with the returned value then the call to constrain had no effect except to burn a few CPU cycles.

If you intend to have a variable stay within some constraints then the code that updates the variable needs to be written to keep it within those constraints. The constrain() function is designed to help do this - each time it is called, it returns a value which is within the constraints specified by its arguments.

If this doesn't make sense then I suggest you Google the difference between an imperative language and a declarative one. 'C' and C++ are imperative languages.

I got assistance and constructive feedback elsewhere.