Started on the webserver sketch, connected it to the motor code with tcp communication, implemented a simple webserver interface to control the device

This commit is contained in:
2025-08-07 19:51:38 +02:00
parent b178edebd3
commit 4cf349b20f
12 changed files with 748 additions and 216 deletions
+2 -1
View File
@@ -1,2 +1,3 @@
*.FCBak
*.3mf
*.3mf
Code/.vscode
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-215
View File
@@ -1,215 +0,0 @@
#include <AccelStepper.h>
// === Pin Definitions ===
#define M1_STEP_PIN 0 // Reel motor step
#define M1_DIR_PIN 1 // Reel motor direction
#define M2_STEP_PIN 2 // Carriage motor step
#define M2_DIR_PIN 3 // Carriage motor direction
#define HOME_SW_PIN 6 // Home limit switch
#define END_SW_PIN 5 // End limit switch
AccelStepper reelMotor(AccelStepper::DRIVER, M1_STEP_PIN, M1_DIR_PIN);
AccelStepper carriageMotor(AccelStepper::DRIVER, M2_STEP_PIN, M2_DIR_PIN);
float RAIL_LENGTH = 50; // 100mm linear rail
float CENTER_POSITION = RAIL_LENGTH / 2.0f; // Center position
// === Motor Configuration ===
const int MOTOR_STEPS = 200; // 200 steps/rev for NEMA 17
const int MICROSTEPPING = 8; // Set on driver board (MS1/MS2 jumpers)
const float SCREW_LEAD = 4.0; // mm per revolution (T8 screw)
const float CALIBRATION_FACTOR = 2.0;
const float STEPS_PER_MM = ((MOTOR_STEPS * MICROSTEPPING) / (SCREW_LEAD / CALIBRATION_FACTOR));
// === Speed Settings ===
const float REEL_RPM = 150; // Reel motor speed
const float CARRIAGE_RPM = 100; // Carriage motor speed
// State management
enum State {
IDLE,
HOMING,
FIND_END,
RUNNING
};
State currentState = HOMING;
// Manual distance tracking
long targetSteps = 0;
long stepsMoved = 0;
// Position tracking
float currentPositionMM = 0; // Tracks actual position in mm
float desiredPosition = 25;
bool bounceBool = false;
void setup() {
Serial.begin(115200);
// Configure limit switches
pinMode(HOME_SW_PIN, INPUT_PULLUP);
pinMode(END_SW_PIN, INPUT_PULLUP);
Serial.begin(115200);
Serial.println("Starting motors...");
// Configure reel motor (constant speed)
reelMotor.setMaxSpeed((REEL_RPM * MOTOR_STEPS * MICROSTEPPING) / 60.0);
reelMotor.setSpeed(-reelMotor.maxSpeed()); // Negative for reverse
reelMotor.setMinPulseWidth(50); // 50µs pulse width
// Configure carriage motor (constant speed)
carriageMotor.setMaxSpeed((CARRIAGE_RPM * MOTOR_STEPS * MICROSTEPPING) / 60.0);
carriageMotor.setSpeed(carriageMotor.maxSpeed()); // Positive direction
carriageMotor.setMinPulseWidth(50); // 50µs pulse width
}
void loop() {
// State machine for carriage
switch(currentState) {
case HOMING:
runHoming();
break;
case FIND_END:
runFindEnd();
break;
case RUNNING:
//reelMotor.runSpeed();
if(bounceBool == false){
if(runMoveToPosition(desiredPosition - 0 )){
bounceBool = true;
}
}
else {
if(runMoveToPosition(desiredPosition - 20.0)){
bounceBool = false;
}
}
break;
}
}
void runHoming(){
// Move carriage in positive direction
if (carriageMotor.runSpeed()) {
stepsMoved++;
}
if (digitalRead(HOME_SW_PIN) == LOW) { // Switch pressed (LOW with pullup)
carriageMotor.stop(); // Stop motor
carriageMotor.setSpeed(0); // Set speed to zero
stepsMoved = 0;
// Reset position tracking
currentPositionMM = 0;
carriageMotor.setCurrentPosition(0);
// Calculate steps needed to reach center
targetSteps = CENTER_POSITION * STEPS_PER_MM;
carriageMotor.setSpeed(-carriageMotor.maxSpeed()); // Positive direction
currentState = FIND_END;
}
}
void runFindEnd() {
// Run carriage at constant speed
if (carriageMotor.runSpeed()) {
stepsMoved++;
// Update position based on direction
currentPositionMM += (carriageMotor.speed() > 0) ?
(1.0 / STEPS_PER_MM) :
(-1.0 / STEPS_PER_MM);
// Print position every 100ms
// static unsigned long lastPrint = 0;
// if (millis() - lastPrint > 100) {
// lastPrint = millis();
// Serial.print("Position: ");
// Serial.print(currentPositionMM);
// Serial.println(" mm");
// }
}
if (digitalRead(END_SW_PIN) == LOW) { // Switch pressed (LOW with pullup)
currentState = RUNNING;
// Stop carriage motor completely
carriageMotor.stop();
carriageMotor.setSpeed(0);
// Print final position
Serial.print("Final position: ");
Serial.print(currentPositionMM);
RAIL_LENGTH = abs(currentPositionMM);
CENTER_POSITION = RAIL_LENGTH / 2.0f;
}
}
bool runMoveToPosition(float position){
float distance = abs(abs(currentPositionMM) - position);
float margin = 0.1f;
// Print position every 100ms
// static unsigned long lastPrint = 0;
// if (millis() - lastPrint > 100) {
// lastPrint = millis();
// Serial.print("Position: ");
// Serial.print(abs(currentPositionMM));
// Serial.println(" mm");
// Serial.print("Desired Position: ");
// Serial.print(position);
// Serial.println(" mm");
// Serial.println(distance);
// }
// Calculate direction
if(distance > margin){
int direction = sign(position - abs(currentPositionMM));
int previousDirection = (carriageMotor.speed() / -1.0f) / carriageMotor.maxSpeed();
if(previousDirection != direction){
carriageMotor.setSpeed(carriageMotor.maxSpeed() * direction * -1.0f);
}
}
// Run carriage at constant speed
if (carriageMotor.runSpeed()) {
stepsMoved++;
// Update position based on direction
currentPositionMM += (carriageMotor.speed() > 0) ?
(1.0 / STEPS_PER_MM) :
(-1.0 / STEPS_PER_MM);
if (distance <= margin) {
// Stop carriage motor completely
carriageMotor.setSpeed(0);
carriageMotor.stop();
return true;
}
}
if (distance <= margin) {
// Stop carriage motor completely
carriageMotor.setSpeed(0);
carriageMotor.stop();
return true;
}
return false;
}
bool withinRange(float value, float target, float margin) {
return (value >= (target - margin)) && (value <= (target + margin));
}
float sign(float value) {
return float((value>0)-(value<0));
}
+372
View File
@@ -0,0 +1,372 @@
#include <AccelStepper.h>
#include <ArduinoJson.h>
#include <WiFi.h>
// === Pin Definitions ===
#define M1_STEP_PIN 0 // Reel motor step
#define M1_DIR_PIN 1 // Reel motor direction
#define M2_STEP_PIN 2 // Carriage motor step
#define M2_DIR_PIN 3 // Carriage motor direction
#define START_SW_PIN 6 // Home limit switch
#define END_SW_PIN 5 // End limit switch
// Wi-Fi credentials
const char* ssid = "";
const char* password = "";
WiFiServer motorServer(3333); // Open port 3333
WiFiClient activeClient; // Store the current client
String recvBuffer = "";
AccelStepper reelMotor(AccelStepper::DRIVER, M1_STEP_PIN, M1_DIR_PIN);
AccelStepper carriageMotor(AccelStepper::DRIVER, M2_STEP_PIN, M2_DIR_PIN);
// === Motor Configuration ===
const int MOTOR_STEPS = 200; // 200 steps/rev for NEMA 17
const int MICROSTEPPING = 8; // Set on driver board (MS1/MS2 jumpers)
const float DISTANCE_PER_REVOLUTION = 2.0; // mm per revolution (best to do a revolution by hand and measure distance and input it here)
const float STEPS_PER_MM = (MOTOR_STEPS * MICROSTEPPING) / DISTANCE_PER_REVOLUTION;
// === Speed Settings ===
const float REEL_RPM = 40; // Reel motor speed
float CARRIAGE_RPM = 100; // Carriage motor speed (will be dynamically set)
#define FORWARD -1 // In my setup the carriage is moving forward is in negative speed, meaning away from the motor, that why we need to invert the movement in tracking
// System state management
enum SystemState {
IDLE,
SYSTEM_CALIBRATION,
REEL_CALIBRATION,
REELING
};
SystemState currentSystemState = IDLE;
enum SystemCalibrationState {
FIND_START,
FIND_END
};
SystemCalibrationState systemCalibrationState = FIND_START;
// Position tracking
float railLength = 0;
float currentPositionMM = 0;
float targetPosition = 0;
bool isMovingToEnd = false;
// Gap values
float reelGapStartPosition = -1;
float reelGapEndPosition = -1;
bool starterSet = false; // Is start gap position set?
bool endSet = false; // Is start gap position set?
void setup() {
Serial.begin(115200);
Serial.println("Motor ESP Connecting");
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nMotor ESP connected. IP: " + WiFi.localIP().toString());
// FIXME : Perhaps use UDP communication instead maybe it will not block the ESP32C3 as much
motorServer.begin(); // Start TCP server
pinMode(START_SW_PIN, INPUT_PULLUP);
pinMode(END_SW_PIN, INPUT_PULLUP);
// Configure reel motor
reelMotor.setMaxSpeed((REEL_RPM * MOTOR_STEPS * MICROSTEPPING) / 60.0);
reelMotor.setSpeed(-reelMotor.maxSpeed()); // To reel the line in toward the fishing reel, i need the fishing reel to move anti-clockwise
reelMotor.setMinPulseWidth(50);
// Configure carriage motor
carriageMotor.setMaxSpeed((CARRIAGE_RPM * MOTOR_STEPS * MICROSTEPPING) / 60.0);
carriageMotor.setSpeed(carriageMotor.maxSpeed());
carriageMotor.setMinPulseWidth(50);
}
void loop() {
// Accept new clients
if (!activeClient || !activeClient.connected()) {
activeClient = motorServer.available();
}
if (activeClient && activeClient.connected() && activeClient.available()) {
while (activeClient.available()) {
char c = activeClient.read();
if (c == '\n') {
recvBuffer.trim(); // Remove trailing \r or whitespace
if (recvBuffer.length() > 0) {
handleCommand(recvBuffer, activeClient);
}
recvBuffer = ""; // Reset for next command
} else {
recvBuffer += c;
// Optional: protect against overflow
if (recvBuffer.length() > 200) recvBuffer = ""; // Reset if too long
}
}
}
// Main state machine
switch (currentSystemState) {
case IDLE: break;
case REELING: runReeling(); break;
case REEL_CALIBRATION: runCalibration(); break;
case SYSTEM_CALIBRATION:
if (systemCalibrationState == FIND_START) runFindStart();
else if (systemCalibrationState == FIND_END) runFindEnd();
break;
}
}
void runFindStart() {
// Force the carriage motor to find the start switch by moving it positive direction, meaning toward the motor
if(carriageMotor.speed() <= 0){
carriageMotor.setSpeed(carriageMotor.maxSpeed());
}
carriageMotor.runSpeed();
//
if (digitalRead(START_SW_PIN) == LOW) {
carriageMotor.stop();
carriageMotor.setSpeed(0);
currentPositionMM = 0; // Start from zero
carriageMotor.setCurrentPosition(0);
carriageMotor.setSpeed(carriageMotor.maxSpeed()); // Always move forward from here
systemCalibrationState = FIND_END;
}
}
void runFindEnd() {
// Force the carriage motor to find the end switch by moving it negative direction, meaning away from the motor
if(carriageMotor.speed() >= 0){
carriageMotor.setSpeed(carriageMotor.maxSpeed() * FORWARD);
}
if (carriageMotor.runSpeed()) {
currentPositionMM += (1.0 / STEPS_PER_MM); // Calculate the new position when the motor actually does steps
}
if (digitalRead(END_SW_PIN) == LOW) {
carriageMotor.stop();
carriageMotor.setSpeed(0);
railLength = currentPositionMM; // Assign the maximum length the motor can travel
targetPosition = railLength;
currentSystemState = IDLE;
}
}
void runReeling() {
if(reelGapStartPosition < 0 || reelGapEndPosition < 0){
// TODO : Maybe throw an error for the user
stopMotors();
return;
}
if (isWithinRange(currentPositionMM, reelGapStartPosition, reelGapEndPosition)) {
if(reelMotor.speed() == 0){
reelMotor.setSpeed(-reelMotor.maxSpeed());
}
reelMotor.runSpeed();
}
// === Oscillate effect ===
if (!isMovingToEnd) {
if (runMoveToPosition(reelGapStartPosition)) {
isMovingToEnd = true;
}
} else {
if (runMoveToPosition(reelGapEndPosition)) {
isMovingToEnd = false;
}
}
}
void runCalibration() {
runMoveToPosition(targetPosition);
}
bool runMoveToPosition(float position) {
// If it want's to move out of bounds, stop the motors, maybe it will damage the setup
if(position < 0.0f || position > railLength){
stopMotors();
return false;
}
float distance = abs(currentPositionMM - position);
float margin = 0.01f;
if (distance <= margin) {
carriageMotor.setSpeed(0);
carriageMotor.stop();
return true;
}
int direction = sign(position - currentPositionMM);
int previousDirection = (carriageMotor.speed() / FORWARD) / carriageMotor.maxSpeed();
if (previousDirection != direction) {
carriageMotor.setSpeed(carriageMotor.maxSpeed() * direction * FORWARD);
}
if (carriageMotor.runSpeed()) {
currentPositionMM += (carriageMotor.speed() > 0) ? (-1.0 / STEPS_PER_MM) : (1.0 / STEPS_PER_MM);
if (distance <= margin) {
carriageMotor.setSpeed(0);
carriageMotor.stop();
return true;
}
}
return false;
}
void stopMotors(){
currentSystemState = IDLE;
carriageMotor.stop();
carriageMotor.setSpeed(0);
reelMotor.stop();
reelMotor.setSpeed(0);
}
float calculateCarriageRPM(float reelRPM, float gapLengthMM) {
float timeForReelRevs = 4.0f * 60.0f / reelRPM;
float mmPerSec = gapLengthMM / timeForReelRevs;
float carriageRevsPerSec = mmPerSec / DISTANCE_PER_REVOLUTION;
return carriageRevsPerSec * 60.0f;
}
bool isWithinRange(float currentPosition, float start, float end) {
return currentPosition >= start && currentPosition <= end;
}
float sign(float value) {
return float((value > 0) - (value < 0));
}
String stateToString(SystemState systemState) {
switch(systemState) {
case IDLE: return "IDLE";
case REELING: return "REELING";
case REEL_CALIBRATION: return "REEL_CALIBRATION";
case SYSTEM_CALIBRATION: return "SYSTEM_CALIBRATION";
default: return "UNKNOWN";
}
}
void handleCommand(const String& cmd, WiFiClient& client) {
if (cmd.startsWith("starter-position-input")) {
float value;
int scanned = sscanf(cmd.c_str(), "starter-position-input %f", &value);
if (scanned == 1) {
reelGapStartPosition = value;
starterSet = true;
if (starterSet && endSet) {
float gap = reelGapEndPosition - reelGapStartPosition;
float newCarriageRPM = calculateCarriageRPM(REEL_RPM, gap);
CARRIAGE_RPM = newCarriageRPM;
float maxSpeed = (newCarriageRPM * MOTOR_STEPS * MICROSTEPPING) / 60.0;
carriageMotor.setMaxSpeed(maxSpeed);
}
client.println("OK");
} else {
client.println("Invalid starter-position-input command");
}
} else if (cmd.startsWith("end-position-input")) {
float value;
int scanned = sscanf(cmd.c_str(), "end-position-input %f", &value);
if (scanned == 1) {
reelGapEndPosition = value;
endSet = true;
if (starterSet && endSet) {
float gap = reelGapEndPosition - reelGapStartPosition;
float newCarriageRPM = calculateCarriageRPM(REEL_RPM, gap);
CARRIAGE_RPM = newCarriageRPM;
float maxSpeed = (newCarriageRPM * MOTOR_STEPS * MICROSTEPPING) / 60.0;
carriageMotor.setMaxSpeed(maxSpeed);
}
client.println("OK");
} else {
client.println("Invalid end-position-input command");
}
} else if (cmd == "status") {
StaticJsonDocument<200> doc;
doc["position"] = currentPositionMM;
doc["state"] = stateToString(currentSystemState);
doc["railLength"] = railLength;
doc["starterSet"] = starterSet;
doc["endSet"] = endSet;
String json;
serializeJson(doc, json);
client.println(json);
} else if (cmd == "calibrate") {
currentSystemState = SYSTEM_CALIBRATION;
systemCalibrationState = FIND_START;
client.println("System calibration started");
} else if (cmd == "reel_cal") {
if(currentSystemState != REEL_CALIBRATION){
currentSystemState = REEL_CALIBRATION;
} else {
currentSystemState = IDLE;
}
if(starterSet && endSet){
targetPosition = (reelGapEndPosition - reelGapStartPosition) / 2.0f;
}else {
targetPosition = 0;
}
client.println("Reel calibration mode");
} else if (cmd == "start") {
if (starterSet && endSet) {
currentSystemState = REELING;
client.println("Started reeling");
} else {
client.println("Error: Gap not set");
}
} else if (cmd == "stop") {
stopMotors();
client.println("Stopped");
} else if (cmd.startsWith("move")) {
float value;
int scanned = sscanf(cmd.c_str(), "move %f", &value);
if (scanned == 1) {
targetPosition = value;
currentSystemState = REEL_CALIBRATION; // Use existing logic to move to target
client.println("OK");
} else {
client.println("Invalid end-position-input command");
}
}else {
client.println("Unknown command");
}
}
+139
View File
@@ -0,0 +1,139 @@
#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include <LittleFS.h>
// Wi-Fi credentials
const char* ssid = "";
const char* password = "";
// Web server on port 80
WebServer server(80);
// TCP client for talking to motor ESP
WiFiClient motorClient;
IPAddress motorIP(192, 168, 1, 18); // Motor ESP IP (must be static or fixed by DHCP)
bool starterSet = false;
bool endSet = false;
// =================== COMMUNICATION ===================
bool ensureConnected() {
if (!motorClient.connected()) {
return motorClient.connect(motorIP, 3333); // Port must match motor ESP
}
return true;
}
String sendMotorCommand(const String& cmd) {
if (!ensureConnected()) return "Motor Not Connected";
motorClient.println(cmd);
motorClient.flush();
String response = "";
unsigned long start = millis();
while (millis() - start < 300) {
while (motorClient.available()) {
char c = motorClient.read();
if (c == '\n') return response;
response += c;
}
}
return response;
}
// =================== SETUP ===================
void setup() {
Serial.begin(115200);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nConnected to Wi-Fi. IP: " + WiFi.localIP().toString());
if (!LittleFS.begin(true)) {
Serial.println("Failed to mount LittleFS");
return;
}
// Routes
server.on("/", handleRoot);
server.on("/cmd", handleCommand);
server.on("/move", handleMove);
server.on("/set", handleSet);
server.on("/status", handleStatus);
server.begin();
}
void loop() {
server.handleClient();
}
// =================== WEB HANDLERS ===================
void handleRoot() {
File file = LittleFS.open("/index.html", "r");
if (!file) {
server.send(500, "text/plain", "Failed to load HTML file");
return;
}
server.streamFile(file, "text/html");
file.close();
}
void handleCommand() {
String command = server.arg("code");
String reply = sendMotorCommand(command);
server.send(200, "text/plain", reply.length() > 0 ? reply : "OK");
}
void handleSet() {
if (!server.hasArg("type") || !server.hasArg("val")) {
server.send(400, "text/plain", "Missing arguments");
return;
}
String type = server.arg("type");
float value = server.arg("val").toFloat();
if (type == "starter-position-input") {
starterSet = true;
String cmd = "starter-position-input " + String(value, 2);
sendMotorCommand(cmd);
} else if (type == "end-position-input") {
endSet = true;
String cmd = "end-position-input " + String(value, 2);
sendMotorCommand(cmd);
} else {
server.send(400, "text/plain", "Invalid type");
return;
}
server.send(200, "text/plain", "OK");
}
void handleStatus() {
String json = sendMotorCommand("status");
if (json.startsWith("{")) {
server.send(200, "application/json", json);
} else {
server.send(500, "text/plain", "Invalid status");
}
}
void handleMove() {
float position = server.arg("pos").toFloat();
String cmd = "move " + String(position, 2);
sendMotorCommand(cmd);
// MUST send a response to complete the request
server.send(200, "text/plain", "OK");
}
+235
View File
@@ -0,0 +1,235 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AFRS 1.3</title>
<style>
body{font-family:sans-serif;margin:20px}
button,input{padding:8px 12px;margin:4px}
.group
{
display: flex;
flex-direction: row;
gap: 10px;
align-items: center;
}
</style>
</head>
<body>
<div class="group">
<div id="system-state"> State : IDLE </div>
</div>
<div class="group">
<div id="carriage-position-label">Carriage Position : 0.0 mm </div>
</div>
<div class="group">
<button onclick="sendCommand('calibrate')" id="system-calibrate-button">System Calibration Mode</button>
</div>
<div class="group">
<button onclick="sendCommand('reel_cal')" id="reel-calibratation-button">Reel Calibration Mode</button>
</div>
<div class="group">
Target Position : <input type="number" id="target-position-input" value="0">
<button onclick="moveToPosition()" id="move-button">Move</button>
<button onclick="adjustSetPosition('adjust-set-start-button')" id="adjust-set-start-button">Set Start</button>
<button onclick="adjustSetPosition('adjust-set-end-button')" id="adjust-set-end-button">Set End</button>
</div>
<div class="group">
<button onclick="adjustPosition(1)">+1mm</button>
<button onclick="adjustPosition(-1)">-1mm</button>
</div>
<div class="group">
Start: <input type="number" id="starter-position-input" value="0" onchange="setChangedPosition('starter-position-input')">
<button onclick="setPosition('starter-position-input')" id="start-set-button">Set</button>
<input type="checkbox" id="starter-position-input-set" disabled>
End: <input type="number" id="end-position-input" value="0" onchange="setChangedPosition('end-position-input')">
<button onclick="setPosition('end-position-input')" id="end-set-button">Set</button>
<input type="checkbox"id="end-position-input-set" disabled>
</div>
<div class="group">
<button onclick="sendCommand('start')" id="start-reeling-button">Start Reeling</button>
<button onclick="sendCommand('stop')" id="stop-reeling-button">Stop Reeling</button>
</div>
<script>
let currentState = 'IDLE';
let currentPosition = 0;
let railLength = 50;
let systemCalibrated = false;
let reelCalibrated = false;
let starterSet = false;
let endSet = false;
// Update UI based on system state
function updateUI() {
// Update state indicator
const stateElement = document.getElementById('system-state');
stateElement.textContent = `State : ${currentState}`;
document.getElementById("starter-position-input-set").checked = starterSet;
document.getElementById("end-position-input-set").checked = endSet;
// Update position
document.getElementById('carriage-position-label').textContent = `Carriage Position : ${currentPosition.toFixed(2)} mm`;
if(!systemCalibrated){
document.getElementById('reel-calibratation-button').disabled = true;
document.getElementById('target-position-input').disabled = true;
document.getElementById('move-button').disabled = true;
document.getElementById('starter-position-input').disabled = true;
document.getElementById('start-set-button').disabled = true;
document.getElementById('end-position-input').disabled = true;
document.getElementById('end-set-button').disabled = true;
document.getElementById('start-reeling-button').disabled = true;
document.getElementById('stop-reeling-button').disabled = true;
}
else if(systemCalibrated && !reelCalibrated && currentState == "IDLE"){
document.getElementById('system-calibrate-button').disabled = false;
document.getElementById('reel-calibratation-button').disabled = false;
document.getElementById('target-position-input').disabled = true;
document.getElementById('move-button').disabled = true;
document.getElementById('starter-position-input').disabled = true;
document.getElementById('start-set-button').disabled = true;
document.getElementById('end-position-input').disabled = true;
document.getElementById('end-set-button').disabled = true;
document.getElementById('start-reeling-button').disabled = true;
document.getElementById('stop-reeling-button').disabled = true;
}
else if(systemCalibrated && currentState == "CALIBRATE_REEL"){
document.getElementById('system-calibrate-button').disabled = true;
document.getElementById('reel-calibratation-button').disabled = false;
document.getElementById('target-position-input').disabled = false;
document.getElementById('move-button').disabled = false;
document.getElementById('starter-position-input').disabled = false;
document.getElementById('start-set-button').disabled = false;
document.getElementById('end-position-input').disabled = false;
document.getElementById('end-set-button').disabled = false;
document.getElementById('start-reeling-button').disabled = true;
document.getElementById('stop-reeling-button').disabled = true;
}
else if(systemCalibrated && reelCalibrated && currentState == "IDLE"){
document.getElementById('system-calibrate-button').disabled = false;
document.getElementById('reel-calibratation-button').disabled = false;
document.getElementById('target-position-input').disabled = true;
document.getElementById('move-button').disabled = true;
document.getElementById('starter-position-input').disabled = true;
document.getElementById('start-set-button').disabled = true;
document.getElementById('end-position-input').disabled = true;
document.getElementById('end-set-button').disabled = true;
document.getElementById('start-reeling-button').disabled = false;
document.getElementById('stop-reeling-button').disabled = false;
}
}
function sendCommand(cmd) {
fetch(`/cmd?code=${cmd}`)
.catch(e => console.error('Error:', e));
}
function moveToPosition() {
const pos = document.getElementById('target-position-input').value;
fetch(`/move?pos=${pos}`)
.catch(e => console.error('Error:', e));
}
function adjustPosition(delta) {
const currentTargetPosition = document.getElementById('target-position-input').value;
let newTargetPosition = parseFloat(currentTargetPosition) + delta;
if(newTargetPosition < 0){
newTargetPosition = 0;
} else if (newTargetPosition > railLength)
{
newTargetPosition = railLength;
}
document.getElementById('target-position-input').value = newTargetPosition;
}
function adjustSetPosition(type){
let newVal = document.getElementById("target-position-input").value;
if(newVal < 0){
newVal = 0;
} else if (newVal > railLength)
{
newVal = railLength;
}
if(type === "adjust-set-start-button"){
document.getElementById("starter-position-input").value = newVal;
} else if(type === "adjust-set-end-button"){
document.getElementById("end-position-input").value = newVal;
}
}
function setPosition(type) {
const val = document.getElementById(type).value;
fetch(`/set?type=${type}&val=${val}`)
.catch(e => console.error('Error:', e));
}
function setChangedPosition(type){
let inputValue = parseFloat(document.getElementById(type).value);
if(inputValue < 0){
inputValue = 0;
}
else if(inputValue > railLength){
inputValue = railLength;
}
document.getElementById(type).value = inputValue;
}
// Get system status from ESP32
function getStatus() {
fetch('/status')
.then(response => response.json())
.then(data => {
currentState = data.state;
currentPosition = data.position;
railLength = data.railLength;
// Update workflow states based on device
systemCalibrated = (railLength > 0);
starterSet = data.starterSet;
endSet = data.endSet;
reelCalibrated = (data.starterSet && data.endSet);
updateUI();
})
.catch(error => console.error('Error fetching status:', error));
}
// Initialize the controller
function initController() {
// Get initial status
getStatus();
// Set up periodic status updates
setInterval(getStatus, 1000);
}
// Initialize when page loads
window.onload = initController;
</script>
</body>
</html>