Light sensors are used in all kinds of robotics, industrial, and commercial applications. Let's teach your cyber:bot to navigate using visible light. Using a pair of small light sensors, called phototransistors, your cyber:bot can measure and compare the light levels on its right and its left. It can then turn toward the brighter side as it navigates. This way, the cyber:bot can be programmed to find its way out of a dark space, or to follow a flashlight.
These activities are written assuming you are completing the cyber:bot Prerequisite tutorials first and then doing the Main tutorials in sequence. You should complete through Navigation [1] and Circuits [2] at a minimum first.
For this tutorial you will need:
Once you have learned how to use phototransistor sensors, you will be able to include visible light seeking or avoiding behavior in your robot applications.
A transistor is like a valve that regulates the amount of electric current that passes through two of its three terminals. The third terminal controls just how much current passes through the other two. Depending on the type of transistor, the current flow can be controlled by voltage, current, or in the case of the phototransistor, by light.
The image below shows the schematic and part drawing of the phototransistor in your cyber:bot kit. The brightness of the light shining on the phototransistor’s base (B) terminal determines how much current it will allow to pass into its collector (C) terminal, and out through its emitter (E) terminal. Brighter light results in more current; dimmer light results in less current.
The phototransistor looks a little bit like an LED. The two devices do have two similarities. First, if you connect the phototransistor in the circuit backwards, it won’t work right. Second, it also has two different length pins and a flat spot on its plastic case for identifying its terminals. The longer of the two pins indicates the phototransistor’s collector terminal. The shorter pin connected to the flat spont on the plastic case indicates the emitter.
In the ocean, you can measure the distance between the peaks of two adjacent waves in feet or meters. Light also travels in waves, but the distance between adjacent peaks is measured in nanometers (nm) which are billionths of meters. The figure below shows the wavelengths for colors of light we are familiar with, along with some the human eye cannot detect, such as ultraviolet and infrared.
The phototransistor in the cyber:bot kit is most sensitive to 850 nm wavelengths, which is in the infrared range. Infrared light is not visible to the human eye, but many different light sources emit considerable amounts of it, including halogen and incandescent lamps and especially the sun. This phototransistor also responds to visible light, though it’s less sensitive, especially to wavelengths below 450 nm.
The phototransistor circuits in this chapter work well indoors, with fluorescent or incandescent lighting. They are less sensitive to LED lighting. Make sure to avoid direct sunlight and direct halogen lights; they would flood the phototransistors with too much infrared light.
Imagine that your cyber:bot is navigating a course, and there’s a dark or shady area at the end, such as a cardboard box garage. Your robot’s final task in the course is to stop inside that dark area. Or, perhaps you want the robot to search for and stop under bright light. There’s a simple phototransistor circuit you can use that lets the micro:bit module know it detected bright or dim light by comparing the ambient light to some specified level.
Ambient means ‘existing or present on all sides’ according to Merriam Webster’s dictionary. For the light level in a room, think about ambient light as the overall level of brightness.
(1) phototransistor
(2) jumper wires
(1) resistor, 2 kΩ (red-black-red)
(1) cardboard box "garage" that fits the cyber:bot
(1) Optional - a flashlight or desk lamp, incandescent works best
After some testing, and depending on the light conditions, you might end up replacing the 2 kΩ resistor with one of these resistors, so keep them handy:
(1) resistor, 220 Ω (red-red-brown)
(1) resistor, 470 Ω (yellow-violet-brown)
(1) resistor, 1 kΩ (brown-black-red)
(1) resistor, 4.7 kΩ (yellow-violet-red)
(1) resistor, 10 kΩ (brown-black-orange)
The drawing below will help you tell apart the phototransistor and infrared LED, since they look similar.
The schematic and wiring diagram below show the schematic and wiring diagram of a circuit very similar to the ones in streetlights that turn on automatically at night. The circuit outputs a voltage that varies depending on how much light shines on the phototransistor. The cyber:bot will monitor the voltage level with one of its analog to digital pins.
In the circuit you just built, a wire connects A/D2 to the row where the phototransistor’s emitter and resistor meet. The voltage at this part of the circuit will change as the light level sensed by the phototransistor changes. The phototransistor_voltage script measures the voltage at A/D2— one of the micro:bit module ’s three analog to digital input channels—and scrolls that value on the micro:bit module’s display. You will use this sketch to take and write down voltage readings of the ambient light, shade cast by your hand, and optionally of bright light from a flashlight if you have one handy.
Example script: phototransistor_voltage
# phototransistor_voltage from cyberbot import * while True: ad2 = pin2.read_analog() volts = ad2 * (3.3/1024) out = "volts = " + str(volts) + "V" display.scroll(out, 80) sleep(500)
Measurements will vary with ambient light levels, but in general, brighter measurements will tend toward 3.3, and darker ones will tend toward 0 V. If you point the phototransistor at the sun or a bright flashlight, the measurements should be close to 3.3 V. As you block the light and cast darker shade, the measurements should decrease.
Once you have a resistor value in place that works well for differentiating ambient light and shade in your area, you are ready for the next step.
The script halt_under_shadow will make the cyber:bot go forward until the phototransistor detects a shadow that’s dark enough to make the voltage applied to D/A2 drop below 0.1 V, or a different threshold you choose.
#halt_under_shadow from cyberbot import * bot(18).servo_speed(75) bot(19).servo_speed(-75) while True: ad2 = pin2.read_analog() volts = ad2 * (3.3/1024) if volts < 0.1: # Update voltage threshold value here bot(18).servo_speed(None) bot(19).servo_speed(None)
The micro:bit module’s A/D0, A/D1, and A/D2 sockets are connected to its Nordic chip's pins that are configured for analog to digital conversion. Analog to digital conversion, called "A to D" and abbreviated A/D, is how microcontrollers measure voltage. The microcontroller splits a voltage range into many numbered, equal divisions, with each number representing a voltage level. More divisions provide a higher resolution, with more precise voltage measurements.
Each of the micro:bit module’s analog inputs has a 10-bit resolution, meaning that it uses 10 binary digits to describe its voltage measurement. With 10 binary digits, you can count from 0 to 1023; that’s a total of 1024 voltage levels if you include zero.
By default, the cyber:bot’s read_analog function is configured to use the 0…1023 values to describe where a voltage measurement falls in a 3.3 V scale. If you split 3.3 V into 1024 different levels, each level is 3.3/1024ths of a volt apart. 3.3/1024ths of a volt is approximately 0.00322266 V, or about 3.22 thousandths of a volt. So, to convert a value returned by read_analog to a voltmeter-style value, all the volts function has to do is multiply by 3.3 and divide by 1024.
Example: The read_analog function returns 742; how many volts is that?
Answer:
V = 742 x 3.3 V / 1024
= 2.39121094 V
= 2.39 V
The previous scripts have been storing the read_analog function values as the variable ad2. This variable is stored as an integer since it returns the values between 0 and 1023. It is then multiplied by 3.3 and divided by 1024 to get the voltage value (just like we converted 742), and this is being stored as the float variable volts.
ad2 = pin2.read_analog()
volts = ad2 * (3.3/1024)
The script phototransistor_voltage displays the value returned by volts with the display.scroll function.
The script halt_under_shadow script uses that value to bring the cyber:bot to a stop when it detects a shadow (if volts < 0.1).
Binary vs. Analog and Digital
A binary sensor can transmit two different states, typically to indicate the presence or absence of something. For example, a whisker sends a high signal if it is not pressed, or a low signal if it is pressed.
An analog sensor sends a continuous range of values that correspond to a continuous range of measurements. The phototransistor circuits in this activity are examples of analog sensors. They provide continuous ranges of values that correspond to continuous ranges of light levels.
A digital value is a number expressed by digits. Computers and microcontrollers store analog measurements as digital values. The process of measuring an analog sensor and storing that measurement as a digital value is called analog to digital conversion. The measurement is called a digitized measurement. Analog to digital conversion documents will also call them quantized measurements.
A resistor “resists” the flow of current. Voltage in a circuit with a resistor can be likened to water pressure. For a given amount of electric current, more voltage (pressure) is lost across a larger resistor than a smaller resistor that has the same amount of current passing through it. If you instead keep the resistance constant and vary the current, you can measure a larger voltage (pressure drop) across the same resistor with more current, or less voltage with less current.
The micro:bit module’s analog inputs are invisible to the phototransistor circuit. So, a circuit plugged into the A/D2 socket on the cyber:bot board is monitored by the micro:bit, but the micro:bit has no affect on the circuit.
Take a look at the circuit below. With 3.3 volts (3.3 V) at the top and GND (0 V) at the bottom of the circuit, 3.3 V of electrical pressure (voltage) makes the supply of electrons in the cyber:bot’s batteries want to flow through it.
The reason the voltage at A/D2 (VAD2) changes with light is because the phototransistor lets more current pass when more light shines on it, or less current pass with less light. That current, which is labeled I in this circuit, also has to pass through the resistor. When more current passes through a resistor, the voltage across it will be higher. When less current passes, the voltage will be lower. Since one end of the resistor is tied to GND = 0 V, the voltage at the VAD2 end goes up with more current and down with less current.
If you replace the 2 kΩ resistor with a 1 kΩ resistor, VAD2 will see smaller values for the same currents. It will take twice as much current to get VAD2 to the same voltage level, which means the shadow will have to be twice as dark to reach the 0.1 V level, which is the default voltage in the script halt_under_shadow that makes the cyber:bot stop.
So, a smaller resistor in series with the phototransistor makes the circuit less sensitive to light. If you instead replace the 2 kΩ resistor with a 10 kΩ resistor, VAD2 will be 5 times larger with the same current, and it’ll only take 1/5th the light to generate 1/5th the current to get VAD2 past the 0.1 V level. So, a larger resistor makes the circuit more sensitive to light.
Connected in Series — When two or more elements are connected end-to-end, they are connected in series. The phototransistor and resistor in this circuit are connected in series.
Two properties affect the voltage at VAD2: current and resistance, and Ohm’s Law explains how it works. Ohm’s Law states that the voltage (V) across a resistor is equal to the current (I) passing through it multiplied by its resistance (R). So, if you know two of these values, you can use the Ohm’s Law equation to calculate the third:
V = I x R
Voltage (V) is measured in units of volts, which are abbreviated with an upper-case V. Current (I) is measured in amperes, or amps, which are abbreviated A. Resistance (R) is measured in ohms which is abbreviated with the Greek letter omega (Ω). The current levels you are likely to see through this circuit are in milliamps (mA). The lower-case m indicates that it’s a measurement of thousandths of amps. Similarly, the lower-case k in kΩ indicates that the measurement is in thousands of ohms.
In some textbooks, you will see E = I × R instead. E stands for electric potential, which is another way to say “volts."
Let’s use Ohm’s Law to calculate VAD2 with the phototransistor, letting two different amounts of current flow through the circuit:
The examples below show the conditions and their solutions. When you try these calculations, remember that milli (m) is thousandths and kilo (k) is thousands when you substitute the numbers into Ohm’s Law.
Example 1: I = 0.92 mA and R = 2 kΩ
Example 2: I = 0.25 mA and R = 2 kΩ
Let’s say that the ambient light in your room is twice as bright as the light that resulted in VA3 = 3.1 V for bright light and 0.5 V for shade. Another situation that could cause higher current is if the ambient light is a stronger source of infrared. In either case, the phototransistor could allow twice as much current to flow through the circuit, which could lead to measurement difficulties.
Question: What could you do to bring the circuit’s voltage response back down to 3.1 V for bright light and 0.5 V for dim?
Answer: Cut the resistor value in half; make it 1 kΩ instead of 2 kΩ.
Does it bring VA3 back to 3.1 V for bright light and 0.5 V for dim light with twice the current? (It should; if it didn’t for you, check your calculations.)
The A/D circuit for Park in the Dark works over a limited light range. You might get that circuit all nice and calibrated in one room, then take it to a brighter room and find that all the voltage measurements will stay above 0.1 V. Or, maybe you’ll take it into a darker room, and the voltages will end up never making it past 0.1 V.
Let's try a different kind of phototransistor circuit that the cyber:bot can use to measure a much wider range of light levels. This circuit and script can return values ranging from 0 to over 75,000. Just note: with this circuit, smaller values indicate bright light, and large values indicate low light, the opposite of our previous circuit. This new circuit uses a new component: a capacitor.
A capacitor is a device that stores an electrical charge. It is a fundamental building block of many circuits. Batteries are also devices that store charge, and for these activities it will be convenient to think of capacitors as tiny batteries that can be charged, discharged, and recharged.
How much charge a capacitor can store is measured in farads (F). A farad is a very large value that’s not practical for use with these cyber:bot circuits. The capacitors in your kit store fractions of millionths of farads. A millionth of a farad is called a microfarad, and it is abbreviated μF. This one stores one hundredth of one millionth of a farad: 0.01 μF.
Your cyber:bot kit's electronic component pack comes with two different capacitors. One is marked 103 and the other is marked 104. These marks are a measurement in picofarads. In this labeling system, the value is the number 10 followed by the specified number of zeros added.
For example, 103 is the number 10 with 3 zeros added capacitor’s case is a measurement in picofarads or (pF). In this labeling system, 103 is the number 10 with three zeros added, so the capacitor is 10,000 pF, which is 0.01 μF.
(10,000) × (1 × 10-12) F = (10 × 103) × (1 × 10-12) F
10 × 10-9 F = 0.01 × 10-6 F
= 0.01 μF.
The capacitor labeled 103 with the value of 0.01 µF is the value we will use next.
The circuits shown here can respond independently to the light level reaching each phototransistor. Each one naturally adapts to ambient light levels without having to swap out resistors. The phototransistors will be pointing upward at about 45°, one forward-left and the other forward-right. This way, a script monitoring the values of both phototransistor circuits can determine which side of the cyber:bot is exposed to brighter light. Then, this information can be used for navigation decisions.
(2) phototransistors
(2) capacitors, 0.01 μF (marked 103)
(2) resistors, 220 Ω (red-red-brown)
(2) jumper wires
The roaming examples in this chapter will depend on the phototransistors being pointed upward and outward to detect differences in light levels from different directions. Adjust the phototransistors to point upward at a 45° from the breadboard, and outward about 90° apart, as shown below.
Think of each capacitor in this circuit as a tiny rechargeable battery, and think of each phototransistor as a light-controlled current valve. Each capacitor can be charged to 3.3 V and then allowed to drain through its phototransistor. The rate that the capacitor discharges depends how much current the phototransistor (current valve) allows to pass, which in turn depends on the brightness of the light shining on the phototransistor’s base. Again, brighter light results in more current passing, shadows result in less current.
This kind of phototransistor/capacitor circuit is called a charge transfer circuit. The cyber:bot will determine the rate at which each capacitor loses its charge through its phototransistor by measuring how long it takes the capacitor’s voltage to decay, that is, to drop below a certain voltage value. The decay time corresponds to how wide open that current valve is, which is controlled by the brightness of the light reaching the phototransistor’s base. More light means faster decay, less light means slower decay.
QT Circuit — A common abbreviation for charge transfer is QT. The letter Q refers to electrical charge (an accumulation of electrons), and T is for transfer.
Connected in Parallel — The phototransistor and capacitor shown in the figure above are connected in parallel; each of their leads are connected to common terminals (also called nodes). The phototransistor and the capacitor each have one lead connected to GND, and they also each have one lead connected to the same 1 kΩ resistor lead.
The script left_light_sensor charges the capacitor in the P8 circuit, measures the time it takes for the capacitor to discharge, and displays that value on the micro:bit module’s LED matrix. Remember, with this circuit and script, lower numbers mean brighter light now!
# left_light_sensor from cyberbot import * while True: bot(8).write_digital(1) qt_left = bot(8).rc_time(1) display.scroll(str(qt_left)) sleep(500)
The other phototransistor circuit on the right side of the robot also needs testing!
These steps are important!
Your circuits and code must pass these tests before continuing. The rest of the examples in this chapter rely on both light sensors working correctly.
The charge transfer measurement is done with these two lines of code:
bot(8).write_digital(1) qt_left = bot(8).rc_time(1)
The first line, bot(8).write_digital(1), does two things. First, it charges the capacitor by setting Propeller I/O pin P8 to output high (3.3 volts). Then, it waits one millisecond for the capacitor to fully charge - more than enough time for this tiny one.
The next line, qt_left = bot(8).rc_time(1), is doing a lot more. The rc_time function:
Here is an example of a charge transfer measured with an oscilloscope, a device that displays voltage as it changes over time. The vertical axis on the left is volts, and time increases by milliseconds along the bottom.
The red line that’s graphing voltage is called a trace. The trace plots the capacitor’s voltage in the P8 QT circuit; that’s the left light sensor. In response to bot(8).write_digital(1), the voltage quickly rises from 0 V to almost 3.3 V at about the 1 ms mark, and stays there for 1 millisecond. Then, at the 2 ms mark, the rc_time call allows the voltage in the capacitor to start draining, or "decay." The rc_time function measures the time it takes the voltage to decay to the Propeller I/O pin's logic threshold of about 1.6 V. This measured rc decay time gets stored in the qt_left variable. In the plot, it looks like that decay took about 1 ms, so the qt_left variable would store a value close to 1000.
Keep in mind that these are not the voltage measurements from Activity 1, they are time measurements. When the voltage decay takes a short time the number will be small, and that means bright light. When the voltage decay takes a long time, the number will be larger, and that means dimmer light, shade, or for really large numbers, darkness.
Keep in mind that these are not the voltage measurements from Activity 1, they are time measurements. When the voltage decay takes a short time the number will be small, and that means bright light. When the voltage decay takes a long time, the number will be larger, and that means dimmer light, shade, or for really large numbers, darkness.
The rc-time circuits in this tutorial can work under a variety of lighting conditions. Now we need some code that can adapt as well. An example of script code that cannot adapt to change would be:
if qt_left > 2500)... # Not good for navigation.
That statement might work well for turning away from shadows in one room, but take it to another with brighter lights, and it might never detect a shadow. Or, take it to a darker room, and it might think it’s seeing shadows all the time.
For the cyber:bot to navigate with phototransistors, the exact light levels measured aren't really important. What matters is which sensor detects the brightest light.
The next example script takes a light level measurement from each sensor. Then, it uses an equation to turn the two measurements into a single value between -0.5 and +0.5. A value of zero means the two photoresistors are detecting equal brightness.
Let's run the script first, then examine what it is doing.
ERROR FALSE ALARM! On line 11 of the script flash norm_diff_shade_value, you may see a compiler error warning "Operator "+" not supported for this combination of types." This is just a false alarm. The script actually works just fine, so go ahead and send it to the micro:bit.
# norm_diff_shade_value from cyberbot import * while True: bot(8).write_digital(1) qt_left = bot(8).rc_time(1) bot(6).write_digital(1) qt_right = bot(6).rc_time(1) norm_diff_shade = (qt_right / (qt_right + qt_left)) - 0.5 display.scroll(norm_diff_shade) sleep(500)
For navigation, what matters is the difference in how much light the two photoresistors detect, so the robot can turn toward the sensor seeing brighter light (or away from it, depending on what you want.) The script norm_diff_shade_value finds this difference by dividing the right sensor measurement into the sum of both. The result will always be in the 0 to 1 range. This technique is an example of a normalized differential measurement. Here’s what this technique looks like as an equation:
For example, a normalized differential measurement of 0.25 would mean “the light is 1/2 as bright over the right sensor as it is over the left.” The actual values for qt_right and qt_left might be small in a bright room or large in a dark room, but the answer will still be 0.25 if the light is 1/2 as bright over the right sensor. A measurement of 0.5 would mean that the qt_right and qt_left values are equal. They could both be large, or both be small, but if the result is 0.5, it means the sensors are detecting the same level of brightness.
But, the script norm_diff_shade_value adds one more step: it subtracts 0.5 from the normalized differential shade measurement. That way, the results range from –0.5 to +0.5 instead of 0 to 1, and a measurement of 0 means equal brightness. The result is a zero-justified normalized differential shade measurement, that looks like this as an equation:
But why bother with the extra step? The value range –0.5 to +0.5 is great for navigation scripts because the positive and negative values can be used to scale the wheels speeds. Here is how the zero-justified normalized differential shade equation appears in the script:
norm_diff_shade = (qt_right / (qt_right + qt_left)) - 0.5
This line is used in the next two example scripts, which will show its usefulness.
The micro:bit module’s display can be used to show which side of the cyber:bot is detecting brighter light. The following program shows a visual display of where the brigher light is hitting, reflecting the value of the norm_diff_shade variable. If the light is on the right side, the display will light up a pixel on the right side, if the light is in the middle it will light up a pixel in the middle, and so on.
ERROR FALSE ALARM! On line 11 of the script norm_diff_shade_display, you may see a compiler error warning "Operator "+" not supported for this combination of types." This is just a false alarm. The script actually works just fine, so go ahead and send it to the micro:bit.
# norm_diff_shade_display from cyberbot import * while True: bot(8).write_digital(1) qt_left = bot(8).rc_time(1) bot(6).write_digital(1) qt_right = bot(6).rc_time(1) norm_diff_shade = (qt_right / (qt_right + qt_left)) - 0.5 display.clear() if norm_diff_shade > -0.5 and norm_diff_shade <= -0.35: display.set_pixel(0, 2, 9) elif norm_diff_shade > -0.35 and norm_diff_shade <= -0.1: display.set_pixel(1, 1, 9) elif norm_diff_shade > -0.1 and norm_diff_shade <= 0.1: display.set_pixel(2, 0, 9) elif norm_diff_shade > 0.1 and norm_diff_shade <= 0.35: display.set_pixel(3, 1, 9) elif norm_diff_shade > 0.35 and norm_diff_shade < 0.5: display.set_pixel(4, 2, 9) sleep(50)
To make the cyber:bot roam toward light, the code's job is to get from the raw sensor values to a norm_diff_shade value that can be used to adjust the servo speeds. We want cyber:bot turn a little—or a lot—when the contrast between the light detected on each side is a little—or a lot. The following equation in code makes the norm_diff_shade value to integer between -100 and 100.
norm_diff_shade = (200 * qt_right) / (qt_right + qt_left + 1) - 100
Let's confirm this strategy works before using it in a navigation script.
ERROR FALSE ALARM! On line 12 of the script test_integer_shade_value, you may see a compiler error warning "Operator "+" not supported for this combination of types." This is just a false alarm. The script actually works just fine, so go ahead and send it to the micro:bit.
# test_integer_shade_value from cyberbot import * while True: bot(8).write_digital(1) qt_left = bot(8).rc_time(1) bot(6).write_digital(1) qt_right = bot(6).rc_time(1) norm_diff_shade = (200 * qt_right) / (qt_right + qt_left + 1) - 100 display.scroll(norm_diff_shade)
Make sure the micro:bit should display values between -100 and 100 depending on which sides the light and shadow are on. The values do not necessarily have to reach the -100 and 100 end points, but they should get close.
Now, using this new strategy, we can manipulate the servos to drive based on which direction the light is hitting the cyber:bot. The light-seeking script and some ideas for adapting it are included below. How this script works is on the next page.
ERROR FALSE ALARM! On line 12 of the script seek_bright_light, you may see a compiler error warning "Operator "+" not supported for this combination of types." This is just a false alarm. The script actually works just fine, so go ahead and send it to the micro:bit.
# seek_bright_light from cyberbot import * while True: bot(8).write_digital(1) qt_left = bot(8).rc_time(1) bot(6).write_digital(1) qt_right = bot(6).rc_time(1) norm_diff_shade = (200 * qt_right) / (qt_right + qt_left + 1) - 100 if norm_diff_shade > 0: left_speed = 75 - norm_diff_shade right_speed = -75 else: left_speed = 75 right_speed = -75 - norm_diff_shade bot(18).servo_speed(left_speed) bot(19).servo_speed(right_speed)
You can change the cyber:bot's responsiveness by changing the value 200 in this line of the script:
norm_diff_shade = (200 * qt_right) / (qt_right + qt_left + 1) - 100
Here are several more light-sensing navigation ideas for your cyber:bot that can be made with adjustments to the while True: function:
Take a look at the image below. It illustrates how shade over one of the photoresistors affects the cyber:bot wheels' speeds.
Let's take a closer look. The navigation code is in an infinite while True loop. At the beginning of each loop, the familiar rc_time function takes a reading from each phototransistor circuit. The P8 circuit measurement is stored in at_left and the P6 circuit measurement is stored in qt_right.
from cyberbot import * while True: bot(8).write_digital(1) qt_left = bot(8).rc_time(1) bot(6).write_digital(1) qt_right = bot(6).rc_time(1)
Then, the values of qt_right and qt_left are used in an equation to get an integer value representing which side of the cyber:bot is in brighter light. The value is stored in the norm_diff_shade variable.
norm_diff_shade = (200 * qt_right) / (qt_right + qt_left + 1) - 100
Now take another look at the illustration above. Light is hitting the left photoresistor but shade is over the right one. If the light is hitting the left side, then we want to slow down the left servo down so the cyber:bot moves more towards the left. This was done with the following statement:
if norm_diff_shade > 0: left_speed = 75 - norm_diff_shade right_speed = -75
Since light is hitting the left side, the variable norm_diff_shade will be greater than 0, and the if statement will run. The variable right_speed will stay at -75 (full speed clockwise to go forward) while the variable left_speed will subtract the value of norm_diff_shade from 75. The brighter the light on the left side, the larger the value subtracted.
If it light were hitting the right side of the cyber:bot and instead norm_diff_shade was less than or equal to 0, the c else: condition code would execute instead. It works the same way, to slow down right_speed by subtracting norm_diff_shade, but keeps the variable left_speed at 75 (full speed counterclockwise to go forward).
else: left_speed = 75 right_speed = -75 - norm_diff_shade
Then, the following script uses the updated left_speed and right_speed values to control each servo's speed:
bot(18).servo_speed(left_speed) bot(19).servo_speed(right_speed)
These lines simply run the servos at the speeds from the if statement. And, that is all it takes!
Links
[1] https://learn.parallax.com/tutorials/robot/cyberbot/navigation-cyberbot
[2] https://learn.parallax.com/tutorials/robot/cyberbot/circuits-cyberbot