×

INDI Library v2.0.7 is Released (01 Apr 2024)

Bi-monthly release with minor bug fixes and improvements

Moonlite focuser protocol

  • Posts: 21
  • Thank you received: 1

Replied by Cees on topic Moonlite focuser protocol

Speed does not seem to be a problem. I scavenged a stepper motor from an old epson r230 printer and am using a easydriver stepper board with 12V supply to the motor. Seems to work nicely. I've also connected arduino pin 4 to the easydriver sleep pin and switch it low when isRunnig is low and back on when receiving the FQ command to start moving. Keeps the board cool.
Of course rain has come and I haven't been able to test it outside yet. Maybe next weekend.
9 years 11 months ago #1041

Please Log in or Create an account to join the conversation.

  • Posts: 85
  • Thank you received: 3

Hi.
I also want to run a homemade focuser with an arduino+easy stepper with indi running on a raspberry pi.

I've looked into running the INDIDUINOStepper firmware (indiduino.wordpress.com/2012/12/03/focusser/)
but I don't understand fully how it will work without a driver, or am I missing something?

Running with the moonlite driver sounds like a good option and I was wondering if it was possible to use your arduino sketch modified for indi?

Regards
Daniel
9 years 11 months ago #1060

Please Log in or Create an account to join the conversation.

  • Posts: 21
  • Thank you received: 1

Replied by Cees on topic Moonlite focuser protocol

Sure.
The original script is by orly_andico orlygoingthirty.blogspot.co.nz/2014/04/a...user-controller.html.

I have attached a file with my modifications. The instructions for printing the leading zeros I found somewhere on the net but can't remember where.

I am using an arduino pro-mini 3.3V and cp2102 based USB to TTL converter (all ebay). I do not use a capacitor between GND and RESET (the converter doesn't have a proper reset pin). It seems to work. All that is connected is RXD TXD 5V and GND on the converter to TXD RXD VCC and GND on the arduino.
pin 2,3,4 are connected to step, dir and sleep on the easydriver. The easy driver is powered with a seperate 12V supply.

It runs on a leonardo as well through usb. Only tried it in simulation mode without the easydriver connected but it connects and does respond to commands from the moonlite driver.

Hope this helps
9 years 11 months ago #1066

Please Log in or Create an account to join the conversation.

  • Posts: 21
  • Thank you received: 1

Replied by Cees on topic Moonlite focuser protocol

Whoops. Didn't insert the file. Try again

nope. file attach doesn't work. try code
// Moonlite-compatible stepper controller
//
// Uses AccelStepper (http://www.airspayce.com/mikem/arduino/AccelStepper/)
//
// Requires a 10uf - 100uf capacitor between RESET and GND on the motor shield; this prevents the
// Arduino from resetting on connect (via DTR going low).  Without the capacitor, this sketch works
// with the stand-alone Moonlite control program (non-ASCOM) but the ASCOM driver does not detect it.
// Adding the capacitor allows the Arduino to respond quickly enough to the ASCOM driver probe
//
// orly.andico@gmail.com, 13 April 2014
//
// adapted for libindi and easydriver Cees Lensink
 
#include <AccelStepper.h>
 
int stepperPin = 2;
int dirPin = 3;
int powerPin = 4;
 
// maximum speed is 160pps which should be OK for most
// tin can steppers
#define MAXSPEED 160
#define SPEEDMULT 3
 
AccelStepper stepper(AccelStepper::DRIVER, stepperPin, dirPin);
 
#define MAXCOMMAND 8
 
char inChar;
char cmd[MAXCOMMAND];
char param[MAXCOMMAND];
char line[MAXCOMMAND];
long pos;
int isRunning = 0;
int speed = 32;
int eoc = 0;
int idx = 0;
 
char tempString[8]; 
 
void setup()
{  
  Serial.begin(9600);
 
  // we ignore the Moonlite speed setting because Accelstepper implements
  // ramping, making variable speeds un-necessary
  stepper.setSpeed(MAXSPEED);
  stepper.setMaxSpeed(MAXSPEED);
  stepper.setAcceleration(50);
  stepper.enableOutputs();
  memset(line, 0, MAXCOMMAND);
  // Easydriver Sleep mode or power off
  pinMode(powerPin,OUTPUT);
  // Easydriver Power off (Low = powered down)
  digitalWrite(powerPin, LOW);
 
}
 
 
 
void loop(){
  // run the stepper if there's no pending command and if there are pending movements
  if (!Serial.available())
  {
    if (isRunning) {
      stepper.run();
    } 
    else {
      stepper.disableOutputs();
      digitalWrite(powerPin, LOW); 
    }
    if (stepper.distanceToGo() == 0) {
      stepper.run();
      isRunning = 0;
    }
  } 
  else {
    // read the command until the terminating # character
    while (Serial.available() && !eoc) {
      inChar = Serial.read();
      if (inChar != '#' && inChar != ':') {
        line[idx++] = inChar;
        if (idx >= MAXCOMMAND) {
          idx = MAXCOMMAND - 1;
        }
      } 
      else {
        if (inChar == '#') {
          eoc = 1;
        }
      }
    }
  } // end if (!Serial.available())
 
  // process the command we got
  if (eoc) {
    memset(cmd, 0, MAXCOMMAND);
    memset(param, 0, MAXCOMMAND);
 
    int len = strlen(line);
    if (len >= 2) {
      strncpy(cmd, line, 2);
    }
 
    if (len > 2) {
      strncpy(param, line + 2, len - 2);
    }
 
    memset(line, 0, MAXCOMMAND);
    eoc = 0;
    idx = 0;
    // initiate a move
    if (!strcasecmp(cmd, "FG")) {
      isRunning = 1;
      digitalWrite(powerPin, HIGH);
      stepper.enableOutputs();
    }
    // stop a move
    if (!strcasecmp(cmd, "FQ")) {
      isRunning = 0;
      stepper.moveTo(stepper.currentPosition());
      stepper.run();
    }
    // get the temperature coefficient, hard-coded
    if (!strcasecmp(cmd, "GC")) {
      Serial.print("02#");
    }
    // get the current motor speed, only values of 02, 04, 08, 10, 20
    if (!strcasecmp(cmd, "GD")) {
      sprintf(tempString, "%02X", speed);
      Serial.print(tempString);
 
      Serial.print("#");
    }
    // whether half-step is enabled or not, always return "00"
    if (!strcasecmp(cmd, "GH")) {
      Serial.print("00#");
    }
    // motor is moving - 01 if moving, 00 otherwise
    if (!strcasecmp(cmd, "GI")) {
      if (stepper.distanceToGo() > 0) {
        Serial.print("01#");
      } 
      else {
        Serial.print("00#");
      }
    }
    // get the new motor position (target)
    if (!strcasecmp(cmd, "GN")) {
      pos = stepper.targetPosition();
      sprintf(tempString, "%04X", pos);
      Serial.print(tempString);
      Serial.print("#");
    }
    // get the current motor position
    if (!strcasecmp(cmd, "GP")) {
      pos = stepper.currentPosition();
      sprintf(tempString, "%04X", pos);
      Serial.print(tempString);
      Serial.print("#");
    }
    // get the current temperature, hard-coded
    if (!strcasecmp(cmd, "GT")) {
      Serial.print("0020#");
    }
    // firmware value, always return "10"
    if (!strcasecmp(cmd, "GV")) {
      Serial.print("10#");
    }
    // LED backlight value, always return "00"
    if (!strcasecmp(cmd, "GB")) {
      Serial.print("00#");
    }
 
    // home the motor, hard-coded, ignore parameters since we only have one motor
    if (!strcasecmp(cmd, "PH")) { 
      stepper.setCurrentPosition(8000);
      stepper.moveTo(0);
      isRunning = 1;
    }
    // set speed, only acceptable values are 02, 04, 08, 10, 20
    if (!strcasecmp(cmd, "SD")) {
      speed = hexstr2long(param);
 
      // we ignore the Moonlite speed setting because Accelstepper implements
      // ramping, making variable speeds un-necessary
 
      // stepper.setSpeed(speed * SPEEDMULT);
      // stepper.setMaxSpeed(speed * SPEEDMULT);
      stepper.setSpeed(MAXSPEED);
      stepper.setMaxSpeed(MAXSPEED);
    }
    // set current motor position
    if (!strcasecmp(cmd, "SP")) {
      pos = hexstr2long(param);
      stepper.setCurrentPosition(pos);
    }
 
    // set new motor position
    if (!strcasecmp(cmd, "SN")) {
      pos = hexstr2long(param);
      stepper.moveTo(pos);
    }
 
  }
} // end loop
 
long hexstr2long(char *line) {
  long ret = 0;
 
  ret = strtol(line, NULL, 16);
  return (ret);
}
 
 
The following user(s) said Thank You: Daniel Franzén
Last edit: 9 years 11 months ago by Cees.
9 years 11 months ago #1067

Please Log in or Create an account to join the conversation.

  • Posts: 85
  • Thank you received: 3
Thank you very much. I got my stepper motor to run using the moonlite focuser driver. Now I only have to assemble the focuser on my telescope :)

/Daniel
9 years 11 months ago #1076

Please Log in or Create an account to join the conversation.

  • Posts: 21
  • Thank you received: 1

Replied by Cees on topic Moonlite focuser protocol

Glad it works for you.
I'm going to have another look at this script and learn some arduino programming in the process.
I still haven't been able to try this out under clear skies but I'm finding that the auto focus routine (canon eos camera) the focuser driver reports the focuser reached the required position before it is actually there. Almost likes like it reports this before it has even started moving. It will than take the next frame to early. I suspect it has something to do with timing and running AccelStepper. Perhaps the Serial communication is to slow or blocking the stepper from starting . I don't know. We'll see.

Anyway, big thank you to orly_andico for getting this started.
9 years 11 months ago #1077

Please Log in or Create an account to join the conversation.

  • Posts: 11
  • Thank you received: 0
The reason it works without the capacitor is because the INDI driver is not interrogating the Moonlite controller on startup.

The ASCOM driver, once you connect, it immediately interrogates the controller, and if it doesn't immediately receive a response it does not detect the controller.

However the stand-alone app (and presumably the INDI driver) merely opens the connection and then starts merrily sending Moonlite commands. So long as the commands come in >2 seconds after connection (to give the Arduino a chance to reset) then all is well... :)
9 years 11 months ago #1087

Please Log in or Create an account to join the conversation.

  • Posts: 21
  • Thank you received: 1

Replied by Cees on topic Moonlite focuser protocol

I have made some more modifications. (Hope you are ok with this orly_andico ?).
The issue I saw was that the focus module would start capturing a new image when the focuser was still moving. Also, the inward move did not always report the correct position. Turns out there is a small bug in the original :GI# response.
stepper.distanceToGo() according to the AccelStepper "the distance from the current position to the target position in steps. Positive is clockwise from the current position" Therefor, in the original code any inward movement followed by a :GI# request would get a "I'm not moving" response when distanceToGo() < 0 and that is incorrect.
I have also modified the loop it bit and use the enablePin rather than the sleep pin although I haven't been able to try this other than simulation. (Still raining)

Any comments and or suggestions are welcome.

Can't figure out how to add an attachment to the post so here is the code
// Moonlite-compatible stepper controller
//
// Uses AccelStepper (http://www.airspayce.com/mikem/arduino/AccelStepper/)
//
// Inspired by (http://orlygoingthirty.blogspot.co.nz/2014/04/arduino-based-motor-focuser-controller.html)
// orly.andico@gmail.com, 13 April 2014
//
// Modified for indilib, easydriver by Cees Lensink
 
 
#include <AccelStepper.h>
 
int stepperPin = 2;
int dirPin = 3;
int powerPin = 4;
boolean useSleep = true; // true= use sleep pin, false = use enable pin
int ledPin = 13;
 
// maximum speed is 160pps which should be OK for most
// tin can steppers
#define MAXSPEED 160
#define SPEEDMULT 3
 
AccelStepper stepper(1, stepperPin, dirPin);
 
#define MAXCOMMAND 8
 
char inChar;
char cmd[MAXCOMMAND];
char param[MAXCOMMAND];
char line[MAXCOMMAND];
long pos;
int eoc = 0;
int idx = 0;
boolean isRunning = false;
 
char tempString[10];
 
 
void setup()
{  
  Serial.begin(9600);
  pinMode(powerPin,OUTPUT);
  // we ignore the Moonlite speed setting because Accelstepper implements
  // ramping, making variable speeds un-necessary
  stepper.setSpeed(MAXSPEED);
  stepper.setMaxSpeed(MAXSPEED);
  stepper.setAcceleration(50);
  turnOff();
  memset(line, 0, MAXCOMMAND);
}
 
 
//
 
//
 
 
void loop(){
  if (isRunning) { // only have to do this is stepper is on
    stepper.run();
    if (stepper.distanceToGo() == 0) {
      //  we have arrived, remove power from motor
      turnOff();
    }
  }
 
  // read the command until the terminating # character
  while (Serial.available() && !eoc) {
    inChar = Serial.read();
    if (inChar != '#' && inChar != ':') {
      line[idx++] = inChar;
      if (idx >= MAXCOMMAND) {
        idx = MAXCOMMAND - 1;
      }
    } 
    else {
      if (inChar == '#') {
        eoc = 1;
      }
    }
  } // end while Serial.available()
  // we may not have a complete command yet but there is no character coming in for now and might as well loop in case stepper needs updating
  // eoc will flag if a full command is there to act upon
 
  // process the command we got
  if (eoc) {
    memset(cmd, 0, MAXCOMMAND);
    memset(param, 0, MAXCOMMAND);
 
    int len = strlen(line);
    if (len >= 2) {
      strncpy(cmd, line, 2);
    }
 
    if (len > 2) {
      strncpy(param, line + 2, len - 2);
    }
 
    memset(line, 0, MAXCOMMAND);
    eoc = 0;
    idx = 0;
 
    //now execute the command 
 
    //Immediately stop any focus motor movement. returns nothing
    //code from Quickstop example. This is blocking
    if (!strcasecmp(cmd, "FQ")) {
      turnOn();
      stepper.stop(); // Stop as fast as possible: sets new target
      stepper.runToPosition(); 
      // Now stopped after quickstop
    }
 
    //Go to the new position as set by the ":SNYYYY#" command. returns nothing    // initiate a move
    //turn stepper on and flag it is running
    // is this the only command that should actually make the stepper run ?
    if (!strcasecmp(cmd, "FG")) {
      turnOn();
    }
 
    //Returns the temperature coefficient where XX is a two-digit signed (2’s complement) hex number.
    //hardcoded
    if (!strcasecmp(cmd, "GC")) {
      Serial.print("02#");      
    }
 
    //Returns the current stepping delay where XX is a two-digit unsigned hex number. See the :SD# command for a list of possible return values.
    //hardcoded for now
    // might turn this into AccelStepper acceleration at some point
    if (!strcasecmp(cmd, "GD")) {
      Serial.print("02#");      
    }
 
    //Returns "FF#" if the focus motor is half-stepped otherwise return "00#"
    //hardcoded
    if (!strcasecmp(cmd, "GH")) {
      Serial.print("00#");
    }
 
    //Returns "00#" if the focus motor is not moving, otherwise return "01#",
    //AccelStepper returns Positive as clockwise
    if (!strcasecmp(cmd, "GI")) {
      if (stepper.distanceToGo() == 0) {
        Serial.print("00#");
      } 
      else {
        Serial.print("01#");
      }
    }
 
    //Returns the new position previously set by a ":SNYYYY" command where YYYY is a four-digit unsigned hex number.
    if (!strcasecmp(cmd, "GN")) {
      pos = stepper.targetPosition();
      sprintf(tempString, "%04X", pos);
      Serial.print(tempString);
      Serial.print("#");
    }
 
    //Returns the current position where YYYY is a four-digit unsigned hex number.
    if (!strcasecmp(cmd, "GP")) {
      pos = stepper.currentPosition();
      sprintf(tempString, "%04X", pos);
      Serial.print(tempString);
      Serial.print("#");
    }
 
    //Returns the current temperature where YYYY is a four-digit signed (2’s complement) hex number.
    if (!strcasecmp(cmd, "GT")) {
      Serial.print("0020#");
    }
 
    //Get the version of the firmware as a two-digit decimal number where the first digit is the major version number, and the second digit is the minor version number.
    //hardcoded
    if (!strcasecmp(cmd, "GV")) {
      Serial.print("10#");
    }
 
    //Set the new temperature coefficient where XX is a two-digit, signed (2’s complement) hex number.
    if (!strcasecmp(cmd, "SC")) {
      //do nothing yet
    }
 
    //Set the new stepping delay where XX is a two-digit,unsigned hex number.
    if (!strcasecmp(cmd, "SD")) {
      //do nothing yet
    }
 
    //Set full-step mode.
    if (!strcasecmp(cmd, "SF")) {
      //do nothing yet
    }
 
    //Set half-step mode.
    if (!strcasecmp(cmd, "SH")) {
      //do nothing yet
    }
 
    //Set the new position where YYYY is a four-digit
    if (!strcasecmp(cmd, "SN")) {
      pos = hexstr2long(param);
      // stepper.enableOutputs(); // turn the motor on here ??
      turnOn();
      stepper.moveTo(pos);
    }
 
    //Set the current position where YYYY is a four-digit unsigned hex number.
    if (!strcasecmp(cmd, "SP")) {
      pos = hexstr2long(param);
      stepper.setCurrentPosition(pos);
    }
 
  }// end if(eoc)
 
 
} // end loop
 
long hexstr2long(char *line) {
  long ret = 0;
 
  ret = strtol(line, NULL, 16);
  return (ret);
}
 
void turnOn() {
  if (useSleep) {
    digitalWrite(powerPin, HIGH);
  } else {
    digitalWrite(powerPin, LOW);
  }
  digitalWrite(ledPin, HIGH);
  isRunning = true;
}
void turnOff() {
  if (useSleep) {
    digitalWrite(powerPin, LOW);
  } else {
    digitalWrite(powerPin, HIGH);
  }
  digitalWrite(ledPin, LOW);
  isRunning = false; 
}
 
Last edit: 9 years 11 months ago by Cees. Reason: code update
9 years 11 months ago #1098

Please Log in or Create an account to join the conversation.

  • Posts: 11
  • Thank you received: 0
Sounds good. I've set up a google code repository for this and my other astro hacks.

code.google.com/p/astrohacks/source/brow...2Ftrunk%2Fastrohacks

if you have a google account (who doesn't) and want to be added just ping me. it's better if there's one central location rather than "source control by email"

Interestingly the stock Windows client for Moonlite worked just fine even with the buggy :GI# implementation hence I never seem to have hit this issue. My "fix" is a bit different..
Last edit: 9 years 11 months ago by Orlando Andico.
9 years 11 months ago #1100

Please Log in or Create an account to join the conversation.

  • Posts: 85
  • Thank you received: 3
Hi, good to know that the sketch is beeing worked on.
I have a quick question, what is the difference between the sleepPin and enablePin? I currently only have sleepPin connected to my easy driver board and to connect enablePin will require some soldering.

Oh another thing I noticed was (this is using your first version of the sketch, I haven't tried the latest) that when I set the step size to small values (like <50 ticks) the stepper first made a small move in the wrong direction, and if the step size was small enough it didn't move back in the right direction after that initial wrong direction step.
9 years 11 months ago #1101

Please Log in or Create an account to join the conversation.

  • Posts: 21
  • Thank you received: 1

Replied by Cees on topic Moonlite focuser protocol

danielfranzen:
It is my understanding that the sleep pin turns the whole board off including power to the motor and the enable pin only switches the power to the motor. If you do not connect them the whole thing should still run.

My new version of the code didn't work when I connected it to the board. Turns out that the enablePin needs to be inverted for AccelStepper as in HIGH means off and LOW means on. Easy to do with a stepper.setPinsInverted( false, false, true); in setup
I have edited the code in the previous post to reflect this change and some other minor changes. I'm still not convinced this is actually working correct because the easydriver board still maintains power to the motor when it shouldn't as far as I can tell. I'll keep tinkering.

I have not noticed the problems with the small steps. Or perhaps I have? I sometimes noticed that the reported position is not always the actual position. I suspect this is a indi driver artifact. E.g start at 2000. Move 50 out. At completion it would report position 2049. Move 50 in. Reported position would than go 2049->2050->2049->2048 etc etc
I suspect that the indi driver gets a "not moving" when the arduino is at 2050 and the driver is still at 2049 . Because it is "not moving" ithe driver doesn't update to the actual position.
I'm going to make a version where I can snoop on the arduino with another serial port and see whther the indi driver and arduino are in sync or not


orly_andico:
I have taken your initial code as an opportunity to learn more about arduino and indilib. I only just getting my feet wet with this.
I'll check out the code.google.com thing and let you know.
fwiw, the version I use doesn't seem to work with the Windows Client for Moonlite. Go figure
Perhasp one day we'll have a version that works for all.
9 years 11 months ago #1105

Please Log in or Create an account to join the conversation.

  • Posts: 21
  • Thank you received: 1

Replied by Cees on topic Moonlite focuser protocol

Ok. This is the last time I will do it this way. Next time I have an update it will be at some file download place.
I have edited the version in the previous post. It seems to work with the either the sleep or the enable pin.
At the top somewhere you choose which one you use. If you do not use either it will still work but it will keep the motor powered up all the time.
9 years 11 months ago #1106

Please Log in or Create an account to join the conversation.

Time to create page: 1.294 seconds