Goniometer control for Marco Braun Probehead (AXYs) added

This commit is contained in:
Markus Rosenstihl 2016-04-29 19:12:21 +00:00
parent 9202ad2297
commit 9f4a3d6b53

125
src/tools/goniometer.py Normal file
View File

@ -0,0 +1,125 @@
__author__ = 'Markus Rosenstihl <markus.rosenstihl@physik.tu-darmstadt.de>'
import re
import serial
import time
import logging
import os
logfile = os.path.expanduser("~/.goniometer.log")
logging.basicConfig(filename=logfile,level=logging.INFO)
logger = logging.getLogger()
logger.name = "goniometer"
class goniometer:
"""
This class is meant to control the goniometer probe head from Marco Braun (AXYs)
"""
def __init__(self, dev="/dev/ttyUSB0",
baudrate=38400,
timeout=1,
return_to_origin=True,
loglevel=2,
logangle=False):
"""
Upon creating an instance the goniometer will be initialised and the current angle defined as being 0.
The goniometer log can be found in `~/.goniometer.log`.
:param return_to_origin: Set to true if you want the stepper to return to the beginning when
the class instance is deleted (for example with "del" ). Default: True
:type return_to_origin: bool
:param loglevel: This sets the log level 0=DEBUG,1=INFO,2=WARNING. Default: 2
:type loglevel: int
:param logangle: Should a history of the angles be kept? The log can be accessed in the `_angle_history`
variable. Default: False
:type logangle: bool
"""
self.serial = serial.Serial(port=dev, baudrate=baudrate, timeout=timeout)
logger.setLevel([logging.DEBUG,logging.INFO,logging.WARNING][loglevel])
self.serial.readlines() # empty serial buffer
self.current_angle = 0.0
self._angle_history = []
self.initialise()
self.return_to_origin = return_to_origin
self.logangel = logangle
def __del__(self):
if self.return_to_origin:
logging.info("Return to origin")
self._send("g1")
self._wait()
self.serial.close()
def _send(self, string_to_send):
formatted_string = "%s>\r\n"%string_to_send
logging.debug("send: %s"%(repr(formatted_string)))
self.serial.write(formatted_string)
def _recv(self):
retstr = self.serial.readline().strip().replace("\x00","")
search_result = re.search("<(\d+)>", retstr)
if search_result != None:
angle = float(search_result.group(1))/36.0
self.current_angle = angle
if self.logangle:
self._angle_history.append(angle)
logging.debug("%.2f"%angle)
return angle
else:
return None
def _wait(self):
logging.debug("Wait until rotation finnished (current: %.2f)"%(self.current_angle))
time.sleep(4)
while True:
retstr = self._recv()
if not retstr:
logging.debug("Rotation finnished (current: %.2f)"%(self.current_angle))
break
def initialise(self):
logging.info("Initialize goniometer")
self._send("R000")
self.current_angle = 0.0
def stop(self):
"""
Stops the current movement, not possible while doing :func:`step` and :func:`angle`
"""
logging.info("Stop goniometer")
self._send("S456")
def step(self, sample_rotation_degree=1.0):
"""
How many degrees should we step further. Negative values are not allowed, the stepper would return to 0.
A ValueError exception is raised in this case.
:param sample_rotation_degree: How many degrees to rotate. Default: 1
:type sample_rotation_degree: float
"""
if sample_rotation_degree <= 0:
raise ValueError,"This does not what you expect, would move to the start position whatever the value"
logging.info("Step goniometer: %.2f"%sample_rotation_degree)
direction = "g" if (sample_rotation_degree < 0) else "G"
sample_rotation_degree = -1*sample_rotation_degree if sample_rotation_degree < 0 else sample_rotation_degree
steps = int(sample_rotation_degree%360)
self._send("%s%i"%(direction, steps ))
self._wait()
def angle(self, angle_degree):
"""
To what angle, in degrees, should we rotate. Mod 360 is calculated for `angle_degree`.
If angle is smaller than current angle an exception will be raised.
(From the underlying :func:`step` function)
TODO: rotate either back or over to the wanted position.
:param angle_degree: position in degree
:type angle_degree: float
"""
angle_degree %= 360
delta_degree = angle_degree - self.current_angle
logging.info("Rotate tp %.2f (from %.2f, i.e. delta=%.2f)"%(angle_degree, self.current_angle, delta_degree))
self.step(sample_rotation_degree=delta_degree)