示例#1
0
    def get_serial_ports_list(self):
        """ Lists serial port names

            :raises EnvironmentError:
                On unsupported or unknown platforms
            :returns:
                A list of the serial ports available on the system
        """
        if sys.platform.startswith('win'):
            ports = ['COM%s' % (i + 1) for i in range(256)]
        elif (sys.platform.startswith('linux') or
              sys.platform.startswith('cygwin')):
            # this excludes your current terminal "/dev/tty"
            ports = glob.glob('/dev/tty[A-Za-z]*')
        elif sys.platform.startswith('darwin'):
            ports = glob.glob('/dev/tty.*')
        else:
            raise EnvironmentError('Unsupported platform')

        result = []
        for port in ports:
            try:
                if 'usbmodem' in port or 'COM' in port:
                    s = serial.Serial(port)
                    s.close()
                    result.append(port)
            except Exception as e:
                log.debug(
                    "Serial",
                    'Exception in testing port {}'.format(port))
                log.debug("Serial", e)
        return result
示例#2
0
    def move_head(self, mode='absolute', **kwargs):

        self.set_coordinate_system(mode)
        current = self.get_head_position()['target']

        log.debug('Motor Driver', 'Current Head Position: {}'.format(current))
        target_point = {
            axis: kwargs.get(
                axis,
                0 if mode == 'relative' else current[axis]
            )
            for axis in 'xyz'
        }
        log.debug('Motor Driver', 'Destination: {}'.format(target_point))

        time_interval = 0.5
        # convert mm/min -> mm/sec,
        # multiply by time interval to get increment in mm
        increment = self.head_speed / 60 * time_interval

        vector_list = break_down_travel(
            current, Vector(target_point), mode=mode, increment=increment)

        # turn the vector list into axis args
        args_list = []
        for vector in vector_list:
            flipped_vector = self.flip_coordinates(vector, mode)
            args_list.append(
                {axis.upper(): flipped_vector[axis]
                 for axis in 'xyz' if axis in kwargs})

        return self.consume_move_commands(args_list, increment)
示例#3
0
    def move(self, x=None, y=None, z=None, speed=None, absolute=True, **kwargs):

        if speed:
            code = self.MOVE
        else:
            code = self.RAPID_MOVE

        if absolute:
            self.send_command(self.ABSOLUTE_POSITIONING)
        else:
            self.send_command(self.RELATIVE_POSITIONING)

        args = {}

        """
        Add x, y and z back to the kwargs.  They're omitted when we name them
        as explicit keyword arguments, but it's much nicer to be able to pass
        them as anonymous parameters when calling this method.
        """
        if x is not None:
            args['x'] = x
        if y is not None:
            args['y'] = y
        if z is not None:
            args['z'] = z

        for k in kwargs:
            args[k.upper()] = kwargs[k]

        log.debug("MotorDriver", "Moving: {}".format(args))

        self.send_command(code, **args)
示例#4
0
 def wait_for_stat(self, stat=None):
     if self.DEBUG_ON:
         log.debug("Serial", "Turning on debug mode.")
         log.debug("Serial", "Awaiting stat responses.")
         self.send_command(self.DEBUG_ON)
         self._wait_for_stat = True
         if stat is not None:
             self._stat_command = stat
示例#5
0
 def plunge(self, volume):
     debug(
         "PipetteMotor",
         "Plunging {} axis ({}) to volume of {}µl."
         .format(self.axis, self.name, volume)
     )
     depth = self.pipette.plunge_depth(volume)
     self.move(depth)
示例#6
0
    def process_command(self, command):
        parsed_command = self.parse_command(command)

        command_mapping = {
            'G': self.process_nop,
            'M': self.process_nop,
            'G0': self.process_move_command,
            'G4': self.process_dwell_command,
            'M114': self.process_get_position,
            'G92': self.process_set_position_command,
            'G28': self.process_home_command,
            'M119': self.process_get_endstops,
            'M999': self.process_calm_down,
            'M63': self.process_disengage_feedback,
            'G90': self.process_absolute_positioning,
            'G91': self.process_relative_positioning,
            'M40': self.process_mosfet_state,
            'M41': self.process_mosfet_state,
            'M42': self.process_mosfet_state,
            'M43': self.process_mosfet_state,
            'M44': self.process_mosfet_state,
            'M45': self.process_mosfet_state,
            'M46': self.process_mosfet_state,
            'M47': self.process_mosfet_state,
            'M48': self.process_mosfet_state,
            'M49': self.process_mosfet_state,
            'M50': self.process_mosfet_state,
            'M51': self.process_mosfet_state,
            'M17': self.process_power_on,
            'M18': self.process_power_off,
            'version': self.process_version,
            'config-get': self.process_config_get,
            'config-set': self.process_config_set
        }
        if parsed_command:
            command = parsed_command['command']
            arguments = parsed_command['arguments']
            if command in command_mapping:
                command_func = command_mapping[command]
                log.debug(
                    'Virtual Smoothie',
                    'Processing {} calling {}'.format(
                        parsed_command,
                        command_func.__name__))
                message = command_func(arguments)
                self.insert_response(message)
            else:
                log.error(
                    'Virtual Smoothie',
                    'Command {} is not supported'.format(command))
示例#7
0
 def _run(self, index):
     cur = self._commands[index]
     command = list(cur)[0]
     kwargs = cur[command]
     self._run_in_context_handler(command, **kwargs)
     for h in self._handlers:
         debug(
             "Protocol",
             "{}.{}: {}"
             .format(type(h).__name__, command, kwargs)
         )
         h.before_each()
         method = getattr(h, command)
         method(**kwargs)
         h.after_each()
示例#8
0
 def write_to_serial(self, data, max_tries=10, try_interval=0.2):
     log.debug("Serial", "Write: {}".format(str(data).encode()))
     if self.connection is None:
         log.warn("Serial", "No connection found.")
         return
     if self.is_connected():
         self.connection.write(str(data).encode())
         return self.wait_for_response()
     elif max_tries > 0:
         self.reset_port()
         return self.write_to_serial(
             data, max_tries=max_tries - 1, try_interval=try_interval
         )
     else:
         log.error("Serial", "Cannot connect to serial port.")
         return b''
示例#9
0
    def readline_from_serial(self):
        msg = b''
        if self.is_connected():
            # serial.readline() returns an empty byte string if it times out
            msg = self.connection.readline().strip()
            if msg:
                log.debug("Serial", "Read: {}".format(msg))

        # detect if it hit a home switch
        if b'!!' in msg or b'limit' in msg:
            # TODO (andy): allow this to bubble up so UI is notified
            log.debug('Serial', 'home switch hit')
            self.flush_port()
            self.calm_down()
            raise RuntimeWarning('limit switch hit')

        return msg
示例#10
0
    def get_position(self):
        res = self.send_command(self.GET_POSITION)
        # remove the "ok " from beginning of response
        res = res.decode('utf-8')[3:]
        coords = {}
        try:
            response_dict = json.loads(res).get(self.GET_POSITION)
            coords = {'target': {}, 'current': {}}
            for letter in 'xyzab':
                # the lowercase axis are the "real-time" values
                coords['current'][letter] = response_dict.get(letter, 0)
                # the uppercase axis are the "target" values
                coords['target'][letter] = response_dict.get(letter.upper(), 0)

        except JSON_ERROR:
            log.debug("Serial", "Error parsing JSON string:")
            log.debug("Serial", res)

        return coords
示例#11
0
 def wait_for_response(self, timeout=20.0):
     count = 0
     max_retries = int(timeout / self.serial_timeout)
     while count < max_retries:
         count = count + 1
         out = self.readline_from_serial()
         if out:
             log.debug(
                 "Serial",
                 "Waited {} lines for response {}.".format(count, out)
             )
             return out
         else:
             if count == 1 or count % 10 == 0:
                 # Don't log all the time; gets spammy.
                 log.debug(
                     "Serial",
                     "Waiting {} lines for response.".format(count)
                 )
     raise RuntimeWarning('no response after {} seconds'.format(timeout))
示例#12
0
    def consume_move_commands(self, args_list, step):
        tolerance = step * 0.5
        self.current_commands = list(args_list)
        while self.can_move.wait():
            if self.stopped.is_set():
                self.resume()
                return (False, self.STOPPED)
            if self.current_commands:
                args = self.current_commands.pop(0)
            else:
                self.wait_for_arrival()
                break

            self.wait_for_arrival(tolerance)

            log.debug("MotorDriver", "Moving head: {}".format(args))
            res = self.send_command(self.MOVE, **args)
            if res != b'ok':
                return (False, self.SMOOTHIE_ERROR)
        return (True, self.SMOOTHIE_SUCCESS)
示例#13
0
    def connect_to_physical_smoothie(self, port, options=None):
        try:
            self.connection = serial.Serial(
                port=port,
                baudrate=115200,
                timeout=self.serial_timeout
            )

            # sometimes pyserial swallows the initial b"Smoothie\r\nok\r\n"
            # so just always swallow it ourselves
            self.reset_port()

            log.debug("Serial", "Connected to {}".format(port))

            return self.calm_down()

        except serial.SerialException as e:
            log.debug(
                "Serial",
                "Error connecting to {}".format(port))
            log.error("Serial", e)
            return False
示例#14
0
 def write_to_serial(self, data, max_tries=10, try_interval=0.2):
     log.debug("Serial", "Write: {}".format(str(data).encode()))
     if self.connection is None:
         log.warn("Serial", "No connection found.")
         return
     if self.connection.isOpen():
         self.connection.write(str(data).encode())
         if self._wait_for_stat is True and self._stat_command:
             waiting = True
             count = 0
             while waiting:
                 count = count + 1
                 out = self.connection.readline().decode().strip()
                 log.debug("Serial", "Read: {}".format(out))
                 if out == self._stat_command:
                     waiting = False
                     log.debug(
                         "Serial",
                         "Waited {} lines for stat.".format(count)
                     )
                 else:
                     if count == 1 or count % 10 == 0:
                         # Don't log all the time; gets spammy.
                         log.debug(
                             "Serial",
                             "Waiting {} lines for stat ({})."
                             .format(count, self._stat_command)
                         )
         else:
             out = self.connection.readline()
             log.debug("Serial", "Read: {}".format(out))
         return out
     elif max_tries > 0:
         time.sleep(try_interval)
         self.write_to_serial(
             data, max_tries=max_tries - 1, try_interval=try_interval
         )
     else:
         log.error("Serial", "Cannot connect to serial port.")
示例#15
0
    def test_calibrate_placeable(self):
        well = self.plate[0]
        pos = well.from_center(x=0, y=0, z=0, reference=self.plate)
        location = (self.plate, pos)

        well_deck_coordinates = well.center(well.get_deck())
        dest = well_deck_coordinates + Vector(1, 2, 3)
        log.debug('Unit test', 'Destination: {}'.format(well_deck_coordinates))

        self.robot._driver.move_head(x=dest['x'], y=dest['y'], z=dest['z'])

        self.p200.calibrate_position(location)

        expected_calibration_data = {
            'A2': {
                'children': {
                    '96-flat': {
                        'delta': (1.0, 2.0, 3.0)
                    }}}}

        self.assertDictEqual(
            self.p200.calibration_data,
            expected_calibration_data)
示例#16
0
 def move_motors(self, **kwargs):
     debug("MotorHandler", "Moving: {}".format(kwargs))
     self._driver.move(**kwargs)
示例#17
0
 def droptip(self):
     debug(
         "PipetteMotor",
         "Droptip on {} axis ({}).".format(self.axis, self.name)
     )
     self.move(self.pipette.droptip)
示例#18
0
 def blowout(self):
     debug(
         "PipetteMotor",
         "Blowout on {} axis ({}).".format(self.axis, self.name)
     )
     self.move(self.pipette.blowout)
示例#19
0
 def reset(self):
     debug(
         "PipetteMotor",
         "Resetting {} axis ({}).".format(self.axis, self.name)
     )
     self.move(0)
示例#20
0
 def connect(self, device=None, port=None):
     self.connection = serial.Serial(port=device or port)
     self.connection.close()
     self.connection.open()
     log.debug("Serial", "Connected to {}".format(device or port))
     self.wait_for_stat()
示例#21
0
 def write(self, data):
     if self.isOpen() is False:
         raise IOError("Connection not open.")
     log.debug('GCodeLogger', 'Writing: {}'.format(data))
     self.write_buffer.append(data)