02 - Lab Light Detection

Video

# Lab: Ambient Light Sensor - Basic Light Detection ## Objective Learn to read ambient light values from the TinkerBlock TK20 Ambient Light Sensor module. The sensor detects the intensity of ambient light and converts it to analog values. This lab introduces light sensing concepts and demonstrates how to read, process, and display light sensor data. ## Learning Outcomes - Understand ambient light sensing and photoresistor operation - Learn about light-dependent resistance and voltage division - Master analogRead() function for light sensor input - Create responsive light detection systems - Use Serial communication for light value monitoring - Understand light intensity measurement and calibration ## Required Components ![](https://cdn.shopify.com/s/files/1/0331/9994/7908/files/Pasted_image_20250722151023.png?v=1753823996) 1. **Lonely Binary UNO R3** - Main Arduino board 2. **TinkerBlock UNO R3 Shield** - Expansion shield that plugs onto the UNO R3 3. **TinkerBlock TK20 - Ambient Light Sensor** - Light sensor module with 4-pin connector ## Theory ### Ambient Light Sensing Concepts - **Photoresistor**: Light-dependent resistor (LDR) that changes resistance with light - **Light Intensity**: Amount of light falling on the sensor surface - **Resistance Change**: Lower resistance in bright light, higher in darkness - **Voltage Division**: Creates variable voltage output based on light level - **Analog Conversion**: Light intensity converted to digital values (0-1023) ### Light Sensor Operation - **Photoconductive Material**: Semiconductor that conducts more current when illuminated - **Response Time**: Typically 10-100ms for light changes - **Spectral Response**: Most sensitive to visible light (400-700nm) - **Dynamic Range**: Wide range from darkness to bright sunlight - **Temperature Dependence**: Slight variation with temperature ### Light-Dependent Resistance - **Dark Conditions**: High resistance (100KΩ - 1MΩ) - **Bright Conditions**: Low resistance (1KΩ - 10KΩ) - **Non-linear Response**: Logarithmic relationship with light intensity - **Hysteresis**: Slight delay in response to rapid light changes ### Voltage Division Principle ``` Vout = Vin × (R2 / (R1 + R2)) ``` - **Vin**: 5V (supply voltage) - **R1**: Photoresistor (variable resistance based on light) - **R2**: Fixed resistor (voltage divider) - **Vout**: Variable output voltage (0-5V) ### Key Functions Used - `pinMode(pin, mode)`: Configures a pin as input or output - `analogRead(pin)`: Reads analog value from specified pin (0-1023) - `analogWrite(pin, value)`: Outputs PWM signal (0-255) - `Serial.begin(baud)`: Initializes serial communication - `Serial.print()` and `Serial.println()`: Outputs data to Serial Monitor - `delay(milliseconds)`: Pauses the program for a specified time - `map(value, fromLow, fromHigh, toLow, toHigh)`: Maps values between ranges ## Circuit Diagram ![](https://cdn.shopify.com/s/files/1/0331/9994/7908/files/Pasted_image_20250722151043.png?v=1753824000) ## Connection Instructions 1. **Assemble the Hardware:** - Place the TinkerBlock UNO R3 Shield onto the Lonely Binary UNO R3 - Ensure all pins are properly aligned and seated - The shield should fit snugly on top of the Arduino board 2. **Connect the Light Sensor Module:** - Take the TinkerBlock TK20 - Ambient Light Sensor module - Align the 4-pin connector with any available 4-pin slot on the shield - Gently push the module into the slot until it clicks into place - The module will automatically connect: - **GND** pin to ground - **VCC** pin to 5V power - **NC** pin remains unconnected - **Signal** pin to analog pin A3 3. **Important Notes:** - No breadboard or jumper wires required - The TK20 sensor has a built-in voltage divider circuit - The sensor provides smooth analog output based on light intensity - Multiple 4-pin slots are available on the shield for expansion - The sensor is most sensitive to visible light wavelengths ## Code ```cpp // Lab: Ambient Light Sensor - Basic Light Detection // Light sensor connected to analog pin A3 // Define the analog pin const int lightSensorPin = A3; // Light sensor input pin // Variables for reading and processing int lightValue = 0; // Raw analog value (0-1023) int lightValueMapped = 0; // Mapped value (0-100) float voltage = 0.0; // Calculated voltage (0-5V) int lightLevel = 0; // Light level category (0-4) // Smoothing variables const int numReadings = 10; int readings[numReadings]; int readIndex = 0; int total = 0; void setup() { // Configure light sensor pin as input (optional for analog pins) pinMode(lightSensorPin, INPUT); // Initialize serial communication for monitoring Serial.begin(9600); Serial.println("Ambient Light Sensor Lab Started"); Serial.println("Expose the sensor to different light levels"); Serial.println("----------------------------------------"); Serial.println("Format: Raw | Mapped | Voltage | Light Level"); Serial.println("----------------------------------------"); // Initialize smoothing array for (int i = 0; i < numReadings; i++) { readings[i] = 0; } } void loop() { // Read the analog value from the light sensor lightValue = analogRead(lightSensorPin); // Apply smoothing to reduce noise lightValue = smoothReading(lightValue); // Map the value to different ranges for demonstration lightValueMapped = map(lightValue, 0, 1023, 0, 100); // Calculate voltage (assuming 5V reference) voltage = (lightValue * 5.0) / 1023.0; // Determine light level category lightLevel = determineLightLevel(lightValue); // Display the values Serial.print("Raw: "); Serial.print(lightValue); Serial.print(" | Mapped: "); Serial.print(lightValueMapped); Serial.print("% | Voltage: "); Serial.print(voltage, 2); Serial.print("V | Level: "); Serial.print(lightLevel); Serial.print(" | "); // Display light level description switch(lightLevel) { case 0: Serial.println("Very Dark"); break; case 1: Serial.println("Dark"); break; case 2: Serial.println("Low Light"); break; case 3: Serial.println("Normal Light"); break; case 4: Serial.println("Bright Light"); break; default: Serial.println("Unknown"); break; } // Small delay to make the output readable delay(500); } // Function to smooth analog readings int smoothReading(int newReading) { // Subtract the last reading total = total - readings[readIndex]; // Read from the sensor readings[readIndex] = newReading; // Add the reading to the total total = total + readings[readIndex]; // Advance to the next position in the array readIndex = (readIndex + 1) % numReadings; // Return the average return total / numReadings; } // Function to determine light level category int determineLightLevel(int sensorValue) { if (sensorValue < 20) { return 0; // Very Dark } else if (sensorValue < 60) { return 1; // Dark } else if (sensorValue < 100) { return 2; // Low Light } else if (sensorValue < 400) { return 3; // Normal Light } else { return 4; // Bright Light } } ``` ## Code Explanation ### Setup Function ```cpp void setup() { pinMode(lightSensorPin, INPUT); Serial.begin(9600); } ``` - Configures analog pin A3 as input for light sensor - Initializes serial communication for value monitoring - Sets up smoothing array for noise reduction ### Main Loop Logic ```cpp void loop() { lightValue = analogRead(lightSensorPin); lightValue = smoothReading(lightValue); lightValueMapped = map(lightValue, 0, 1023, 0, 100); voltage = (lightValue * 5.0) / 1023.0; lightLevel = determineLightLevel(lightValue); } ``` **Light Sensor Reading:** - `analogRead(lightSensorPin)`: Reads raw light sensor value (0-1023) - **0**: Very dark conditions (high resistance) - **1023**: Very bright conditions (low resistance) - **Smoothing**: Reduces noise and fluctuations **Value Processing:** - **Mapping**: Converts to percentage (0-100%) - **Voltage Calculation**: Shows actual voltage across sensor - **Level Classification**: Categorizes light intensity ### Smoothing Function ```cpp int smoothReading(int newReading) { total = total - readings[readIndex]; readings[readIndex] = newReading; total = total + readings[readIndex]; readIndex = (readIndex + 1) % numReadings; return total / numReadings; } ``` - **10-point moving average**: Reduces noise and jitter - **Stable readings**: Smooth transitions between light levels - **Responsive**: Still responds to light changes ### Light Level Classification ```cpp int determineLightLevel(int sensorValue) { if (sensorValue < 20) return 0; // Very Dark else if (sensorValue < 60) return 1; // Dark else if (sensorValue < 100) return 2; // Low Light else if (sensorValue < 400) return 3; // Normal Light else return 4; // Bright Light } ``` **Light Level Categories:** - **Level 0 (0-99)**: Very Dark - Night time, dark rooms - **Level 1 (100-299)**: Dark - Dim lighting, shadows - **Level 2 (300-499)**: Low Light - Indoor lighting, cloudy day - **Level 3 (500-799)**: Normal Light - Bright indoor, overcast day - **Level 4 (800-1023)**: Bright Light - Direct sunlight, bright conditions ### Key Variables - **lightValue**: Raw light sensor reading (0-1023) - **lightValueMapped**: Percentage value (0-100) - **voltage**: Calculated voltage (0-5V) - **lightLevel**: Categorized light level (0-4) - **readings[]**: Array for smoothing calculations ### Value Ranges - **Raw ADC**: 0-1023 (10-bit resolution) - **Mapped**: 0-100 (percentage) - **Voltage**: 0.00-5.00V (2 decimal places) - **Light Level**: 0-4 (categorized levels) ## Testing and Verification 1. **Upload the code to Lonely Binary UNO R3** 2. **Open Serial Monitor** in Arduino IDE (Tools → Serial Monitor) 3. **Test different light conditions:** - **Very dark**: Cover sensor completely, should show level 0 - **Dark**: Dim lighting, should show level 1 - **Low light**: Normal indoor lighting, should show level 2 - **Normal light**: Bright indoor or cloudy day, should show level 3 - **Bright light**: Direct light or sunlight, should show level 4 4. **Verify value ranges:** - **Raw values**: 0-1023 - **Mapped values**: 0-100% - **Voltage**: 0.00-5.00V - **Light levels**: 0-4 with appropriate descriptions 5. **Verify connections:** - Ensure the TK20 module is firmly connected to the shield - Check that the shield is properly seated on the Arduino - Confirm the sensor responds to light changes ## Troubleshooting ### Light sensor doesn't respond: - Check if the TinkerBlock shield is properly seated on the Arduino - Ensure the TK20 module is firmly connected to the shield - Verify the module is connected to a slot that uses A3 pin - Check if code uploaded successfully to the Lonely Binary UNO R3 - Open Serial Monitor to see if values are being read ### Values not changing with light: - Check if the sensor is exposed to light properly - Verify the module is connected to analog pin A3 - Check Serial Monitor output to see if readings are stable - Ensure the sensor surface is clean and unobstructed - Try exposing the sensor to different light sources ### Values jumping or unstable: - Check if the module is properly seated in the shield - Verify all pins are making good contact - Try reconnecting the module to a different 4-pin slot - Check for loose connections or bent pins - Increase smoothing by changing `numReadings` to a higher value ### Values not in expected range: - Check if the sensor is properly exposed to light - Verify the mapping calculations are correct - Ensure the reference voltage is 5V - Try calibrating the sensor for your specific lighting conditions ### Serial Monitor shows no output: - Ensure Serial Monitor is set to 9600 baud rate - Check that Serial.begin(9600) is in setup() - Verify the correct COM port is selected in Arduino IDE ## Experiment Variations ### 1. Light-Dependent Actions Add actions based on light levels: ```cpp void loop() { int lightValue = analogRead(lightSensorPin); int lightLevel = determineLightLevel(lightValue); switch(lightLevel) { case 0: // Very Dark Serial.println("Night mode activated"); break; case 1: // Dark Serial.println("Low power mode"); break; case 2: // Low Light Serial.println("Normal operation"); break; case 3: // Normal Light Serial.println("High performance mode"); break; case 4: // Bright Light Serial.println("Maximum performance"); break; } delay(1000); } ``` ### 2. Light Threshold Detection Add threshold-based monitoring: ```cpp const int DARK_THRESHOLD = 200; const int BRIGHT_THRESHOLD = 800; bool wasDark = false; bool wasBright = false; void loop() { int lightValue = analogRead(lightSensorPin); // Detect transitions if (lightValue < DARK_THRESHOLD && !wasDark) { Serial.println("Light level dropped - entering dark mode"); wasDark = true; wasBright = false; } else if (lightValue > BRIGHT_THRESHOLD && !wasBright) { Serial.println("Light level increased - entering bright mode"); wasBright = true; wasDark = false; } delay(100); } ``` ### 3. Light Data Logging Add data logging functionality: ```cpp unsigned long startTime = 0; int readingCount = 0; void setup() { // ... existing setup code ... startTime = millis(); } void loop() { int lightValue = analogRead(lightSensorPin); unsigned long currentTime = millis(); // Log data every 10 readings if (readingCount % 10 == 0) { Serial.print("Time: "); Serial.print((currentTime - startTime) / 1000); Serial.print("s | Light: "); Serial.print(lightValue); Serial.print(" | Level: "); Serial.println(determineLightLevel(lightValue)); } readingCount++; delay(100); } ``` ### 4. Light Calibration Add calibration functionality: ```cpp int minLightValue = 1023; int maxLightValue = 0; bool calibrated = false; void loop() { int lightValue = analogRead(lightSensorPin); if (!calibrated) { // Update min and max values if (lightValue < minLightValue) minLightValue = lightValue; if (lightValue > maxLightValue) maxLightValue = lightValue; Serial.print("Calibrating... Min: "); Serial.print(minLightValue); Serial.print(" Max: "); Serial.println(maxLightValue); // Calibrate for 10 seconds if (millis() > 10000) { calibrated = true; Serial.println("Calibration complete!"); } } else { // Use calibrated range int calibratedValue = map(lightValue, minLightValue, maxLightValue, 0, 100); Serial.print("Calibrated light level: "); Serial.print(calibratedValue); Serial.println("%"); } delay(500); } ``` ## Questions for Understanding 1. How does a photoresistor change resistance with light intensity? 2. What is the relationship between light intensity and voltage output? 3. Why do we use smoothing for light sensor readings? 4. How does the voltage divider circuit work in the light sensor? 5. What are the advantages of categorizing light levels? 6. How would you modify the code to detect sudden light changes? 7. What are the limitations of using a photoresistor for light sensing? ## Next Steps - Try connecting the light sensor to control LED brightness automatically - Experiment with different light sources and their effects on readings - Learn about other light sensors (photodiodes, phototransistors) - Explore other TinkerBlock sensor modules for environmental monitoring - Try creating automatic lighting control systems - Implement light-based security or automation systems ## Safety Notes - Always disconnect power before connecting or disconnecting modules - Handle the TinkerBlock shield and modules carefully to avoid bending pins - Ensure proper alignment when connecting modules to prevent damage - The built-in voltage divider in the module prevents component damage - Keep the Lonely Binary UNO R3 and shield in a stable position during operation - Do not apply voltages higher than 5V to analog inputs - Avoid exposing the sensor to extremely bright light sources --- **Lab Completion Checklist:** - [ ] TinkerBlock shield properly seated on Lonely Binary UNO R3 - [ ] TK20 Ambient Light Sensor module connected to shield (A3) - [ ] Code uploaded successfully to Lonely Binary UNO R3 - [ ] Light sensor responds to different light conditions - [ ] Raw values range from 0-1023 - [ ] Mapped values range from 0-100% - [ ] Voltage calculation shows 0.00-5.00V - [ ] Light level categorization works correctly - [ ] Serial Monitor displays all values correctly - [ ] Values change smoothly with light changes - [ ] Troubleshooting completed (if needed) - [ ] Experiment variations tried - [ ] Questions answered