From be60a720c1b837fab21d84c78fd24f077f57b353 Mon Sep 17 00:00:00 2001 From: atharv Date: Wed, 7 May 2025 17:32:27 -0700 Subject: [PATCH 1/3] wrote reverse movement functionality for focus motor, cleaned up some formatting and comments, removed threading because it didn't work. still need to test this all. --- .../focusController.ino | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) rename focusController.ino => focusController/focusController.ino (84%) diff --git a/focusController.ino b/focusController/focusController.ino similarity index 84% rename from focusController.ino rename to focusController/focusController.ino index 823ab37..8599666 100644 --- a/focusController.ino +++ b/focusController/focusController.ino @@ -25,9 +25,7 @@ #include // MAC address and IP address for controller -byte mac[] = { - 0xA8, 0x61, 0x0A, 0xAE, 0x25, 0x13 -}; +byte mac[] = {0xA8, 0x61, 0x0A, 0xAE, 0x25, 0x13}; IPAddress ip(192, 168, 1, 11); // Initialize the Ethernet server library @@ -36,7 +34,7 @@ IPAddress ip(192, 168, 1, 11); EthernetServer server(80); // Multithread for handling motor movement in background -Thread moveMotor = Thread(); +// Thread moveMotor = Thread(); // Focuser fields volatile int position = 0; @@ -82,9 +80,9 @@ void setup() { Serial.print("Server starting at "); Serial.println(Ethernet.localIP()); - //initialize thread - moveMotor.onRun(startMovement); - moveMotor.enabled = true; + // initialize thread + // moveMotor.onRun(startMovement); + // moveMotor.enabled = true; } @@ -101,7 +99,7 @@ void loop() { // close the connection: client.stop(); - //Serial.println("client disconnected"); + // Serial.println("client disconnected"); } } @@ -129,25 +127,35 @@ void handleClient(EthernetClient client) { */ /* - Command: move?steps - Paramters: steps: - Returns: {code: } - ^ Descriptions of each json field are described in Focuser Arduino Specification Google Doc - Test code: "curl -X POST http://192.168.1.11/move?steps=500" + Command: move?steps + Paramters: steps: + Returns: {code: } + ^ Descriptions of each json field are described in Focuser Arduino Specification Google Doc + Test code: "curl -X POST http://192.168.1.11/move?steps=500" */ - - if (strstr(request, "POST /move?steps")) { char* stepsParam = strstr(request, "steps="); - if (stepsParam && moveMotor.shouldRun()) { - moveSteps = atoi(stepsParam + 6); + if (stepsParam) { // moveMotor.shouldRun() + // if the request contains '-', then switch to negative direction + char* negative = strstr(request, "-"); + if (negative > stepsParam) { + digitalWrite(8, LOW); // is this the right value to write? + moveSteps = atoi(stepsParam + 7); // jump to the value after - sign + } + else { + digitalWrite(8, HIGH); + moveSteps = atoi(stepsParam + 6); // jump to the value after = sign + } + + // now tell them we are moving Serial.print("moving "); Serial.println(moveSteps); - moveMotor.run(); - } + // moveMotor.run(); + startMovement(); sendJSONResponse(client, 200, "\"code\":200"); } + /* Command: status Paramters: None @@ -212,9 +220,7 @@ bool checkLimits() { } void startMovement() { - //Disable thread so another movement call won't overwrite the current movement - moveMotor.enabled = false; moving = true; // Period is 1/f, we want to convert to ms then divide by 2 since pulseTime should be half of a clock cycle @@ -242,6 +248,6 @@ void startMovement() { Serial.println("Movement Finished"); moving = false; - moveMotor.enabled = true; + // moveMotor.enabled = true; } From 3194ad1780b167eac4b0baed7d7e202153f9df55 Mon Sep 17 00:00:00 2001 From: timpy2by3 Date: Sat, 17 May 2025 10:42:46 -0700 Subject: [PATCH 2/3] tested this code at mro - use focus controller new --- focusController/focusController.ino | 136 +++++---- focusControllerNew/focusControllerNew.ino | 325 ++++++++++++++++++++++ focusControllerOld.ino | 216 -------------- focusControllerOld/focusControllerOld.ino | 323 +++++++++++++++++++++ 4 files changed, 715 insertions(+), 285 deletions(-) create mode 100644 focusControllerNew/focusControllerNew.ino delete mode 100644 focusControllerOld.ino create mode 100644 focusControllerOld/focusControllerOld.ino diff --git a/focusController/focusController.ino b/focusController/focusController.ino index 8599666..159f6ca 100644 --- a/focusController/focusController.ino +++ b/focusController/focusController.ino @@ -20,9 +20,9 @@ #include #include -#include -#include -#include +// #include +// #include +// #include // MAC address and IP address for controller byte mac[] = {0xA8, 0x61, 0x0A, 0xAE, 0x25, 0x13}; @@ -85,24 +85,64 @@ void setup() { // moveMotor.enabled = true; } +// Code for formatting json return strings +void sendJSONResponse(EthernetClient client, int code, String body) { + client.println("HTTP/1.1 " + String(code) + " OK"); + client.println("Content-Type: application/json"); + client.println("Connection: close"); + client.println(); + client.println("{" + body + "}"); +} -void loop() { - // listen for incoming clients - updatePosition(); - EthernetClient client = server.available(); - if (client) { +// Emulating the potentiometer position +void updatePosition() { + if (moving && (millis() - lastStepTime > stepDelay)) { + position += (target_steps > 0) ? 1 : -1; + target_steps -= (target_steps > 0) ? 1 : -1; + lastStepTime = millis(); + + if (target_steps == 0 || checkLimits()) { + moving = false; + position = constrain(position, down_limit, up_limit); + } + } +} - handleClient(client); +bool checkLimits() { + return (position >= up_limit) || (position <= down_limit); +} - // give the web browser time to receive the data - delay(1); +void startMovement() { + //Disable thread so another movement call won't overwrite the current movement + moving = true; - // close the connection: - client.stop(); - // Serial.println("client disconnected"); + // Period is 1/f, we want to convert to ms then divide by 2 since pulseTime should be half of a clock cycle + long pulseTime = long(float(1)*500000.0/clkFreq); + + int i = 0; + while (i < moveSteps && !abortMovement) { + long pastTime = micros(); + digitalWrite(clkPin, HIGH); + Serial.print("clkHigh"); + + // delay until halfway through period designated by clk_frequency + while (micros() - pastTime < pulseTime) {} + + pastTime = micros(); + digitalWrite(clkPin, LOW); + Serial.print("clkLow"); + + // delay until reach the end of period + while (micros() - pastTime < pulseTime) {} + + i++; } -} + Serial.println(); + Serial.println("Movement Finished"); + moving = false; + // moveMotor.enabled = true; +} void handleClient(EthernetClient client) { char request[128]; @@ -190,64 +230,22 @@ void handleClient(EthernetClient client) { sendJSONResponse(client, 300, "\"code\":300"); } + } } -// Code for formatting json return strings -void sendJSONResponse(EthernetClient client, int code, String body) { - client.println("HTTP/1.1 " + String(code) + " OK"); - client.println("Content-Type: application/json"); - client.println("Connection: close"); - client.println(); - client.println("{" + body + "}"); -} - -// Emulating the potentiometer position -void updatePosition() { - if (moving && (millis() - lastStepTime > stepDelay)) { - position += (target_steps > 0) ? 1 : -1; - target_steps -= (target_steps > 0) ? 1 : -1; - lastStepTime = millis(); - - if (target_steps == 0 || checkLimits()) { - moving = false; - position = constrain(position, down_limit, up_limit); - } - } -} - -bool checkLimits() { - return (position >= up_limit) || (position <= down_limit); -} - -void startMovement() { - //Disable thread so another movement call won't overwrite the current movement - moving = true; - - // Period is 1/f, we want to convert to ms then divide by 2 since pulseTime should be half of a clock cycle - long pulseTime = long(float(1)*500000.0/clkFreq); - - int i = 0; - while (i < moveSteps && !abortMovement) { - long pastTime = micros(); - digitalWrite(clkPin, HIGH); - Serial.print("clkHigh"); +void loop() { + // listen for incoming clients + updatePosition(); + EthernetClient client = server.available(); + if (client) { - // delay until halfway through period designated by clk_frequency - while (micros() - pastTime < pulseTime) {} - - pastTime = micros(); - digitalWrite(clkPin, LOW); - Serial.print("clkLow"); + handleClient(client); - // delay until reach the end of period - while (micros() - pastTime < pulseTime) {} + // give the web browser time to receive the data + delay(1); - i++; + // close the connection: + client.stop(); + // Serial.println("client disconnected"); } - Serial.println(); - Serial.println("Movement Finished"); - - moving = false; - // moveMotor.enabled = true; } - diff --git a/focusControllerNew/focusControllerNew.ino b/focusControllerNew/focusControllerNew.ino new file mode 100644 index 0000000..2979a91 --- /dev/null +++ b/focusControllerNew/focusControllerNew.ino @@ -0,0 +1,325 @@ +/* + MRO Focus Controller (NON THREADED VERSION) + + An arduino that sends focussing based commands to the Manastash Ridge Observatory + + The arduino hosts a simple Arduino web server, and recieves commands via + web server actions sent over it's ethernet port + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + * Clock Motor Output - pin 9 + * Direction Motor Output - pin 8 + * Enable Motor Output - pin 7 + * Limit pin 1 - pin 6 + * Limit pin 2 - pin 5 + * Potentiometer - TinkerKit connection "IN3" + + Code written by AUEG Arduino Team 2025! + */ + +#include +#include + +// MAC address and IP address for controller +byte mac[] = { 0xA8, 0x61, 0x0A, 0xAE, 0x25, 0x13 }; +IPAddress ip(72, 233, 250, 86); + +// Initialize the Ethernet server library +// with the IP address and port you want to use +// (port 80 is default for HTTP): +EthernetServer server(80); + + +// Focuser fields +volatile int position = 0; +bool moving = false; +int target_steps = 0; +unsigned long lastStepTime = 0; +const int stepDelay = 100; // ms per step +const int up_limit = 100; +const int down_limit = -100; + +int moveSteps = 0; +bool abortMovement = false; + +// Movement Tuning parameters +float maxClkFreq = 770; // in Hz +float minClkFreq = 400; // in Hz +float clkRamp = 2; // in Hz + +// Limit Conditionals +bool atTop; +bool atBottom; + +// Pin Numbers +int clkPin = 9; // yellow +int dirPin = 8; // brown +int enPin = 7; // green +int topLimPin = 3; +int botLimPin = 2; +// ground is black + +void setup() { + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + Serial.println("Ethernet WebServer Booting"); + + // start the Ethernet connection and the server: + Ethernet.begin(mac, ip); + + // Check for Ethernet hardware present + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + while (true) { + delay(1); // do nothing, no point running without Ethernet hardware + } + } + if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + } + + // Define pins + pinMode(clkPin, OUTPUT); + pinMode(dirPin, OUTPUT); + pinMode(enPin, OUTPUT); + pinMode(topLimPin, INPUT); + pinMode(botLimPin, INPUT); + + // Check Limits Before starting + atTop = digitalRead(topLimPin) == LOW; // Based on Measurements from fall, 0V means limit hit and 3.3V means limit not hit + atBottom = digitalRead(botLimPin) == LOW; + digitalWrite(enPin, HIGH); + + // start the server + server.begin(); + Serial.print("Server starting at "); + Serial.println(Ethernet.localIP()); +} + + +void loop() { + // listen for incoming clients + updatePosition(); + EthernetClient client = server.available(); + if (client) { + + handleClient(client); + + // give the web browser time to receive the data + delay(1); + + // close the connection: + client.stop(); + } +} + + +void handleClient(EthernetClient client) { + char request[128]; + int i = 0; + + // Retrieve client command + while (client.connected() && i < 127) { + if (client.available()) { + char c = client.read(); + if (c == '\n' || c == '\r') break; + request[i++] = c; + } + } + request[i] = '\0'; + + + /* + To test the following commands enter something like "192.168.1.11/status" in web browser + can also test with "curl -X GET http://192.168.1.11/status" in terminal like powershell + ^ Make sure ethernet port IP of test computer is configured + (E.g. access ethernet settings of computer, change from DHCP to manual, use ip like 192.168.1.9 and basic mask like 255.255.0.0 ) + */ + + /* + Command: move?steps + Paramters: steps: + Returns: {code: } + ^ Descriptions of each json field are described in Focuser Arduino Specification Google Doc + Test code: "curl -X POST http://192.168.1.11/move?steps=500" + */ + if (strstr(request, "POST /move?steps")) { + char* stepsParam = strstr(request, "steps="); + bool positiveDirection; + if (stepsParam) { // moveMotor.shouldRun() + // if the request contains '-', then switch to negative direction + char* negative = strstr(request, "-"); + if (negative > stepsParam) { + digitalWrite(dirPin, LOW); // is this the right value to write? (SWAP DIGITAL WRITE AT OBSERVATORY IF REVERSED) + moveSteps = atoi(stepsParam + 7); // jump to the value after - sign + positiveDirection = false; + Serial.println("Going to move backward " + String(moveSteps) + " steps"); + } else { + digitalWrite(dirPin, HIGH); + moveSteps = atoi(stepsParam + 6); // jump to the value after = sign + positiveDirection = true; + Serial.println("Going to move forward " + String(moveSteps) + " steps"); + } + + if (moving) { + sendJSONResponse(client, 523, "\"code\":523"); + Serial.println("MOVEMENT CANCELLED: Motor Already Running"); + } else if (moveSteps > 10000 or moveSteps < 10) { + sendJSONResponse(client, 522, "\"code\":522"); + Serial.println("MOVEMENT CANCELLED: Incorrect step size! Try int32 that is >=10 and <=10000"); + } else { + startMovement(client, positiveDirection); + } + } + } + + + + /* + Command: status + Paramters: None + Returns: {moving: , voltage: , upper_limit: , lower_limit: , step: } + ^ Descriptions of each json field are described in Focuser Arduino Specification Google Doc + Test code: "curl -X GET http://192.168.1.11/status" + */ + if (strstr(request, "GET /status")) { + sendJSONResponse(client, 200, + "\"moving\":" + String(moving) + ",\"step\":" + String(position) + ",\"limit\":" + String(checkLimits())); + + Serial.println("Status Message Sent! :D"); + } + + /* + Command: abort + Paramters: none + Returns: {code: } + ^ Descriptions of each json field are described in Focuser Arduino Specification Google Doc + Test code: "curl -X POST http://192.168.1.11/abort" + */ + else if (strstr(request, "POST /abort")) { + if (moving) { + abortMovement = true; + sendJSONResponse(client, 200, "\"code\":200"); + Serial.println("Movement Aborted"); + } else { + sendJSONResponse(client, 530, "\"code\":530"); + Serial.println("ABORT CANCELLED: Motor is not currently moving"); + } + } +} + + +// Code for formatting json return strings +void sendJSONResponse(EthernetClient client, int code, String body) { + client.println("HTTP/1.1 " + String(code) + " OK"); + client.println("Content-Type: application/json"); + client.println("Connection: close"); + client.println(); + client.println("{" + body + "}"); +} + +bool checkLimits() { + return (digitalRead(topLimPin) == LOW || digitalRead(botLimPin) == LOW); +} +// Emulating the potentiometer position +void updatePosition() { + if (moving && (millis() - lastStepTime > stepDelay)) { + position += (target_steps > 0) ? 1 : -1; + target_steps -= (target_steps > 0) ? 1 : -1; + lastStepTime = millis(); + + if (target_steps == 0 || checkLimits()) { + moving = false; + position = constrain(position, down_limit, up_limit); + } + } +} + +void startMovement(EthernetClient client, bool positiveDirection) { + moving = true; + int maxFreq = maxClkFreq; + + + // Period is 1/f, we want to convert to ms then divide by 2 since pulseTime should be half of a clock cycle + long minPeriod = long(float(1) * 500000.0 / maxClkFreq); + long currPeriod = long(float(1) * 500000.0 / minClkFreq); + + int rampDistance = (maxClkFreq-minClkFreq) / clkRamp; + Serial.println("RAMP DISTANCE" + String(rampDistance)); + + //Pre Define Stages + int rampUpEnd = rampDistance; + int rampDownStart = moveSteps - rampDistance; + if(rampDistance > int(moveSteps/2)) { + rampUpEnd = int(moveSteps/2); + rampDownStart = int(moveSteps/2) + 1; + maxFreq = int(minClkFreq+rampUpEnd*clkRamp); + minPeriod = long(float(1) * 500000.0 / maxFreq); + } + + int i = 0; + while (i < moveSteps) { + long pastTime = micros(); + + // Check all conditions before sending clock signal + if (abortMovement) { + abortMovement = false; + return; + } else if (digitalRead(topLimPin) == LOW) { + sendJSONResponse(client, 520, "\"code\":520"); + position = position + i; + Serial.println(); + Serial.println("MOVEMENT CANCELLED: Top limit hit!"); + return; + } else if (digitalRead(botLimPin) == LOW) { + position = position - i; + sendJSONResponse(client, 521, "\"code\":521"); + Serial.println(); + Serial.println("MOVEMENT CANCELLED: Bottom limit hit!"); + return; + } else { + //Positive edge of clk + digitalWrite(clkPin, HIGH); + Serial.print("clkHigh"); + + // delay until halfway through period designated by clk_frequency + while (micros() - pastTime < currPeriod) {Serial.println("WAITING");} + + pastTime = micros(); + digitalWrite(clkPin, LOW); + Serial.print("clkLow"); + + i++; + + // CODE FOR DETERMINING THE NEXT CLOCK PERIOD LENGTH + if(i <= rampUpEnd && currPeriod != minPeriod){ + long newPeriod = long(float(1) * 500000.0 / (minClkFreq+i*clkRamp)); // If at i = 1 and clkRamp = 2, sets clk Freq to 1*2 + startClkFreq (in Hz) + if(newPeriod > minPeriod) { + currPeriod = newPeriod; + } + } + else if (i >= rampDownStart){ + currPeriod = long(float(1) * 500000.0 / (maxFreq - (i-rampDownStart)*clkRamp)); + } + } + + // delay until reach the end of period + while (micros() - pastTime < currPeriod) {Serial.println("WAITING");} + } + + Serial.println(); + Serial.println("Movement successfully finished (Huge Dub)"); + moving = false; + if (positiveDirection) { + position = position + moveSteps; + } + else { + position = position - moveSteps; + } + + sendJSONResponse(client, 200, "\"code\":200"); +} \ No newline at end of file diff --git a/focusControllerOld.ino b/focusControllerOld.ino deleted file mode 100644 index 5209784..0000000 --- a/focusControllerOld.ino +++ /dev/null @@ -1,216 +0,0 @@ -// Define driver output pins -int engPin = 7; -int dirPin = 6; -int clkPin = 5; - -void setup() { - pinMode(clkPin, OUTPUT); - pinMode(engPin, OUTPUT); - pinMode(dirPin, OUTPUT); - - Serial.begin(9600); - - // Wait for Serial connection to initialize before proceeding - while (!Serial) ; - Serial.println("Input 1 to Turn LED on and 2 to turn off"); -} - -void loop() { - if (Serial.available()) - { - int state = Serial.parseInt(); - switch (state) { - case 1: - Serial.println("Move Forward"); - - digitalWrite(engPin, LOW); // Motor is enabled when eng = 0 - digitalWrite(dirPin, LOW); - - moveMotor(clkPin, 250); - break; - - case 2: - Serial.println("Move Backward"); - - digitalWrite(engPin, LOW); - digitalWrite(dirPin, HIGH); - - moveMotor(clkPin, 250); - break; - - case 3: - Serial.println("Motor Off"); - - digitalWrite(engPin, HIGH); - break; - - case 4: - Serial.println("Basic Test"); - - digitalWrite(engPin, LOW); - digitalWrite(dirPin, HIGH); - - int period = 25; - for (int i = 0; i < 100; i++) - { - digitalWrite(clkPin, HIGH); - delay(period); - digitalWrite(clkPin, LOW); - delay(period); - } - break; - default: - // statements - break; - } - - - - if (state == 4) - { - Serial.println("Basic Test"); - - digitalWrite(engPin, LOW); - digitalWrite(dirPin, HIGH); - int period = 25; - for (int i = 0; i < 10; i++) - { - digitalWrite(clkPin, HIGH); - delay(period); - digitalWrite(clkPin, LOW); - delay(period); - } - } - } -} - -void testMotor(int clkPin) -{ - int testPeriod = 500; - int numSpin = 2; - for (int i = 0; i < numSpin; i++) - { - digitalWrite(clkPin, HIGH); - delay(testPeriod); - digitalWrite(clkPin, LOW); - delay(testPeriod); - } -} - -void moveMotor(int clkPin, int targetNumSteps) // Linear ramp to stop speed then -{ - int slowPeriod = 20; // 20 Hz, could be changed to whatever - int fastPeriod = 10; // 500 Hz (Measured clock speed at MRO was 770 Hz) - int accelTime = slowPeriod - fastPeriod; //Number of steps to reach max clk speed, in the case of linear ramp it is just slow - fast - int numSteps= 0; - - // Start Motor - // Non linear example: for ( int i = slowPeriod, i>= fastPeriod; i = int(i/1.33) ) - - //Linear Ramp: - int clkPeriod = slowPeriod; - while(clkPeriod >= fastPeriod && numSteps < targetNumSteps - accelTime) - { - digitalWrite(clkPin, HIGH); - delay(clkPeriod); - digitalWrite(clkPin, LOW); - delay(clkPeriod); - - Serial.print("Accelerating, Clkperiod = "); Serial.println(clkPeriod); - numSteps++; - clkPeriod--; - } - - //Stay at max speed until we are ready to decelerate - while (numSteps < targetNumSteps - accelTime) - { - digitalWrite(clkPin, HIGH); - delay(fastPeriod); - digitalWrite(clkPin, LOW); - delay(fastPeriod); - - Serial.print("Max speed, Clkperiod = "); Serial.println(clkPeriod); - numSteps++; - } - - //Linear ramp down to slowPeriod - clkPeriod = fastPeriod; - while(clkPeriod < slowPeriod && numSteps < targetNumSteps) - { - digitalWrite(clkPin, HIGH); - delay(clkPeriod); - digitalWrite(clkPin, LOW); - delay(clkPeriod); - - Serial.print("Deccelerating, Clkperiod = "); Serial.println(clkPeriod); - Serial.println(clkPeriod); - numSteps++; - clkPeriod++; - } - - Serial.println("Motor has stopped...hopefully ._."); -} - -void moveMotorSmooth(int motorPin) -{ - float freq = 150; // Initial frequency of the clock signal (2 Hz) - float targetFreq = 3080; // Target frequency of the clock signal (770 Hz) - float k = 0.05; // Rate of frequency change - unsigned long prevMillis = 0; // Used to time frequency changes - unsigned long interval = 1; // Interval for frequency updates (in milliseconds) - bool moveCancelled = false; - - while(!moveCancelled) - { - // Calculate the current frequency using asymptotic formula from chat gpt - // Asymptotic: - //freq = freq - (freq - targetFreq) / (1 + exp(-k * ((millis() / 1000.0) - 1000))); - freq++; - // Update the frequency every 'interval' milliseconds - unsigned long currentMillis = millis(); - if (currentMillis - prevMillis >= interval) { - prevMillis = currentMillis; - - // Update the tone frequency - tone(motorPin, freq); // Generate the clock signal with the calculated frequency - } - - // Optionally print the current frequency to the Serial Monitor - Serial.println(freq); - - //If the frequency reaches or exceeds the target, stop generating the clock signal - if (freq >= targetFreq - 1) { - //noTone(motorPin); // Stop the clock signal when target is reached - Serial.println("Target frequency reached."); - moveCancelled = true; - } - } - - delay(800); - - while(freq > 0) - { - // Calculate the current frequency using asymptotic formula from chat gpt - // Asymptotic: freq = freq - (freq - targetFreq) / (1 + exp(-k * (millis() / 1000.0 - 1000))); - freq--; - // Update the frequency every 'interval' milliseconds - unsigned long currentMillis = millis(); - if (currentMillis - prevMillis >= interval) { - prevMillis = currentMillis; - - // Update the tone frequency - tone(motorPin, freq); // Generate the clock signal with the calculated frequency - } - - // Optionally print the current frequency to the Serial Monitor - Serial.println(freq); - - // If the frequency reaches or exceeds the target, stop generating the clock signal - if (freq <= 150) { - freq = 0; - noTone(motorPin); // Stop the clock signal when target is reached - Serial.println("Target frequency reached."); - } - } - -} \ No newline at end of file diff --git a/focusControllerOld/focusControllerOld.ino b/focusControllerOld/focusControllerOld.ino new file mode 100644 index 0000000..65641a6 --- /dev/null +++ b/focusControllerOld/focusControllerOld.ino @@ -0,0 +1,323 @@ +/* + MRO Focus Controller (NON THREADED VERSION) + + An arduino that sends focussing based commands to the Manastash Ridge Observatory + + The arduino hosts a simple Arduino web server, and recieves commands via + web server actions sent over it's ethernet port + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + * Clock Motor Output - pin 9 + * Direction Motor Output - pin 8 + * Enable Motor Output - pin 7 + * Limit pin 1 - pin 6 + * Limit pin 2 - pin 5 + * Potentiometer - TinkerKit connection "IN3" + + Code written by AUEG Arduino Team 2025! + */ + +#include +#include + +// MAC address and IP address for controller +byte mac[] = { 0xA8, 0x61, 0x0A, 0xAE, 0x25, 0x13 }; +IPAddress ip(192, 168, 1, 11); + +// Initialize the Ethernet server library +// with the IP address and port you want to use +// (port 80 is default for HTTP): +EthernetServer server(80); + + +// Focuser fields +volatile int position = 0; +bool moving = false; +int target_steps = 0; +unsigned long lastStepTime = 0; +const int stepDelay = 100; // ms per step +const int up_limit = 100; +const int down_limit = -100; + +int moveSteps = 0; +bool abortMovement = false; + +// Movement Tuning parameters +float maxClkFreq = 770; // in Hz +float minClkFreq = 10; // in Hz +float clkRamp = 2; // in Hz + +// Limit Conditionals +bool atTop; +bool atBottom; + +// Pin Numbers +int clkPin = 9; +int dirPin = 8; +int enPin = 7; +int topLimPin = 3; +int botLimPin = 2; + +void setup() { + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + Serial.println("Ethernet WebServer Booting"); + + // start the Ethernet connection and the server: + Ethernet.begin(mac, ip); + + // Check for Ethernet hardware present + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + while (true) { + delay(1); // do nothing, no point running without Ethernet hardware + } + } + if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + } + + // Define pins + pinMode(clkPin, OUTPUT); + pinMode(dirPin, OUTPUT); + pinMode(enPin, OUTPUT); + pinMode(topLimPin, INPUT); + pinMode(botLimPin, INPUT); + + // Check Limits Before starting + atTop = digitalRead(topLimPin) == LOW; // Based on Measurements from fall, 0V means limit hit and 3.3V means limit not hit + atBottom = digitalRead(botLimPin) == LOW; + + // start the server + server.begin(); + Serial.print("Server starting at "); + Serial.println(Ethernet.localIP()); +} + + +void loop() { + // listen for incoming clients + updatePosition(); + EthernetClient client = server.available(); + if (client) { + + handleClient(client); + + // give the web browser time to receive the data + delay(1); + + // close the connection: + client.stop(); + } +} + + +void handleClient(EthernetClient client) { + char request[128]; + int i = 0; + + // Retrieve client command + while (client.connected() && i < 127) { + if (client.available()) { + char c = client.read(); + if (c == '\n' || c == '\r') break; + request[i++] = c; + } + } + request[i] = '\0'; + + + /* + To test the following commands enter something like "192.168.1.11/status" in web browser + can also test with "curl -X GET http://192.168.1.11/status" in terminal like powershell + ^ Make sure ethernet port IP of test computer is configured + (E.g. access ethernet settings of computer, change from DHCP to manual, use ip like 192.168.1.9 and basic mask like 255.255.0.0 ) + */ + + /* + Command: move?steps + Paramters: steps: + Returns: {code: } + ^ Descriptions of each json field are described in Focuser Arduino Specification Google Doc + Test code: "curl -X POST http://192.168.1.11/move?steps=500" + */ + if (strstr(request, "POST /move?steps")) { + char* stepsParam = strstr(request, "steps="); + bool positiveDirection; + if (stepsParam) { // moveMotor.shouldRun() + // if the request contains '-', then switch to negative direction + char* negative = strstr(request, "-"); + if (negative > stepsParam) { + digitalWrite(dirPin, LOW); // is this the right value to write? (SWAP DIGITAL WRITE AT OBSERVATORY IF REVERSED) + moveSteps = atoi(stepsParam + 7); // jump to the value after - sign + positiveDirection = false; + Serial.println("Going to move backward " + String(moveSteps) + " steps"); + } else { + digitalWrite(dirPin, HIGH); + moveSteps = atoi(stepsParam + 6); // jump to the value after = sign + positiveDirection = true; + Serial.println("Going to move forward " + String(moveSteps) + " steps"); + } + + if (moving) { + sendJSONResponse(client, 523, "\"code\":523"); + Serial.println("MOVEMENT CANCELLED: Motor Already Running"); + } else if (moveSteps > 10000 or moveSteps < 10) { + sendJSONResponse(client, 522, "\"code\":522"); + Serial.println("MOVEMENT CANCELLED: Incorrect step size! Try int32 that is >=10 and <=10000"); + } else { + startMovement(client, positiveDirection); + } + } + } + + + + /* + Command: status + Paramters: None + Returns: {moving: , voltage: , upper_limit: , lower_limit: , step: } + ^ Descriptions of each json field are described in Focuser Arduino Specification Google Doc + Test code: "curl -X GET http://192.168.1.11/status" + */ + if (strstr(request, "GET /status")) { + sendJSONResponse(client, 200, + "\"moving\":" + String(moving) + ",\"step\":" + String(position) + ",\"limit\":" + String(checkLimits())); + + Serial.println("Status Message Sent! :D"); + } + + /* + Command: abort + Paramters: none + Returns: {code: } + ^ Descriptions of each json field are described in Focuser Arduino Specification Google Doc + Test code: "curl -X POST http://192.168.1.11/abort" + */ + else if (strstr(request, "POST /abort")) { + if (moving) { + abortMovement = true; + sendJSONResponse(client, 200, "\"code\":200"); + Serial.println("Movement Aborted"); + } else { + sendJSONResponse(client, 530, "\"code\":530"); + Serial.println("ABORT CANCELLED: Motor is not currently moving"); + } + } +} + + +// Code for formatting json return strings +void sendJSONResponse(EthernetClient client, int code, String body) { + client.println("HTTP/1.1 " + String(code) + " OK"); + client.println("Content-Type: application/json"); + client.println("Connection: close"); + client.println(); + client.println("{" + body + "}"); +} + +bool checkLimits() { + return (digitalRead(topLimPin) == LOW || digitalRead(botLimPin) == LOW); +} +// Emulating the potentiometer position +void updatePosition() { + if (moving && (millis() - lastStepTime > stepDelay)) { + position += (target_steps > 0) ? 1 : -1; + target_steps -= (target_steps > 0) ? 1 : -1; + lastStepTime = millis(); + + if (target_steps == 0 || checkLimits()) { + moving = false; + position = constrain(position, down_limit, up_limit); + } + } +} + +void startMovement(EthernetClient client, bool positiveDirection) { + moving = true; + int maxFreq = maxClkFreq; + + + // Period is 1/f, we want to convert to ms then divide by 2 since pulseTime should be half of a clock cycle + long minPeriod = long(float(1) * 500000.0 / maxClkFreq); + long currPeriod = long(float(1) * 500000.0 / minClkFreq); + + int rampDistance = (maxClkFreq-minClkFreq) / clkRamp; + Serial.println("RAMP DISTANCE" + String(rampDistance)); + + //Pre Define Stages + int rampUpEnd = rampDistance; + int rampDownStart = moveSteps - rampDistance; + if(rampDistance > int(moveSteps/2)) { + rampUpEnd = int(moveSteps/2); + rampDownStart = int(moveSteps/2) + 1; + maxFreq = int(minClkFreq+rampUpEnd*clkRamp); + minPeriod = long(float(1) * 500000.0 / maxFreq); + } + + int i = 0; + while (i < moveSteps) { + long pastTime = micros(); + + // Check all conditions before sending clock signal + if (abortMovement) { + abortMovement = false; + return; + } else if (digitalRead(topLimPin) == LOW) { + sendJSONResponse(client, 520, "\"code\":520"); + position = position + i; + Serial.println(); + Serial.println("MOVEMENT CANCELLED: Top limit hit!"); + return; + } else if (digitalRead(botLimPin) == LOW) { + position = position - i; + sendJSONResponse(client, 521, "\"code\":521"); + Serial.println(); + Serial.println("MOVEMENT CANCELLED: Bottom limit hit!"); + return; + } else { + //Positive edge of clk + digitalWrite(clkPin, HIGH); + Serial.print("clkHigh"); + + // delay until halfway through period designated by clk_frequency + while (micros() - pastTime < currPeriod) {Serial.println("WAITING");} + + pastTime = micros(); + digitalWrite(clkPin, LOW); + Serial.print("clkLow"); + + i++; + + // CODE FOR DETERMINING THE NEXT CLOCK PERIOD LENGTH + if(i <= rampUpEnd && currPeriod != minPeriod){ + long newPeriod = long(float(1) * 500000.0 / (minClkFreq+i*clkRamp)); // If at i = 1 and clkRamp = 2, sets clk Freq to 1*2 + startClkFreq (in Hz) + if(newPeriod > minPeriod) { + currPeriod = newPeriod; + } + } + else if (i >= rampDownStart){ + currPeriod = long(float(1) * 500000.0 / (maxFreq - (i-rampDownStart)*clkRamp)); + } + } + + // delay until reach the end of period + while (micros() - pastTime < currPeriod) {Serial.println("WAITING");} + } + + Serial.println(); + Serial.println("Movement successfully finished (Huge Dub)"); + moving = false; + if (positiveDirection) { + position = position + moveSteps; + } + else { + position = position - moveSteps; + } + + sendJSONResponse(client, 200, "\"code\":200"); +} \ No newline at end of file From b7c6ca8f65499c9425b8bc8690de444c3d08d257 Mon Sep 17 00:00:00 2001 From: timpy2by3 Date: Sat, 17 May 2025 12:59:11 -0700 Subject: [PATCH 3/3] working focuser as of 5.17.2025; removed all print statements during the main loop in the start movement method. --- focusControllerNew/focusControllerNew.ino | 28 ++++++++++++----------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/focusControllerNew/focusControllerNew.ino b/focusControllerNew/focusControllerNew.ino index 2979a91..ed759e6 100644 --- a/focusControllerNew/focusControllerNew.ino +++ b/focusControllerNew/focusControllerNew.ino @@ -243,13 +243,13 @@ void startMovement(EthernetClient client, bool positiveDirection) { moving = true; int maxFreq = maxClkFreq; - - // Period is 1/f, we want to convert to ms then divide by 2 since pulseTime should be half of a clock cycle + // Period is 1/f, we want to convert to us then divide by 2 since pulseTime should be half of a clock cycle long minPeriod = long(float(1) * 500000.0 / maxClkFreq); long currPeriod = long(float(1) * 500000.0 / minClkFreq); int rampDistance = (maxClkFreq-minClkFreq) / clkRamp; - Serial.println("RAMP DISTANCE" + String(rampDistance)); + Serial.println("RAMP DISTANCE " + String(rampDistance)); + Serial.println("minPd " + String(minPeriod) + " maxPd " + String(currPeriod)); //Pre Define Stages int rampUpEnd = rampDistance; @@ -258,14 +258,14 @@ void startMovement(EthernetClient client, bool positiveDirection) { rampUpEnd = int(moveSteps/2); rampDownStart = int(moveSteps/2) + 1; maxFreq = int(minClkFreq+rampUpEnd*clkRamp); - minPeriod = long(float(1) * 500000.0 / maxFreq); + minPeriod = long(float(1) * 50000.0 / maxFreq); } int i = 0; + while (i < moveSteps) { long pastTime = micros(); - // Check all conditions before sending clock signal if (abortMovement) { abortMovement = false; return; @@ -281,17 +281,19 @@ void startMovement(EthernetClient client, bool positiveDirection) { Serial.println(); Serial.println("MOVEMENT CANCELLED: Bottom limit hit!"); return; - } else { + } + + else { //Positive edge of clk digitalWrite(clkPin, HIGH); - Serial.print("clkHigh"); + //Serial.print("clkHigh"); // delay until halfway through period designated by clk_frequency - while (micros() - pastTime < currPeriod) {Serial.println("WAITING");} + while (micros() - pastTime < currPeriod) {} //Serial.println("WAITING"); pastTime = micros(); digitalWrite(clkPin, LOW); - Serial.print("clkLow"); + //Serial.print("clkLow"); i++; @@ -305,11 +307,11 @@ void startMovement(EthernetClient client, bool positiveDirection) { else if (i >= rampDownStart){ currPeriod = long(float(1) * 500000.0 / (maxFreq - (i-rampDownStart)*clkRamp)); } - } - // delay until reach the end of period - while (micros() - pastTime < currPeriod) {Serial.println("WAITING");} - } + // delay until reach the end of period + while (micros() - pastTime < currPeriod) {} //Serial.println("WAITING - END"); + } + } Serial.println(); Serial.println("Movement successfully finished (Huge Dub)");