×

INDI Library v2.0.6 is Released (02 Feb 2024)

Bi-monthly release with minor bug fixes and improvements

Focus driver question

  • Posts: 105
  • Thank you received: 23
Hi,

Currently I am working on a INDI driver for my SmartFocus unit. I have a working driver now that supports absolute motions. There is a problem however. The focuser doesn't always end up at the exact position requested. Therefore my driver reads the actual position at the end of the motion and updates the FocusAbsPosN[0] property. This actual position does not end up in the Ekos user interface. Is there a way to achieve this?

Regards,
Camiel Severijns
8 years 4 months ago #5951

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

Replied by Jasem Mutlaq on topic Focus driver question

What do you mean Ekos user interface? You mean INDI control panel or where exactly?
8 years 4 months ago #5952

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

  • Posts: 105
  • Thank you received: 23
I mean the control panel that one can access from Ekos. It shows amongst others the absolute position of the focuser.
When I enter a new position, e.g., 600, here and press the 'set' button the focuser moves to the requested position.
However, it stops at a slightly different position, e.g., 599. My question is whether it is possible to display the actual position
of 599 here instead of the requested 600.
8 years 4 months ago #5969

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

Replied by Jasem Mutlaq on topic Focus driver question

The value is completely controlled by the INDI focus driver, the INDI control panel just displays whatever value is receives from the driver.
8 years 4 months ago #5970

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

  • Posts: 105
  • Thank you received: 23
Okay, maybe an extract of the code that I have will clarify my problem.
This is what I have in the Focuser::MoveAbsFocusser method:
IPState SmartFocus::MoveAbsFocuser(uint32_t targetPosition) {
  static const char move_abs = 'g';
  static const char expected_respons = move_abs;
  static const char complete = 'c';
  IPState result = IPS_ALERT;
  if (targetPosition < FocusAbsPosN[0].min || targetPosition > FocusAbsPosN[0].max)
    IDMessage(getDeviceName(), "Error, requested absolute position is out of range.");
  else {
    const Ticks destination = static_cast<Ticks>(targetPosition);
    char command[3];
    command[0] = move_abs;
    command[1] = ((destination>>8) & 0xFF);
    command[2] = ( destination     & 0xFF);
    IDMessage(getDeviceName() , "Focuser is moving to requested position...");
    DEBUGF(INDI::Logger::DBG_SESSION, "MoveAbsFocuser: destination= %d", destination);
    if (!isSimulation()) {
      //tcflush(PortFD, TCIOFLUSH);
      if (send(command, sizeof(command), "MoveAbsFocuser")) {
        char respons;
        if (recv(&respons, sizeof(respons), 1, "MoveAbsFocuser")) {
          DEBUGF(INDI::Logger::DBG_SESSION, "MoveAbsFocuser received echo: %c", respons);
          // A 20 second time out should be long enough for any focuser movement to finish
          if (recv(&respons, sizeof(respons), 20, "MoveAbsFocuser")) {
            DEBUGF(INDI::Logger::DBG_SESSION, "MoveAbsFocuser received code: %c (0x%02x)", respons, respons);
            SFgetParameters();
            result = ( respons == complete ? IPS_OK : IPS_ALERT );
            DEBUGF(INDI::Logger::DBG_SESSION, "MoveAbsFocuser position: %d %f", position, FocusAbsPosN[0].value);
          }
        }
      }
    }
  }
  return result;
}

Basically what happens here is that the 'g' command is sent to the focuser, which is confirmed by an echo of the 'g' command.
Upon completion of the motion the focuser sends a 'c' on success or an 'r' on error. Hereafter the SFgetParameters() method is called
to retrieve the state of the smartfocus unit and update the properties of the Focusser class as follows:
void SmartFocus::SFgetParameters(void) {
  const Flags flags = SFgetFlags();
  FlagsL[STATUS_SERIAL_FRAMING_ERROR].s = ( flags & SerFramingError   ? IPS_ALERT : IPS_OK );
  FlagsL[STATUS_SERIAL_OVERRUN_ERROR].s = ( flags & SerOverrunError   ? IPS_ALERT : IPS_OK );
  FlagsL[STATUS_MOTOR_ENCODE_ERROR  ].s = ( flags & MotorEncoderError ? IPS_ALERT : IPS_OK );
  FlagsL[STATUS_AT_ZERO_POSITION    ].s = ( flags & AtZeroPosition    ? IPS_ALERT : IPS_OK );
  FlagsL[STATUS_AT_MAX_POSITION     ].s = ( flags & AtMaxPosition     ? IPS_ALERT : IPS_OK );
  IDSetLight(&FlagsLP,NULL);
 
  if ( (position = SFgetPosition()) == TicksInvalid ) {
    FocusAbsPosNP.s = IPS_ALERT;
    IDSetNumber(&FocusAbsPosNP, "Error while reading SmartFocus position");
  }
  else {
    FocusAbsPosN[0].value = position;
    FocusAbsPosNP.s = IPS_OK;
    IDSetNumber(&FocusAbsPosNP, NULL);
  }
}

The second half of this routine reads the position from the smartfocus unit and updates the FocusAbsPos property accordingly.
Am I doing something wrong here that prevents the actual position of the smartfocus unit to be set?
8 years 4 months ago #5971

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

Replied by Jasem Mutlaq on topic Focus driver question

How is SFgetParameters() called? From where?
8 years 4 months ago #5973

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

  • Posts: 105
  • Thank you received: 23
Hi,

SFgetParameters() is called from MoveAbsFocuser() just after the confirmation/error respons is received from the smartfocus unit.
This is in the body of the deepest level if-statement in the first piece of source code in my previous reply:
...
if (recv(&respons, sizeof(respons), 20, "MoveAbsFocuser")) {
           DEBUGF(INDI::Logger::DBG_SESSION, "MoveAbsFocuser received code: %c (0x%02x)", respons, respons);
           SFgetParameters();
...
8 years 4 months ago #5974

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

Replied by Jasem Mutlaq on topic Focus driver question

Right, but ONCE you return IPS_OK, you're telling the focus framework that operation completed successfully and hence it sets it to requested value. In your case, I'd suggest calling SFgetParameters from within a TimerHit() function. In ::Connect(), just call SetTimer(1000) for example and TimerHit() will be called once a second. You can see TimerHit() used in many other drivers.
8 years 4 months ago #5981

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

  • Posts: 105
  • Thank you received: 23
Okay, I got this working now. The driver seems to work fine now in my office set up. I will test it in my imaging set up in the coming time.
Would you be interested in including the SmartFocus driver in the standard INDI livrary?
8 years 4 months ago #6050

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

Replied by Jasem Mutlaq on topic Focus driver question

Sure! Can you also prepare write up for the Devices page? Something like this: indilib.org/devices/focusers/focuslynx.html
8 years 4 months ago #6052

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

  • Posts: 105
  • Thank you received: 23
Hi, I have a tar.gz file with the source code and HTML documentation ready.
It have tried to attach it here but it seems that there is a problem uploading the file.
Could it be the file size? It's about 700 kbyte with all the HTML stuff.
8 years 3 months ago #6109

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

Replied by Jasem Mutlaq on topic Focus driver question

email to me (This email address is being protected from spambots. You need JavaScript enabled to view it.)
8 years 3 months ago #6111

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

Time to create page: 0.743 seconds