Image-stitching and virtual tour solutions My account Updates
It is currently Thu Oct 23, 2014 10:27 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 27 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sat Mar 09, 2013 8:03 pm 
Offline
Member
User avatar

Joined: Fri Mar 16, 2012 4:23 am
Posts: 168
Location: Lee, Maine, USA
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.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 09, 2013 8:28 pm 
Offline
Member

Joined: Wed Nov 14, 2007 2:12 pm
Posts: 14038
Location: Isleham, Cambridgeshire, UK.
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.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 09, 2013 9:32 pm 
Offline
Member
User avatar

Joined: Fri Mar 16, 2012 4:23 am
Posts: 168
Location: Lee, Maine, USA
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. ;-)


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 09, 2013 9:42 pm 
Offline
Member
User avatar

Joined: Fri Mar 16, 2012 4:23 am
Posts: 168
Location: Lee, Maine, USA
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


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 10, 2013 8:04 pm 
Offline
Member
User avatar

Joined: Wed Dec 07, 2005 6:21 pm
Posts: 5826
Location: Grenoble, France
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


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 12, 2013 11:24 am 
Offline
Member
User avatar

Joined: Wed Dec 07, 2005 6:21 pm
Posts: 5826
Location: Grenoble, France
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:
# -*- 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


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 12, 2013 2:37 pm 
Offline
Member
User avatar

Joined: Wed Dec 07, 2005 6:21 pm
Posts: 5826
Location: Grenoble, France
Here is a new version, with a few fixes:

Code:
# -*- 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


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 25, 2013 8:06 am 
Offline
Member
User avatar

Joined: Tue Feb 19, 2008 10:52 pm
Posts: 78
Location: la roche-en-ardenne
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.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 25, 2013 8:13 am 
Offline
Member
User avatar

Joined: Wed Dec 07, 2005 6:21 pm
Posts: 5826
Location: Grenoble, France
!!!! 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


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 25, 2013 8:24 am 
Offline
Member
User avatar

Joined: Tue Feb 19, 2008 10:52 pm
Posts: 78
Location: la roche-en-ardenne
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.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 25, 2013 8:32 am 
Offline
Member
User avatar

Joined: Wed Dec 07, 2005 6:21 pm
Posts: 5826
Location: Grenoble, France
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


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 25, 2013 8:47 am 
Offline
Member
User avatar

Joined: Tue Feb 19, 2008 10:52 pm
Posts: 78
Location: la roche-en-ardenne
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.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 25, 2013 9:32 am 
Offline
Member
User avatar

Joined: Wed Dec 07, 2005 6:21 pm
Posts: 5826
Location: Grenoble, France
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


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 25, 2013 9:46 am 
Offline
Member
User avatar

Joined: Tue Feb 19, 2008 10:52 pm
Posts: 78
Location: la roche-en-ardenne
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.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 25, 2013 9:54 am 
Offline
Member
User avatar

Joined: Wed Dec 07, 2005 6:21 pm
Posts: 5826
Location: Grenoble, France
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


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 25, 2013 5:28 pm 
Offline
Member

Joined: Tue Apr 19, 2011 7:46 pm
Posts: 85
Location: Polska
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

_________________
Panoramy sferyczne, wirtualne spacery, zdjęcia trójwymiarowe.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 25, 2013 6:03 pm 
Offline
Member
User avatar

Joined: Tue Feb 19, 2008 10:52 pm
Posts: 78
Location: la roche-en-ardenne
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

_________________
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.


Last edited by dim on Thu Apr 25, 2013 6:05 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 25, 2013 9:54 pm 
Offline
Member
User avatar

Joined: Wed Dec 07, 2005 6:21 pm
Posts: 5826
Location: Grenoble, France
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


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 25, 2013 9:54 pm 
Offline
Member
User avatar

Joined: Wed Dec 07, 2005 6:21 pm
Posts: 5826
Location: Grenoble, France
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


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 26, 2013 9:28 am 
Offline
Member

Joined: Tue Apr 19, 2011 7:46 pm
Posts: 85
Location: Polska
Same syntax error
(WinPython-64bit-2.7.3.3; python 64bit 2.7.4)

_________________
Panoramy sferyczne, wirtualne spacery, zdjęcia trójwymiarowe.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 26, 2013 9:45 am 
Offline
Member
User avatar

Joined: Wed Dec 07, 2005 6:21 pm
Posts: 5826
Location: Grenoble, France
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


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 26, 2013 3:19 pm 
Offline
Member

Joined: Tue Apr 19, 2011 7:46 pm
Posts: 85
Location: Polska
Done as you wrote. Now have
Code:
Traceback (most recent call last):
  File "C:\Users\MT\Desktop\s.py", line 12, in <module>
    import serial
ImportError: No module named serial
>>>



_________________
Panoramy sferyczne, wirtualne spacery, zdjęcia trójwymiarowe.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 26, 2013 3:28 pm 
Offline
Member
User avatar

Joined: Wed Dec 07, 2005 6:21 pm
Posts: 5826
Location: Grenoble, France
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


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 26, 2013 3:54 pm 
Offline
Member

Joined: Tue Apr 19, 2011 7:46 pm
Posts: 85
Location: Polska
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:
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

_________________
Panoramy sferyczne, wirtualne spacery, zdjęcia trójwymiarowe.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 26, 2013 4:56 pm 
Offline
Member
User avatar

Joined: Wed Dec 07, 2005 6:21 pm
Posts: 5826
Location: Grenoble, France
Code:
# 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


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 27 posts ]  Go to page 1, 2  Next

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group