Controlling servo's with LDR

Hello I am kind of new to all this so, if I behave like a noob, I am sorry.

I am working on a project for my studies, in which we are trying to make a snake like lamp that moves, when people are standing close to it.

We made a working snake, on which you pull wires to move it in a certain direction.

So to achieve this pulling we use 2 servos 1 for each axis (which would pull 2 wires, so in rest the servo would be at 90 degrees and when a person is close to one side the servo will go that way by going to 0 or 180 depending on which side the person is on) as sensors, we use LDRs one on each side of the snake, so that if a person is standing in front of it the light will be blocked en the snake will "know" to go in that direction.

I am first trying to get the control of 1 servo working with one LDR, but I am having some problems. (BTW using my hand to block the LDR atm, but will of course change the value's accordingly once I get it working)

When I map the LDR value's to 0-180 and then write them to the servo, it works, but it is more advanced then what I need + it is quite sensitive so the servo will keep moving between small degrees even though the person (hand) is standing still and it is also quite hard to let it reach the 180 and 0 degrees (but of course I can make this easier by lowering the range of the mapped value's)
My code for this:

#include <Servo.h>
 
Servo myservo;

int ldr = A0; //input pin for sensor
int val;         //variable for sensor value's
int pos = 90;  //rest position
 
void setup()
{
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  Serial.begin(9600);
  pinMode(ldr, INPUT);
  myservo.write(pos); //write rest position
}
 
void loop()
{
 Serial.println(analogRead(ldr));   // Print the value from the sensor  
 val = analogRead(ldr);            // Read sensor value
 val= map(val, 300, 700 , 0 , 180);    //map sensor value to value's of servo
 myservo.write(val);                 //move servo to position given by the amount of light
 delay(100);                          //wait for restart
}

So for a less advanced and better working system (in our case at least), I tried to use if/else statements, to compare the sensor value's to a threshold(=sensor value's when light is blocked by person/hand) and then write 180 or 0 degrees to the servos, but I can't seem to get it working. For now I only hooked up 1 LDR and want it to go to 180 for when the LDR is blocked and to 0 when it isn't, so that I could see if it would work.
My code for this:

#include <Servo.h>
 
Servo myservo;

int ldr = A0; //input pin for sensor
int val;         //variable for sensor value's
int thresh = 600;      //threshold LDR
int pos = 0;  //rest position
 
void setup()
{
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  Serial.begin(9600);
  pinMode(ldr, INPUT);
  myservo.write(pos); //write rest position
}
 
void loop()
{
 Serial.println(analogRead(ldr));     // Print the value from the sensor  
 val = analogRead(ldr);              // Read sensor vlue

 if (val < thresh) {                //compare threshold to sensor value
 myservo.write(180);                //move servo to position given by the amount of light 
 delay(300);
 }
 
 else if (val > thresh) {          //compare threshold to sensor value
 myservo.write(0);                 //move servo to position given by the amount of light 
 delay(300);
 }
}

With this code the servo only resets to the the 90degrees rest position and after that, it doesn't move at all, when I put my hand in front of the LDR or not, while if I open the serial monitor, it clearly show value's below and above the threshold, so I don't know what the problem is.
Does anyone know what's wrong with the code, or has any suggestions for a better way to achieve this.
(I know LDRs aren't the perfect solution for this kind of thing, but we need to keep the costs low and it only has to show our concept, so it will be sufficient)

Thanks in advance!

Forgot to post specific hardware I am using:

  • Arduino Uno R3
  • 2 Blue Bird BMS-620MG servo's
  • Separate power supply for the servo (6V and 1.5A)
  • LDRs (with 10K resistors)
 Serial.println(analogRead(ldr));     // Print the value from the sensor  
 val = analogRead(ldr);              // Read sensor vlue

would be better written

 val = analogRead(ldr);
  Serial.println(val);
 pinMode(ldr, INPUT);

is unnecessary.

if (val < thresh) {                //compare threshold to sensor value
 myservo.write(180);                //move servo to position given by the amount of light 
 delay(300);
 }
 
 else if (val > thresh) {

It's unlikely, but what if they're equal?

I have a few LDRs that I plan to use to detect model trains. Their resistance varies widely depending on the ambient light level and I doubt if the value detected by the ADC is directly usable. What I plan to do (and have already tested successfully) is to detect the ambient light level from time to time and then consider an LDR to have been covered (in my case by a train) when the level varies by a pre-programmed amount from the background level. In your case it might be useful to have an extra LDR that is not affected by people to give a standard against which to measure the others.

I presume you have your LDRs wired as a voltage divider to provide the data for the ADC to work with. The other thing I have done (on a spreadsheet) is to try different sizes of resistor in the voltage divider to ensure that the variations in light cause a sufficient difference in voltage at the ADC at different ambient light levels. I haven't come to a firm conclusion yet, but the answer will depend on the specific LDR you are using.

...R

Thank you both.

AWOL
I changed the things you suggested :wink: as for the what if they are equal question yeah I know, could just change one of them into => or <=, but that of course doesn't solve the servos not moving at all.

Robin2
Good advise will see if I can arrange that once I get this movement working like I want, but I don't mind changing the value's manually sometimes, cause I just need to show how the concept would work once (at least for now).

svenolio:
as for the what if they are equal question yeah I know, could just change one of them into => or <=,

Decide how many distinct conditions you want to handle. If you want to treat the == case differently to the other two, you need to handle it separately. If you actually only want to handle two possible conditions (i.e. do one action or the other) then you don't need the second 'if' at all, just code it as:

if (val < thresh)
{
  // under threshold
  myservo.write(180);
  delay(300);
}
else
{ 
  // over threshold
  ... etc

If you don't allow for changing ambient light you may find your "once" demo doesn't work at the critical moment. Be conscious that our eyes are very deceptive about ambient light levels - two situations that seem equally bright may be very different as viewed by the LDR.

svenolio:
I just need to show how the concept would work once (at least for now).

Thanks again guys! :slight_smile: Will keep it in mind while continuing to program.
Finally find out why the second code didn't work and the first one did seem to work, apparently the servo only writes degrees between 30 and 150, found that out while trying out the sweep example, I noticed that at the end of each sweep, it seemed that it took longer for the servo to go back the other way, then it took him to take each individual step (it kept on counting and writing, but the servo couldn't go further apperently). So problem 'solved' and will start working on the rest.