Advertisement
Guest User

ESP32 Code

a guest
May 9th, 2025
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.32 KB | None | 0 0
  1. #include <WiFi.h>
  2. #include <WebServer.h>
  3.  
  4. //--------Pin definitions for Sensors-------
  5. #define SENSOR1 0
  6. #define SENSOR2 1
  7. #define SENSOR3 2
  8. #define SENSOR4 3
  9. #define SENSOR5 4
  10. //------------------------------------------
  11.  
  12. //--------Pin definitions for the TB6612FNG Motor Driver----
  13. #define AIN1 5
  14. #define AIN2 6
  15. #define BIN1 7
  16. #define BIN2 8
  17. #define PWMA 9
  18. #define PWMB 10
  19. //------------------------------------------------------------
  20.  
  21. //--------WiFi Configuration--------
  22. const char* ssid = "Pranav's Line Follower";
  23. const char* password = "DogBalls69";
  24. WebServer server(80);
  25. //---------------------------------
  26.  
  27. //--------Enter Line Details here---------
  28. bool isBlackLine = 1; //keep 1 in case of black line. In case of white line change this to 0
  29. unsigned int lineThickness = 15; //Enter line thickness in mm. Works best for thickness between 10 & 35
  30. const unsigned int numSensors = 5; // Using 5 sensors as requested
  31. //-----------------------------------------
  32.  
  33. int P, D, I, previousError, PIDvalue;
  34. double error;
  35. int lsp, rsp;
  36. int lfSpeed = 150;
  37. int currentSpeed = 30;
  38. int sensorWeight[5] = { 4, 2, 0, -2, -4 };
  39. int activeSensors;
  40. float Kp = 0.08;
  41. float Kd = 0.15;
  42. float Ki = 0;
  43.  
  44. int onLine = 1;
  45. int minValues[5], maxValues[5], threshold[5];
  46. int sensorValue[5], sensorArray[5];
  47.  
  48. bool isCalibrating = false;
  49. bool isRunning = false;
  50.  
  51. String webPage = "";
  52. String debugLog = ""; // Log to store debug messages
  53.  
  54. void setup() {
  55. Serial.begin(115200);
  56.  
  57. // Initialize motor driver pins
  58. pinMode(AIN1, OUTPUT);
  59. pinMode(AIN2, OUTPUT);
  60. pinMode(BIN1, OUTPUT);
  61. pinMode(BIN2, OUTPUT);
  62. pinMode(PWMA, OUTPUT);
  63. pinMode(PWMB, OUTPUT);
  64.  
  65. // Initialize sensor pins
  66. pinMode(SENSOR1, INPUT);
  67. pinMode(SENSOR2, INPUT);
  68. pinMode(SENSOR3, INPUT);
  69. pinMode(SENSOR4, INPUT);
  70. pinMode(SENSOR5, INPUT);
  71.  
  72. // Set up proper PWM initialization
  73. /* ledcSetup(0, 5000, 8); // Channel 0, 5kHz, 8-bit resolution
  74. ledcSetup(1, 5000, 8); // Channel 1, 5kHz, 8-bit resolution
  75. ledcAttachPin(PWMA, 0); // Attach PWMA to channel 0
  76. ledcAttachPin(PWMB, 1); // Attach PWMB to channel 1 */
  77.  
  78. if (!ledcAttach(PWMA, 5000, 8)) {
  79. Serial.println("LEDC attach failed!");
  80. }
  81. // Similarly for PWMB:
  82. if (!ledcAttach(PWMB, 5000, 8)) {
  83. Serial.println("LEDC attach failed!");
  84. }
  85.  
  86. // Set up WiFi Access Point
  87. WiFi.softAP(ssid, password);
  88. IPAddress myIP = WiFi.softAPIP();
  89. Serial.print("AP IP address: ");
  90. Serial.println(myIP);
  91. logMessage("AP IP address: " + myIP.toString());
  92.  
  93. // Set up Web Server routes
  94. server.on("/", handleRoot);
  95. server.on("/calibrate", handleCalibrate);
  96. server.on("/start", handleStart);
  97. server.on("/stop", handleStop);
  98. server.on("/sensors", handleSensors);
  99. server.on("/logs", handleLogs);
  100. server.on("/clearlogs", handleClearLogs);
  101. server.begin();
  102. Serial.println("HTTP server started");
  103. logMessage("HTTP server started");
  104.  
  105. lineThickness = constrain(lineThickness, 10, 35);
  106. }
  107.  
  108. void loop() {
  109. server.handleClient();
  110.  
  111. if (isCalibrating) {
  112. calibrate();
  113. isCalibrating = false;
  114. }
  115.  
  116. if (isRunning) {
  117. readLine();
  118. if (currentSpeed < lfSpeed) currentSpeed++;
  119.  
  120. if (onLine == 1) { // PID LINE FOLLOW
  121. linefollow();
  122. } else {
  123. if (error > 0) {
  124. motor1run(-50);
  125. motor2run(lfSpeed);
  126. } else {
  127. motor1run(lfSpeed);
  128. motor2run(-50);
  129. }
  130. }
  131. } else {
  132. // Stop motors when not running
  133. motor1run(0);
  134. motor2run(0);
  135. }
  136. }
  137.  
  138. void handleRoot() {
  139. buildWebPage();
  140. server.send(200, "text/html", webPage);
  141. }
  142.  
  143. void handleCalibrate() {
  144. isCalibrating = true;
  145. isRunning = false;
  146. logMessage("Starting calibration...");
  147. server.sendHeader("Location", "/");
  148. server.send(303);
  149. }
  150.  
  151. void handleStart() {
  152. isRunning = true;
  153. logMessage("Robot started");
  154. server.sendHeader("Location", "/");
  155. server.send(303);
  156. }
  157.  
  158. void handleStop() {
  159. isRunning = false;
  160. logMessage("Robot stopped");
  161. server.sendHeader("Location", "/");
  162. server.send(303);
  163. }
  164.  
  165. void handleSensors() {
  166. String sensorJSON = "{";
  167. for (int i = 0; i < numSensors; i++) {
  168. int rawValue = analogRead(i);
  169. sensorJSON += "\"sensor" + String(i+1) + "\":{";
  170. sensorJSON += "\"raw\":" + String(rawValue) + ",";
  171. if (isRunning) {
  172. sensorJSON += "\"processed\":" + String(sensorValue[i]) + ",";
  173. sensorJSON += "\"binary\":" + String(sensorArray[i]);
  174. } else {
  175. sensorJSON += "\"processed\":0,";
  176. sensorJSON += "\"binary\":0";
  177. }
  178. sensorJSON += "}";
  179. if (i < numSensors-1) sensorJSON += ",";
  180. }
  181. sensorJSON += "}";
  182.  
  183. server.send(200, "application/json", sensorJSON);
  184. }
  185.  
  186. void handleLogs() {
  187. server.send(200, "text/plain", debugLog);
  188. }
  189.  
  190. void handleClearLogs() {
  191. debugLog = "";
  192. logMessage("Logs cleared");
  193. server.sendHeader("Location", "/");
  194. server.send(303);
  195. }
  196.  
  197. // Function to add messages to both Serial and web debug log
  198. void logMessage(String message) {
  199. String timestamp = String(millis() / 1000.0, 2);
  200. String logEntry = "[" + timestamp + "s] " + message + "\n";
  201.  
  202. Serial.print(logEntry);
  203.  
  204. // Keep log size manageable (limit to last ~5000 chars)
  205. if (debugLog.length() > 5000) {
  206. int cutPoint = debugLog.indexOf('\n', debugLog.length() - 4000);
  207. if (cutPoint > 0) {
  208. debugLog = debugLog.substring(cutPoint + 1);
  209. }
  210. }
  211.  
  212. debugLog += logEntry;
  213. }
  214.  
  215. void buildWebPage() {
  216. webPage = "<!DOCTYPE html>";
  217. webPage += "<html lang='en'>";
  218. webPage += "<head>";
  219. webPage += "<meta charset='UTF-8'>";
  220. webPage += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
  221. webPage += "<title>Line Follower Robot</title>";
  222. webPage += "<style>";
  223. webPage += "body { font-family: Arial, sans-serif; margin: 0; padding: 20px; max-width: 800px; margin: 0 auto; }";
  224. webPage += "h1 { color: #333; }";
  225. webPage += ".button { display: inline-block; background-color: #4CAF50; color: white; padding: 10px 20px; ";
  226. webPage += "text-align: center; text-decoration: none; font-size: 16px; margin: 4px 2px; cursor: pointer; border-radius: 4px; }";
  227. webPage += ".button.red { background-color: #f44336; }";
  228. webPage += ".button.blue { background-color: #2196F3; }";
  229. webPage += ".button.gray { background-color: #9e9e9e; }";
  230. webPage += ".sensors { margin-top: 20px; }";
  231. webPage += ".sensor-bar { height: 30px; margin: 5px 0; background-color: #ddd; position: relative; }";
  232. webPage += ".sensor-value { height: 100%; width: 0%; background-color: #4CAF50; position: absolute; left: 0; transition: width 0.3s ease; }";
  233. webPage += ".sensor-binary { width: 30px; height: 30px; display: inline-block; border-radius: 50%; margin-right: 10px; }";
  234. webPage += ".sensor-label { font-weight: bold; }";
  235. webPage += ".debug-log { margin-top: 20px; background-color: #f5f5f5; padding: 10px; border-radius: 4px; height: 200px; overflow-y: auto; font-family: monospace; white-space: pre-wrap; }";
  236. webPage += ".tabs { display: flex; border-bottom: 1px solid #ccc; margin-top: 20px; }";
  237. webPage += ".tab { padding: 10px 20px; cursor: pointer; background-color: #f1f1f1; border: 1px solid #ccc; border-bottom: none; margin-right: 5px; border-radius: 4px 4px 0 0; }";
  238. webPage += ".tab.active { background-color: white; border-bottom: 1px solid white; margin-bottom: -1px; }";
  239. webPage += ".tab-content { display: none; padding: 20px; border: 1px solid #ccc; border-top: none; }";
  240. webPage += ".tab-content.active { display: block; }";
  241. webPage += "</style>";
  242. webPage += "</head>";
  243. webPage += "<body>";
  244. webPage += "<h1>Line Follower Robot Control</h1>";
  245. webPage += "<div class='controls'>";
  246. webPage += "<a href='/calibrate' class='button blue'>Calibrate</a> ";
  247.  
  248. if (isRunning) {
  249. webPage += "<a href='/stop' class='button red'>Stop</a>";
  250. } else {
  251. webPage += "<a href='/start' class='button'>Start</a>";
  252. }
  253.  
  254. webPage += "</div>";
  255.  
  256. webPage += "<div class='tabs'>";
  257. webPage += "<div class='tab active' onclick='openTab(\"sensors-tab\")'>Sensors</div>";
  258. webPage += "<div class='tab' onclick='openTab(\"status-tab\")'>Status</div>";
  259. webPage += "<div class='tab' onclick='openTab(\"debug-tab\")'>Debug Log</div>";
  260. webPage += "</div>";
  261.  
  262. webPage += "<div id='sensors-tab' class='tab-content active'>";
  263. webPage += "<h2>Sensor Values</h2>";
  264. webPage += "<div class='sensors'>";
  265.  
  266. for (int i = 0; i < numSensors; i++) {
  267. webPage += "<div class='sensor'>";
  268. webPage += "<div class='sensor-label'>Sensor " + String(i+1) + ":</div>";
  269. webPage += "<div class='sensor-bar'><div class='sensor-value' id='value" + String(i+1) + "'></div></div>";
  270. webPage += "<div>Raw: <span id='raw" + String(i+1) + "'>0</span>, ";
  271. webPage += "Processed: <span id='processed" + String(i+1) + "'>0</span></div>";
  272. webPage += "<div class='sensor-binary' id='binary" + String(i+1) + "'></div>";
  273. webPage += "</div>";
  274. }
  275.  
  276. webPage += "</div>";
  277. webPage += "</div>";
  278.  
  279. webPage += "<div id='status-tab' class='tab-content'>";
  280. webPage += "<h2>Status</h2>";
  281. webPage += "<div>On Line: <span id='onLine'>No</span></div>";
  282. webPage += "<div>Error: <span id='error'>0</span></div>";
  283. webPage += "<div>Left Speed: <span id='leftSpeed'>0</span></div>";
  284. webPage += "<div>Right Speed: <span id='rightSpeed'>0</span></div>";
  285. webPage += "</div>";
  286.  
  287. webPage += "<div id='debug-tab' class='tab-content'>";
  288. webPage += "<h2>Debug Log</h2>";
  289. webPage += "<div class='debug-controls'>";
  290. webPage += "<a href='/clearlogs' class='button gray'>Clear Logs</a>";
  291. webPage += "</div>";
  292. webPage += "<div class='debug-log' id='debug-log'></div>";
  293. webPage += "</div>";
  294.  
  295. webPage += "<script>";
  296. webPage += "function openTab(tabId) {";
  297. webPage += " const tabs = document.getElementsByClassName('tab');";
  298. webPage += " for (let i = 0; i < tabs.length; i++) {";
  299. webPage += " tabs[i].classList.remove('active');";
  300. webPage += " }";
  301. webPage += " const tabContents = document.getElementsByClassName('tab-content');";
  302. webPage += " for (let i = 0; i < tabContents.length; i++) {";
  303. webPage += " tabContents[i].classList.remove('active');";
  304. webPage += " }";
  305. webPage += " document.getElementById(tabId).classList.add('active');";
  306. webPage += " if (tabId === 'sensors-tab') {";
  307. webPage += " document.getElementsByClassName('tab')[0].classList.add('active');";
  308. webPage += " } else if (tabId === 'status-tab') {";
  309. webPage += " document.getElementsByClassName('tab')[1].classList.add('active');";
  310. webPage += " } else if (tabId === 'debug-tab') {";
  311. webPage += " document.getElementsByClassName('tab')[2].classList.add('active');";
  312. webPage += " updateDebugLog();";
  313. webPage += " }";
  314. webPage += "}";
  315.  
  316. webPage += "function updateSensors() {";
  317. webPage += " fetch('/sensors')";
  318. webPage += " .then(response => response.json())";
  319. webPage += " .then(data => {";
  320. webPage += " for (let i = 1; i <= " + String(numSensors) + "; i++) {";
  321. webPage += " const sensor = data['sensor'+i];";
  322. webPage += " document.getElementById('raw'+i).textContent = sensor.raw;";
  323. webPage += " document.getElementById('processed'+i).textContent = sensor.processed;";
  324. webPage += " document.getElementById('value'+i).style.width = (sensor.processed/10) + '%';";
  325. webPage += " document.getElementById('binary'+i).style.backgroundColor = sensor.binary ? '#4CAF50' : '#f44336';";
  326. webPage += " }";
  327. webPage += " });";
  328. webPage += "}";
  329.  
  330. webPage += "function updateDebugLog() {";
  331. webPage += " fetch('/logs')";
  332. webPage += " .then(response => response.text())";
  333. webPage += " .then(data => {";
  334. webPage += " const logElement = document.getElementById('debug-log');";
  335. webPage += " logElement.textContent = data;";
  336. webPage += " logElement.scrollTop = logElement.scrollHeight;";
  337. webPage += " });";
  338. webPage += "}";
  339.  
  340. webPage += "setInterval(updateSensors, 200);";
  341. webPage += "setInterval(() => {";
  342. webPage += " if (document.getElementById('debug-tab').classList.contains('active')) {";
  343. webPage += " updateDebugLog();";
  344. webPage += " }";
  345. webPage += "}, 1000);";
  346. webPage += "</script>";
  347. webPage += "</body></html>";
  348. }
  349.  
  350. void linefollow() {
  351. error = 0;
  352. activeSensors = 0;
  353.  
  354. for (int i = 0; i < numSensors; i++) {
  355. error += sensorWeight[i] * sensorArray[i] * sensorValue[i];
  356. activeSensors += sensorArray[i];
  357. }
  358.  
  359. if (activeSensors > 0) {
  360. error = error / activeSensors;
  361. }
  362.  
  363. P = error;
  364. I = constrain(I + error, -100, 100); // Add bounds to prevent integral windup
  365. D = error - previousError;
  366.  
  367. PIDvalue = (Kp * P) + (Ki * I) + (Kd * D);
  368. previousError = error;
  369.  
  370. lsp = currentSpeed - PIDvalue;
  371. rsp = currentSpeed + PIDvalue;
  372.  
  373. lsp = constrain(lsp, 0, 255);
  374. rsp = constrain(rsp, 0, 255);
  375.  
  376. motor1run(lsp);
  377. motor2run(rsp);
  378. }
  379.  
  380. void calibrate() {
  381. logMessage("Starting calibration process...");
  382.  
  383. // Initialize min/max values
  384. for (int i = 0; i < numSensors; i++) {
  385. minValues[i] = analogRead(i);
  386. maxValues[i] = analogRead(i);
  387. }
  388.  
  389. // Calibration routine - turn in place while reading min/max values
  390. for (int i = 0; i < 3000; i++) {
  391. motor1run(50);
  392. motor2run(-50);
  393.  
  394. for (int j = 0; j < numSensors; j++) {
  395. int value = analogRead(j);
  396. if (value < minValues[j]) {
  397. minValues[j] = value;
  398. }
  399. if (value > maxValues[j]) {
  400. maxValues[j] = value;
  401. }
  402. }
  403. delay(2);
  404. }
  405.  
  406. // Calculate thresholds
  407. String thresholdValues = "Thresholds: ";
  408. for (int i = 0; i < numSensors; i++) {
  409. threshold[i] = (minValues[i] + maxValues[i]) / 2;
  410. thresholdValues += threshold[i];
  411. if (i < numSensors - 1) thresholdValues += ", ";
  412. }
  413. logMessage(thresholdValues);
  414.  
  415. // Stop motors after calibration
  416. motor1run(0);
  417. motor2run(0);
  418. logMessage("Calibration complete");
  419. }
  420.  
  421. void readLine() {
  422. onLine = 0;
  423.  
  424. for (int i = 0; i < numSensors; i++) {
  425. int rawValue = analogRead(i);
  426.  
  427. if (isBlackLine) {
  428. sensorValue[i] = map(rawValue, minValues[i], maxValues[i], 0, 1000);
  429. } else {
  430. sensorValue[i] = map(rawValue, minValues[i], maxValues[i], 1000, 0);
  431. }
  432.  
  433. sensorValue[i] = constrain(sensorValue[i], 0, 1000);
  434. sensorArray[i] = sensorValue[i] > 500;
  435.  
  436. if (sensorArray[i]) {
  437. onLine = 1;
  438. }
  439. }
  440. }
  441.  
  442. //--------Function to run Motor 1-----------------
  443. void motor1run(int motorSpeed) {
  444. motorSpeed = constrain(motorSpeed, -255, 255);
  445. if (motorSpeed > 0) {
  446. digitalWrite(AIN1, 1);
  447. digitalWrite(AIN2, 0);
  448. ledcWrite(0, motorSpeed);
  449. } else if (motorSpeed < 0) {
  450. digitalWrite(AIN1, 0);
  451. digitalWrite(AIN2, 1);
  452. ledcWrite(0, abs(motorSpeed));
  453. } else {
  454. digitalWrite(AIN1, 1);
  455. digitalWrite(AIN2, 1);
  456. ledcWrite(0, 0);
  457. }
  458. }
  459.  
  460. //--------Function to run Motor 2-----------------
  461. void motor2run(int motorSpeed) {
  462. motorSpeed = constrain(motorSpeed, -255, 255);
  463. if (motorSpeed > 0) {
  464. digitalWrite(BIN1, 1);
  465. digitalWrite(BIN2, 0);
  466. ledcWrite(1, motorSpeed);
  467. } else if (motorSpeed < 0) {
  468. digitalWrite(BIN1, 0);
  469. digitalWrite(BIN2, 1);
  470. ledcWrite(1, abs(motorSpeed));
  471. } else {
  472. digitalWrite(BIN1, 1);
  473. digitalWrite(BIN2, 1);
  474. ledcWrite(1, 0);
  475. }
  476. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement