×

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

Bi-monthly release with minor bug fixes and improvements

Pulse guiding does not seem to work with Telescope Simulator

  • Posts: 5
  • Thank you received: 3
I started work on porting my MoonPanoramaMaker software from ASCOM to INDI. Since it's written in Python, I use the PyIndi package. Basically, I need two functions: slewing to a RA/DEC position, and a pulse guide operation in N/S/E/W for small coordinate adjustments. I managed to get the first one right. But I'm trying in vane to get pulse guiding working. To illustrate what I'm doing, please have a look at the following example code:
# get coordinate object
    telescope_radec = None
    while not telescope_radec:
        time.sleep(0.5)
        telescope_radec = device.getNumber("EQUATORIAL_EOD_COORD")
 
    # get pulse guide objects
    telescope_guideNS = None
    while not telescope_guideNS:
        time.sleep(0.5)
        telescope_guideNS = device.getNumber("TELESCOPE_TIMED_GUIDE_NS")
 
    # wait until the scope has finished moving
    while telescope_radec.s == PyIndi.IPS_BUSY:
        time.sleep(0.2)
 
    # Stationary state reached, store measured position.
    ra_before = telescope_radec[0].value
    de_before = telescope_radec[1].value
 
    # Issue an INDI "move north" instruction and wait a short time.
    print("Move north 10000 milliseconds.")
    telescope_guideNS[0].value = 10000.
    telescope_guideNS[1].value = 0
    indiclient.sendNewNumber(telescope_guideNS)
    time.sleep(1.)
 
    # wait until the scope has finished moving
    while telescope_radec.s == PyIndi.IPS_BUSY:
        time.sleep(0.2)
 
    # Stationary state reached, store measured position.
    ra_after = telescope_radec[0].value
    de_after = telescope_radec[1].value
    print("The telescope has moved north by "+str(3600*(de_after-de_before)) + "arc seconds.")

I look up the telescope position before the pulse guide operation, then do a pulse guide with some number of milliseconds (10000 in this case, but the result is the same for smaller values), and finally check the position again. Then I print out by how much the telescope moved during the pulse guide. The result is always zero.

I tried the same with the Ekos interface to the Telescope Simulator (see attachment). There I enter a pulse guide north by 10000 milliseconds (see the yellow light which indicates that the operation is underway), but the declination coordinate does not change.

Is there any way to get the pulse guide working? And how can I change the pulse guide speed?

Any help is very much appreciated!

All the best,
Rolf

Attachment not found

The following user(s) said Thank You: Jasem Mutlaq, Oleg, Radek Kaczorek
6 years 3 weeks ago #23818

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

Great work! In the Telescope Simulator alone, use the EQUATORIAL_PE property since this is what changes (and is then picked by the CCD driver) when you perform guiding. For actual telescopes, EQUATORIAL_EOD_COORD should be used as you already do.
The following user(s) said Thank You: Rolf Hempel
6 years 3 weeks ago #23819

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

  • Posts: 5
  • Thank you received: 3
Thank you very much for your quick reply. I tried to find some documentation of the EQUATORIAL_PE property in the web, but this was unsuccessful. I then tried to just replace EQUATORIAL_EOD_COORD with EQUATORIAL_PE in my example code. That was how I interpreted your short comment in your post:
# get coordinate object
    equatorial_pe = None
    while not equatorial_pe:
        time.sleep(0.5)
        equatorial_pe = device.getNumber("EQUATORIAL_PE")
 
    # Slew to fixed position in the sky.
    ra = 1.5
    de = 25.4
    print("Slew to RA= " + str(ra) + ", DE= " + str(de))
    equatorial_pe[0].value = ra
    equatorial_pe[1].value = de
    indiclient.sendNewNumber(equatorial_pe)
 
    # get pulse guide objects
    telescope_guideNS = None
    while not telescope_guideNS:
        time.sleep(0.5)
        telescope_guideNS = device.getNumber("TELESCOPE_TIMED_GUIDE_NS")
 
    # # wait until the scope has finished moving
    # while equatorial_pe.s == PyIndi.IPS_BUSY:
    #     time.sleep(0.2)
 
    # Stationary state reached, store measured position.
    ra_before = equatorial_pe[0].value
    de_before = equatorial_pe[1].value
 
    # Issue an INDI "move north" instruction and wait a short time.
    print("Move north 10000 milliseconds.")
    telescope_guideNS[0].value = 1000.
    telescope_guideNS[1].value = 0
    indiclient.sendNewNumber(telescope_guideNS)
    time.sleep(4.)
 
    # # wait until the scope has finished moving
    # while equatorial_pe.s == PyIndi.IPS_BUSY:
    #     time.sleep(0.2)
 
    # Stationary state reached, store measured position.
    ra_after = equatorial_pe[0].value
    de_after = equatorial_pe[1].value
    print("The telescope has moved north by "+str(3600*(de_after-de_before)) + "arc seconds.")
The first thing I noticed is that waiting for the telecscope to finish moving does not seem to work as with EQUATORIAL_EOD_COORD, so I commented it out. Then the code ran through without errors. When I looked at the Ekos window of the telescope simulator, however, I saw that the RA/DEC coordinates do not change with the initial slew-to operation. It seems, therefore, that EQUATORIAL_PE is not just the replacement of EQUATORIAL_EOD_COORD for the case of the telescope simulator. And the result was the same as before: 0.0 arc seconds movement with the guideNS operation.

I'm very frustrated with the almost complete absence of documentation for the whole INDI system. Is there any place in the web where I can find how to use the telescope interface from Python? It is very difficult to find out everything by trial and error.

All the best,
Rolf
6 years 3 weeks ago #23820

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

  • Posts: 314
  • Thank you received: 95
  • Posts: 5
  • Thank you received: 3
Hi Oleh,

Thank you for pointing me at those web ressources. In fact, I had already read all of them. The problem is that none of them provides a detailed and systematic documentation of the interface.

I now gave up on the simulator and connected my Celestron NexStar mount instead. By trial and error I got the "slew to" and pulse guide operations working. So, I think it will be possible to port my software. That's good!

For the configuration setup in my program, I would like to present the user a list of all telescope drivers connected to the INDI server. I can produce a list of all drivers by using this code for the IndiClient class definition:
class IndiClient(PyIndi.BaseClient):
    def __init__(self, device_list, device_name_list):
        super(IndiDeviceListClient, self).__init__()
        self.device_list = device_list
        self.device_name_list = device_name_list
    def newDevice(self, d):
        self.device_list.append(d)
        self.device_name_list.append(d.getDeviceName())
I then have a list of all device names in "self.device_name_list". Is there any way in PyIndi to find out the type of a device? Then I could filter out devices for CCD, dome control etc., and only present the telescope devices to choose from.

All the best,
Rolf
6 years 3 weeks ago #23824

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

  • Posts: 314
  • Thank you received: 95
Hi Rolf,
maybe, DCD INDI client will be useful for you.
It wrote on Python.

You can try my open project Astronomy Linux
Last edit: 6 years 3 weeks ago by Oleg.
6 years 3 weeks ago #23825
Attachments:

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

The reason there is EQUATORIAL_PE is to enable a difference between reported mount coordinate and actual coordinates, and this controlled functionality is used for many aspects of testing (Guiding, astrometry..etc). So the Telescope Simulator for your development is not ideal. If you use EQMod driver with Simulator turned on, then your code would work fine. Just slew first to any object and track, and then your code would work just fine from there.

For device type, property DRIVER_INFO.DRIVER_INTERFACE contains ORed values of Driver Interfaces . You can then know from that the type of the device. Not sure if there is a built in functionality for this in PyINDI.

I agree that PyINDI documentation is not as good as the C++ one, need to work on that. If you can help, that would be great as well!
The following user(s) said Thank You: Rolf Hempel
6 years 3 weeks ago #23826

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

  • Posts: 5
  • Thank you received: 3
Hi Jasem,
Something like this is what I need. Given the complete lack of documentation, however, it's impossible for me to find out myself how to access this info. You are right that PyIndi documentation is even worse than the rest. This really makes using PyIndi an extremely frustrating experience! I again had to do random experiments for several hours without success.

I found that there is a DRIVER_INFO property vector for drivers in PyIndi. I then tried to access the details of it. For example using this code:
driver_info = monitored_device.getText("DRIVER_INFO")
while not driver_info:
    driver_info = monitored_device.getText("DRIVER_INFO")
    time.sleep(0.05)
 
print ("DRIVER_INFO has type: " + str(type(driver_info)))
for element in driver_info:
    print(driver_info[0].text
The printed type of DRIVER_INFO turned out to be <class 'PyIndi.ITextVectorProperty'>. The elements of driver_info printed out as:
Telescope Simulator
indi_simulator_telescope
1.0
5
I guess that the first entry is the device name, the second the executable, the third is the version number, and the fourth one I don't know. So, this does not help.

Again by trial and error I then found that there is a function
monitored_device.getDriverInterface()
When I call it, I get a <Swig Object of type 'uint16_t *' >. This seems to correspond to the definitions in your C++ code:
/**
     * @brief The DRIVER_INTERFACE enum defines the class of devices the driver implements. A driver may implement one or more interfaces.
     */
    enum DRIVER_INTERFACE
    {
        GENERAL_INTERFACE   = 0,         /**< Default interface for all INDI devices */
        TELESCOPE_INTERFACE = (1 << 0),  /**< Telescope interface, must subclass INDI::Telescope */
        CCD_INTERFACE       = (1 << 1),  /**< CCD interface, must subclass INDI::CCD */
        GUIDER_INTERFACE    = (1 << 2),  /**< Guider interface, must subclass INDI::GuiderInterface */
        FOCUSER_INTERFACE   = (1 << 3),  /**< Focuser interface, must subclass INDI::FocuserInterface */
        FILTER_INTERFACE    = (1 << 4),  /**< Filter interface, must subclass INDI::FilterInterface */
        DOME_INTERFACE      = (1 << 5),  /**< Dome interface, must subclass INDI::Dome */
        GPS_INTERFACE       = (1 << 6),  /**< GPS interface, must subclass INDI::GPS */
        WEATHER_INTERFACE   = (1 << 7),  /**< Weather interface, must subclass INDI::Weather */
        AO_INTERFACE        = (1 << 8),  /**< Adaptive Optics Interface */
        DUSTCAP_INTERFACE   = (1 << 9),  /**< Dust Cap Interface */
        LIGHTBOX_INTERFACE  = (1 << 10), /**< Light Box Interface */
        DETECTOR_INTERFACE  = (1 << 11), /**< Detector interface, must subclass INDI::Detector */
        ROTATOR_INTERFACE   = (1 << 12), /**< Rotator interface, must subclass INDI::RotatorInterface */
        AUX_INTERFACE       = (1 << 15), /**< Auxiliary interface */
};
Is there any way I can compare the Swig object with some "TELESCOPE_INTERFACE" PyIndi constant? Is there a list of all PyIndi constants?

It would be sad if I had to give up on INDI at this point. So I really would very much appreciate if someone who knows about PyIndi could help me.

All the best,
Rolf
6 years 3 weeks ago #23846

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

  • Posts: 226
  • Thank you received: 88
Hi,
Please remember that PyIndi is a Python wrapper to the Indi C++ classes. Thus the PyIndi documentation IS the Indi C++ documentation.
The only difference is that you use a python notation to access members/methods of the Indi C++ objects, and that C++ vectors/arrays are wrapped to python lists (only INDI BLOB are mapped to Python ByteArrays). And C++ enums become Python constants at the module level (there were no enums in Python before 3.4, and no enums in 2.7).
PyIndi uses swig to perform the mapping, and the interface file is just a list of C++ include files. I did not put every C++ Indi include files in the PyIndi client, excluding some driver include files. Thus there may lack some definitions on client side, this was the case for instance of the BLOBHandling enum that I added manually in the interface file, but this is not the normal way to do. Anyway I would suggest that you define yourself a python DRIVER_INTERFACE enum (or constants) and performs the desired ORed computations with the result of the getDriverInterface function (which is a real call to the Indi C++ function from your python interpreter).
I would suggest you use completion when you get a PyIndi object rather than what you call trial/error: you will obtain its members/methods, and may see these are exactly the C++ members/methods. Hence in your example you could also print the "label" of your ItextVectorProperties elements together with their "text" member. Note at that point that PyIndi is not responsible for the definition of those properties and their meanings, that's Indi stuff.
Lastly there may be a way to automatically generate a python documentation from the C++ documentation using swig (I believe that's what PyQt does), I did not investigate by now, but you won't get nothing more than the C++ documentation.
The following user(s) said Thank You: Jasem Mutlaq, Rolf Hempel
6 years 3 weeks ago #23865

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

  • Posts: 5
  • Thank you received: 3
Hi,

Thank you very much for your suggestions. I must admit that none of them is easy enough for me to solve the problem myself. I don't know anything about swig, and I have little C++ experience. So, I had hoped to just use the PyIndi interface for porting my Python application code.

From what you wrote it seems to me that the most promising way is to use the getDriverInterface function, and somehow get the comparison with the 2byte constants done. I will investigate on that further.

All the best,
Rolf
6 years 3 weeks ago #23868

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

Time to create page: 0.940 seconds