amc:ss2025:group-x:start
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
amc:ss2025:group-x:start [2025/07/28 23:04] – removed emir-talha.fidan | amc:ss2025:group-x:start [2025/07/29 21:20] (current) – 34862_students.hsrw | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Smart NightLight====== | ||
+ | \\ | ||
+ | |||
+ | === By: === | ||
+ | \\ | ||
+ | '' | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | ==== Introduction ==== | ||
+ | '' | ||
+ | \\ | ||
+ | Many people use a night light to help them navigate their home in the dark. However there are many issues with the common night light. One issue is that a regular nightlight is static and dose not move. This means that the night light either does not have a large field of illumination or is very broad and lights up everything. The problem is made even worse by the fact that conventional nightlights attach directly to a wall socket. This is where our project the Smart Sightlight comes in. Our nightlight actively waits for a person to enter the vicinity. Once a person is in the vicinity the nightlight scans the room and calculates position and direction of movement of the person. It then uses this information to illuminate the light in-front of the person. | ||
+ | |||
+ | ==== Method ==== | ||
+ | |||
+ | === 1.CAD === | ||
+ | '' | ||
+ | |||
+ | In order to house all the electronics in a space friendly and secure way it is necessary to design a housing that can be easily printed and assembled. This was done using OnShape which is free for all students. The housing is made of three main pieces. The center piece houses the two PIR sensors at a 45 degree angle from the wall in both directions. This means the PIR sensors have a very large field of view allowing for early detection. The center piece also has standoffs with screw holes which allows the PIR sensors to be securely attached to the 3d print. The other two main pieces are the two housings for the servos. These housing were designed with an extruding attachment part. this part allowed the servos to slide into place and then be attached using the screw holes which were also included in the 3D design. Lastly there where also to caps printed for the top and the bottom. Theses where made to allow the servos to have enough space for the TOF sensor and the light to be attached to. Furthermore it was made sure that there would be enough space for the 3D print not to interfere with the movement of either of the servos. | ||
+ | |||
+ | {{: | ||
+ | |||
+ | Figure 1: Picture of the PIR housing | ||
+ | |||
+ | {{: | ||
+ | |||
+ | Figure 2: Picture of the servo housing | ||
+ | |||
+ | {{: | ||
+ | |||
+ | Figure 3: Picture of the roof and floor | ||
+ | |||
+ | |||
+ | ==== Hardware Components ==== | ||
+ | '' | ||
+ | |||
+ | |||
+ | | Component | ||
+ | | ESP32 | Main microcontroller | ||
+ | | VL53L0X | ||
+ | | PIR sensors (2x) | Detect left/right motion | ||
+ | | Servos (2x) | Rotate ToF and LED for tracking | ||
+ | | NeoPixel LED | Light | | ||
+ | |||
+ | |||
+ | ==== Wireing ==== | ||
+ | '' | ||
+ | |||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | ==== Libraries Used ==== | ||
+ | '' | ||
+ | |||
+ | |||
+ | Adafruit_VL53L0X: | ||
+ | |||
+ | Adafruit_NeoPixel: | ||
+ | |||
+ | ESP32Servo: PWM servo motor control on ESP32. | ||
+ | |||
+ | |||
+ | ==== Logic ==== | ||
+ | '' | ||
+ | |||
+ | |||
+ | At startup, the system performs an initial environmental benchmark by scanning from 0° to 180°, saving the distance data for each angle. | ||
+ | |||
+ | ->Then it enters a loop waiting for PIR motion detection. | ||
+ | |||
+ | When motion is detected: | ||
+ | |||
+ | ->It determines direction (left or right PIR). | ||
+ | |||
+ | -> | ||
+ | |||
+ | If a significant difference from the benchmark is found: | ||
+ | |||
+ | ->It activates a white LED. | ||
+ | |||
+ | ->It moves a secondary servo to point an LED at the change. | ||
+ | |||
+ | The system re-benchmarks the environment every 5 minutes | ||
+ | |||
+ | |||
+ | ==== Code ==== | ||
+ | '' | ||
+ | |||
+ | |||
+ | <code java> | ||
+ | |||
+ | //--- include libaries --- | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | |||
+ | // --- Defines Pins --- | ||
+ | #define PIR_LEFT_PIN | ||
+ | #define PIR_RIGHT_PIN | ||
+ | #define LED_PIN | ||
+ | #define TOF_SERVO_PIN | ||
+ | #define LED_SERVO_PIN | ||
+ | |||
+ | // --- Constants --- | ||
+ | #define NUM_PIXELS | ||
+ | #define MAX_ANGLE | ||
+ | #define STEP_ANGLE | ||
+ | #define CHANGE_THRESHOLD | ||
+ | #define BENCHMARK_INTERVAL 300000 | ||
+ | #define PIR_DEBOUNCE_TIME | ||
+ | |||
+ | // --- Globals --- | ||
+ | Adafruit_VL53L0X lox = Adafruit_VL53L0X(); | ||
+ | Adafruit_NeoPixel pixels(NUM_PIXELS, | ||
+ | |||
+ | Servo tofServo; | ||
+ | Servo ledServo; | ||
+ | |||
+ | int benchmark[MAX_ANGLE + 1]; | ||
+ | bool scanning = false; | ||
+ | bool benchmarkReady = false; | ||
+ | int lastMotionDirection = -1; // 0 = left, 1 = right | ||
+ | unsigned long lastBenchmarkTime = 0; | ||
+ | unsigned long lastPirTime = 0; | ||
+ | |||
+ | // --- Function Prototypes --- | ||
+ | void lightUp(bool on); | ||
+ | void moveTofServo(int angle); | ||
+ | void moveLedServo(int angle); | ||
+ | void performBenchmark(); | ||
+ | bool scanMotion(int startAngle, int endAngle); | ||
+ | |||
+ | |||
+ | // | ||
+ | // | ||
+ | // PIR pins. | ||
+ | // ToF sensor in continuous mode. | ||
+ | // | ||
+ | // | ||
+ | // | ||
+ | |||
+ | void setup() { | ||
+ | Serial.begin(115200); | ||
+ | |||
+ | pinMode(PIR_LEFT_PIN, | ||
+ | pinMode(PIR_RIGHT_PIN, | ||
+ | |||
+ | if (!lox.begin()) { | ||
+ | Serial.println(F(" | ||
+ | while (1); | ||
+ | } | ||
+ | lox.startRangeContinuous(); | ||
+ | | ||
+ | | ||
+ | |||
+ | // Servos | ||
+ | ESP32PWM:: | ||
+ | ESP32PWM:: | ||
+ | ESP32PWM:: | ||
+ | ESP32PWM:: | ||
+ | tofServo.setPeriodHertz(50); | ||
+ | ledServo.setPeriodHertz(50); | ||
+ | tofServo.attach(TOF_SERVO_PIN, | ||
+ | ledServo.attach(LED_SERVO_PIN, | ||
+ | |||
+ | pixels.begin(); | ||
+ | pixels.setBrightness(100); | ||
+ | pixels.setPixelColor(0, | ||
+ | pixels.show(); | ||
+ | |||
+ | performBenchmark(); | ||
+ | } | ||
+ | |||
+ | void loop() { | ||
+ | unsigned long now = millis(); | ||
+ | |||
+ | // Re-benchmark every 5 minutes | ||
+ | if ((now - lastBenchmarkTime > BENCHMARK_INTERVAL) && !scanning) { | ||
+ | performBenchmark(); | ||
+ | } | ||
+ | |||
+ | // Motion detection with filtering | ||
+ | //Checks if PIRs are triggered over 300ms to reduce false positives. Triggers scanning only if a direction is confidently detected. | ||
+ | if (!scanning && benchmarkReady) { | ||
+ | if ((now - lastPirTime) > PIR_DEBOUNCE_TIME) { | ||
+ | bool leftTriggered = false; | ||
+ | bool rightTriggered = false; | ||
+ | |||
+ | // Read the PIR pins multiple times over ~300ms | ||
+ | for (int i = 0; i < 6; i++) { | ||
+ | if (digitalRead(PIR_LEFT_PIN) == HIGH) leftTriggered = true; | ||
+ | if (digitalRead(PIR_RIGHT_PIN) == HIGH) rightTriggered = true; | ||
+ | delay(50); // 6 × 50ms = 300ms total sampling | ||
+ | } | ||
+ | |||
+ | if (leftTriggered) { | ||
+ | Serial.println(" | ||
+ | lastMotionDirection = 0; | ||
+ | scanning = true; | ||
+ | lastPirTime = now; | ||
+ | } else if (rightTriggered) { | ||
+ | Serial.println(" | ||
+ | lastMotionDirection = 1; | ||
+ | scanning = true; | ||
+ | lastPirTime = now; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Start scanning Sweeps back and forth. Scans until it finds two consecutive sweeps with no changes. | ||
+ | if (scanning) { | ||
+ | int noChangeSweeps = 0; | ||
+ | int start = (lastMotionDirection == 0) ? 0 : 90; | ||
+ | int end = MAX_ANGLE; | ||
+ | |||
+ | while (noChangeSweeps < 2) { | ||
+ | Serial.printf(" | ||
+ | bool changed = scanMotion(start, | ||
+ | if (changed) { | ||
+ | noChangeSweeps = 0; | ||
+ | } else { | ||
+ | noChangeSweeps++; | ||
+ | } | ||
+ | |||
+ | // Reverse sweep direction for next run | ||
+ | int temp = start; | ||
+ | start = end; | ||
+ | end = temp; | ||
+ | } | ||
+ | |||
+ | Serial.println(" | ||
+ | lightUp(false); | ||
+ | scanning = false; | ||
+ | } | ||
+ | } | ||
+ | // Sweeps 0°–180°, | ||
+ | void performBenchmark() { | ||
+ | Serial.println(" | ||
+ | for (int angle = 0; angle <= MAX_ANGLE; angle += STEP_ANGLE) { | ||
+ | moveTofServo(angle); | ||
+ | delay(15); | ||
+ | int dist = lox.readRange(); | ||
+ | if (dist == 0) { | ||
+ | angle -= STEP_ANGLE; | ||
+ | continue; // Retry this angle | ||
+ | } | ||
+ | benchmark[angle] = dist; | ||
+ | Serial.printf(" | ||
+ | } | ||
+ | benchmarkReady = true; | ||
+ | lastBenchmarkTime = millis(); | ||
+ | Serial.println(" | ||
+ | } | ||
+ | //Reads distance at each angle. | ||
+ | //Compares it with the benchmark value. | ||
+ | //If difference > CHANGE_THRESHOLD (100 mm): Activates LED | ||
+ | //Moves LED servo to angle (inverted) | ||
+ | |||
+ | bool scanMotion(int startAngle, int endAngle) { | ||
+ | bool foundChange = false; | ||
+ | int step = (startAngle < endAngle) ? STEP_ANGLE : -STEP_ANGLE; | ||
+ | |||
+ | for (int angle = startAngle; angle != endAngle + step; angle += step) { | ||
+ | moveTofServo(angle); | ||
+ | delay(15); | ||
+ | int distance = lox.readRange(); | ||
+ | if (distance == 0) continue; | ||
+ | |||
+ | int diff = abs(distance - benchmark[angle]); | ||
+ | if (diff > CHANGE_THRESHOLD) { | ||
+ | Serial.printf(" | ||
+ | moveLedServo(angle); | ||
+ | lightUp(true); | ||
+ | foundChange = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if (!foundChange) { | ||
+ | lightUp(false); | ||
+ | } | ||
+ | |||
+ | return foundChange; | ||
+ | } | ||
+ | |||
+ | void moveTofServo(int angle) { | ||
+ | tofServo.write(angle); | ||
+ | } | ||
+ | |||
+ | void moveLedServo(int angle) { | ||
+ | ledServo.write(160 - angle); // Inverted to match orientation | ||
+ | } | ||
+ | |||
+ | void lightUp(bool on) { | ||
+ | if (on) { | ||
+ | pixels.setPixelColor(0, | ||
+ | } else { | ||
+ | pixels.setPixelColor(0, | ||
+ | } | ||
+ | pixels.show(); | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | ==== Discussion ==== | ||
+ | '' | ||
+ | |||
+ | The smart sight light project successfully demonstrates the integration of motion detection and directional lighting to create a responsive and energy-efficient lighting system.\\ | ||
+ | The core idea of the project is to provide illumination only when and where it is needed. This is achieved through the use of sensors that detect the presence of a person and activate the light only in the area immediately in front of them. As the person moves, the lighting follows, ensuring continuous visibility while minimizing unnecessary illumination.\\ | ||
+ | This targeted approach to lighting offers several clear advantages. First, it significantly reduces light pollution, which is an increasing concern in both urban and residential environments. By avoiding the illumination of unused areas, the system ensures that the surrounding environment remains dark, preserving natural night conditions for humans, wildlife, and also astronomy. Second, the system leads to lower energy consumption, | ||
+ | Throughout the development process, certain challenges were encountered, | ||
+ | Additionally, | ||
+ | |||
+ | ==== Concept, 3D-Modeling, | ||
+ | '' | ||
+ | \\ | ||
+ | {{ : | ||
+ | \\ | ||
+ | |||
+ | |||
+ | ==== Conclusion ==== | ||
+ | '' | ||
+ | |||
+ | The development of the smart sight light system has shown how combining sensor technology with targeted lighting control can lead to practical and energy-efficient solutions. By illuminating only the path in front of a moving person, it reduces both power consumption and light pollution, while still ensuring safety and visibility for people walking in its scanning area.\\ | ||
+ | Overall, the project has provided valuable insights into sensor integration, | ||
+ | |||
+ | |||
+ | |||
amc/ss2025/group-x/start.1753736681.txt.gz · Last modified: 2025/07/28 23:04 by emir-talha.fidan