Control Panogear from Stellarium?  

English support for Panogear kit
User avatar
aaronpriest
Member
 
Posts: 168
Joined: Fri Mar 16, 2012 4:23 am
Location: Lee, Maine, USA

Control Panogear from Stellarium?

by aaronpriest » Sat Mar 09, 2013 8:03 pm

I have a Panogear with bluetooth module and it works fine from my laptop via Papywizard. Is there anyway to use it with Stellarium over bluetooth? I'd like to track the Pan-STARRS comet with a telephoto this weekend and shoot it. I don't have the GOTO controller. I've been unsuccessful getting Stellarium to communicate with the Merlin/Panogear.

no avatar
mediavets
Moderator
 
Posts: 14163
Joined: Wed Nov 14, 2007 2:12 pm
Location: Isleham, Cambridgeshire, UK.

by mediavets » Sat Mar 09, 2013 8:28 pm

aaronpriest wrote:I have a Panogear with bluetooth module and it works fine from my laptop via Papywizard. Is there anyway to use it with Stellarium over bluetooth? I'd like to track the Pan-STARRS comet with a telephoto this weekend and shoot it. I don't have the GOTO controller. I've been unsuccessful getting Stellarium to communicate with the Merlin/Panogear.

I can't see that Stellarium has anything to do with controlling astrotelescope mounts.

Is this the software you are referring to?:

http://www.stellarium.org/wiki/index.php/Introduction

Perhaps you need something like this software?:

http://www.ursaminor.hu/ursaminor_introduction_en.html
Andrew Stephens
Many different Nodal Ninja and Agnos pano heads. Merlin/Panogear mount with Papywizard on Nokia Internet tablets.
Nikon D5100 and D40, Sigma 8mm f3.5 FE, Nikon 10.5mm FE, 35mm, 50mm, 18-55mm, 70-210mm. Promote control.

User avatar
aaronpriest
Member
 
Posts: 168
Joined: Fri Mar 16, 2012 4:23 am
Location: Lee, Maine, USA

by aaronpriest » Sat Mar 09, 2013 9:32 pm

Sure Stellarium does! Been a plugin for several versions now:
http://www.stellarium.org/wiki/index.php/Telescope_Control_plug-in

UrsaMinor does more if you have an autoguider of course, I was just looking for something quick and dirty using hardware I already had available for tonight. ;-)

User avatar
aaronpriest
Member
 
Posts: 168
Joined: Fri Mar 16, 2012 4:23 am
Location: Lee, Maine, USA

by aaronpriest » Sat Mar 09, 2013 9:42 pm

BTW, that test program on the UrsaMinor page worked fine with my Panogear on COM4. Unfortunately telescope control is purposely disabled in their demo and there's no way to buy it online without contacting dealers that are not located in my country. No way I'd have something working by tonight with them. Haha

User avatar
fma38
Member
 
Posts: 5826
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Sun Mar 10, 2013 8:04 pm

Stellarium can natively drive a Panogear with the GOTO hand controller... Without it, it needs a little server. The protocole is described here:

https://stellarium.svn.sourceforge.net/svnroot/stellarium/trunk/telescope_server/stellarium_telescope_protocol.txt
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

User avatar
fma38
Member
 
Posts: 5826
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Tue Mar 12, 2013 11:24 am

Here is a python script which act as stellarium server to drive the Panogear head. I only tested it through the EthernetDriver, using the simulator which comes with Papywizard. Let me know if it works.

Note: I used the serial drive, so you first need to pair with the bluetooth module from the system, then give the correct virtual serial port at the top of the script (you can use Windows syntax on that OS: COM1, COM4...), and launch it. Then, connect from Stellarium (I used the port 9999).

Code: Select all
# -*- coding: utf-8 -*-

""" v0.1
"""

import struct
import SocketServer
import threading
import socket

import serial

# Stellarium server params
HOST, PORT = "localhost", 9999
PACKET_SIZE = 20

# Merlin/Orion params
ENCODER_ZERO = 0x800000

# Driver params
SERIAL_PORT = "/dev/ttyS0"
SERIAL_BAUDRATE = 9600


class AbstractDriver(object):
    """ Base (abstract) class for bus drivers.
    """
    def __init__(self):
        """ Init the driver.
        """
        self._lock = threading.RLock()

    def init(self):
        """ Init the connection.
        """
        raise NotImplementedError("AbstractDriver.init() must be overidden")

    def shutdown(self):
        """ Shutdown the connection.
        """
        raise NotImplementedError("AbstractDriver.shutdown() must be overidden")

    def acquireBus(self):
        """ Acquire and lock the bus.
        """
        #print "AbstractDriver.acquireBus()"
        self._lock.acquire()

    def releaseBus(self):
        """ Unlock and release the bus.
        """
        #print "AbstractDriver.releaseBus()"
        self._lock.release()

    def setTimeout(self, timeout):
        """ Set the timeout delay.

        @param timeout: timeout delay, in s
        @type timeout: float
        """
        raise NotImplementedError("AbstractDriver.setTimeout() must be overloaded")

    def empty(self):
        """ Empty buffer.
        """
        raise NotImplementedError("AbstractDriver.empty() must be overloaded")

    def write(self, data):
        """ Write data.

        @param data: data to write
        @type data: str

        @return: size of data written
        @rtype: int
        """
        raise NotImplementedError("AbstractDriver.write() must be overloaded")

    def read(self, size):
        """ Read data.

        @param size: size of the data to read
        @type size: int

        @return: read data
        @rtype: str
        """
        raise NotImplementedError("AbstractDriver.read() must be overloaded")


class SerialDriver(AbstractDriver):
    """ Driver for serial connection.
    """
    def init(self):
        try:
            self._serial = serial.Serial(port=SERIAL_PORT, baudrate=SERIAL_BAUDRATE, timeout=3)
            self.empty()
        except:
            print "SerialDriver._init()"
            raise

    def shutdown(self):
        self._serial.close()

    def setRTS(self, level):
        """ Set RTS signal to specified level.

        @param level: level to set to RTS signal
        @type level: int
        """
        self._serial.setRTS(level)

    def setDTR(self, level):
        """ Set DTR signal to specified level.

        @param level: level to set to DTR signal
        @type level: int
        """
        self._serial.setDTR(level)

    def setTimeout(self, timeout):
        self._serial.timeout = timeout

    def empty(self):
        if hasattr(self._serial, "inWaiting"):
            self.read(self._serial.inWaiting())

    def write(self, data):
        #print "SerialDriver.write(): data=%s" % repr(data)
        size = self._serial.write(data)
        return size

    def read(self, size):
        data = self._serial.read(size)
        #print "SerialDriver.read(): data=%s" % repr(data)
        if size and not data:
            raise IOError("Timeout while reading on serial bus (size=%d, data=%s)" % (size, repr(data)))
        else:
            return data


class EthernetDriver(AbstractDriver):
    """ Driver for TCP ethernet connection.
    """
    def init(self):
        print "EthernetDriver._init(): trying to connect to %s:%d..." % ("localhost", 7165)
        try:
            #import time
            #time.sleep(3)
            self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self._sock.connect(("localhost", 7165))
            self._sock.settimeout(3)
            self.empty()
        except Exception, msg:
            print "EthernetDriver.init()"
            raise Exception(msg)
        else:
            print "EthernetDriver._init(): successfully connected to %s:%d" % ("localhost", 7165)

    def shutdown(self):
        self._sock.close()

    def setTimeout(self, timeout):
        self._sock.settimeout(timeout)

    def empty(self):
        pass

    def write(self, data):
        #Logger().debug("EthernetDriver.write(): data=%s" % repr(data))
        try:
            size = self._sock.send(data)
            #if size != len(data) + 2:
                #raise IOError("Failed to send data on ethernet")
            #else:
                #return size
            return size
        except socket.timeout:
            raise IOError("Timeout while writing on ethernet")
        except socket.error, msg:
            raise IOError(msg)

    def read(self, size):
        try:
            data = self._sock.recv(size)
            #print "EthernetDriver.read(): data=%s" % repr(data)
            if not data:
                raise IOError("Connection lost")
            else:
                return data
        except socket.timeout:
            raise IOError("Timeout while reading on ethernet bus")
        except socket.error, msg:
            raise IOError(msg)


class MerlinOrionHardware(object):
    """ Merlin/Orion low-level hardware.
    """
    def __init__(self, axis, driver):
        """
        """
        self._axis = axis
        self._driver = driver

        self._encoderFullCircle = None

    def _decodeAxisValue(self, strValue):
        """ Decode value from axis.

        Values (position, speed...) returned by axis are
        32bits-encoded strings, low byte first.

        @param strValue: value returned by axis
        @type strValue: str

        @return: value
        @rtype: int
        """
        value = 0
        for i in xrange(3):
            value += eval("0x%s" % strValue[i*2:i*2+2]) * 2 ** (i * 8)

        return value

    def _encodeAxisValue(self, value):
        """ Encode value for axis.

        Values (position, speed...) to send to axis must be
        32bits-encoded strings, low byte first.

        @param value: value
        @type value: int

        @return: value to send to axis
        @rtype: str
        """
        strHexValue = "000000%s" % hex(value)[2:]
        strValue = strHexValue[-2:] + strHexValue[-4:-2] + strHexValue[-6:-4]

        return strValue.upper()

    def _encoderToAngle(self, codPos):
        """ Convert encoder value to degres.

        @param codPos: encoder position
        @type codPos: int

        @return: position, in °
        @rtype: float
        """
        return (codPos - ENCODER_ZERO) * 360. / self._encoderFullCircle

    def _angleToEncoder(self, pos):
        """ Convert degres to encoder value.

        @param pos: position, in °
        @type pos: float

        @return: encoder position
        @rtype: int
        """
        return int(pos * self._encoderFullCircle / 360. + ENCODER_ZERO)

    def _sendCmd(self, cmd, param=""):
        """ Send a command to the axis.

        @param cmd: command to send
        @type cmd: str

        @return: answer
        @rtype: str
        """
        cmd = ":%s%d%s\r" % (cmd, self._axis, param)
        #print "MerlinOrionHardware._sendCmd(): axis %d cmd=%s" % (self._axis, repr(cmd))
        for nbTry in xrange(3):
            try:
                answer = ""
                self._driver.empty()
                self._driver.write(cmd)
                c = ''
                while c not in ('=', '!'):
                    c = self._driver.read(1)
                    #print "MerlinOrionHardware._sendCmd(): c=%s" % repr(c)
                if c == '!':
                    c = self._driver.read(1) # Get error code
                    raise IOError("Error in command %s (err=%s)" % (repr(cmd), c))
                answer = ""
                while True:
                    c = self._driver.read(1)
                    #print "MerlinOrionHardware._sendCmd(): c=%s" % repr(c)
                    if c == '\r':
                        break
                    answer += c

            except IOError:
                print "MerlinOrionHardware._sendCmd(): axis %d can't sent command %s. Retrying..." % (self._axis, repr(cmd))
            else:
                break
        else:
            raise Exception("axis %d can't send command %s" % (self._axis, repr(cmd)))
        #print "MerlinOrionHardware._sendCmd(): axis %d ans=%s" % (self._axis, repr(answer))

        return answer

    def init(self):
        """ Init the MerlinOrion hardware.

        Done only once per axis.
        """
        self._driver.acquireBus()
        try:

            # Stop motor
            self._sendCmd("L")

            # Check motor?
            self._sendCmd("F")

            # Get firmeware version
            value = self._sendCmd("e")
            print "MerlinOrionHardware.init(): firmeware version=%s" % value

            # Get encoder full circle
            value = self._sendCmd("a")
            self._encoderFullCircle = self._encoderFullCircle_ = self._decodeAxisValue(value)
            print "MerlinOrionHardware.init(): encoder full circle=%s" % hex(self._encoderFullCircle)

            # Get sidereal rate
            value = self._sendCmd("D")
            print "MerlinOrionHardware.init(): sidereal rate=%s" % hex(self._decodeAxisValue(value))

        finally:
            self._driver.releaseBus()

    def overwriteEncoderFullCircle(self, encoderFullCircle):
        """ Overwrite firmware value.
        """
        print "MerlinOrionHardware.overwriteEncoderFullCircle(): encoderFullCircle=%x" % encoderFullCircle
        self._encoderFullCircle = encoderFullCircle

    def useFirmwareEncoderFullCircle(self):
        """ Use value from firmware.
        """
        self._encoderFullCircle = self._encoderFullCircle_
        print "MerlinOrionHardware.useFirmwareEncoderFullCircle(): encoderFullCircle=%x" % self._encoderFullCircle

    def read(self):
        """ Read the axis position.

        @return: axis position, in °
        @rtype: float
        """
        self._driver.acquireBus()
        try:
            value = self._sendCmd("j")
        finally:
            self._driver.releaseBus()
        pos = self._encoderToAngle(self._decodeAxisValue(value))
        return pos

    def drive(self, pos):
        """ Drive the axis.

        @param pos: position to reach, in °
        @type pos: float
        """
        strValue = self._encodeAxisValue(self._angleToEncoder(pos))
        self._driver.acquireBus()
        try:
            self._sendCmd("L")
            self._sendCmd("G", "00")
            self._sendCmd("S", strValue)
            self._sendCmd("J")
        finally:
            self._driver.releaseBus()

    def stop(self):
        """ Stop the axis.
        """
        self._driver.acquireBus()
        try:
            self._sendCmd("L")
        finally:
            self._driver.releaseBus()

    def startJog(self, dir_, speed):
        """ Start the axis.

        @param dir_: direction ('+', '-')
        @type dir_: str

        @param speed: speed
        @type speed: int
        """
        self._driver.acquireBus()
        try:
            self._sendCmd("L")
            if dir_ == '+':
                self._sendCmd("G", "30")
            elif dir_ == '-':
                self._sendCmd("G", "31")
            else:
                raise ValueError("Axis %d dir. must be in ('+', '-')" % self._axis)
            self._sendCmd("I", self._encodeAxisValue(speed))
            self._sendCmd("J")
        finally:
            self._driver.releaseBus()

    def getStatus(self):
        """ Get axis status.

        @return: axis status
        @rtype: str
        """
        self._driver.acquireBus()
        try:
            return self._sendCmd("f")
        finally:
            self._driver.releaseBus()

    def setOutput(self, state):
        """ Set output state.

        @param state: new state of the the output
        @type state: bool
        """
        self._driver.acquireBus()
        try:
            self._sendCmd("O", str(int(state)))
        finally:
            self._driver.releaseBus()


class IncomingPacket(object):
    """ Incoming packet from Stellarium.
    """
    def __init__(self, message):
        """ Create the packet
        """
        self.message = message

        length, type_, time_, ra, dec =  struct.unpack("<HHQIi", message)
        self.length = length
        self.type_ = type_
        self.time_ = time_
        self.ra = ra * 90. / 0x40000000
        self.dec = dec * 90. / 0x40000000


class MyTCPHandler(SocketServer.BaseRequestHandler):
    """ The RequestHandler class for our server.
    """
    def handle(self):

        # self.request is the TCP socket connected to the client
        self.packet = IncomingPacket(self.request.recv(PACKET_SIZE).strip())
        print "MyTCPHandler.handle(): {} wrote:".format(self.client_address[0])
        print "MyTCPHandler.handle(): %s" % repr(self.packet.message)
        print "MyTCPHandler.handle(): time=%d, RA=%.2f, DEC=%.2f" % (self.packet.time_, self.packet.ra, self.packet.dec)
        yaw.drive(self.packet.dec)
        pitch.drive(self.packet.ra)
        while yaw.getStatus()[1] != '0' and pitch.getStatus()[1] != '0':
            time.sleep(0.1)
        print "MyTCPHandler.handle(): done"

        # just send back the same data
        #self.request.sendall(struct.pack("<HHQIii", length+4, type_, time_, ra+50000, dec-50000, 0))


class MyServer(SocketServer.TCPServer):
    allow_reuse_address = True


#driver = EthernetDriver()
driver = SerialDriver()
driver.init()

yaw = MerlinOrionHardware(1, driver)
yaw.init()
pitch = MerlinOrionHardware(2, driver)
pitch.init()

if __name__ == "__main__":

    # Create the server, binding to localhost on port 9999
    server = MyServer((HOST, PORT), MyTCPHandler)

    # Activate the server; this will keep running until you
    # interrupt the program with Ctrl-C
    server.serve_forever()
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

User avatar
fma38
Member
 
Posts: 5826
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Tue Mar 12, 2013 2:37 pm

Here is a new version, with a few fixes:

Code: Select all
# -*- coding: utf-8 -*-

""" v0.2
"""

import struct
import SocketServer
import threading
import socket
import time

import serial

# Stellarium server params
HOST, PORT = "localhost", 9999
PACKET_SIZE = 20

# Merlin/Orion params
ENCODER_ZERO = 0x800000

# Driver params
SERIAL_PORT = "/dev/ttyS0"
SERIAL_BAUDRATE = 9600


class AbstractDriver(object):
    """ Base (abstract) class for bus drivers.
    """
    def __init__(self):
        """ Init the driver.
        """
        self._lock = threading.RLock()

    def init(self):
        """ Init the connection.
        """
        raise NotImplementedError("AbstractDriver.init() must be overidden")

    def shutdown(self):
        """ Shutdown the connection.
        """
        raise NotImplementedError("AbstractDriver.shutdown() must be overidden")

    def acquireBus(self):
        """ Acquire and lock the bus.
        """
        #print "AbstractDriver.acquireBus()"
        self._lock.acquire()

    def releaseBus(self):
        """ Unlock and release the bus.
        """
        #print "AbstractDriver.releaseBus()"
        self._lock.release()

    def setTimeout(self, timeout):
        """ Set the timeout delay.

        @param timeout: timeout delay, in s
        @type timeout: float
        """
        raise NotImplementedError("AbstractDriver.setTimeout() must be overloaded")

    def empty(self):
        """ Empty buffer.
        """
        raise NotImplementedError("AbstractDriver.empty() must be overloaded")

    def write(self, data):
        """ Write data.

        @param data: data to write
        @type data: str

        @return: size of data written
        @rtype: int
        """
        raise NotImplementedError("AbstractDriver.write() must be overloaded")

    def read(self, size):
        """ Read data.

        @param size: size of the data to read
        @type size: int

        @return: read data
        @rtype: str
        """
        raise NotImplementedError("AbstractDriver.read() must be overloaded")


class SerialDriver(AbstractDriver):
    """ Driver for serial connection.
    """
    def init(self):
        try:
            self._serial = serial.Serial(port=SERIAL_PORT, baudrate=SERIAL_BAUDRATE, timeout=3)
            self.empty()
        except:
            print "SerialDriver._init()"
            raise

    def shutdown(self):
        self._serial.close()

    def setRTS(self, level):
        """ Set RTS signal to specified level.

        @param level: level to set to RTS signal
        @type level: int
        """
        self._serial.setRTS(level)

    def setDTR(self, level):
        """ Set DTR signal to specified level.

        @param level: level to set to DTR signal
        @type level: int
        """
        self._serial.setDTR(level)

    def setTimeout(self, timeout):
        self._serial.timeout = timeout

    def empty(self):
        if hasattr(self._serial, "inWaiting"):
            self.read(self._serial.inWaiting())

    def write(self, data):
        #print "SerialDriver.write(): data=%s" % repr(data)
        size = self._serial.write(data)
        return size

    def read(self, size):
        data = self._serial.read(size)
        #print "SerialDriver.read(): data=%s" % repr(data)
        if size and not data:
            raise IOError("Timeout while reading on serial bus (size=%d, data=%s)" % (size, repr(data)))
        else:
            return data


class EthernetDriver(AbstractDriver):
    """ Driver for TCP ethernet connection.
    """
    def init(self):
        print "EthernetDriver._init(): trying to connect to %s:%d..." % ("localhost", 7165)
        try:
            #import time
            #time.sleep(3)
            self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self._sock.connect(("localhost", 7165))
            self._sock.settimeout(3)
            self.empty()
        except Exception, msg:
            print "EthernetDriver.init()"
            raise Exception(msg)
        else:
            print "EthernetDriver._init(): successfully connected to %s:%d" % ("localhost", 7165)

    def shutdown(self):
        self._sock.close()

    def setTimeout(self, timeout):
        self._sock.settimeout(timeout)

    def empty(self):
        pass

    def write(self, data):
        #Logger().debug("EthernetDriver.write(): data=%s" % repr(data))
        try:
            size = self._sock.send(data)
            #if size != len(data) + 2:
                #raise IOError("Failed to send data on ethernet")
            #else:
                #return size
            return size
        except socket.timeout:
            raise IOError("Timeout while writing on ethernet")
        except socket.error, msg:
            raise IOError(msg)

    def read(self, size):
        try:
            data = self._sock.recv(size)
            #print "EthernetDriver.read(): data=%s" % repr(data)
            if not data:
                raise IOError("Connection lost")
            else:
                return data
        except socket.timeout:
            raise IOError("Timeout while reading on ethernet bus")
        except socket.error, msg:
            raise IOError(msg)


class MerlinOrionHardware(object):
    """ Merlin/Orion low-level hardware.
    """
    def __init__(self, axis, driver):
        """
        """
        self._axis = axis
        self._driver = driver

        self._encoderFullCircle = None

    def _decodeAxisValue(self, strValue):
        """ Decode value from axis.

        Values (position, speed...) returned by axis are
        32bits-encoded strings, low byte first.

        @param strValue: value returned by axis
        @type strValue: str

        @return: value
        @rtype: int
        """
        value = 0
        for i in xrange(3):
            value += eval("0x%s" % strValue[i*2:i*2+2]) * 2 ** (i * 8)

        return value

    def _encodeAxisValue(self, value):
        """ Encode value for axis.

        Values (position, speed...) to send to axis must be
        32bits-encoded strings, low byte first.

        @param value: value
        @type value: int

        @return: value to send to axis
        @rtype: str
        """
        strHexValue = "000000%s" % hex(value)[2:]
        strValue = strHexValue[-2:] + strHexValue[-4:-2] + strHexValue[-6:-4]

        return strValue.upper()

    def _encoderToAngle(self, codPos):
        """ Convert encoder value to degres.

        @param codPos: encoder position
        @type codPos: int

        @return: position, in °
        @rtype: float
        """
        return (codPos - ENCODER_ZERO) * 360. / self._encoderFullCircle

    def _angleToEncoder(self, pos):
        """ Convert degres to encoder value.

        @param pos: position, in °
        @type pos: float

        @return: encoder position
        @rtype: int
        """
        return int(pos * self._encoderFullCircle / 360. + ENCODER_ZERO)

    def _sendCmd(self, cmd, param=""):
        """ Send a command to the axis.

        @param cmd: command to send
        @type cmd: str

        @return: answer
        @rtype: str
        """
        cmd = ":%s%d%s\r" % (cmd, self._axis, param)
        #print "MerlinOrionHardware._sendCmd(): axis %d cmd=%s" % (self._axis, repr(cmd))
        for nbTry in xrange(3):
            try:
                answer = ""
                self._driver.empty()
                self._driver.write(cmd)
                c = ''
                while c not in ('=', '!'):
                    c = self._driver.read(1)
                    #print "MerlinOrionHardware._sendCmd(): c=%s" % repr(c)
                if c == '!':
                    c = self._driver.read(1) # Get error code
                    raise IOError("Error in command %s (err=%s)" % (repr(cmd), c))
                answer = ""
                while True:
                    c = self._driver.read(1)
                    #print "MerlinOrionHardware._sendCmd(): c=%s" % repr(c)
                    if c == '\r':
                        break
                    answer += c

            except IOError:
                print "MerlinOrionHardware._sendCmd(): axis %d can't sent command %s. Retrying..." % (self._axis, repr(cmd))
            else:
                break
        else:
            raise Exception("axis %d can't send command %s" % (self._axis, repr(cmd)))
        #print "MerlinOrionHardware._sendCmd(): axis %d ans=%s" % (self._axis, repr(answer))

        return answer

    def init(self):
        """ Init the MerlinOrion hardware.

        Done only once per axis.
        """
        self._driver.acquireBus()
        try:

            # Stop motor
            self._sendCmd("L")

            # Check motor?
            self._sendCmd("F")

            # Get firmeware version
            value = self._sendCmd("e")
            print "MerlinOrionHardware.init(): firmeware version=%s" % value

            # Get encoder full circle
            value = self._sendCmd("a")
            self._encoderFullCircle = self._encoderFullCircle_ = self._decodeAxisValue(value)
            print "MerlinOrionHardware.init(): encoder full circle=%s" % hex(self._encoderFullCircle)

            # Get sidereal rate
            value = self._sendCmd("D")
            print "MerlinOrionHardware.init(): sidereal rate=%s" % hex(self._decodeAxisValue(value))

        finally:
            self._driver.releaseBus()

    def overwriteEncoderFullCircle(self, encoderFullCircle):
        """ Overwrite firmware value.
        """
        print "MerlinOrionHardware.overwriteEncoderFullCircle(): encoderFullCircle=%x" % encoderFullCircle
        self._encoderFullCircle = encoderFullCircle

    def useFirmwareEncoderFullCircle(self):
        """ Use value from firmware.
        """
        self._encoderFullCircle = self._encoderFullCircle_
        print "MerlinOrionHardware.useFirmwareEncoderFullCircle(): encoderFullCircle=%x" % self._encoderFullCircle

    def read(self):
        """ Read the axis position.

        @return: axis position, in °
        @rtype: float
        """
        self._driver.acquireBus()
        try:
            value = self._sendCmd("j")
        finally:
            self._driver.releaseBus()
        pos = self._encoderToAngle(self._decodeAxisValue(value))
        return pos

    def drive(self, pos):
        """ Drive the axis.

        @param pos: position to reach, in °
        @type pos: float
        """
        strValue = self._encodeAxisValue(self._angleToEncoder(pos))
        self._driver.acquireBus()
        try:
            self._sendCmd("L")
            self._sendCmd("G", "00")
            self._sendCmd("S", strValue)
            self._sendCmd("J")
        finally:
            self._driver.releaseBus()

    def stop(self):
        """ Stop the axis.
        """
        self._driver.acquireBus()
        try:
            self._sendCmd("L")
        finally:
            self._driver.releaseBus()

    def startJog(self, dir_, speed):
        """ Start the axis.

        @param dir_: direction ('+', '-')
        @type dir_: str

        @param speed: speed
        @type speed: int
        """
        self._driver.acquireBus()
        try:
            self._sendCmd("L")
            if dir_ == '+':
                self._sendCmd("G", "30")
            elif dir_ == '-':
                self._sendCmd("G", "31")
            else:
                raise ValueError("Axis %d dir. must be in ('+', '-')" % self._axis)
            self._sendCmd("I", self._encodeAxisValue(speed))
            self._sendCmd("J")
        finally:
            self._driver.releaseBus()

    def getStatus(self):
        """ Get axis status.

        @return: axis status
        @rtype: str
        """
        self._driver.acquireBus()
        try:
            return self._sendCmd("f")
        finally:
            self._driver.releaseBus()

    def setOutput(self, state):
        """ Set output state.

        @param state: new state of the the output
        @type state: bool
        """
        self._driver.acquireBus()
        try:
            self._sendCmd("O", str(int(state)))
        finally:
            self._driver.releaseBus()


class IncomingPacket(object):
    """ Incoming packet from Stellarium.
    """
    def __init__(self, message):
        """ Create the packet
        """
        self.message = message

        length, type_, time_, ra, dec =  struct.unpack("<HHQIi", message)
        self.length = length
        self.type_ = type_
        self.time_ = time_
        self.ra = ra * 90. / 0x40000000
        self.dec = dec * 90. / 0x40000000


class MyTCPHandler(SocketServer.BaseRequestHandler):
    """ The RequestHandler class for our server.
    """
    def handle(self):
        while True:

            # self.request is the TCP socket connected to the client
            self.packet = IncomingPacket(self.request.recv(PACKET_SIZE).strip())
            print "MyTCPHandler.handle(): {} wrote:".format(self.client_address[0])
            print "MyTCPHandler.handle(): %s" % repr(self.packet.message)
            print "MyTCPHandler.handle(): length=%d, time=%d, RA=%.2f, DEC=%.2f" % (self.packet.length, self.packet.time_, self.packet.ra, self.packet.dec)
            self.server.yaw.drive(self.packet.dec)
            self.server.pitch.drive(self.packet.ra)
            while self.server.yaw.getStatus()[1] != '0' and self.server.pitch.getStatus()[1] != '0':
                time.sleep(0.1)
            print "MyTCPHandler.handle(): done"

            # just send back the reached position
            self.request.sendall(struct.pack("<HHQIii", self.packet.length+4, self.packet.type_, time.time(), self.packet.ra, self.packet.dec, 0))


class MyServer(SocketServer.TCPServer):
    allow_reuse_address = True



def main():

    #driver = EthernetDriver()
    driver = SerialDriver()
    driver.init()

    # Create the server, binding to localhost on port 9999
    server = MyServer((HOST, PORT), MyTCPHandler)

    server.yaw = MerlinOrionHardware(1, driver)
    server.yaw.init()
    server.pitch = MerlinOrionHardware(2, driver)
    server.pitch.init()

    # Activate the server; this will keep running until you
    # interrupt the program with Ctrl-C
    server.serve_forever()


if __name__ == "__main__":
    main()
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

User avatar
dim
Member
 
Posts: 78
Joined: Tue Feb 19, 2008 10:52 pm
Location: la roche-en-ardenne

by dim » Thu Apr 25, 2013 8:06 am

I have also a Panogear & Merlin (thank you!) on a Macbook with ubuntu 12.04... It works perfectly! And i read this very interresting topic. So i tried to use the Panogear & bluetooth with Stellarium 0.12.1.. When i launch the server, it make screen copy!
eos5Dc, eos5D2 + Magic Lantern 2.3 & nightbuild, canon 24-70mm f:2.8, sigma 180mm macro f:5.6, samyang 14mm f:2.8, helios-40 85mm f1.5, old yashica 800mm f8, manfrotto 302+ hackée, merlin + BTursaminor, macbook + ubuntu 12.04, osx, win7, intel quadcore + ubuntu 13.04 studio, win7, Darktable, GretagMcB eye-one, epson V750.

User avatar
fma38
Member
 
Posts: 5826
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Thu Apr 25, 2013 8:13 am

!!!! Did you install a python interpreter?

Does anyone alse tried my script to drive a Merlin from Stellarium?
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

User avatar
dim
Member
 
Posts: 78
Joined: Tue Feb 19, 2008 10:52 pm
Location: la roche-en-ardenne

by dim » Thu Apr 25, 2013 8:24 am

I think so! Python & libpython (2.7, 3.2, 3.3) are installed.

I don't know! I discover last night the possibility to drive Merlin with Stellarium!
eos5Dc, eos5D2 + Magic Lantern 2.3 & nightbuild, canon 24-70mm f:2.8, sigma 180mm macro f:5.6, samyang 14mm f:2.8, helios-40 85mm f1.5, old yashica 800mm f8, manfrotto 302+ hackée, merlin + BTursaminor, macbook + ubuntu 12.04, osx, win7, intel quadcore + ubuntu 13.04 studio, win7, Darktable, GretagMcB eye-one, epson V750.

User avatar
fma38
Member
 
Posts: 5826
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Thu Apr 25, 2013 8:32 am

How do you start the server? Better try from a console...
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

User avatar
dim
Member
 
Posts: 78
Joined: Tue Feb 19, 2008 10:52 pm
Location: la roche-en-ardenne

by dim » Thu Apr 25, 2013 8:47 am

In the console & the message: "line 4 $ v0.2 \n': command not found"
eos5Dc, eos5D2 + Magic Lantern 2.3 & nightbuild, canon 24-70mm f:2.8, sigma 180mm macro f:5.6, samyang 14mm f:2.8, helios-40 85mm f1.5, old yashica 800mm f8, manfrotto 302+ hackée, merlin + BTursaminor, macbook + ubuntu 12.04, osx, win7, intel quadcore + ubuntu 13.04 studio, win7, Darktable, GretagMcB eye-one, epson V750.

User avatar
fma38
Member
 
Posts: 5826
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Thu Apr 25, 2013 9:32 am

I think you are trying to run the python script using the shell interpreter!!!

As I didn't put a shebang at the start of the file, you need to start it with:

$ python <script>

Or add this to the first line:

#!/usr/bin/python

and make the file executable, and launch it with:

$ ./<script>
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

User avatar
dim
Member
 
Posts: 78
Joined: Tue Feb 19, 2008 10:52 pm
Location: la roche-en-ardenne

by dim » Thu Apr 25, 2013 9:46 am

Thanks for patience! I'm new with python and not a programmer. I will try it this night! I will tell you about it.

dimitri
eos5Dc, eos5D2 + Magic Lantern 2.3 & nightbuild, canon 24-70mm f:2.8, sigma 180mm macro f:5.6, samyang 14mm f:2.8, helios-40 85mm f1.5, old yashica 800mm f8, manfrotto 302+ hackée, merlin + BTursaminor, macbook + ubuntu 12.04, osx, win7, intel quadcore + ubuntu 13.04 studio, win7, Darktable, GretagMcB eye-one, epson V750.

User avatar
fma38
Member
 
Posts: 5826
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Thu Apr 25, 2013 9:54 am

No problem. Thanks for your feedback.
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

no avatar
Mateusz Malinowski
Member
 
Posts: 85
Joined: Tue Apr 19, 2011 7:46 pm
Location: Polska

by Mateusz Malinowski » Thu Apr 25, 2013 5:28 pm

fma38 wrote:Does anyone alse tried my script to drive a Merlin from Stellarium?

Hi
am I doing something wrong?
1
- installed python 3.3.1 64bit http://www.python.org/ftp/python/3.3.1/python-3.3.1.amd64.msi
- create s.py with code http://www.kolor.com/forum/p112973-2013-03-12-15-37-56#p112973
- run "Python (command line)" - drag and drop s.py -> enter
- Syntax error: invalid syntax

2
- installed python 3.3.1 64bit http://www.python.org/ftp/python/3.3.1/python-3.3.1.amd64.msi
- installed winpython http://code.google.com/p/winpython/downloads/detail?name=WinPython-64bit-3.3.0.0beta2.exe
- run "WinPython Interpreter.exe" - drag and drop s.py -> enter
- Syntax error: invalid syntax

User avatar
dim
Member
 
Posts: 78
Joined: Tue Feb 19, 2008 10:52 pm
Location: la roche-en-ardenne

by dim » Thu Apr 25, 2013 6:03 pm

So! I can't find the correct virtual serial port used by bluetooth... I create one (sudo rfcomm connect rfcomm4 00:12:6F:21:AE:9B, mac address to find with hcitool scan), set it in the script & launch the server...It works! Launch Stellarium & connect to the Merlin... Connected. Send a star position... No problem.
Great! Good job! thanks a lot! Frédéric


dimitri
Last edited by dim on Thu Apr 25, 2013 6:05 pm, edited 1 time in total.
eos5Dc, eos5D2 + Magic Lantern 2.3 & nightbuild, canon 24-70mm f:2.8, sigma 180mm macro f:5.6, samyang 14mm f:2.8, helios-40 85mm f1.5, old yashica 800mm f8, manfrotto 302+ hackée, merlin + BTursaminor, macbook + ubuntu 12.04, osx, win7, intel quadcore + ubuntu 13.04 studio, win7, Darktable, GretagMcB eye-one, epson V750.

User avatar
fma38
Member
 
Posts: 5826
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Thu Apr 25, 2013 9:54 pm

Good :)
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

User avatar
fma38
Member
 
Posts: 5826
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Thu Apr 25, 2013 9:54 pm

Mateusz, try with python 2.x...
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

no avatar
Mateusz Malinowski
Member
 
Posts: 85
Joined: Tue Apr 19, 2011 7:46 pm
Location: Polska

by Mateusz Malinowski » Fri Apr 26, 2013 9:28 am

Same syntax error
(WinPython-64bit-2.7.3.3; python 64bit 2.7.4)

User avatar
fma38
Member
 
Posts: 5826
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Fri Apr 26, 2013 9:45 am

Please, give the entire traceback...

Also try to run the script from IDLE, the python IDE.

- Right-click on the script, and choose 'Edit with IDLE'
- Run the script by pressing F5
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

no avatar
Mateusz Malinowski
Member
 
Posts: 85
Joined: Tue Apr 19, 2011 7:46 pm
Location: Polska

by Mateusz Malinowski » Fri Apr 26, 2013 3:19 pm

Done as you wrote. Now have
Code: Select all
Traceback (most recent call last):
  File "C:\Users\MT\Desktop\s.py", line 12, in <module>
    import serial
ImportError: No module named serial
>>>



User avatar
fma38
Member
 
Posts: 5826
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Fri Apr 26, 2013 3:28 pm

You need to install this module :

http://pyserial.sourceforge.net

;)
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

no avatar
Mateusz Malinowski
Member
 
Posts: 85
Joined: Tue Apr 19, 2011 7:46 pm
Location: Polska

by Mateusz Malinowski » Fri Apr 26, 2013 3:54 pm

Sorry, it's hard to understand pythhon if never used it before. I'm not sure I succesfully installed it (http://pyserial.sourceforge.net/pyserial.html#installation)

Code: Select all
Traceback (most recent call last):
  File "C:\Users\MT\Desktop\s.py", line 15, in <module>
    HOST, PORT = "localhost", COM7
NameError: name 'COM7' is not defined

User avatar
fma38
Member
 
Posts: 5826
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Fri Apr 26, 2013 4:56 pm

Code: Select all
# Stellarium server params
HOST, PORT = "localhost", 9999  <<<<<<<<< do not change anything here...
PACKET_SIZE = 20

# Merlin/Orion params
ENCODER_ZERO = 0x800000

# Driver params
SERIAL_PORT = "/dev/ttyS0"  <<<<<<<<<<<<<< change your Merlin serial port here
SERIAL_BAUDRATE = 9600
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

Next

Return to Panogear

Who is online

Users browsing this forum: No registered users and 1 guest

cron