Bi-monthly release with minor bug fixes and improvements
Please Log in or Create an account to join the conversation.
#include <AccelStepper.h> // https://www.pjrc.com/teensy/td_libs_AccelStepper.html
#define EnablePin 12
#define IN1 4
#define IN2 5
#define IN3 6
#define IN4 7
#define MotorInterfaceType 4
#include <EEPROM.h>
// EEPROM addresses
#define FOCUSER_POS_START 0
#define STEPPER_SPEED_ADD 3
AccelStepper stepper(MotorInterfaceType, IN1, IN2, IN3, IN4);
// Global vars
boolean moving = false;
boolean hold = false;
boolean reversed;
boolean positionSaved; // Flag indicates if stepper position was saved as new focuser position
boolean firstPrint = false;
boolean homeFound = true;
String inputString; // Serial input command string (terminated with \n)
boolean findingHome = false;
// ************* this value must be changed for each specific setup ***************************************
long maxSteps = 505960; // **** steps needed for 2 complete revolutions. prevent cord wrap.
long minStep = 0;
// Must also enter this value/720 = steps/degree for first time ASCOM driver setup, click "properties
// ******************************************************************************************************
int manualMoveStepSize = 50; //higher number for faster manual moves
int findHomeStepSize = 100; //adjusts finding home speed
int buttonStateCW = HIGH;
int buttonStateCCW = HIGH;
boolean manualMoveCW = false;
boolean manualMoveCCW = false;
int HEState = 0;
long lastDebounceTime = 0;
long debounceDelay = 20;
void setup()
{
// Initialize serial
Serial.begin(57600);
pinMode(EnablePin, OUTPUT);
analogWrite(EnablePin, 0);
// Initialize stepper motor
stepper.setMaxSpeed(200);// 5000 works good, use 500000 for confrom test1000 geared rotator10000 for geared stepper 200 for non-geared large stepper(500 max) also may depend on what else is on loop()
stepper.setAcceleration(1000);//1000 for geared rotator 10000 for geared stepper 1000 for non-geared large stepper
//stepper.setCurrentPosition(readFocuserPos());
stepper.setCurrentPosition(0);
positionSaved = true;
inputString = "";
reverseDir(false);
}
void loop()
{
if (findingHome == true) {
findHome();
}
// Stepper loop
if (stepper.distanceToGo() == 0) {
if (hold == false) {
analogWrite(EnablePin, HIGH);
}
} else {
analogWrite(EnablePin, 200);
}
if (stepper.distanceToGo() == 0 && !positionSaved) {
saveFocuserPos(stepper.currentPosition());
positionSaved = true;
}
if (stepper.distanceToGo() != 0 && !firstPrint) {
firstPrint = true;
}
if (stepper.distanceToGo() != 0) {
moving = true;
} else {
moving = false;
}
stepper.run();
}
// Interrupt serial event
void reverseDir(boolean rev) {
stepper.setPinsInverted(rev, false, false); //for FSQ85(true, false, false) --- for TSA 120should be (false, false, false) (dir, step, enable)
//not reversed is std setup for tsa-120
reversed = rev;
}
void Hold(boolean conthold) {
hold = conthold;
}
void serialEvent() {
while (Serial.available() > 0) {
char inChar = (char)Serial.read();
if (inChar == ':' || inChar == '#') {
if (inputString == "PV") inputString = "V"; // Version
if (inputString == "GA") inputString = "B"; // bit 1 for switch 2
if (inputString == "SH") inputString = "H"; // Starts the Find Home routine
if (inputString == "GS") inputString = "Z"; // bit 2 for In limit switch
if (inputString == "GT") inputString = "D"; // Sensor temperature in tenths of a degree, ex: 25°C = 250d
if (inputString == "GV") inputString = "E"; // System voltage in tenths of a volt, ex 12.0V = 120d
if (inputString == "PD") inputString = "D"; // Set the display brightness
if (inputString == "PL") inputString = "D"; // Set the display sleep brightness
if (inputString == "PF") inputString = "F"; // Gets the current focuser type. Ex: "2.5 NC#"
if (inputString == "PS") inputString = "X"; // Gets the current focuser serial number
if (inputString == "PU") inputString = "W"; // Gets a user defined field
if (inputString == "PE") inputString = "C"; // Enables or disables the encoders
if (inputString == "PR") inputString = "J"; // Issues a reset
if (inputString == "Pt") inputString = "D"; // Adjusts the temperature offset
if (inputString == "Pu") inputString = "Y"; // Sets the user text field
serialCommand(inputString);
inputString = "";
}
else {
inputString += inChar;
}
}
}
void serialCommand(String command) {
String param = command.substring(4);
String comando = command.substring(0, 3); //:2SN 12345678#
if (comando == "2GP") command = "G"; // Current position count, 8 digits, signed, 0 padding
if (comando == "1GP") command = "K"; // DUMMY Current position
if (comando == "3GP") command = "K"; // DUMMY Current position
if (comando == "2GM") command = "Q"; // IS MOVING
if (comando == "2GN") command = "A"; // New (or Target) position count, 8 digits, signed, 0 padding
if (comando == "2GR") command = "A"; // Motor step delay in 100 microsecond intervals
if (comando == "2SQ") command = "S"; // Stops motor
if (comando == "2SM") command = "A"; // Starts motor to move to the “NEW” focus position
if (comando == "2SP") command = "P"; // Set the current position, 32 bit value, signed
if (comando == "2SN") command = "M"; // Move to the New position count, 32 bit value, signed
if (comando == "1SR") command = "A"; // Set the motor step rate in 100 microsecond intervals.
if (comando == "2SR") command = "A"; // Set the motor step rate in 100 microsecond intervals.
if (comando == "3SR") command = "A"; // Set the motor step rate in 100 microsecond intervals.
//Serial.println(command);
switch (command.charAt(0)) {
case 'Q':
if (moving == true) {
Serial.println("01#");
} else {
Serial.println("00#");
}
case 'Y':
Serial.println("RC 8#");
break;
case 'K':
Serial.println("30000#");
break;
case 'A':
Serial.println("#");
break;
case 'B':
Serial.println("00#");
break;
case 'Z':
Serial.println("00#");
break;
case 'D':
Serial.println("105#");
break;
case 'E':
Serial.println("123#");
break;
case 'F':
Serial.println("3.5 NC#");
break;
case 'X':
Serial.println("20200516#");
break;
case 'W':
Serial.println("StarPI Rotator#");
break;
case 'G':
printCurrentPosition();
break;
case 'P':
saveCurrentPos(stringToLong(param));
break;
case 'H': // find home
if (param = 2) findHome();
break;
case 'M':
moveStepper(stringToLong(param), false);
break;
case 'S':
halt();
break;
case 'R':
int value;
value = (stringToNumber(param));
if (value == 0) {
reverseDir(false);
} else {
reverseDir(true);
}
break;
case 'C':// continuos hold
int value2;
value2 = (stringToNumber(param));
if (value2 == 0) {
Hold(false);
} else {
Hold(true);
}
Serial.println("#");
break;
case 'V':
Serial.println("1.3#");
break;
case 'J': // Reset Arduino myFocuserPro2 controller
software_Reboot();
break;
}
}
void printCurrentPosition() {
Serial.print("00");
if (stepper.currentPosition() < 100000) Serial.print("0");
if (stepper.currentPosition() < 10000) Serial.print("0");
if (stepper.currentPosition() < 1000) Serial.print("0");
if (stepper.currentPosition() < 100) Serial.print("0");
if (stepper.currentPosition() < 10) Serial.print("0");
Serial.print(stepper.currentPosition());
Serial.println("#");
}
void moveStepper(long newPos, boolean manualMove) {
Serial.println("#");
if (findingHome == true) {
stepper.moveTo(newPos);
return;
}
if (newPos != stepper.currentPosition()) {
if (newPos < minStep || newPos > maxSteps) {
return;
} else {
stepper.moveTo(newPos);
positionSaved = false;
firstPrint = false;
}
}
}
void halt() {
Serial.println("#");
stepper.stop();
}
void saveCurrentPos(long newPos) {
Serial.println("#");
if (newPos < minStep) newPos = minStep;
stepper.setCurrentPosition(newPos);
moveStepper(newPos, false);
saveFocuserPos(newPos);
positionSaved = true;
}
void findHome() {
Serial.println("#");
long newPos = maxSteps / 4;
homeFound = true;
findingHome = false;
saveCurrentPos(newPos);
}
// reboot the Arduino
void software_Reboot() {
// jump to the start of the program
asm volatile ( "jmp 0");
}
void saveFocuserPos(long newPos) {
writeLong(getSaveFocuserPosAddress() + 1, newPos);
}
long readFocuserPos() {
return readLong(getReadFocuserPosAddress() + 1);
}
void writeWord(word address, word value) {
EEPROM.update(address, lowByte(value));
EEPROM.update(address + 1, highByte(value));
}
word readWord(word address) {
return word(EEPROM.read(address + 1), EEPROM.read(address));
}
long readLong(word address) {
word lowWord = readWord(address);
word highWord = readWord(address + 2);
return lowWord + highWord * 65536;
}
void writeLong(word address, long value) {
word lowWord = value % 65536;
word highWord = value / 65536;
writeWord(address, lowWord);
writeWord(address + 2, highWord);
}
int stringToNumber(String thisString) {
int i, value = 0, length;
length = thisString.length();
for (i = 0; i < length; i++) {
value = (10 * value) + thisString.charAt(i) - (int) '0';
}
return value;
}
long stringToLong(String thisString) {
boolean neg = false;
if (thisString.indexOf("-") == 0) {
thisString = thisString.substring(1);
neg = true;
}
//Serial.println(thisString);
long value = 0;
int i, length;
length = thisString.length();
for (i = 0; i < length; i++) {
value = (10 * value) + thisString.charAt(i) - (int) '0';
}
if (neg == true) {
value = maxSteps - value;
}
return value;
}
// Simple EEPROM wear leveling
int getSaveFocuserPosAddress() {
for (byte x = 0; x < 20; x++) {
int address = FOCUSER_POS_START + 5 * x;
if (EEPROM.read(address) == 0) {
EEPROM.update(address, 0xFF);
return address;
}
}
// Array is full, erase it and start from 0 - takes about 100ms
for (byte x = 0; x < 20; x++) {
EEPROM.update(FOCUSER_POS_START + 5 * x, 0);
EEPROM.update(FOCUSER_POS_START, 0xFF);
return FOCUSER_POS_START;
}
}
int getReadFocuserPosAddress() {
for (byte x = 0; x < 20; x++) {
int address = FOCUSER_POS_START + 5 * x;
if (EEPROM.read(address) == 0) {
return FOCUSER_POS_START + 5 * (x - 1);
}
}
}
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.