Ejemplo n.º 1
0
 def probe_serial(self):
     # probe new nmea data devices
     if not self.probedevice:
         try:
             self.probeindex = self.devices.index(False)
         except:
             self.probeindex = len(self.devices)
         self.probedevicepath = serialprobe.probe('nmea%d' % self.probeindex, [38400, 4800])
         if self.probedevicepath:
             try:
                 self.probedevice = NMEASerialDevice(self.probedevicepath)
                 self.probetime = time.time()
             except serial.serialutil.SerialException:
                 print('failed to open', self.probedevicepath, 'for nmea data')
                 pass
     elif time.time() - self.probetime > 5:
         print('nmea serial probe timeout', self.probedevicepath)
         self.probedevice = None # timeout
     else:
         # see if the probe device gets a valid nmea message
         if self.probedevice:
             if self.probedevice.readline():
                 print('new nmea device', self.probedevicepath)
                 serialprobe.success('nmea%d' % self.probeindex, self.probedevicepath)
                 if self.probeindex < len(self.devices):
                     self.devices[self.probeindex] = self.probedevice
                 else:
                     self.devices.append(self.probedevice)
                 fd = self.probedevice.device.fileno()
                 self.device_fd[fd] = self.probedevice
                 self.poller.register(fd, select.POLLIN)
                 self.devices_lastmsg[self.probedevice] = time.time()
                 self.probedevice = None
Ejemplo n.º 2
0
    def poll(self):
        # no gpsd devices: probe
        t0 = time.monotonic()

        while True:
            events = self.poller.poll(0)
            if not events:
                break
            while events:
                event = events.pop()
                fd, flag = event
                if flag != select.POLLIN:
                    # hope this is never hit
                    print('gpsd got flag for pipe:', flag)
                    continue
                self.last_read_time = t0
                self.read()

        return # don't probe gpsd anymore
        if (not self.devices is False) and (t0 - self.last_read_time > 20 or not self.devices):
            device_path = serialprobe.probe('gpsd', [4800], 4)
            if device_path:
                print('gpsd serial probe', device_path)
                self.probe_device, baud = device_path
                self.process.pipe.send(self.probe_device)
Ejemplo n.º 3
0
    def probe_serial(self):
        # probe new nmea data devices
        if not self.probedevice:
            try:
                index = self.devices.index(False)
            except:
                index = len(self.devices)
            if self.probeindex != index and \
               (self.probeindex >= len(self.devices) or not self.devices[self.probeindex]):
                serialprobe.relinquish('nmea%d' % self.probeindex)
            self.probeindex = index

            self.probedevicepath = serialprobe.probe(
                'nmea%d' % self.probeindex, [38400, 4800], 8)
            if self.probedevicepath:
                print('nmea probe', self.probedevicepath)
                try:
                    self.probedevice = NMEASerialDevice(self.probedevicepath)
                    self.probetime = time.monotonic()
                except Exception as e:  # serial.serialutil.SerialException:
                    print(_('failed to open'), self.probedevicepath,
                          'for nmea data', e)

            return

        # see if the probe device gets a valid nmea message
        if self.probedevice.readline():
            #print('nmea new device', self.probedevicepath)
            serialprobe.success('nmea%d' % self.probeindex,
                                self.probedevicepath)
            if self.probeindex < len(self.devices):
                self.devices[self.probeindex] = self.probedevice
            else:
                self.devices.append(self.probedevice)
            fd = self.probedevice.device.fileno()
            self.device_fd[fd] = self.probedevice
            self.poller.register(fd, select.POLLIN)
            self.devices_lastmsg[self.probedevice] = time.monotonic()
            self.probedevice = None
        elif time.monotonic() - self.probetime > 5:
            #print('nmea serial probe timeout', self.probeindex, index, self.probedevicepath)
            self.probedevice = None  # timeout
Ejemplo n.º 4
0
    def poll(self):
        if not self.driver:
            device_path = serialprobe.probe('servo', [38400], 1)
            if device_path:
                #from arduino_servo.arduino_servo_python import ArduinoServo
                from arduino_servo.arduino_servo import ArduinoServo
                try:
                    device = serial.Serial(*device_path)
                    device.timeout = 0  #nonblocking
                    fcntl.ioctl(device.fileno(), TIOCEXCL)  #exclusive
                except Exception as e:
                    print 'failed to open servo on:', device_path, e
                    return
                self.driver = ArduinoServo(device.fileno(), device_path[1])
                uncorrected_max_current = max(
                    0, self.max_current.value -
                    self.current.offset.value) / self.current.factor.value
                self.send_driver_params(uncorrected_max_current)
                self.device = device
                self.device.path = device_path[0]
                self.lastpolltime = time.time()

        if not self.driver:
            return

        self.servo_calibration.poll()

        result = self.driver.poll()

        if result == -1:
            print 'servo lost'
            self.close_driver()
            return

        if result == 0:
            d = time.time() - self.lastpolltime
            if d > 5:  # correct for clock skew
                self.lastpolltime = time.time()
            elif d > 4:
                print 'servo timeout', d
                self.close_driver()
        else:
            self.lastpolltime = time.time()

            if self.controller.value == 'none':
                device_path = [self.device.port, self.device.baudrate]
                print 'arduino servo found on', device_path
                serialprobe.success('servo', device_path)
                self.controller.set('arduino')
                self.driver.command(0)

        t = time.time()
        self.server.TimeStamp('servo', t)
        if result & ServoTelemetry.VOLTAGE:
            # apply correction
            corrected_voltage = self.voltage.factor.value * self.driver.voltage
            corrected_voltage += self.voltage.offset.value
            self.voltage.set(round(corrected_voltage, 3))

        if result & ServoTelemetry.CONTROLLER_TEMP:
            self.controller_temp.set(self.driver.controller_temp)
        if result & ServoTelemetry.MOTOR_TEMP:
            self.motor_temp.set(self.driver.motor_temp)
        if result & ServoTelemetry.RUDDER:
            if self.driver.rudder and not math.isnan(self.driver.rudder):
                data = {
                    'angle': self.driver.rudder,
                    'timestamp': t,
                    'device': self.device.path
                }
                self.sensors.write('rudder', data, 'servo')
        if result & ServoTelemetry.CURRENT:
            # apply correction
            corrected_current = self.current.factor.value * self.driver.current
            corrected_current = max(
                0, corrected_current + self.current.offset.value)

            self.current.set(round(corrected_current, 3))
            # integrate power consumption
            dt = (t - self.current_timestamp)
            #print 'have current', round(1/dt), dt
            self.current_timestamp = t
            if self.current.value:
                amphours = self.current.value * dt / 3600
                self.amphours.set(self.amphours.value + amphours)
            lp = .003 * dt  # 5 minute time constant to average wattage
            self.watts.set((1 - lp) * self.watts.value +
                           lp * self.voltage.value * self.current.value)

        if result & ServoTelemetry.FLAGS:
            self.max_current.set_max(40 if self.driver.flags
                                     & ServoFlags.CURRENT_RANGE else 20)
            flags = self.flags.value & ~ServoFlags.DRIVER_MASK | self.driver.flags

            # if rudder angle comes from serial or tcp, may need to set these flags
            angle = self.sensors.rudder.angle.value
            if angle:  # note, this is ok here for both False and 0
                if abs(angle) > self.sensors.rudder.range.value:
                    if angle > 0:
                        flags |= ServoFlags.MIN_RUDDER
                    else:
                        flags |= ServoFlags.MAX_RUDDER

            self.flags.update(flags)

            self.engaged.update(not not self.driver.flags & ServoFlags.ENGAGED)

        if result & ServoTelemetry.EEPROM:  # occurs only once after connecting
            self.max_current.set(self.driver.max_current)
            self.max_controller_temp.set(self.driver.max_controller_temp)
            self.max_motor_temp.set(self.driver.max_motor_temp)
            self.max_slew_speed.set(self.driver.max_slew_speed)
            self.max_slew_slow.set(self.driver.max_slew_slow)
            #print "GOT EEPROM", self.driver.rudder_scale, self.driver.rudder_offset, self.driver.rudder_range
            self.sensors.rudder.scale.set(self.driver.rudder_scale)
            self.sensors.rudder.nonlinearity.set(
                self.driver.rudder_nonlinearity)
            self.sensors.rudder.offset.set(self.driver.rudder_offset)
            self.sensors.rudder.range.set(self.driver.rudder_range)
            self.current.factor.set(self.driver.current_factor)
            self.current.offset.set(self.driver.current_offset)
            self.voltage.factor.set(self.driver.voltage_factor)
            self.voltage.offset.set(self.driver.voltage_offset)
            self.min_speed.set(self.driver.min_motor_speed)
            self.max_speed.set(self.driver.max_motor_speed)
            self.gain.set(self.driver.gain)

        if self.fault():
            if not self.flags.value & ServoFlags.FWD_FAULT and \
               not self.flags.value & ServoFlags.REV_FAULT:
                self.faults.set(self.faults.value + 1)

            # if overcurrent then fault in the direction traveled
            # this prevents moving further in this direction
            if self.flags.value & ServoFlags.OVERCURRENT:
                if self.lastdir > 0:
                    self.flags.fwd_fault()
                    self.position.set(1)
                elif self.lastdir < 0:
                    self.flags.rev_fault()
                    self.position.set(-1)

            self.reset()  # clear fault condition

        if not self.sensors.rudder.invalid():
            self.position.set(self.sensors.rudder.angle.value)

        self.send_command()
Ejemplo n.º 5
0
    def poll(self):
        if not self.driver:
            device_path = serialprobe.probe('servo', [38400], 5)
            if device_path:
                print('servo probe', device_path, time.monotonic())
                try:
                    device = serial.Serial(*device_path)
                except Exception as e:
                    print('failed to open servo on:', device_path, e)
                    return

                try:
                    device.timeout=0 #nonblocking
                    fcntl.ioctl(device.fileno(), TIOCEXCL) #exclusive
                except Exception as e:
                    print('failed set nonblocking/exclusive', e)
                    device.close()
                    return
                #print('driver', device_path, device)
                from pypilot.arduino_servo.arduino_servo import ArduinoServo

                self.driver = ArduinoServo(device.fileno())
                self.send_driver_params()
                self.device = device
                self.device.path = device_path[0]
                self.lastpolltime = time.monotonic()

        if not self.driver:
            return

        result = self.driver.poll()
        if result == -1:
            print('servo lost')
            self.close_driver()
            return
        t = time.monotonic()
        if result == 0:
            d = t - self.lastpolltime
            if d > 4:
                #print('servo timeout', d)
                self.close_driver()
        else:
            self.lastpolltime = t

            if self.controller.value == 'none':
                device_path = [self.device.port, self.device.baudrate]
                print('arduino servo found on', device_path)
                serialprobe.success('servo', device_path)
                self.controller.set('arduino')
                self.driver.command(0)


        if result & ServoTelemetry.VOLTAGE:
            # apply correction
            corrected_voltage = self.voltage.factor.value*self.driver.voltage
            corrected_voltage += self.voltage.offset.value
            self.voltage.set(round(corrected_voltage, 3))

        if result & ServoTelemetry.CONTROLLER_TEMP:
            self.controller_temp.set(self.driver.controller_temp)
        if result & ServoTelemetry.MOTOR_TEMP:
            self.motor_temp.set(self.driver.motor_temp)
        if result & ServoTelemetry.RUDDER:
            if self.driver.rudder:
                if math.isnan(self.driver.rudder): # rudder no longer valid
                    if self.sensors.rudder.source.value == 'servo':
                        self.sensors.lostsensor(self.sensors.rudder)
                else:
                    data = {'angle': self.driver.rudder, 'timestamp' : t,
                            'device': self.device.path}
                    self.sensors.write('rudder', data, 'servo')
        if result & ServoTelemetry.CURRENT:
            # apply correction
            corrected_current = self.current.factor.value*self.driver.current
            if self.driver.current:
                corrected_current = max(0, corrected_current + self.current.offset.value)
            
            self.current.set(round(corrected_current, 3))
            # integrate power consumption
            dt = (t - self.current.lasttime)
            self.current.lasttime = t
            if self.current.value:
                amphours = self.current.value*dt/3600
                self.amphours.set(self.amphours.value + amphours)
            lp = .003*dt # 5 minute time constant to average wattage
            self.watts.set((1-lp)*self.watts.value + lp*self.voltage.value*self.current.value)

        if result & ServoTelemetry.FLAGS:
            self.max_current.set_max(40 if self.driver.flags & ServoFlags.CURRENT_RANGE else 20)
            flags = self.flags.value & ~ServoFlags.DRIVER_MASK | self.driver.flags

            # if rudder angle comes from serial or tcp, may need to set these flags
            # to prevent rudder movement
            angle = self.sensors.rudder.angle.value
            if angle: # note, this is ok here for both False and 0
                if abs(angle) > self.sensors.rudder.range.value:
                    if angle > 0:
                        flags |= ServoFlags.MAX_RUDDER_FAULT
                    else:
                        flags |= ServoFlags.MIN_RUDDER_FAULT
            self.flags.update(flags)
            self.engaged.update(not not self.driver.flags & ServoFlags.ENGAGED)

        if result & ServoTelemetry.EEPROM and self.use_eeprom.value: # occurs only once after connecting
            self.max_current.set(self.driver.max_current)
            self.max_controller_temp.set(self.driver.max_controller_temp)
            self.max_motor_temp.set(self.driver.max_motor_temp)
            self.max_slew_speed.set(self.driver.max_slew_speed)
            self.max_slew_slow.set(self.driver.max_slew_slow)
            self.sensors.rudder.scale.set(self.driver.rudder_scale)
            self.sensors.rudder.nonlinearity.set(self.driver.rudder_nonlinearity)
            self.sensors.rudder.offset.set(self.driver.rudder_offset)
            self.sensors.rudder.range.set(self.driver.rudder_range)
            self.sensors.rudder.update_minmax()
            self.current.factor.set(self.driver.current_factor)
            self.current.offset.set(self.driver.current_offset)
            self.voltage.factor.set(self.driver.voltage_factor)
            self.voltage.offset.set(self.driver.voltage_offset)
            self.speed.min.set(self.driver.min_speed)
            self.speed.max.set(self.driver.max_speed)
            self.gain.set(self.driver.gain)

        if self.fault():
            if not self.flags.value & ServoFlags.PORT_OVERCURRENT_FAULT and \
               not self.flags.value & ServoFlags.STARBOARD_OVERCURRENT_FAULT:
                self.faults.set(self.faults.value + 1)
            
            # if overcurrent then fault in the direction traveled
            # this prevents moving further in this direction
            if self.flags.value & ServoFlags.OVERCURRENT_FAULT:
                if self.lastdir > 0:
                    self.flags.port_overcurrent_fault()
                elif self.lastdir < 0:
                    self.flags.starboard_overcurrent_fault()
                if self.sensors.rudder.invalid() and self.lastdir:
                    rudder_range = self.sensors.rudder.range.value
                    new_position = self.lastdir*rudder_range
                    if self.hardover_calculation_valid * self.lastdir < 0:
                        # estimate hardover time if possible, this helps with
                        # clearing the overcurrent conditions at reasonable positions
                        d = (new_position + self.position.value) / (2*rudder_range)
                        hardover_time = self.hardover_time.value*abs(d)
                        hardover_time = min(max(hardover_time, 1), 30)
                        self.hardover_time.set(hardover_time)
                    self.hardover_calculation_valid = self.lastdir
                    self.position.set(new_position)

            self.reset() # clear fault condition

        # update position from rudder feedback    
        if not self.sensors.rudder.invalid():
            self.position.set(self.sensors.rudder.angle.value)

        self.send_command()
        self.controller_temp.timeout()
        self.motor_temp.timeout()
Ejemplo n.º 6
0
    def poll(self):
        if not self.driver:
            device_path = serialprobe.probe('servo', [38400], 1)
            if device_path:
                #from arduino_servo.arduino_servo_python import ArduinoServo
                from arduino_servo.arduino_servo import ArduinoServo
                try:
                    device = serial.Serial(*device_path)
                    device.timeout=0 #nonblocking
                    fcntl.ioctl(device.fileno(), TIOCEXCL) #exclusive
                except Exception as e:
                    print 'failed to open servo:', e
                    return
                self.driver = ArduinoServo(device.fileno())
                self.send_driver_max_values(self.max_current.value)

                t0 = time.time()
                if self.driver.initialize(device_path[1]):
                    self.device = device
                    print 'arduino servo found on', device_path
                    serialprobe.success('servo', device_path)
                    self.controller.set('arduino')

                    self.driver.command(0)
                    self.lastpolltime = time.time()
                else:
                    print 'failed in ', time.time()-t0
                    device.close()
                    self.driver = False
                    print 'failed to initialize servo on', device

        if not self.driver:
            return
        self.servo_calibration.poll()
        result = self.driver.poll()
        #print 'servo poll', result

        if result == -1:
            print 'servo poll -1'
            self.close_driver()
            return

        if result == 0:
            d = time.time() - self.lastpolltime
            if d > 5: # correct for clock skew
                self.lastpolltime = time.time()
            elif d > 4:
                print 'servo timeout', d
                self.close_driver()
        else:
            self.lastpolltime = time.time()

        t = time.time()
        self.server.TimeStamp('servo', t)
        if result & ServoTelemetry.VOLTAGE:
            self.voltage.set(self.driver.voltage)
        if result & ServoTelemetry.CONTROLLER_TEMP:
            self.controller_temp.set(self.driver.controller_temp)
        if result & ServoTelemetry.MOTOR_TEMP:
            self.motor_temp.set(self.driver.motor_temp)
        if result & ServoTelemetry.RUDDER:
            if math.isnan(self.driver.rudder):
                self.rudder.update(False)
            else:
                self.rudder.set(self.rudder_scale.value *
                                (self.driver.rudder +
                                 self.rudder_offset.value - 0.5))
        if result & ServoTelemetry.CURRENT:
            self.current.set(self.driver.current)
            # integrate power consumption
            dt = (t - self.current_timestamp)
            #print 'have current', round(1/dt), dt
            self.current_timestamp = t
            if self.current.value:
                amphours = self.current.value*dt/3600
                self.amphours.set(self.amphours.value + amphours)
            lp = .003*dt # 5 minute time constant to average wattage
            self.watts.set((1-lp)*self.watts.value + lp*self.voltage.value*self.current.value)
        if result & ServoTelemetry.FLAGS:
            self.max_current.set_max(60 if self.driver.flags & ServoFlags.CURRENT_RANGE else 20)
            self.flags.update(self.flags.value & ~ServoFlags.DRIVER_MASK | self.driver.flags)
            self.engaged.update(not not self.driver.flags & ServoFlags.ENGAGED)

        if self.fault():
            if not self.flags.value & ServoFlags.FWD_FAULT and \
               not self.flags.value & ServoFlags.REV_FAULT:
                self.faults.set(self.faults.value + 1)
            
            # if overcurrent then fault in the direction traveled
            # this prevents moving further in this direction
            if self.flags.value & ServoFlags.OVERCURRENT:
                if self.lastdir > 0:
                    self.flags.fwd_fault()
                    self.position.set(1)
                elif self.lastdir < 0:
                    self.flags.rev_fault()
                    self.position.set(-1)

            self.reset() # clear fault condition

        self.send_command()