Programing the robot to use the light sensor to find light

From ROBOTC API Guide
Jump to: navigation, search
ArduinoArduino Tutorials and Guided ProjectsLego + Arduino, Mobile Robotics Platform → Programing the robot to use the light sensor to find light

Contents

The robot following light using the alternate setup

Concept

A fun way to use the light sensors with the Lego robot is to write a program which will make it turn towards the direction of strongest light and drive towards it. This means you could even guide it around with a flashlight!

The first thing we need to do is configure robotC for our light sensors. Open up Robot > Motors and sensors setup, choose the Analog 0-5 tab, and then configure anlg0 as leftLight and anlg1 as rightLight. The type for both should be set to Light Sensor.

The configuration Screen

Afterwards, your configuration code should look like this:

#pragma config(CircuitBoardType, typeCktBoardUNO)
#pragma config(PluginCircuitBoard, typeShieldDFRobotMotor)
#pragma config(UART_Usage, UART0, uartSystemCommPort, baudRate200000, IOPins, dgtl1, dgtl0)
#pragma config(Sensor, anlg0,  leftLight,      sensorReflection)
#pragma config(Sensor, anlg1,  rightLight,     sensorReflection)
#pragma config(Motor,  motor_5,         leftServo,     tmotorInternalHBridgeSinglePWM, openLoop, reversed, IOPins, dgtl5, dgtl4)
#pragma config(Motor,  motor_6,         rightServo,    tmotorInternalHBridgeSinglePWM, openLoop, reversed, IOPins, dgtl6, dgtl7)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

The Formula

The inherent problem with anything that senses light is that every room has different lighting. Human eyes are exceptional in their ability to account for this change, but to a robot, a room that seems well lit could be either very dark, or very light. Therefore, something like this:

if (SensorValue[leftLight] > 120) {
  //Do something
}

will NOT work. That is because any given light value could be taken as either light or dark, depending on the room that the robot is in.

What to do?

Don't panic, all is not lost. Thankfully, we can use the magic Zero Justified Normalized Differential Shade calculation (Yes, it's really called that) to determine some relevant data about light levels.

How does it work?

Basically, we cannot find out if, say, the room is 'light' or 'dark'. That's too subjective for the robot to handle (though it can tell if the room has become lighter or darker). What we can do, however, is find the side of the robot where the light is the brightest, and also how much brighter this is than the other side. We can get this value, then, and use it on our drive motors so that we can ultimately make the robot steer towards the light.

The calculation

The Zero Justified Normalized Differential Shade calculation can be written as:

vRight * 100 / (vRight + vLeft) - (100/2).

Where vRight is the value of the right light Sensor and vLeft is the value of the left light sensor.

In order to make the result of this equation have more of an effect on the motor, we multiply the whole thing by 2

(vRight * 100 / (vRight + vLeft) - (100/2)) * 2

This algorithm will give us a percentage (ranging from -100% to +100% of how far the brightest light is relative to the center. For example, if the light is a bit to the left, we will get a value near -20. If the light is far to the right, we will get a value of around +50. We can use this knowledge, then, to make the robot steer towards the light. How? In this situation, a diagram might be helpful:

Steering towards the light

Since the percentage we get from the formula is positive if the light is on the right and negative if the light is towards the left, then we want to add the value to the left servo and subtract the value from the right servo, as a number minus a negative is of course an addition.

We want to perform these operations on a base value - that is, the speed the motors should go when the formula returns zero (when the light is directly ahead). Let's leave that at 100.

Programming

With all that figured out, we get this program:

#pragma config(CircuitBoardType, typeCktBoardUNO)
#pragma config(PluginCircuitBoard, typeShieldDFRobotMotor)
#pragma config(UART_Usage, UART0, uartSystemCommPort, baudRate200000, IOPins, dgtl1, dgtl0)
#pragma config(Sensor, anlg0,  leftLight,      sensorReflection)
#pragma config(Sensor, anlg1,  rightLight,     sensorReflection)
#pragma config(Motor,  motor_5,         leftServo,     tmotorInternalHBridgeSinglePWM, openLoop, reversed, IOPins, dgtl5, dgtl4)
#pragma config(Motor,  motor_6,         rightServo,    tmotorInternalHBridgeSinglePWM, openLoop, reversed, IOPins, dgtl6, dgtl7)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//
 
task main()
{
  while(true)
  {
    //Find the shade differential
    int shadeDiff = ((SensorValue[rightLight] * 100) / (SensorValue[leftLight] + SensorValue[rightLight]) - (100 / 2)) * 2; 
 
    //Use the shade differential to modify the motor speeds
    motor[leftServo] = 100 + shadeDiff;
    motor[rightServo] = 100 - shadeDiff;
 
    //If the loop cycles too quickly, the debugger can return incorrect values. (this is not a bug)
    //adding a small delay solves this problem
    wait1Msec(10);
  }
 
}

Try it out with a flashlight, or better yet, a lamp in a dark area. The robot should steer towards the light. Keep in mind that the sensors do not have a long range, so they will not be able to seek out light sources at too far a distance. They will only be able to detect the difference in light level of their immediate area.

Modification

You may notice that the robot does not react as much as you want it to when there is a significant light difference. To change this, standard practice is to multiply the result by a factor - e.g. 1.2 or 0.5. Since the RobotC Arduino UNO firmware cannot support decimals, we will instead incorporate the factor into the formula, so instead of returning a range of -100 to 100, it will return a range of -80 to 80, say, or -150 to 150. To do this, we will add another variable called 'factor' and replace the instances of '100'.

#pragma config(CircuitBoardType, typeCktBoardUNO)
#pragma config(PluginCircuitBoard, typeShieldDFRobotMotor)
#pragma config(UART_Usage, UART0, uartSystemCommPort, baudRate200000, IOPins, dgtl1, dgtl0)
#pragma config(Sensor, anlg0,  leftLight,      sensorReflection)
#pragma config(Sensor, anlg1,  rightLight,     sensorReflection)
#pragma config(Motor,  motor_5,         leftServo,     tmotorInternalHBridgeSinglePWM, openLoop, reversed, IOPins, dgtl5, dgtl4)
#pragma config(Motor,  motor_6,         rightServo,    tmotorInternalHBridgeSinglePWM, openLoop, reversed, IOPins, dgtl6, dgtl7)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//
 
 
task main()
{
  while(true)
  {
    int factor = 120; //This value worked for us however you might want to change it for your robot/flashlight intensity.
 
    //Find the shade differential
    int shadeDiff = ((SensorValue[rightLight] * factor) / (SensorValue[leftLight] + SensorValue[rightLight]) - (factor / 2)) * 2; 
 
    //Use the shade differential to modify the motor speeds
    motor[leftServo] = 100 + shadeDiff;
    motor[rightServo] = 100 - shadeDiff;
 
 
    //If the loop cycles too quickly, we get calculation errors. Therefore we regulate the speed by waiting a bit.
    wait1Msec(10);
  }
 
}

Potential Problems

  • This program will NOT work under normal lighting. The NXT light sensor almost stops going down in value around 40-42, the value for a decently lit room. Its absolute minimum is 38, when a bright light is sitting inches away from it. This difference is not nearly enough to cause the robot to adjust its motors to turn towards the light dependably. Darker rooms work better, as the difference between the light and the rest of the room is much greater, and thus the robot can more easily identify and follow the light. Also take note that in rooms that have unblocked windows, the robot will naturally tend to steer towards them in the daytime, as they are a significant light source.
  • Due to the omnidirectional nature of the sensor, lights behind the robot register similar values to those in front (note, however, that the robot will still turn towards the light, just more slowly). In the rare instance where you have somehow gotten the light perfectly behind the robot so that it will only go forward, simply move the light a little to one side or the other and the robot will start turning again.
  • The sensor's placement causes lights that are low to the ground not to register very well because the light sensor is pointed upwards.(you can change the placement of the sensors around to see how different setups affect the robot's sensing)
  • Also note that the brighter (and more diffuse) the light source, the better. In a dark room with some light coming through the windows, the robot will tend to go towards them instead of a small flashlight. On the other hand, in the same situation, it would be attracted to a bright incandescent lamp sitting several feet away more than the relatively dim windows.
  • In general, the more light sources in the room, the more confused the robot will be, and the less it'll be able to follow the light source you want it to. This kind of sensor issue can be a serious problem for many robotics programmers at the professional level, because unlike you (who can usually hunt up a nice dark room somewhere for your robot to drive around in if your current one isn't working out) they are stuck having to deal with the environment their robot is supposed to work in.

Modifying the Sensor Placement

Robots never have a single "correct" configuration, both physically and in their coding. There are always multiple ways of doing things, each of which have their own peculiar advantages and drawbacks.

Take the light sensors in this program, for example. What would happen if we flipped them upside down and had them read the ambient light nearer the floor?

The Light sensors flipped upside down, left side
The Light sensors flipped upside down
The Light sensors flipped upside down (from the front)

Keep in mind that if you place the light sensor too close to the ground, it will function actively and read only the light reflected from the ground. We want it to be far enough away that it catches ambient light as well.

Try the code again with the light sensors flipped over. Did you notice any differences?

First of all, the robot tends to respond a lot faster to the light, mostly because the sensor is now in the shadow of the robot, so that a light coming from one side of the robot will not reach the light sensor on the other side, since it is blocked by the robot's body. This in turn makes the robot much faster in turning to face the light that is positioned on one of its sides. That is not the only benefit, however: the robot is also much better at following the light when the light is in front of it. Unlike the sensors up configuration, which tends to have problems zeroing in on a light source, the sensors down robot follows the light precisely, making minor adjustments every time the light moves. The only time that the robot does not benefit from this new configuration is when the light is on of the back of the robot. In both configurations, the robot is fairly slow to turn to face the light.

There is one drawback to this setup: Since the sensors are pointing down to the ground, light reflected off of the ground can change the sensor values. The darker the surface, the less light is reflected, and the better the robot performs. We found that the robot became much less responsive when we placed it on our usual whiteboard surface than it was when we tested it on the black tile mats.

On the other hand, the robot can now successfully execute this program in normal lighting conditions, which it could not do previously. Note, however, that the robot is somewhat less responsive in normal lighting, especially if the bright light is to the rear of the robot.

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox