Source code for crappy.actuator.kollmorgen_servostar_300

# coding: utf-8

from typing import Union, Optional
import logging

from .meta_actuator import Actuator
from .._global import OptionalModule

try:
  import serial
except (ModuleNotFoundError, ImportError):
  serial = OptionalModule("pyserial")


[docs] class ServoStar300(Actuator): """This class can drive a Kollmorgen ServoStar 300 servomotor conditioner in position, and set it to the analog or serial driving mode. It communicates with the servomotor over a serial connection. The :class:`~crappy.lamcube.Biaxe` Actuator can drive the same hardware, but only in speed. .. versionadded:: 1.4.0 .. versionchanged:: 2.0.0 renamed from *Servostar* to *ServoStar300* """
[docs] def __init__(self, port: str, baudrate: int = 38400, mode: str = "serial") -> None: """Sets the instance attributes and initializes the parent class. Args: port: Path to the serial port used for communication. .. versionchanged:: renamed from *device* to *port* baudrate: The serial baud rate to use, as an :obj:`int`. mode: The driving mode to use when starting the test. Can be `'analog'` or `'serial'`. It can be changed afterward while the test is running, by sending the right command. """ self._ser = None super().__init__() self._port = port self._mode = mode self._baudrate = baudrate self._last_pos = None if mode not in ('analog', 'serial'): raise AttributeError(f"No such mode: {mode}")
[docs] def open(self) -> None: """Initializes the serial connection and sets the desired driving mode.""" # Opening the serial connection self.log(logging.INFO, f"Opening the serial port {self._port} with " f"baudrate {self._baudrate}") self._ser = serial.Serial(self._port, baudrate=self._baudrate, timeout=2) self.log(logging.DEBUG, f"Writing b'ANCNFG 0\\r\\n' to port {self._port}") self._ser.write('ANCNFG 0\r\n') # Setting the desired mode if self._mode == "analog": self._set_mode_analog() else: self._set_mode_serial() self.log(logging.DEBUG, f"Writing b'EN\\r\\n' to port {self._port}") self._ser.write('EN\r\n') self.log(logging.DEBUG, f"Writing b'MH\\r\\n' to port {self._port}") self._ser.write('MH\r\n')
[docs] def set_position(self, pos: Union[float, bool], speed: Optional[float]) -> None: """Sets the target position for the motor. Also allows switching to the serial or analog driving mode if the target position is a :obj:`bool`. The acceleration and deceleration are set to `200`. Args: pos: The target position to reach, as a :obj:`float`. Alternatively, a value of :obj:`True` sets the driving mode to serial, and :obj:`False` sets the driving mode to analog. speed: The speed at which the actuator should reach its target position. If no speed is specified, the default is `20000`. .. versionchanged:: 2.0.0 *speed* is now a mandatory argument .. versionremoved:: 2.0.0 *acc* and *dec* arguments """ if speed is None: speed = 20000 # Nothing to do if the command is the same as the previous if self._last_pos == pos: return # To allow setting the mode with a boolean command, so that the actuator # can be driven from a single generator if isinstance(pos, bool): if pos: self._set_mode_serial() else: self._set_mode_analog() return # The commands can only be set from Crappy in serial mode elif self._mode != "serial": self._set_mode_serial() # Writing the command to the actuator self._ser.flushInput() self.log(logging.DEBUG, f"Writing b'ORDER 0 {int(pos)} {speed} 8192 200 " f"200 0 0 0 0\\r\\n' to port {self._port}") self._ser.write(f"ORDER 0 {int(pos)} {speed} 8192 200 200 0 0 0 0\r\n") self.log(logging.DEBUG, f"Writing b'MOVE 0\\r\\n' to port {self._port}") self._ser.write("MOVE 0\r\n") # Saving the last command self._last_pos = pos
[docs] def get_position(self) -> Optional[float]: """Reads and returns the current position of the motor. .. versionchanged:: 1.5.2 renamed from *get_pos* to *get_position* """ # Requesting a position reading self._ser.flushInput() self.log(logging.DEBUG, f"Writing b'PFB\\r\\n' to port {self._port}") self._ser.write("PFB\r\n") # Reading until getting the stop sequence, or the actuator stops responding r = '' while r != "PFB\r\n": # Keeping only the last 5 received characters if len(r) == 5: r = r[1:] # Reading the next character r += self._ser.read() # Aborting if no new character could be read if not r: self.log(logging.ERROR, "Timeout error ! Make sure the servostar is " "on !") return # The next reading should give the position ret = self._ser.readline() self.log(logging.DEBUG, f"Read {ret} on port {self._port}") return int(ret)
[docs] def stop(self) -> None: """Sends a command for stopping the motor.""" if self._ser is not None: self.log(logging.DEBUG, f"Writing b'DIS\\r\\n' to port {self._port}") self._ser.write("DIS\r\n") self._ser.flushInput()
[docs] def close(self) -> None: """Closes the serial connection.""" if self._ser is not None: self.log(logging.INFO, f"Closing the serial port {self._port}") self._ser.close()
def _set_mode_serial(self) -> None: """Sets the driving mode to serial.""" self._ser.flushInput() self.log(logging.DEBUG, f"Writing b'OPMODE 8\\r\\n' to port {self._port}") self._ser.write('OPMODE 8\r\n') self._mode = "serial" def _set_mode_analog(self) -> None: """Sets the driving mode to analog.""" self._last_pos = None self._ser.flushInput() self.log(logging.DEBUG, f"Writing b'OPMODE A\\r\\n' to port {self._port}") self._ser.write('OPMODE 1\r\n') self._mode = "analog"