Exemple #1
0
    def __call__(self,
                 by=None,
                 to=None,
                 method=NotSet,
                 tolerance=NotSet,
                 timeout=NotSet):
        """Block until the vehicle is within tolerance of the target altitude.

        Args:
            by (Real): Change altitude by this amount. May be negative. Cannot
                be set at the same time as `to`.
            to (Real): Ascend or descend to this altitude. Cannot be set at the
                same time as `by`.
            method (Callable[[Real, Real], Real]): Take two arguments, the
                current altitude and the target altitude, and return a z-axis
                control value [-1, 1].
            tolerance (Real): The allowable error in altitude before the method
                sets the z-axis to 0 and returns.
            timeout (Optional[timedelta]): If not None, the amount of time the
                method has to complete an operation before raising
                CommandTimeout. If None the timeout is datetime.max.
        """
        # NotSet resolution
        method = self.resolve(method, 'method')
        timeout = self.resolve(timeout, 'timeout')
        tolerance = self.resolve(tolerance, 'tolerance')

        # Sanity checks
        if not by and not to:
            raise ValueError('Must set either by or to.')
        elif by and to:
            raise ValueError('Must not set both by and to.')
        if not method or not callable(method):
            raise ValueError('Must have a callable navigation method.')
        if not isinstance(tolerance, Real) or tolerance <= 0:
            raise ValueError(
                'Tolerance must be set to a positive real number.')

        # Timeout
        # TODO Use vehicle time not local
        timeout = datetime.max if timeout is None else timeout + datetime.now()

        target_altitude = (self.nav.altitude + by) if by else to

        while datetime.now() < timeout:
            difference = abs(target_altitude - self.nav.altitude)
            if difference <= tolerance:
                self.info('vnav expected %s actual %s (%s < %s m)',
                          target_altitude, self.nav.altitude, difference,
                          tolerance)
                self.broadcast(Intent(action=ACTION_AXIS_SET, data=('z', 0.0)))
                return self
            control = method(self.nav.altitude, target_altitude)
            self.debug('vnav toward %.3f actual %.3f (%.3f < %.3f m) %.3f',
                       target_altitude, self.nav.altitude, difference,
                       tolerance, control)
            self.broadcast(Intent(action=ACTION_AXIS_SET, data=('z', control)))
            time.sleep(self.nav.sleep_time)
        raise CommandTimeout('vnav exceeded timeout')
Exemple #2
0
 def arm(self):
     """Arm vehicle."""
     print("Arming vehicle")
     self.vehicle.info("Arming vehicle")
     self.vehicle.broadcast(
         Intent(action=ACTION_SEND_COMMAND,
                data=ManualSetpoint(ArmSwitch=3))).first()
     self.vehicle.broadcast(
         Intent(action=ACTION_SEND_COMMAND,
                data=ManualSetpoint(ArmSwitch=1))).first()
Exemple #3
0
 def _mode_posctl(self):
     print("Position control")
     self.vehicle.info("Position control")
     self.vehicle.broadcast(
         Intent(action=ACTION_SEND_COMMAND,
                data=ManualSetpoint(Z=0.5, PosctlSwitch=1,
                                    GearSwitch=1))).first()
 def __exit__(self, exc_type, exc_val, exc_tb):
     # If the context manager exits without error, all good. Otherwise...
     if exc_type:
         if callable(self.failure_callback):
             self.failure_callback(self, (exc_type, exc_val, exc_tb))
         else:
             print('Error in execution. Returning to Launch.')
             self._vehicle.broadcast(Intent(action=ACTION_RTL))
Exemple #5
0
 def _send_telemetry(self):
     mod_z = self.z / 2.0 + 0.5  # [-1, 1] -> [0, 1]
     self.vehicle.broadcast(Intent(
         action=ACTION_SEND_COMMAND,
         data=ManualSetpoint(
             X=self._x, Y=self._y, Z=mod_z, R=self._r,
             PosctlSwitch=1, GearSwitch=1, ArmSwitch=1)
     ))
Exemple #6
0
 def _check_fence(self):
     old = self.fence_violation
     self.fence_violation = self.fence_violation or \
         (self.enabled and self.position not in self)
     if not old and self.fence_violation:
         self.vehicle.error('Encountered Fence Violation at %s',
                            self.position)
         self.vehicle.broadcast(Intent(action=ACTION_RTL))
         print('Encountered fence violation. Press Ctrl-C exit.')
Exemple #7
0
 def takeoff(self):
     """Takeoff"""
     print("Auto takeoff")
     self.vehicle.info("Auto takeoff")
     self.vehicle.broadcast(
         Intent(action=ACTION_SEND_COMMAND,
                data=ManualSetpoint(TransitionSwitch=1,
                                    ArmSwitch=1))).first()
     time.sleep(5)
Exemple #8
0
 def rtl(self):
     """Return to launch."""
     print("RTL")
     self.vehicle.info("RTL")
     self.vehicle.broadcast(
         Intent(action=ACTION_SEND_COMMAND,
                data=ManualSetpoint(ReturnSwitch=1,
                                    GearSwitch=3,
                                    ArmSwitch=1))).first()
Exemple #9
0
    def __call__(self,
                 distance,
                 axis=NotSet,
                 method=NotSet,
                 tolerance=NotSet,
                 timeout=NotSet):
        """Block until the distance traveled is within the tolerance of the
        target distance.

        Args:
            distance (Real): Distance in meters to move.
            axis (str): Must be one of the lateral movement axes (x, y, or z),
                and may be prefixed by an optional "-" for negative movement.
            method (Callable[[Real, Real], Real]): Callable takes two arguments,
                the distance traveled and the target distance, and returns an
                axis control value within [-1, 1].
            tolerance (Real): The allowable error in movement before the method
                sets the control to 0 and returns.
        """
        # NotSet resolution
        axis = self.resolve(axis, 'axis')
        method = self.resolve(method, 'method')
        tolerance = self.resolve(tolerance, 'tolerance')
        timeout = self.resolve(timeout, 'timeout')

        # Sanity checks
        if not method or not callable(method):
            raise ValueError('Must have a callable navigation method.')
        if not isinstance(tolerance, Real) or tolerance <= 0:
            raise ValueError(
                'Tolerance must be set to a positive real number.')

        # Match axis value
        valid = '(-)?([xyz])'
        axis_match = re.match(valid, axis)
        if not axis_match:
            raise ValueError('Axis must match "{}".'.format(valid))
        neg, axis = axis_match.groups()

        # Timeout
        # TODO Use vehicle time not local
        timeout = datetime.max if timeout is None else timeout + datetime.now()

        original = self.nav.position
        while datetime.now() < timeout:
            delta = self.broadcast(
                Intent(action=ACTION_CALC_DISTANCE,
                       data=(original, self.nav.position))).first_result()
            if (distance - delta) < tolerance:
                self.info('lnav expected %s actual %s (%s < %s m)', distance,
                          delta, distance - delta, tolerance)
                self.broadcast(Intent(action=ACTION_AXIS_SET,
                                      data=(axis, 0.0)))
                return self
            control = method(delta, distance)
            control = -control if neg else control
            self.debug('lnav toward %.3f actual %.3f (%.3f < %.3f m) %.3f',
                       distance, delta, distance - delta, tolerance, control)
            self.broadcast(Intent(action=ACTION_AXIS_SET,
                                  data=(axis, control)))
            time.sleep(self.nav.sleep_time)
        raise CommandTimeout('lnav exceeded timeout')
Exemple #10
0
    def __call__(self, waypoints, tolerance=NotSet, timeout=NotSet):
        """Block until the vehicle is within tolerance of the final waypoint.

        Args:
            waypoints: A single waypoint or an iterable of waypoints for the
                vehicle to follow.
            tolerance (Real): The allowable error in altitude before the method
                sets the z-axis to 0 and returns.
            timeout (Optional[timedelta]): If not None, the amount of time the
                method has to complete an operation before raising
                CommandTimeout. If None the timeout is datetime.max.
        """
        # NotSet resolution
        timeout = self.resolve(timeout, 'timeout')
        tolerance = self.resolve(tolerance, 'tolerance')

        # Sanity checks
        if not isinstance(tolerance, Real) or tolerance <= 0:
            raise ValueError('Tolerance must be set to a positive real number.')

        # Timeout
        # TODO Use vehicle time not local
        timeout = datetime.max if timeout is None else timeout + datetime.now()

        # Iterate through all given waypoints
        if not isinstance(waypoints, Iterable):
            waypoints = (waypoints,)
        for prv, cur, nxt in shifter(3, (None,) + tuple(waypoints) + (None,)):
            palt = 0 if not prv else prv.altitude \
                if prv.altitude is not None else self.nav.altitude
            calt = 0 if not cur else cur.altitude \
                if cur.altitude is not None else self.nav.altitude
            nalt = 0 if not nxt else nxt.altitude \
                if nxt.altitude is not None else self.nav.altitude
            pyaw = 0 if not prv else prv.yaw \
                if prv.yaw is not None else self.nav.yaw
            cyaw = 0 if not cur else cur.yaw \
                if cur.yaw is not None else self.nav.yaw
            nyaw = 0 if not nxt else nxt.yaw \
                if nxt.yaw is not None else self.nav.yaw
            self.broadcast(Intent(
                action=ACTION_SEND_COMMAND,
                data=SetpointTriplet(
                    Prev_Lat=prv.latitude if prv is not None else 0,
                    Prev_Lon=prv.longitude if prv is not None else 0,
                    Prev_Alt=palt, Prev_Yaw=pyaw,
                    Prev_Valid=prv is not None,
                    Prev_PositionValid=prv is not None,
                    Cur_Lat=cur.latitude if cur is not None else 0,
                    Cur_Lon=cur.longitude if cur is not None else 0,
                    Cur_Alt=calt, Cur_Yaw=cyaw,
                    Cur_Valid=cur is not None,
                    Cur_PositionValid=cur is not None,
                    Next_Lat=nxt.latitude if nxt is not None else 0,
                    Next_Lon=nxt.longitude if nxt is not None else 0,
                    Next_Alt=nalt, Next_Yaw=nyaw,
                    Next_Valid=nxt is not None,
                    Next_PositionValid=nxt is not None
                )))
            while True:
                if datetime.now() > timeout:
                    raise CommandTimeout('goto exceeded timeout')

                distance = self.broadcast(Intent(
                    action=ACTION_CALC_DISTANCE,
                    data=(cur, self.nav.position),
                )).first_result(0.5)
                if distance < tolerance:
                    self.nav.vehicle.info(
                        'goto expected %s actual %s (%s < %s m)',
                        cur, self.nav.position, distance, tolerance)
                    break
                time.sleep(self.nav.sleep_time)
Exemple #11
0
import time

from pyliner.action import ACTION_RTL
from pyliner.app.communication import Communication
from pyliner.intent import Intent
from pyliner.util import read_json
from pyliner.vehicle import Vehicle

vehicle = Vehicle(
    vehicle_id='rocky',
    communications=Communication(
        airliner_map=read_json('airliner.json'),
        ci_port=5009, to_port=5012
    )
)

vehicle.broadcast(Intent(action=ACTION_RTL))
time.sleep(1)
Exemple #12
0
    def __call__(self, by=None, to=None, method=NotSet, tolerance=NotSet,
                 direction=Direction.NEAREST, timeout=NotSet, underflow=NotSet):
        """Block until the vehicle is within tolerance of the target heading.

        Args:
            by (Real): Change heading by this amount. May be negative. Cannot
                be set at the same time as `to`.
            to (Real): Rotate to this heading. Cannot be set at the same
                time as `by`.
            method (Callable[[Real, Real], Real]): Take two arguments, the
                current heading and the target heading, and return an
                axis control value within [-1, 1].
            tolerance (Real): The allowable error in altitude before the method
                sets the z-axis to 0 and returns.
            direction (Direction): The direction to rotate.
            timeout (Optional[timedelta]): If not None, the amount of time the
                method has to complete an operation before raising
                CommandTimeout. If None the timeout is datetime.max.
            underflow (Real): If the vehicle over-rotates and is outside of
                tolerance this is how far the vehicle is allowed to correct
                the error before resetting to follow the set direction.
        """
        # NotSet resolution
        method = self.resolve(method, 'method')
        tolerance = self.resolve(tolerance, 'tolerance')
        direction = self.resolve(direction, 'direction')
        timeout = self.resolve(timeout, 'timeout')
        underflow = self.resolve(underflow, 'underflow')

        # Sanity checks
        if not by and not to:
            raise ValueError('Must set one of by or to.')
        elif by and to:
            raise ValueError('Must not set both by and to.')
        if not method or not callable(method):
            raise ValueError('Must have a callable navigation method.')
        if not isinstance(tolerance, Real) or tolerance < 0.0:
            raise ValueError('Tolerance must be a non-negative real number.')
        if direction not in Direction:
            raise TypeError('Direction must be a valid Direction.')
        if timeout is not None and not isinstance(timeout, timedelta):
            raise ValueError('Timeout must be None or a timedelta.')
        if not isinstance(underflow, Real) or underflow < 0.0:
            raise ValueError('Underflow must be a non-negative real number.')

        # Timeout
        # TODO Use vehicle time not local
        timeout = datetime.max if timeout is None else datetime.now() + timeout

        original = self.nav.heading
        target = original + by if by else Heading(to)
        tol_range = target.range(tolerance)

        while datetime.now() < timeout:
            current = self.nav.heading
            if current in tol_range:
                self.info('rotate expected %s actual %s (in %s)',
                          target, current, tol_range)
                self.broadcast(Intent(action=ACTION_AXIS_SET, data=('r', 0.0)))
                return self
            distance = Heading.distance(current, target, direction, underflow)
            control = method(0.0, distance)
            self.debug('rotate toward %.3f current %.3f (%.3f < %.3f) %.3f',
                       target, current, abs(distance), tolerance, control)
            self.broadcast(Intent(action=ACTION_AXIS_SET, data=('r', control)))
            time.sleep(self.nav.sleep_time)
        raise CommandTimeout('rotate exceeded timeout')