Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <WiFi.h>
- #include <WebServer.h>
- //--------Pin definitions for Sensors-------
- #define SENSOR1 0
- #define SENSOR2 1
- #define SENSOR3 2
- #define SENSOR4 3
- #define SENSOR5 4
- //------------------------------------------
- //--------Pin definitions for the TB6612FNG Motor Driver----
- #define AIN1 5
- #define AIN2 6
- #define BIN1 7
- #define BIN2 8
- #define PWMA 9
- #define PWMB 10
- //------------------------------------------------------------
- //--------WiFi Configuration--------
- const char* ssid = "Pranav's Line Follower";
- const char* password = "DogBalls69";
- WebServer server(80);
- //---------------------------------
- //--------Enter Line Details here---------
- bool isBlackLine = 1; //keep 1 in case of black line. In case of white line change this to 0
- unsigned int lineThickness = 15; //Enter line thickness in mm. Works best for thickness between 10 & 35
- const unsigned int numSensors = 5; // Using 5 sensors as requested
- //-----------------------------------------
- int P, D, I, previousError, PIDvalue;
- double error;
- int lsp, rsp;
- int lfSpeed = 150;
- int currentSpeed = 30;
- int sensorWeight[5] = { 4, 2, 0, -2, -4 };
- int activeSensors;
- float Kp = 0.08;
- float Kd = 0.15;
- float Ki = 0;
- int onLine = 1;
- int minValues[5], maxValues[5], threshold[5];
- int sensorValue[5], sensorArray[5];
- bool isCalibrating = false;
- bool isRunning = false;
- String webPage = "";
- String debugLog = ""; // Log to store debug messages
- void setup() {
- Serial.begin(115200);
- // Initialize motor driver pins
- pinMode(AIN1, OUTPUT);
- pinMode(AIN2, OUTPUT);
- pinMode(BIN1, OUTPUT);
- pinMode(BIN2, OUTPUT);
- pinMode(PWMA, OUTPUT);
- pinMode(PWMB, OUTPUT);
- // Initialize sensor pins
- pinMode(SENSOR1, INPUT);
- pinMode(SENSOR2, INPUT);
- pinMode(SENSOR3, INPUT);
- pinMode(SENSOR4, INPUT);
- pinMode(SENSOR5, INPUT);
- // Set up proper PWM initialization
- /* ledcSetup(0, 5000, 8); // Channel 0, 5kHz, 8-bit resolution
- ledcSetup(1, 5000, 8); // Channel 1, 5kHz, 8-bit resolution
- ledcAttachPin(PWMA, 0); // Attach PWMA to channel 0
- ledcAttachPin(PWMB, 1); // Attach PWMB to channel 1 */
- if (!ledcAttach(PWMA, 5000, 8)) {
- Serial.println("LEDC attach failed!");
- }
- // Similarly for PWMB:
- if (!ledcAttach(PWMB, 5000, 8)) {
- Serial.println("LEDC attach failed!");
- }
- // Set up WiFi Access Point
- WiFi.softAP(ssid, password);
- IPAddress myIP = WiFi.softAPIP();
- Serial.print("AP IP address: ");
- Serial.println(myIP);
- logMessage("AP IP address: " + myIP.toString());
- // Set up Web Server routes
- server.on("/", handleRoot);
- server.on("/calibrate", handleCalibrate);
- server.on("/start", handleStart);
- server.on("/stop", handleStop);
- server.on("/sensors", handleSensors);
- server.on("/logs", handleLogs);
- server.on("/clearlogs", handleClearLogs);
- server.begin();
- Serial.println("HTTP server started");
- logMessage("HTTP server started");
- lineThickness = constrain(lineThickness, 10, 35);
- }
- void loop() {
- server.handleClient();
- if (isCalibrating) {
- calibrate();
- isCalibrating = false;
- }
- if (isRunning) {
- readLine();
- if (currentSpeed < lfSpeed) currentSpeed++;
- if (onLine == 1) { // PID LINE FOLLOW
- linefollow();
- } else {
- if (error > 0) {
- motor1run(-50);
- motor2run(lfSpeed);
- } else {
- motor1run(lfSpeed);
- motor2run(-50);
- }
- }
- } else {
- // Stop motors when not running
- motor1run(0);
- motor2run(0);
- }
- }
- void handleRoot() {
- buildWebPage();
- server.send(200, "text/html", webPage);
- }
- void handleCalibrate() {
- isCalibrating = true;
- isRunning = false;
- logMessage("Starting calibration...");
- server.sendHeader("Location", "/");
- server.send(303);
- }
- void handleStart() {
- isRunning = true;
- logMessage("Robot started");
- server.sendHeader("Location", "/");
- server.send(303);
- }
- void handleStop() {
- isRunning = false;
- logMessage("Robot stopped");
- server.sendHeader("Location", "/");
- server.send(303);
- }
- void handleSensors() {
- String sensorJSON = "{";
- for (int i = 0; i < numSensors; i++) {
- int rawValue = analogRead(i);
- sensorJSON += "\"sensor" + String(i+1) + "\":{";
- sensorJSON += "\"raw\":" + String(rawValue) + ",";
- if (isRunning) {
- sensorJSON += "\"processed\":" + String(sensorValue[i]) + ",";
- sensorJSON += "\"binary\":" + String(sensorArray[i]);
- } else {
- sensorJSON += "\"processed\":0,";
- sensorJSON += "\"binary\":0";
- }
- sensorJSON += "}";
- if (i < numSensors-1) sensorJSON += ",";
- }
- sensorJSON += "}";
- server.send(200, "application/json", sensorJSON);
- }
- void handleLogs() {
- server.send(200, "text/plain", debugLog);
- }
- void handleClearLogs() {
- debugLog = "";
- logMessage("Logs cleared");
- server.sendHeader("Location", "/");
- server.send(303);
- }
- // Function to add messages to both Serial and web debug log
- void logMessage(String message) {
- String timestamp = String(millis() / 1000.0, 2);
- String logEntry = "[" + timestamp + "s] " + message + "\n";
- Serial.print(logEntry);
- // Keep log size manageable (limit to last ~5000 chars)
- if (debugLog.length() > 5000) {
- int cutPoint = debugLog.indexOf('\n', debugLog.length() - 4000);
- if (cutPoint > 0) {
- debugLog = debugLog.substring(cutPoint + 1);
- }
- }
- debugLog += logEntry;
- }
- void buildWebPage() {
- webPage = "<!DOCTYPE html>";
- webPage += "<html lang='en'>";
- webPage += "<head>";
- webPage += "<meta charset='UTF-8'>";
- webPage += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
- webPage += "<title>Line Follower Robot</title>";
- webPage += "<style>";
- webPage += "body { font-family: Arial, sans-serif; margin: 0; padding: 20px; max-width: 800px; margin: 0 auto; }";
- webPage += "h1 { color: #333; }";
- webPage += ".button { display: inline-block; background-color: #4CAF50; color: white; padding: 10px 20px; ";
- webPage += "text-align: center; text-decoration: none; font-size: 16px; margin: 4px 2px; cursor: pointer; border-radius: 4px; }";
- webPage += ".button.red { background-color: #f44336; }";
- webPage += ".button.blue { background-color: #2196F3; }";
- webPage += ".button.gray { background-color: #9e9e9e; }";
- webPage += ".sensors { margin-top: 20px; }";
- webPage += ".sensor-bar { height: 30px; margin: 5px 0; background-color: #ddd; position: relative; }";
- webPage += ".sensor-value { height: 100%; width: 0%; background-color: #4CAF50; position: absolute; left: 0; transition: width 0.3s ease; }";
- webPage += ".sensor-binary { width: 30px; height: 30px; display: inline-block; border-radius: 50%; margin-right: 10px; }";
- webPage += ".sensor-label { font-weight: bold; }";
- 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; }";
- webPage += ".tabs { display: flex; border-bottom: 1px solid #ccc; margin-top: 20px; }";
- 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; }";
- webPage += ".tab.active { background-color: white; border-bottom: 1px solid white; margin-bottom: -1px; }";
- webPage += ".tab-content { display: none; padding: 20px; border: 1px solid #ccc; border-top: none; }";
- webPage += ".tab-content.active { display: block; }";
- webPage += "</style>";
- webPage += "</head>";
- webPage += "<body>";
- webPage += "<h1>Line Follower Robot Control</h1>";
- webPage += "<div class='controls'>";
- webPage += "<a href='/calibrate' class='button blue'>Calibrate</a> ";
- if (isRunning) {
- webPage += "<a href='/stop' class='button red'>Stop</a>";
- } else {
- webPage += "<a href='/start' class='button'>Start</a>";
- }
- webPage += "</div>";
- webPage += "<div class='tabs'>";
- webPage += "<div class='tab active' onclick='openTab(\"sensors-tab\")'>Sensors</div>";
- webPage += "<div class='tab' onclick='openTab(\"status-tab\")'>Status</div>";
- webPage += "<div class='tab' onclick='openTab(\"debug-tab\")'>Debug Log</div>";
- webPage += "</div>";
- webPage += "<div id='sensors-tab' class='tab-content active'>";
- webPage += "<h2>Sensor Values</h2>";
- webPage += "<div class='sensors'>";
- for (int i = 0; i < numSensors; i++) {
- webPage += "<div class='sensor'>";
- webPage += "<div class='sensor-label'>Sensor " + String(i+1) + ":</div>";
- webPage += "<div class='sensor-bar'><div class='sensor-value' id='value" + String(i+1) + "'></div></div>";
- webPage += "<div>Raw: <span id='raw" + String(i+1) + "'>0</span>, ";
- webPage += "Processed: <span id='processed" + String(i+1) + "'>0</span></div>";
- webPage += "<div class='sensor-binary' id='binary" + String(i+1) + "'></div>";
- webPage += "</div>";
- }
- webPage += "</div>";
- webPage += "</div>";
- webPage += "<div id='status-tab' class='tab-content'>";
- webPage += "<h2>Status</h2>";
- webPage += "<div>On Line: <span id='onLine'>No</span></div>";
- webPage += "<div>Error: <span id='error'>0</span></div>";
- webPage += "<div>Left Speed: <span id='leftSpeed'>0</span></div>";
- webPage += "<div>Right Speed: <span id='rightSpeed'>0</span></div>";
- webPage += "</div>";
- webPage += "<div id='debug-tab' class='tab-content'>";
- webPage += "<h2>Debug Log</h2>";
- webPage += "<div class='debug-controls'>";
- webPage += "<a href='/clearlogs' class='button gray'>Clear Logs</a>";
- webPage += "</div>";
- webPage += "<div class='debug-log' id='debug-log'></div>";
- webPage += "</div>";
- webPage += "<script>";
- webPage += "function openTab(tabId) {";
- webPage += " const tabs = document.getElementsByClassName('tab');";
- webPage += " for (let i = 0; i < tabs.length; i++) {";
- webPage += " tabs[i].classList.remove('active');";
- webPage += " }";
- webPage += " const tabContents = document.getElementsByClassName('tab-content');";
- webPage += " for (let i = 0; i < tabContents.length; i++) {";
- webPage += " tabContents[i].classList.remove('active');";
- webPage += " }";
- webPage += " document.getElementById(tabId).classList.add('active');";
- webPage += " if (tabId === 'sensors-tab') {";
- webPage += " document.getElementsByClassName('tab')[0].classList.add('active');";
- webPage += " } else if (tabId === 'status-tab') {";
- webPage += " document.getElementsByClassName('tab')[1].classList.add('active');";
- webPage += " } else if (tabId === 'debug-tab') {";
- webPage += " document.getElementsByClassName('tab')[2].classList.add('active');";
- webPage += " updateDebugLog();";
- webPage += " }";
- webPage += "}";
- webPage += "function updateSensors() {";
- webPage += " fetch('/sensors')";
- webPage += " .then(response => response.json())";
- webPage += " .then(data => {";
- webPage += " for (let i = 1; i <= " + String(numSensors) + "; i++) {";
- webPage += " const sensor = data['sensor'+i];";
- webPage += " document.getElementById('raw'+i).textContent = sensor.raw;";
- webPage += " document.getElementById('processed'+i).textContent = sensor.processed;";
- webPage += " document.getElementById('value'+i).style.width = (sensor.processed/10) + '%';";
- webPage += " document.getElementById('binary'+i).style.backgroundColor = sensor.binary ? '#4CAF50' : '#f44336';";
- webPage += " }";
- webPage += " });";
- webPage += "}";
- webPage += "function updateDebugLog() {";
- webPage += " fetch('/logs')";
- webPage += " .then(response => response.text())";
- webPage += " .then(data => {";
- webPage += " const logElement = document.getElementById('debug-log');";
- webPage += " logElement.textContent = data;";
- webPage += " logElement.scrollTop = logElement.scrollHeight;";
- webPage += " });";
- webPage += "}";
- webPage += "setInterval(updateSensors, 200);";
- webPage += "setInterval(() => {";
- webPage += " if (document.getElementById('debug-tab').classList.contains('active')) {";
- webPage += " updateDebugLog();";
- webPage += " }";
- webPage += "}, 1000);";
- webPage += "</script>";
- webPage += "</body></html>";
- }
- void linefollow() {
- error = 0;
- activeSensors = 0;
- for (int i = 0; i < numSensors; i++) {
- error += sensorWeight[i] * sensorArray[i] * sensorValue[i];
- activeSensors += sensorArray[i];
- }
- if (activeSensors > 0) {
- error = error / activeSensors;
- }
- P = error;
- I = constrain(I + error, -100, 100); // Add bounds to prevent integral windup
- D = error - previousError;
- PIDvalue = (Kp * P) + (Ki * I) + (Kd * D);
- previousError = error;
- lsp = currentSpeed - PIDvalue;
- rsp = currentSpeed + PIDvalue;
- lsp = constrain(lsp, 0, 255);
- rsp = constrain(rsp, 0, 255);
- motor1run(lsp);
- motor2run(rsp);
- }
- void calibrate() {
- logMessage("Starting calibration process...");
- // Initialize min/max values
- for (int i = 0; i < numSensors; i++) {
- minValues[i] = analogRead(i);
- maxValues[i] = analogRead(i);
- }
- // Calibration routine - turn in place while reading min/max values
- for (int i = 0; i < 3000; i++) {
- motor1run(50);
- motor2run(-50);
- for (int j = 0; j < numSensors; j++) {
- int value = analogRead(j);
- if (value < minValues[j]) {
- minValues[j] = value;
- }
- if (value > maxValues[j]) {
- maxValues[j] = value;
- }
- }
- delay(2);
- }
- // Calculate thresholds
- String thresholdValues = "Thresholds: ";
- for (int i = 0; i < numSensors; i++) {
- threshold[i] = (minValues[i] + maxValues[i]) / 2;
- thresholdValues += threshold[i];
- if (i < numSensors - 1) thresholdValues += ", ";
- }
- logMessage(thresholdValues);
- // Stop motors after calibration
- motor1run(0);
- motor2run(0);
- logMessage("Calibration complete");
- }
- void readLine() {
- onLine = 0;
- for (int i = 0; i < numSensors; i++) {
- int rawValue = analogRead(i);
- if (isBlackLine) {
- sensorValue[i] = map(rawValue, minValues[i], maxValues[i], 0, 1000);
- } else {
- sensorValue[i] = map(rawValue, minValues[i], maxValues[i], 1000, 0);
- }
- sensorValue[i] = constrain(sensorValue[i], 0, 1000);
- sensorArray[i] = sensorValue[i] > 500;
- if (sensorArray[i]) {
- onLine = 1;
- }
- }
- }
- //--------Function to run Motor 1-----------------
- void motor1run(int motorSpeed) {
- motorSpeed = constrain(motorSpeed, -255, 255);
- if (motorSpeed > 0) {
- digitalWrite(AIN1, 1);
- digitalWrite(AIN2, 0);
- ledcWrite(0, motorSpeed);
- } else if (motorSpeed < 0) {
- digitalWrite(AIN1, 0);
- digitalWrite(AIN2, 1);
- ledcWrite(0, abs(motorSpeed));
- } else {
- digitalWrite(AIN1, 1);
- digitalWrite(AIN2, 1);
- ledcWrite(0, 0);
- }
- }
- //--------Function to run Motor 2-----------------
- void motor2run(int motorSpeed) {
- motorSpeed = constrain(motorSpeed, -255, 255);
- if (motorSpeed > 0) {
- digitalWrite(BIN1, 1);
- digitalWrite(BIN2, 0);
- ledcWrite(1, motorSpeed);
- } else if (motorSpeed < 0) {
- digitalWrite(BIN1, 0);
- digitalWrite(BIN2, 1);
- ledcWrite(1, abs(motorSpeed));
- } else {
- digitalWrite(BIN1, 1);
- digitalWrite(BIN2, 1);
- ledcWrite(1, 0);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement