![]() |
|
|
|
|
|
||||||||||
|
| User list | Rules | You are not logged in.
Hi,
after some tests it seems that the new firmware (:e1 =020581) is buggy when driving the head on the yaw axis.
The bugs:
the first move on the yaw axis with fast speed is not ecact(1,8deg overshoot).
the second move on the yaw axis is very slow but exact.
The bugs occurs when driving the head with the handcontroller and with paywizard. So it is a problem of the head.
My question is now:
@ teleskop-austria (as distributor) : Can we get get a new firmware or switch back to the old firmware ? Or send the heads back to the dealer?
Best regards,
Volker
EDIT: The problems with Merlin heads and firmware 2.05.81 are solved with firmware version 2.06.81
http://www.autopano.net/forum/p57039-to … -19#p57039
thanks to all involved ![]()
Last edited by viktorhotel (2010-01-09 09:53:11)
Offline
Hallo Volker, das bringt die Sache auf den Punkt! .... klasse ![]()
Thank you Volker and to all the hard workers on our common problem: In summary thats it now! I allready contacted teleskop-austria! .... so lets wait and see!
I`m afraid, switching back to the old firmware will not be easy !?
reg Chris
www.insight360.de
Offline
viktorhotel wrote:
Hi,
the first move on the yaw axis with fast speed is not ecact(1,8deg overshoot).
the second move on the yaw axis is very slow but exact.
What´s wrong with that? If it´s exact in the end? (most users complain about the slow action of the head . . . )
best, Klaus
Offline
Hi Klaus,
They get a right positionning for the first move, the second is faulty by +/- 1,5 to 2°, the third is right, the fourth is faulty etc ... ![]()
Offline
claudevh wrote:
Hi Klaus,
They get a right positionning for the first move, the second is faulty by +/- 1,5 to 2°, the third is right, the fourth is faulty etc ...
Would this positioning error/lackof-precision really affect the quality of stitching? After all we would still have adequate overlaps.
I would have thought that most manual pano heads were probably less precise than +/- 2 degrees?
Offline
mediavets wrote:
claudevh wrote:
Hi Klaus,
They get a right positionning for the first move, the second is faulty by +/- 1,5 to 2°, the third is right, the fourth is faulty etc ...Would this positioning error/lackof-precision really affect the quality of stitching? After all we would still have adequate overlaps.
I would have thought that most manual pano heads were probably less precise than +/- 2 degrees?
using 25 - 30% overlap . . . . no problem. You can in the end stitch handhelds without major complications . . ![]()
best, Klaus
Offline
claudevh wrote:
Hi Klaus,
They get a right positionning for the first move, the second is faulty by +/- 1,5 to 2°, the third is right, the fourth is faulty etc ...
hi claude!
oh - i see . . . ![]()
best, klaus
Offline
hi,
in summary the inacceptable slow and inexact movements are the problem.
Hope we get a solution as soon as possible.
For those who have a new head please read http://www.autopano.net/forum/viewtopic … 76&p=7
Best regards,
Volker
Offline
viktorhotel wrote:
hi,
in summary the inacceptable slow and inexact movements are the problem.
Hope we get a solution as soon as possible.
For those who have a new head please read http://www.autopano.net/forum/viewtopic … 76&p=7
Best regards,
Volker
I must have misunmderstood - I thought you had identified a workaround that was as fast as Mark I Merlin but slightly less accurate?
Offline
Hi Andrew,
yes the workaround is a speed improvement, but its not a solution. The Tokina 10-17 preset takes 1:36 with the "old" head , 2:16 with the "new" head and workaround and 2:38 without workaround.
So we can state that the new firmware not an "improvement" !
Volker
Offline
So, before we find a *real* solution for this problem, you can try this new version of the Merlin/Orion plugin, which uses slow speed for the goto function.
Just copy/paste the following code, and save it in your plugins config directory (C:\Documents and settings\<user>\Application Data\papywizard2\plugins) under the name you want (something like merlinOrion2.py). Then restart Papywizard. The name of the plugin in the config dialog will be 'Merlin-Orion 2'. Use it only for the yaw axis.
Let me know if it works.
# -*- coding: utf-8 -*-
""" Panohead remote control.
License
=======
- B{Papywizard} (U{http://www.papywizard.org}) is Copyright:
- (C) 2007-2009 Frédéric Mantegazza
This software is governed by the B{CeCILL} license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
U{http://www.cecill.info}.
As a counterpart to the access to the source code and rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors have only limited
liability.
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms.
Module purpose
==============
Hardware
Implements
==========
- MerlinOrionHardware
- MerlinOrionAxis
- MerlinOrionAxisController
- MerlinOrionShutter
- MerlinOrionShutterController
@author: Frédéric Mantegazza
@copyright: (C) 2007-2009 Frédéric Mantegazza
@license: CeCILL
@todo: add private methods to MerlinOrionHardware for sending commands to MerlinOrion
"""
__revision__ = "$Id: merlinOrionPlugins.py 2188 2009-11-12 07:05:09Z fma $"
import time
import sys
import threading
from PyQt4 import QtCore, QtGui
from papywizard.common import config
from papywizard.common.exception import HardwareError
from papywizard.common.loggingServices import Logger
from papywizard.plugins.pluginsManager import PluginsManager
from papywizard.plugins.abstractAxisPlugin import AbstractAxisPlugin
from papywizard.plugins.abstractStandardShutterPlugin import AbstractStandardShutterPlugin
from papywizard.plugins.abstractHardwarePlugin import AbstractHardwarePlugin
from papywizard.plugins.axisPluginController import AxisPluginController
from papywizard.plugins.hardwarePluginController import HardwarePluginController
from papywizard.plugins.standardShutterPluginController import StandardShutterPluginController
from papywizard.view.pluginFields import ComboBoxField, LineEditField, SpinBoxField, DoubleSpinBoxField, CheckBoxField, SliderField
NAME = "Merlin-Orion 2"
DEFAULT_ALTERNATE_DRIVE = True
DEFAULT_INERTIA_ANGLE = 1. # °
#DEFAULT_ALTERNATE_FULL_CIRCLE = False
#DEFAULT_ENCODER_FULL_CIRCLE = 0xE62D3
ALTERNATE_DRIVE_ANGLE = 7. # °
ENCODER_ZERO = 0x800000
ENCODER_FULL_CIRCLE = 0xE62D3
AXIS_ACCURACY = 0.1 # °
AXIS_TABLE = {'yawAxis': 1,
'pitchAxis': 2,
'shutter': 1
}
MANUAL_SPEED_TABLE = {'slow': 170, # "AA0000" / 5
'alternate': 80, # "500000"
'normal': 34, # "220000" nominal
'fast': 17 # "110000" * 2
}
class MerlinOrionHardware(AbstractHardwarePlugin):
"""
"""
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. / ENCODER_FULL_CIRCLE
def _angleToEncoder(self, pos):
""" Convert degres to encoder value.
@param pos: position, in °
@type pos: float
@return: encoder position
@rtype: int
"""
return int(pos * ENCODER_FULL_CIRCLE / 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" % (cmd, AXIS_TABLE[self.capacity], param)
for nbTry in xrange(3):
try:
answer = ""
self._driver.empty()
self._driver.write(":%s\r" % cmd)
c = ''
while c not in ('=', '!'):
c = self._driver.read(1)
if c == '!':
c = self._driver.read(1) # Get error code
raise IOError("Unknown command '%s' (err=%s)" % (cmd, c))
answer = ""
while True:
c = self._driver.read(1)
if c == '\r':
break
answer += c
except IOError:
Logger().exception("MerlinOrionHardware._sendCmd")
Logger().warning("MerlinOrionHardware._sendCmd(): %s axis %d can't sent command '%s'. Retrying..." % (NAME, AXIS_TABLE[self.capacity], cmd))
else:
break
else:
raise HardwareError("%s axis %d can't send command '%s'" % (NAME, AXIS_TABLE[self.capacity], cmd))
#Logger().debug("MerlinOrionHardware._sendCmd(): axis %d cmd=%s, ans=%s" % (AXIS_TABLE[self.capacity], cmd, answer))
return answer
def _initMerlinOrion(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 full circle count
value = self._sendCmd("a")
Logger().debug("MerlinOrionHardware._initMerlinOrion(): full circle count=%s" % hex(self._decodeAxisValue(value)))
# Get sidereal rate
value = self._sendCmd("D")
Logger().debug("MerlinOrionHardware._initMerlinOrion(): sidereal rate=%s" % hex(self._decodeAxisValue(value)))
# Get firmeware version
value = self._sendCmd("e")
Logger().debug("MerlinOrionHardware._initMerlinOrion(): firmeware version=%s" % value)
finally:
self._driver.releaseBus()
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", "40")
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("%s axis %d dir. must be in ('+', '-')" % (NAME, AXIS_TABLE[self.capacity]))
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()
class MerlinOrionAxis(MerlinOrionHardware, AbstractAxisPlugin, QtCore.QThread):
def __init__(self, *args, **kwargs):
MerlinOrionHardware.__init__(self, *args, **kwargs)
AbstractAxisPlugin.__init__(self, *args, **kwargs)
QtCore.QThread.__init__(self)
def _init(self):
Logger().trace("MerlinOrionAxis._init()")
MerlinOrionHardware._init(self)
AbstractAxisPlugin._init(self)
self.__run = False
self.__driveFlag = False
self.__setPoint = None
def _defineConfig(self):
AbstractAxisPlugin._defineConfig(self)
AbstractHardwarePlugin._defineConfig(self)
self._addConfigKey('_alternateDrive', 'ALTERNATE_DRIVE', default=DEFAULT_ALTERNATE_DRIVE)
self._addConfigKey('_inertiaAngle', 'INERTIA_ANGLE', default=DEFAULT_INERTIA_ANGLE)
#self._addConfigKey('_alternateEncoder360', 'ALTERNATE_FULL_CIRCLE', default=DEFAULT_ALTERNATE_FULL_CIRCLE)
#self._addConfigKey('_encoder360', 'ENCODER_FULL_CIRCLE', default=DEFAULT_ENCODER_FULL_CIRCLE)
def activate(self):
Logger().trace("MerlinOrionHardware.activate()")
AbstractAxisPlugin.activate(self)
# Start the thread
self.start()
def deactivate(self):
Logger().trace("MerlinOrionHardware.deactivate()")
# Stop the thread
self._stopThread()
self.wait()
AbstractAxisPlugin.deactivate(self)
def init(self):
Logger().trace("MerlinOrionAxis.init()")
AbstractAxisPlugin.init(self)
self._initMerlinOrion()
def shutdown(self):
Logger().trace("MerlinOrionAxis.shutdown()")
self.stop()
AbstractAxisPlugin.shutdown(self)
def run(self):
""" Main entry of the thread.
"""
threadName = "%s_%s" % (self.name, self.capacity)
threading.currentThread().setName(threadName)
Logger().debug("MerlinOrionAxis.run(): start thread")
self.__run = True
while self.__run:
if self.__driveFlag:
# Choose alternate drive if needed
currentPos = self.read()
if self._config['ALTERNATE_DRIVE'] and \
1.1 * self._config['INERTIA_ANGLE'] < abs(self.__setPoint - currentPos) < ALTERNATE_DRIVE_ANGLE:
self._alternateDrive(self.__setPoint)
else:
self._directDrive(self.__setPoint)
self.__driveFlag = False
self.waitEndOfDrive() # ???
self.msleep(config.SPY_REFRESH_DELAY)
Logger().debug("MerlinOrionAxis.run(): thread terminated")
def _stopThread(self):
""" Stop the thread.
"""
self.__run = False
def read(self):
pos = self._read() - self._offset
return pos
def drive(self, pos, useOffset=True, wait=True):
Logger().debug("MerlinOrionAxis.drive(): '%s' drive to %.1f" % (self.capacity, pos))
currentPos = self.read()
self._checkLimits(pos)
if useOffset:
pos += self._offset
# Only move if needed
if abs(pos - currentPos) > AXIS_ACCURACY:
self.__setPoint = pos
self.__driveFlag = True # Start thread action
# Wait end of movement
if wait:
self.waitEndOfDrive()
def _directDrive(self, pos):
""" Default (hardware) drive.
@param pos: position to reach, in °
@type pos: float
"""
Logger().trace("MerlinOrionAxis._directDrive()")
self._drive(pos)
def _alternateDrive(self, pos):
""" Alternate drive.
This method implements an external closed-loop regulation.
It is faster for angles < 6-7°, because in this case, the
head does not accelerate to full speed, but rather stays at
very low speed.
@param pos: position to reach, in °
@type pos: float
"""
Logger().trace("MerlinOrionAxis._alternateDrive()")
# Compute initial direction
currentPos = self.read()
if pos > currentPos:
dir_ = '+'
else:
dir_ = '-'
stopRequest = False
# Alternate speed move
Logger().debug("MerlinOrionAxis._alternateDrive(): alternate speed move")
self._startJog(dir_, MANUAL_SPEED_TABLE['alternate'])
# Check when stop
while abs(pos - self.read()) > self._config['INERTIA_ANGLE']: # adjust inertia while moving?
# Test if a stop request has been sent
if not self.isMoving():
stopRequest = True
break
time.sleep(0.1)
self._stop()
# Final move
if abs(pos - self.read()) > AXIS_ACCURACY and not stopRequest:
Logger().debug("MerlinOrionAxis._alternateDrive(): final move")
self._drive(pos)
def waitEndOfDrive(self):
while self.isMoving():
time.sleep(0.1)
self.waitStop()
def startJog(self, dir_):
self._startJog(dir_, MANUAL_SPEED_TABLE[self._manualSpeed])
def stop(self):
self.__driveFlag = False
self._stop()
self.waitStop()
def waitStop(self):
pos = self.read()
time.sleep(0.05)
while True:
if round(abs(pos - self.read()), 1) == 0:
break
pos = self.read()
time.sleep(0.05)
def isMoving(self):
status = self._getStatus()
if status[1] != '0' or self.__driveFlag:
return True
else:
return False
class MerlinOrionAxisController(AxisPluginController, HardwarePluginController):
def _defineGui(self):
AxisPluginController._defineGui(self)
HardwarePluginController._defineGui(self)
self._addTab('Hard', QtGui.QApplication.translate("merlinOrionPlugins", 'Hard'))
self._addWidget('Hard', QtGui.QApplication.translate("merlinOrionPlugins", "Alternate drive"),
CheckBoxField, (), 'ALTERNATE_DRIVE')
self._addWidget('Hard', QtGui.QApplication.translate("merlinOrionPlugins", "Inertia angle"),
DoubleSpinBoxField, (0.1, 9.9, 1, .1, "", " deg"), 'INERTIA_ANGLE')
#self._addWidget('Hard', QtGui.QApplication.translate("merlinOrionPlugins", "Alternate full circle"),
#CheckBoxField, (), 'ALTERNATE_FULL_CIRCLE')
#self._addWidget('Hard', QtGui.QApplication.translate("merlinOrionPlugins", "Encoder full circle"),
#SpinBoxField, (0x080000, 0x380000, "", " units/turn"), 'ENCODER_FULL_CIRCLE')
class MerlinOrionShutter(MerlinOrionHardware, AbstractStandardShutterPlugin):
def _init(self):
Logger().trace("MerlinOrionShutter._init()")
MerlinOrionHardware._init(self)
AbstractStandardShutterPlugin._init(self)
def _defineConfig(self):
MerlinOrionHardware._defineConfig(self)
AbstractStandardShutterPlugin._defineConfig(self)
def _triggerOnShutter(self):
""" Set the shutter on.
"""
self._driver.acquireBus()
try:
self._sendCmd("O", "1")
finally:
self._driver.releaseBus()
def _triggerOffShutter(self):
""" Set the shutter off.
"""
self._driver.acquireBus()
try:
self._sendCmd("O", "0")
finally:
self._driver.releaseBus()
def init(self):
Logger().trace("MerlinOrionShutter.init()")
self._initMerlinOrion()
def shutdown(self):
Logger().trace("MerlinOrionShutter.shutdown()")
self._triggerOffShutter()
AbstractStandardShutterPlugin.shutdown(self)
class MerlinOrionShutterController(StandardShutterPluginController, HardwarePluginController):
def _defineGui(self):
StandardShutterPluginController._defineGui(self)
HardwarePluginController._defineGui(self)
def register():
""" Register plugins.
"""
PluginsManager().register(MerlinOrionAxis, MerlinOrionAxisController, capacity='yawAxis', name=NAME)
PluginsManager().register(MerlinOrionAxis, MerlinOrionAxisController, capacity='pitchAxis', name=NAME)
PluginsManager().register(MerlinOrionShutter, MerlinOrionShutterController, capacity='shutter', name=NAME)Offline
hello friends,
we are in contact with Synta about the problem, maybe we can get replacement motherboards. As they continue to develop the Merlin for astronomical purposes, its always possible that something changes. So if there is a solution possible via Papywizard implementation, that would be safer. Just as we did for the recent bluetooth incompability with the newest Merlin charge.
Thank you Frédéric for your fast action!
regards, Tommy
edit: We already have answer from Synta, they will track down the error and send new panels by
airmail. Its easy to change the panels, everybody can do it. Tamàs Butuza is going to write a small test utility for evaluating which panel version you have, and if you need to replace it. Stay tuned!
Last edited by teleskop-austria (2009-11-24 10:46:18)
Offline
Hi Tommy,
good news from "teleskop-austria".
I'm very pleased about the quick and straightforward solution/answer from synta.
Many thanks to you and Tamas,
Volker
Offline
Fine Tommy !
Well done ...
Offline
Good news ![]()
Offline
Very happy about, how things are going on!
Thanks to ALL, who spent a lot of time on this project!
reg Chris
www.insight360.de
Offline
hello friends possessing the new firmware,
Synta asks some specific questions to track the error down, could you please get me a set of answers on them? Of course, they won't use Papywizard as a third party program, but if they could reproduce the error using the Merlin handbox, they are willing to work on it (that is VERY cooperative behaviour already!).
1.Power supply - did you use batteries, accus, or AC adapter? If AC adapter, please specify output voltage, capacity, and if it was a switching power supply.
2.approximate angular position of pre-programmed terrestial points?
3.did you start astro-trcking (pressing both GUIDE and SLOW buttons?) before using the CRUISE function? (answer probably NO... :-)
4.the Merlin can slew fast to the first point, but cannot slew fast to the second point, is that statement right? What was the speed after reching the first point (fast enough to be seen with bare eye or slower?) Did it fully stop for 3-5 seconds or kept crawling at low speed?
Please take the time, I'll try to find answers too, today!
regards, Tommy
Offline
Good to read that teleskop-austria and Synta are working on that problem.
I will place my order for a Marlin when the bug will be fixed and the fixed version will be available.
Best Regards,
ReverZ
Offline
ReverZ wrote:
Good to read that teleskop-austria and Synta are working on that problem.
I will place my order for a Marlin when the bug will be fixed and the fixed version will be available.
Best Regards,
ReverZ
I also
Luca
Offline
Hi Tommy,
http://www.autopano.net/forum/viewtopic.php?id=7576
Using a power supply or a battery makes no difference, the bug is always reproduceable.
My test scenario with the handcontroller:
Power on
press Fast
Store 3 positions on the yaw axis(1. Odeg, 2. 10deg 3. 20deg clockwise using button 5>)
GOto Position 1(counterclockwise) (takes long time to find position, "1" on HC is flashing very long, movement exact)
GOto Position 2 (clockwise) (quick,"2" on HC flashing not very long, movement 2deg over)
GOto Position 3 (clockwise) (takes long time to find position, head is moving slower than before, "3" on HC flashing very long, movement exact)
Volker
Last edited by viktorhotel (2009-11-25 22:59:13)
Offline
Hi Tommy,
In Pitch axis, all movements are equals in time and very accurates ! NO PROBLEM ON PITCH ...
Offline
thank you Volker,
I already passed over your description! My short test also confirmed something weird in the
cruising speed to terrestrial programmed points. Hope I can do it fully tomorrow.
regards Tommy
Offline
Any news?
Offline
Hi "Multifunction-Mount" users,
nearly one month is gone and we have no feedback...
that's disappointing...
I think now its time find a new name for "Multifunction-Mount" maybe "Monofunction-Mount" ?![]()
Merry Christmas,
Volker
Offline
hello everybody,
I submitted Volkers results, and could reproduce time lags in my own test and submitted that too. What I heard at last was the Chinese couldn't reproduce the time lags because they already have a new firmware not showing that behaviour, and no more models using our current firmware.
Seems I have to push them, I'll be back shortly.
regards Tommy
Offline
Powered by PunBB
© Copyright 2002–2005 Rickard Andersson
|
CHOOSING KOLOR Why choose Kolor? Which solution to choose? Download a trial Where can I buy? Education |
SOFTWARE Autopano Pro Autopano Giga Panotour Panotour Pro XnView |
ACCESSORIES Training DVD Panobook PROJECTS Paris 26 Gigapixels Yosemite 17 Gigapixels |
COMMUNITY Forums YouTube channel Google+ |
COMPANY Blog About Kolor Resellers Contact Visit us |
PRESS Press center Press review TOOLS My account |
