pleasedontcode

# Sensor Navigation rev_01

Mar 10th, 2026
35
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 25.61 KB | None | 0 0
  1. /********* Pleasedontcode.com **********
  2.  
  3.     Pleasedontcode thanks you for automatic code generation! Enjoy your code!
  4.  
  5.     - Terms and Conditions:
  6.     You have a non-exclusive, revocable, worldwide, royalty-free license
  7.     for personal and commercial use. Attribution is optional; modifications
  8.     are allowed, but you're responsible for code maintenance. We're not
  9.     liable for any loss or damage. For full terms,
  10.     please visit pleasedontcode.com/termsandconditions.
  11.  
  12.     - Project: # Sensor Navigation
  13.     - Version: 001
  14.     - Source Code NOT compiled for: Arduino Mega
  15.     - Source Code created on: 2026-03-10 05:35:10
  16.  
  17. ********* Pleasedontcode.com **********/
  18.  
  19. /****** SYSTEM REQUIREMENTS *****/
  20. /****** SYSTEM REQUIREMENT 1 *****/
  21.     /* Read 5 IR sensors (Left, FrontLeft, Center, */
  22.     /* FrontRight, Right) to detect path edges and walls */
  23.     /* using analog input */
  24. /****** SYSTEM REQUIREMENT 2 *****/
  25.     /* Use PID controller to calculate steering */
  26.     /* correction based on sensor difference between left */
  27.     /* and right sides to keep car centered on path */
  28. /****** SYSTEM REQUIREMENT 3 *****/
  29.     /* Control two DC motors (left and right) with PWM */
  30.     /* speed and direction pins to execute steering and */
  31.     /* forward movement */
  32. /****** SYSTEM REQUIREMENT 4 *****/
  33.     /* Display current sensor readings, PID error, and */
  34.     /* motor speeds on 16x4 I2C LCD in real-time for */
  35.     /* debugging */
  36. /****** SYSTEM REQUIREMENT 5 *****/
  37.     /* When front sensor detects wall (distance < 18cm), */
  38.     /* car STOPS and scans all sensors 5 times with 100ms */
  39.     /* delays. Only turn if side opening detected. */
  40.     /* Diagonal (FL/FR) and side (L/R) sensors must both */
  41.     /* confirm opening before turning. */
  42. /****** SYSTEM REQUIREMENT 6 *****/
  43.     /* During turns, reduce speed to 60 PWM and monitor */
  44.     /* front sensor. If front clears during turn, stop */
  45.     /* turning and resume wall-following. If wall */
  46.     /* detected while turning, complete 90° turn smoothly */
  47.     /* with timing compensation. */
  48. /****** SYSTEM REQUIREMENT 7 *****/
  49.     /* Car must maintain 8-12cm distance from walls while */
  50.     /* moving. Center between walls if corridor width */
  51.     /* allows. Use low PID gains (Kp=3) to prevent jerky */
  52.     /* corrections that cause corner hits. */
  53. /****** END SYSTEM REQUIREMENTS *****/
  54.  
  55.  
  56. // ===================================================
  57. // MAZE ROBOT – ADVANCED CORNER-SAFE NAVIGATION
  58. // Features: Pre-turn scanning, dual-sensor validation
  59. // Reduced PID Kp=3, Turn monitoring with early abort
  60. // ===================================================
  61.  
  62. #include <Wire.h>
  63. #include <LiquidCrystal_I2C.h>
  64.  
  65. LiquidCrystal_I2C lcd(0x27, 16, 4);
  66.  
  67. // -------- Sensors --------
  68. #define IR_LEFT        A0   // 180° (left side)
  69. #define IR_FRONTLEFT   A1   // 135° (front-left diagonal)
  70. #define IR_FRONT       A2   // 0°   (straight ahead)
  71. #define IR_FRONTRIGHT  A3   // 45°  (front-right diagonal)
  72. #define IR_RIGHT       A4   // 90°  (right side)
  73.  
  74. // -------- Motors --------
  75. #define ENA 5   // Right motor enable
  76. #define IN1 8   // Right motor input 1
  77. #define IN2 9   // Right motor input 2
  78. #define ENB 6   // Left motor enable
  79. #define IN3 10  // Left motor input 1
  80. #define IN4 11  // Left motor input 2
  81.  
  82. // ===================================================
  83. // ROBOT PARAMETERS - CORNER-SAFE TUNING
  84. // ===================================================
  85.  
  86. // Speed settings
  87. #define BASE_SPEED       80  // Normal cruising speed
  88. #define MIN_SPEED        65  // Minimum speed during correction
  89. #define CORNER_SPEED     65  // Speed at corners
  90. #define TURN_SPEED       60  // Speed during turns (REDUCED for safety)
  91.  
  92. // Distance thresholds (in cm)
  93. #define WALL_DETECT      20  // Distance to detect a wall
  94. #define FRONT_CLEAR      18  // Front is clear if > this
  95. #define FRONT_TURN       18  // Distance to prepare for turn
  96. #define FRONT_STOP       20  // Emergency stop distance
  97. #define WALL_IDEAL       8   // TARGET distance from side wall
  98. #define WALL_DEADBAND    2   // Deadband for corrections
  99. #define WALL_DANGER      4   // Dangerously close to wall
  100. #define WALL_FAR         12  // Too far from wall
  101. #define OPEN_SPACE       28  // Consider as open space
  102.  
  103. // PID constants - REDUCED FOR GENTLE CORRECTIONS
  104. #define KP               3.0 // Proportional gain (REDUCED from 5 to 3 for smooth gentle corrections)
  105. #define KD               2.0 // Derivative gain (REDUCED for smoothness)
  106. #define KI               0.05 // Integral gain (REDUCED for smoothness)
  107. #define CORRECTION_LIMIT 8   // Max correction per cycle (REDUCED from 10 to 8)
  108.  
  109. // Motor trim
  110. #define LEFT_MOTOR_TRIM  0
  111. #define RIGHT_MOTOR_TRIM 0
  112.  
  113. // Turn timing
  114. #define TURN_90_TIME     450
  115. #define TURN_PAUSE       200
  116.  
  117. // Pre-turn scanning parameters
  118. #define PRE_TURN_SCANS   5   // Number of consecutive reads for noise elimination
  119. #define SCAN_DELAY       100 // Milliseconds between scans (100ms as specified)
  120.  
  121. // Turn monitoring timeout
  122. #define TURN_TIMEOUT     500 // Maximum milliseconds for a 90 degree turn
  123. #define TURN_CHECK_INTERVAL 50 // Check front sensor every 50ms during turn
  124.  
  125. // ===================================================
  126. // GLOBAL VARIABLES
  127. // ===================================================
  128.  
  129. float L, FL, F, FR, R;
  130. float filteredL, filteredR;
  131.  
  132. // Arrays for pre-turn scanning - stores multiple sensor readings
  133. float scanL[PRE_TURN_SCANS];
  134. float scanFL[PRE_TURN_SCANS];
  135. float scanF[PRE_TURN_SCANS];
  136. float scanFR[PRE_TURN_SCANS];
  137. float scanR[PRE_TURN_SCANS];
  138.  
  139. // Averaged scan values
  140. float avgL, avgFL, avgF, avgFR, avgR;
  141.  
  142. // PID variables
  143. float wallError = 0;
  144. float prevWallError = 0;
  145. float wallIntegral = 0;
  146. float prevCorrection = 0;
  147. float correction = 0;
  148.  
  149. // Wall following state
  150. int followingWall = 0;  // 0 = none, 1 = left wall, 2 = right wall, 3 = both
  151. float wallDistance = 0;
  152. float targetDistance = WALL_IDEAL;
  153.  
  154. // Status strings
  155. String moveStr = "STOP";
  156. String stateStr = "IDLE";
  157. String turnStr = "-";
  158. String wallStr = "NONE";
  159. int currentLeftSpeed = 0;
  160. int currentRightSpeed = 0;
  161.  
  162. // Turn decision variables
  163. bool turning = false;
  164. unsigned long turnStartTime = 0;
  165. int turnDecision = 0;
  166. bool frontClearedDuringTurn = false;
  167.  
  168. // Anti-stall protection
  169. unsigned long lastMoveTime = 0;
  170. int stallCounter = 0;
  171.  
  172. // ===================================================
  173. // DISTANCE MEASUREMENT
  174. // ===================================================
  175.  
  176. float getDist(int pin) {
  177.   int adc = analogRead(pin);
  178.   if (adc < 30) adc = 30;
  179.   return 4800.0 / (adc - 20.0);
  180. }
  181.  
  182. // ===================================================
  183. // READ ALL SENSORS (SINGLE READ)
  184. // ===================================================
  185.  
  186. void readAllSensors() {
  187.   L  = getDist(IR_LEFT);
  188.   FL = getDist(IR_FRONTLEFT);
  189.   F  = getDist(IR_FRONT);
  190.   FR = getDist(IR_FRONTRIGHT);
  191.   R  = getDist(IR_RIGHT);
  192.  
  193.   // Simple filtering
  194.   static float lastL = 0, lastR = 0;
  195.   if (lastL == 0) {
  196.     lastL = L;
  197.     lastR = R;
  198.   } else {
  199.     L = (L + lastL) / 2;
  200.     R = (R + lastR) / 2;
  201.     lastL = L;
  202.     lastR = R;
  203.   }
  204.  
  205.   // Cap values for display
  206.   if (L > 99) L = 99;
  207.   if (FL > 99) FL = 99;
  208.   if (F > 99) F = 99;
  209.   if (FR > 99) FR = 99;
  210.   if (R > 99) R = 99;
  211. }
  212.  
  213. // ===================================================
  214. // PRE-TURN SENSOR SCANNING (NEW)
  215. // Performs 5 consecutive reads with 100ms delays
  216. // to eliminate noise and confirm wall detection
  217. // ===================================================
  218.  
  219. void performPreTurnScanning() {
  220.   Serial.println("\n=== PRE-TURN SCANNING (Noise Elimination) ===");
  221.  
  222.   // Perform 5 consecutive sensor reads with 100ms delays
  223.   for (int i = 0; i < PRE_TURN_SCANS; i++) {
  224.     readAllSensors();
  225.    
  226.     // Store readings in arrays
  227.     scanL[i] = L;
  228.     scanFL[i] = FL;
  229.     scanF[i] = F;
  230.     scanFR[i] = FR;
  231.     scanR[i] = R;
  232.    
  233.     Serial.print("Scan "); Serial.print(i + 1);
  234.     Serial.print(": F="); Serial.print(F);
  235.     Serial.print(" FL="); Serial.print(FL);
  236.     Serial.print(" FR="); Serial.print(FR);
  237.     Serial.print(" L="); Serial.print(L);
  238.     Serial.print(" R="); Serial.println(R);
  239.    
  240.     // Delay 100ms between scans (except after last scan)
  241.     if (i < PRE_TURN_SCANS - 1) {
  242.       delay(SCAN_DELAY);
  243.     }
  244.   }
  245.  
  246.   // Calculate averages from the 5 scans
  247.   avgL = 0, avgFL = 0, avgF = 0, avgFR = 0, avgR = 0;
  248.  
  249.   for (int i = 0; i < PRE_TURN_SCANS; i++) {
  250.     avgL += scanL[i];
  251.     avgFL += scanFL[i];
  252.     avgF += scanF[i];
  253.     avgFR += scanFR[i];
  254.     avgR += scanR[i];
  255.   }
  256.  
  257.   avgL /= PRE_TURN_SCANS;
  258.   avgFL /= PRE_TURN_SCANS;
  259.   avgF /= PRE_TURN_SCANS;
  260.   avgFR /= PRE_TURN_SCANS;
  261.   avgR /= PRE_TURN_SCANS;
  262.  
  263.   Serial.println("\n=== AVERAGED RESULTS (After noise elimination) ===");
  264.   Serial.print("Avg F="); Serial.print(avgF);
  265.   Serial.print(" Avg FL="); Serial.print(avgFL);
  266.   Serial.print(" Avg FR="); Serial.print(avgFR);
  267.   Serial.print(" Avg L="); Serial.print(avgL);
  268.   Serial.print(" Avg R="); Serial.println(avgR);
  269. }
  270.  
  271. // ===================================================
  272. // DUAL-SENSOR VALIDATION (NEW)
  273. // Requires BOTH diagonal (FL/FR) AND side (L/R) sensors
  274. // to confirm opening before allowing turn
  275. // ===================================================
  276.  
  277. bool validateOpeningDualSensor(bool leftTurn) {
  278.   Serial.println("\n=== DUAL-SENSOR VALIDATION ===");
  279.  
  280.   if (leftTurn) {
  281.     // For LEFT turn, check LEFT side
  282.     // BOTH diagonal (FL) AND side (L) must confirm opening
  283.     bool diagonalOpen = (avgFL > OPEN_SPACE);
  284.     bool sideOpen = (avgL > OPEN_SPACE);
  285.    
  286.     Serial.print("LEFT TURN - Diagonal (FL)="); Serial.print(avgFL);
  287.     Serial.print(" ["); Serial.print(diagonalOpen ? "OPEN" : "BLOCKED");
  288.     Serial.print("], Side (L)="); Serial.print(avgL);
  289.     Serial.print(" ["); Serial.print(sideOpen ? "OPEN" : "BLOCKED");
  290.     Serial.println("]");
  291.    
  292.     bool valid = (diagonalOpen && sideOpen);
  293.     Serial.print("LEFT TURN VALIDATION: ");
  294.     Serial.println(valid ? "VALID - PROCEED" : "INVALID - CANCEL");
  295.     return valid;
  296.   } else {
  297.     // For RIGHT turn, check RIGHT side
  298.     // BOTH diagonal (FR) AND side (R) must confirm opening
  299.     bool diagonalOpen = (avgFR > OPEN_SPACE);
  300.     bool sideOpen = (avgR > OPEN_SPACE);
  301.    
  302.     Serial.print("RIGHT TURN - Diagonal (FR)="); Serial.print(avgFR);
  303.     Serial.print(" ["); Serial.print(diagonalOpen ? "OPEN" : "BLOCKED");
  304.     Serial.print("], Side (R)="); Serial.print(avgR);
  305.     Serial.print(" ["); Serial.print(sideOpen ? "OPEN" : "BLOCKED");
  306.     Serial.println("]");
  307.    
  308.     bool valid = (diagonalOpen && sideOpen);
  309.     Serial.print("RIGHT TURN VALIDATION: ");
  310.     Serial.println(valid ? "VALID - PROCEED" : "INVALID - CANCEL");
  311.     return valid;
  312.   }
  313. }
  314.  
  315. // ===================================================
  316. // MOTOR CONTROL
  317. // ===================================================
  318.  
  319. void setMotorSpeeds(int leftSpeed, int rightSpeed) {
  320.   currentLeftSpeed = leftSpeed;
  321.   currentRightSpeed = rightSpeed;
  322.  
  323.   leftSpeed += LEFT_MOTOR_TRIM;
  324.   rightSpeed += RIGHT_MOTOR_TRIM;
  325.  
  326.   // ANTI-STALL PROTECTION - NEVER go below MIN_SPEED when moving forward
  327.   if (leftSpeed > 0 && leftSpeed < MIN_SPEED) leftSpeed = MIN_SPEED;
  328.   if (rightSpeed > 0 && rightSpeed < MIN_SPEED) rightSpeed = MIN_SPEED;
  329.  
  330.   leftSpeed = constrain(leftSpeed, -255, 255);
  331.   rightSpeed = constrain(rightSpeed, -255, 255);
  332.  
  333.   // Left motor
  334.   if (leftSpeed >= 0) {
  335.     digitalWrite(IN3, HIGH);
  336.     digitalWrite(IN4, LOW);
  337.     analogWrite(ENB, leftSpeed);
  338.   } else {
  339.     digitalWrite(IN3, LOW);
  340.     digitalWrite(IN4, HIGH);
  341.     analogWrite(ENB, -leftSpeed);
  342.   }
  343.  
  344.   // Right motor
  345.   if (rightSpeed >= 0) {
  346.     digitalWrite(IN1, HIGH);
  347.     digitalWrite(IN2, LOW);
  348.     analogWrite(ENA, rightSpeed);
  349.   } else {
  350.     digitalWrite(IN1, LOW);
  351.     digitalWrite(IN2, HIGH);
  352.     analogWrite(ENA, -rightSpeed);
  353.   }
  354.  
  355.   // Update last move time for anti-stall
  356.   if (leftSpeed != 0 || rightSpeed != 0) {
  357.     lastMoveTime = millis();
  358.   }
  359. }
  360.  
  361. void stopCar() {
  362.   setMotorSpeeds(0, 0);
  363.   moveStr = "STOP";
  364. }
  365.  
  366. void moveForward(int leftSpeed, int rightSpeed) {
  367.   setMotorSpeeds(leftSpeed, rightSpeed);
  368.   moveStr = "FORWARD";
  369. }
  370.  
  371. // ===================================================
  372. // ANTI-STALL CHECK
  373. // ===================================================
  374.  
  375. void checkForStall() {
  376.   // If we're trying to move but not making progress (detected by sensors)
  377.   if (!turning && (currentLeftSpeed > 0 || currentRightSpeed > 0)) {
  378.    
  379.     // Check if we're stuck against a wall
  380.     if (F < FRONT_STOP && currentLeftSpeed > 0 && currentRightSpeed > 0) {
  381.       stallCounter++;
  382.       if (stallCounter > 5) {
  383.         Serial.println("STALL DETECTED - Backing up");
  384.         // Back up a little
  385.         setMotorSpeeds(-MIN_SPEED, -MIN_SPEED);
  386.         delay(300);
  387.         stopCar();
  388.         delay(200);
  389.         stallCounter = 0;
  390.       }
  391.     } else {
  392.       stallCounter = 0;
  393.     }
  394.   }
  395. }
  396.  
  397. // ===================================================
  398. // TURN FUNCTIONS WITH MONITORING (ENHANCED)
  399. // Monitor front sensor during turn
  400. // If front clears, stop turning and resume wall-following
  401. // ===================================================
  402.  
  403. void turnLeft() {
  404.   stopCar();
  405.   delay(100);
  406.   stateStr = "TURN LEFT";
  407.   turnStr = "LEFT";
  408.   Serial.println(">>> EXECUTING: LEFT TURN WITH MONITORING <<<");
  409.  
  410.   frontClearedDuringTurn = false;
  411.   turnStartTime = millis();
  412.   unsigned long lastCheckTime = turnStartTime;
  413.  
  414.   // Execute turn with periodic front sensor monitoring
  415.   while (millis() - turnStartTime < TURN_90_TIME) {
  416.     unsigned long currentTime = millis();
  417.    
  418.     // Check front sensor every 50ms during turn
  419.     if (currentTime - lastCheckTime >= TURN_CHECK_INTERVAL) {
  420.       readAllSensors();
  421.       lastCheckTime = currentTime;
  422.      
  423.       // If front clears during turn, abort and resume wall-following
  424.       if (F > FRONT_CLEAR + 5) {
  425.         Serial.println("FRONT CLEARED DURING LEFT TURN - ABORTING TURN");
  426.         frontClearedDuringTurn = true;
  427.         break;
  428.       }
  429.     }
  430.    
  431.     // Continue turning at TURN_SPEED
  432.     setMotorSpeeds(-TURN_SPEED, TURN_SPEED);
  433.   }
  434.  
  435.   stopCar();
  436.   delay(TURN_PAUSE);
  437.   turning = false;
  438.   turnDecision = 0;
  439.   turnStr = "-";
  440. }
  441.  
  442. void turnRight() {
  443.   stopCar();
  444.   delay(100);
  445.   stateStr = "TURN RIGHT";
  446.   turnStr = "RIGHT";
  447.   Serial.println(">>> EXECUTING: RIGHT TURN WITH MONITORING <<<");
  448.  
  449.   frontClearedDuringTurn = false;
  450.   turnStartTime = millis();
  451.   unsigned long lastCheckTime = turnStartTime;
  452.  
  453.   // Execute turn with periodic front sensor monitoring
  454.   while (millis() - turnStartTime < TURN_90_TIME) {
  455.     unsigned long currentTime = millis();
  456.    
  457.     // Check front sensor every 50ms during turn
  458.     if (currentTime - lastCheckTime >= TURN_CHECK_INTERVAL) {
  459.       readAllSensors();
  460.       lastCheckTime = currentTime;
  461.      
  462.       // If front clears during turn, abort and resume wall-following
  463.       if (F > FRONT_CLEAR + 5) {
  464.         Serial.println("FRONT CLEARED DURING RIGHT TURN - ABORTING TURN");
  465.         frontClearedDuringTurn = true;
  466.         break;
  467.       }
  468.     }
  469.    
  470.     // Continue turning at TURN_SPEED
  471.     setMotorSpeeds(TURN_SPEED, -TURN_SPEED);
  472.   }
  473.  
  474.   stopCar();
  475.   delay(TURN_PAUSE);
  476.   turning = false;
  477.   turnDecision = 0;
  478.   turnStr = "-";
  479. }
  480.  
  481. void turnAround() {
  482.   stopCar();
  483.   delay(100);
  484.   stateStr = "U-TURN";
  485.   turnStr = "U";
  486.   Serial.println(">>> EXECUTING: U-TURN WITH MONITORING <<<");
  487.  
  488.   frontClearedDuringTurn = false;
  489.   turnStartTime = millis();
  490.   unsigned long lastCheckTime = turnStartTime;
  491.  
  492.   // Execute U-turn (180 degrees) with periodic monitoring
  493.   while (millis() - turnStartTime < (TURN_90_TIME * 2)) {
  494.     unsigned long currentTime = millis();
  495.    
  496.     // Check front sensor every 50ms during turn
  497.     if (currentTime - lastCheckTime >= TURN_CHECK_INTERVAL) {
  498.       readAllSensors();
  499.       lastCheckTime = currentTime;
  500.      
  501.       // For U-turn, only abort if front suddenly becomes very clear
  502.       if (F > FRONT_CLEAR + 10) {
  503.         Serial.println("FRONT CLEARED DURING U-TURN - CONTINUING (may be legitimate)");
  504.         // For U-turns, we don't abort since we're going backwards anyway
  505.       }
  506.     }
  507.    
  508.     // Continue U-turning at TURN_SPEED
  509.     setMotorSpeeds(-TURN_SPEED, TURN_SPEED);
  510.   }
  511.  
  512.   stopCar();
  513.   delay(TURN_PAUSE);
  514.   turning = false;
  515.   turnDecision = 0;
  516.   turnStr = "-";
  517. }
  518.  
  519. // ===================================================
  520. // WALL DETECTION
  521. // ===================================================
  522.  
  523. void selectWallToFollow() {
  524.   bool leftWallDetected = (L < WALL_DETECT);
  525.   bool rightWallDetected = (R < WALL_DETECT);
  526.  
  527.   if (leftWallDetected && rightWallDetected) {
  528.     followingWall = 3;
  529.     wallStr = "BOTH";
  530.     wallDistance = (L + R) / 2;
  531.   }
  532.   else if (leftWallDetected) {
  533.     followingWall = 1;
  534.     wallStr = "LEFT";
  535.     wallDistance = L;
  536.   }
  537.   else if (rightWallDetected) {
  538.     followingWall = 2;
  539.     wallStr = "RIGHT";
  540.     wallDistance = R;
  541.   }
  542.   else {
  543.     followingWall = 0;
  544.     wallStr = "NONE";
  545.   }
  546. }
  547.  
  548. // ===================================================
  549. // CONTINUOUS CENTERING CORRECTION
  550. // Uses REDUCED Kp=3 for smooth gentle corrections
  551. // ===================================================
  552.  
  553. void applyContinuousCentering() {
  554.   // Don't apply centering if we're turning
  555.   if (turning) return;
  556.  
  557.   int leftSpeed = BASE_SPEED;
  558.   int rightSpeed = BASE_SPEED;
  559.  
  560.   // EMERGENCY: Dangerously close to wall
  561.   if (L < WALL_DANGER || R < WALL_DANGER) {
  562.     stateStr = "AVOID";
  563.     if (L < WALL_DANGER) {
  564.       // Too close to left wall - steer RIGHT
  565.       rightSpeed = BASE_SPEED - 20;
  566.     } else {
  567.       // Too close to right wall - steer LEFT
  568.       leftSpeed = BASE_SPEED - 20;
  569.     }
  570.     moveForward(leftSpeed, rightSpeed);
  571.     return;
  572.   }
  573.  
  574.   // CASE 1: BOTH WALLS - Center between them
  575.   if (followingWall == 3) {
  576.     stateStr = "CENTER";
  577.     float centerError = R - L;
  578.    
  579.     if (abs(centerError) < WALL_DEADBAND) {
  580.       correction = 0;
  581.       wallIntegral = 0;
  582.     } else {
  583.       // Smooth P control with reduced Kp for gentle corrections
  584.       correction = centerError * KP * 0.8;
  585.       correction = constrain(correction, -CORRECTION_LIMIT, CORRECTION_LIMIT);
  586.     }
  587.    
  588.     leftSpeed = BASE_SPEED - correction;
  589.     rightSpeed = BASE_SPEED + correction;
  590.   }
  591.  
  592.   // CASE 2: ONLY LEFT WALL - Follow at exact distance
  593.   else if (followingWall == 1) {
  594.     stateStr = "FOLLOW L";
  595.     wallDistance = L;
  596.     float error = wallDistance - targetDistance;
  597.    
  598.     if (abs(error) < WALL_DEADBAND) {
  599.       correction = 0;
  600.     } else {
  601.       // Reduced Kp for smooth gentle wall following
  602.       correction = error * KP * 0.8;
  603.       correction = constrain(correction, -CORRECTION_LIMIT, CORRECTION_LIMIT);
  604.      
  605.       // Apply correction for LEFT wall
  606.       rightSpeed = BASE_SPEED - correction;
  607.     }
  608.   }
  609.  
  610.   // CASE 3: ONLY RIGHT WALL - Follow at exact distance
  611.   else if (followingWall == 2) {
  612.     stateStr = "FOLLOW R";
  613.     wallDistance = R;
  614.     float error = wallDistance - targetDistance;
  615.    
  616.     if (abs(error) < WALL_DEADBAND) {
  617.       correction = 0;
  618.     } else {
  619.       // Reduced Kp for smooth gentle wall following
  620.       correction = error * KP * 0.8;
  621.       correction = constrain(correction, -CORRECTION_LIMIT, CORRECTION_LIMIT);
  622.      
  623.       // Apply correction for RIGHT wall
  624.       leftSpeed = BASE_SPEED - correction;
  625.     }
  626.   }
  627.  
  628.   // CASE 4: NO WALLS - Go straight
  629.   else {
  630.     stateStr = "OPEN";
  631.     leftSpeed = BASE_SPEED;
  632.     rightSpeed = BASE_SPEED;
  633.     wallIntegral = 0;
  634.   }
  635.  
  636.   // Ensure minimum speed
  637.   leftSpeed = max(leftSpeed, MIN_SPEED);
  638.   rightSpeed = max(rightSpeed, MIN_SPEED);
  639.  
  640.   // Apply movement
  641.   moveForward(leftSpeed, rightSpeed);
  642. }
  643.  
  644. // ===================================================
  645. // TURN DECISION - ONLY TURN WHEN FRONT IS BLOCKED
  646. // WITH DUAL-SENSOR VALIDATION AND PRE-SCAN NOISE ELIMINATION
  647. // ===================================================
  648.  
  649. bool shouldTurn() {
  650.   // Don't check if already turning
  651.   if (turning) return false;
  652.  
  653.   // ONLY turn if front is actually blocked
  654.   bool frontBlocked = (F < FRONT_TURN);
  655.  
  656.   // If front is clear, NEVER turn
  657.   if (!frontBlocked) {
  658.     return false;
  659.   }
  660.  
  661.   // Front is blocked - check if sides are open
  662.   bool leftOpen = (L > OPEN_SPACE || FL > OPEN_SPACE);
  663.   bool rightOpen = (R > OPEN_SPACE || FR > OPEN_SPACE);
  664.  
  665.   // If at least one side is open, it's a turn
  666.   if (leftOpen || rightOpen) {
  667.     Serial.println("TURN NEEDED - Front blocked, side open");
  668.     return true;
  669.   }
  670.  
  671.   // If both sides are blocked, it's a dead end
  672.   Serial.println("DEAD END - Front and sides blocked");
  673.   return true;
  674. }
  675.  
  676. int decideTurnDirection() {
  677.   // Perform pre-turn scanning (5 reads with 100ms delays)
  678.   // This eliminates noise and ensures wall detection is accurate
  679.   performPreTurnScanning();
  680.  
  681.   Serial.println("\n=== TURN DECISION WITH DUAL-SENSOR VALIDATION ===");
  682.   Serial.print("Avg F="); Serial.print(avgF);
  683.   Serial.print(" Avg FL="); Serial.print(avgFL);
  684.   Serial.print(" Avg FR="); Serial.print(avgFR);
  685.   Serial.print(" Avg L="); Serial.print(avgL);
  686.   Serial.print(" Avg R="); Serial.println(avgR);
  687.  
  688.   float leftSpace = max(avgFL, avgL);
  689.   float rightSpace = max(avgFR, avgR);
  690.  
  691.   Serial.print("Left Space: "); Serial.print(leftSpace);
  692.   Serial.print(" Right Space: "); Serial.println(rightSpace);
  693.  
  694.   // Dead end - all sides blocked
  695.   if (leftSpace < FRONT_STOP && rightSpace < FRONT_STOP && avgF < FRONT_STOP) {
  696.     Serial.println("DEAD END - U-TURN");
  697.     return 3;
  698.   }
  699.  
  700.   // Evaluate turn directions
  701.   bool canTurnLeft = false;
  702.   bool canTurnRight = false;
  703.  
  704.   // LEFT TURN: Validate using dual-sensor validation
  705.   if (leftSpace > rightSpace + 2) {
  706.     canTurnLeft = validateOpeningDualSensor(true);
  707.   }
  708.  
  709.   // RIGHT TURN: Validate using dual-sensor validation
  710.   if (rightSpace > leftSpace + 2) {
  711.     canTurnRight = validateOpeningDualSensor(false);
  712.   }
  713.  
  714.   // If equal space, check both directions
  715.   if (abs(leftSpace - rightSpace) <= 2) {
  716.     canTurnLeft = validateOpeningDualSensor(true);
  717.     canTurnRight = validateOpeningDualSensor(false);
  718.   }
  719.  
  720.   // Choose valid turn direction
  721.   if (canTurnLeft && !canTurnRight) {
  722.     Serial.println("TURN LEFT - Validated");
  723.     return 1;
  724.   } else if (canTurnRight && !canTurnLeft) {
  725.     Serial.println("TURN RIGHT - Validated");
  726.     return 2;
  727.   } else if (canTurnLeft && canTurnRight) {
  728.     // Both valid - choose direction with more space
  729.     if (leftSpace > rightSpace) {
  730.       Serial.println("TURN LEFT - Both valid, more space on left");
  731.       return 1;
  732.     } else {
  733.       Serial.println("TURN RIGHT - Both valid, more space on right");
  734.       return 2;
  735.     }
  736.   } else {
  737.     // No valid direction - perform U-turn as fallback
  738.     Serial.println("NO VALID DIRECTION - U-TURN");
  739.     return 3;
  740.   }
  741. }
  742.  
  743. // ===================================================
  744. // LCD DISPLAY
  745. // ===================================================
  746.  
  747. void updateLCD() {
  748.   lcd.clear();
  749.  
  750.   lcd.setCursor(0, 0);
  751.   lcd.print("F:");
  752.   lcd.print((int)F);
  753.   lcd.print(" L:");
  754.   lcd.print((int)L);
  755.   lcd.print(" R:");
  756.   lcd.print((int)R);
  757.  
  758.   lcd.setCursor(0, 1);
  759.   lcd.print("FL:");
  760.   lcd.print((int)FL);
  761.   lcd.print(" FR:");
  762.   lcd.print((int)FR);
  763.  
  764.   lcd.setCursor(0, 2);
  765.   lcd.print(moveStr);
  766.   lcd.print(" ");
  767.   lcd.print(stateStr);
  768.   lcd.print(" ");
  769.   lcd.print(wallStr);
  770.  
  771.   lcd.setCursor(0, 3);
  772.   lcd.print("SPD:");
  773.   lcd.print(currentLeftSpeed);
  774.   lcd.print("/");
  775.   lcd.print(currentRightSpeed);
  776.  
  777.   // Serial debug - less frequent
  778.   static unsigned long lastDebug = 0;
  779.   if (millis() - lastDebug > 500) {
  780.     Serial.print("State:");
  781.     Serial.print(stateStr);
  782.     Serial.print(" F:");
  783.     Serial.print(F);
  784.     Serial.print(" L:");
  785.     Serial.print(L);
  786.     Serial.print(" R:");
  787.     Serial.print(R);
  788.     Serial.print(" Speed:");
  789.     Serial.print(currentLeftSpeed);
  790.     Serial.print("/");
  791.     Serial.println(currentRightSpeed);
  792.     lastDebug = millis();
  793.   }
  794. }
  795.  
  796. // ===================================================
  797. // SETUP
  798. // ===================================================
  799.  
  800. void setup() {
  801.   pinMode(ENA, OUTPUT);
  802.   pinMode(IN1, OUTPUT);
  803.   pinMode(IN2, OUTPUT);
  804.   pinMode(ENB, OUTPUT);
  805.   pinMode(IN3, OUTPUT);
  806.   pinMode(IN4, OUTPUT);
  807.  
  808.   lcd.init();
  809.   lcd.backlight();
  810.   lcd.clear();
  811.   lcd.print("ADVANCED CORNER");
  812.   lcd.setCursor(0, 1);
  813.   lcd.print("SAFE NAVIGATOR");
  814.   lcd.setCursor(0, 2);
  815.   lcd.print("v5.0 FINAL");
  816.   delay(2500);
  817.   lcd.clear();
  818.  
  819.   Serial.begin(9600);
  820.   Serial.println("\n=== ADVANCED CORNER-SAFE NAVIGATION ===");
  821.   Serial.println("Features:");
  822.   Serial.println("- Pre-turn scanning (5 reads, 100ms delays)");
  823.   Serial.println("- Dual-sensor validation (diagonal + side)");
  824.   Serial.println("- Reduced Kp=3 for smooth corrections");
  825.   Serial.println("- Turn monitoring with early abort");
  826.   Serial.println("====================================\n");
  827.  
  828.   readAllSensors();
  829.   delay(500);
  830. }
  831.  
  832. // ===================================================
  833. // MAIN LOOP - ADVANCED CORNER-SAFE NAVIGATION
  834. // ===================================================
  835.  
  836. void loop() {
  837.   // Read sensors
  838.   readAllSensors();
  839.  
  840.   // Select which wall to follow
  841.   selectWallToFollow();
  842.  
  843.   // ANTI-STALL: Check if we're stuck
  844.   checkForStall();
  845.  
  846.   // DECISION MAKING - WITH ADVANCED VALIDATION
  847.   if (!turning) {
  848.     // Check if we need to turn (ONLY when front is actually blocked)
  849.     if (F < FRONT_TURN) {
  850.       // Front is blocked - we need to make a decision
  851.       turning = true;
  852.       stopCar();
  853.       delay(300);
  854.      
  855.       // Decide turn direction with pre-scan and dual-sensor validation
  856.       turnDecision = decideTurnDirection();
  857.      
  858.       // Execute the turn with monitoring
  859.       if (turnDecision == 1) {
  860.         turnLeft();
  861.        
  862.         // If front cleared during turn, resume wall-following instead of continuing
  863.         if (frontClearedDuringTurn) {
  864.           Serial.println("Resuming wall-following after turn abort");
  865.           stateStr = "RESUME";
  866.         }
  867.       } else if (turnDecision == 2) {
  868.         turnRight();
  869.        
  870.         // If front cleared during turn, resume wall-following instead of continuing
  871.         if (frontClearedDuringTurn) {
  872.           Serial.println("Resuming wall-following after turn abort");
  873.           stateStr = "RESUME";
  874.         }
  875.       } else {
  876.         turnAround();
  877.       }
  878.     }
  879.     else {
  880.       // Front is clear - just do wall following/centering
  881.       applyContinuousCentering();
  882.     }
  883.   }
  884.  
  885.   // Update display
  886.   updateLCD();
  887.  
  888.   // Small delay for stability
  889.   delay(50);
  890. }
  891.  
  892. /* END CODE */
  893.  
Advertisement
Add Comment
Please, Sign In to add comment