コード例 #1
0
def _calc(point1, knot1, knot2, point2):
    # Chris made this in desmos. I don't know how it works. Don't ask me.
    # https://www.desmos.com/calculator/yri3mwz7kn
    sgn_theta1 = -mathutils.sgn((knot2.y - knot1.y) / (knot2.x - knot1.x) *
                                (point1.x - knot1.x) + knot1.y - point1.y)
    num = knot2.dx2(point1) + knot2.dy2(point1) - knot1.dx2(point1) - knot1.dy2(point1) - knot1.dx2(knot2) - \
          knot1.dy2(knot2)
    angle_theta1 = math.acos(num /
                             (-2 * knot1.dist(knot2) * knot1.dist(point1)))
    theta1 = sgn_theta1 * angle_theta1

    sgn_theta2 = -mathutils.sgn((knot2.y - knot1.y) / (knot2.x - knot1.x) *
                                (point2.x - knot2.x) + knot2.y - point2.y)
    num = knot1.dx2(point2) + knot1.dy2(point2) - knot2.dx2(point2) - knot2.dy2(point2) - knot1.dx2(knot2) - \
          knot1.dy2(knot2)
    print(num / (-2 * knot1.dist(knot2) * knot1.dist(point1)))
    angle_theta2 = math.acos(
        num / (-2 * knot1.dist(knot2) * knot2.dist(point2))) - math.pi
    theta2 = sgn_theta2 * angle_theta2

    d = knot1.dist(knot2)
    print(mathutils.normalize_angle(theta1))
    print(mathutils.normalize_angle(theta2))
    return mathutils.normalize_angle(theta1), d, mathutils.normalize_angle(
        theta2)
コード例 #2
0
    def radius_turn(self, speed, radius):
        # (Vo + Vi) / 2 = pow
        # Vo*r = Vi
        # Vo(1+r)/2 = pow

        # 2*pow/(1+r) = Vo
        # 2*r*pow/(1+r) = Vi

        # With this calculation, it's possible to saturate the motors. If that happens, rescale to maintain the curve.
        turn_dir = mathutils.sgn(radius)
        radius = abs(radius)
        r = self.radius_ratio(radius)
        Vo = 2 * speed / (1 + r)
        Vi = r * Vo
        if Vo > self.max_speed:
            Vi /= Vo
            Vo /= Vo
            Vo *= self.max_speed
            Vi *= self.max_speed

        Vi /= self.max_speed
        Vo /= self.max_speed
        if turn_dir > 0:
            self._set_motor_outputs(Vo, Vi)
            # self.drive_profile_open_loop(Vo, Vi, 0, 0)
        else:
            self._set_motor_outputs(Vi, Vo)
コード例 #3
0
    def _radius_turn(self, pow, radius):
        D = self.robot_width / 2
        turn_dir = mathutils.sgn(radius)
        radius = abs(radius)
        Vo = pow
        Vi = Vo * (radius - D) / (radius + D)

        if turn_dir > 0:
            self._set_motor_outputs(Vo, Vi)
        else:
            self._set_motor_outputs(Vi, Vo)
コード例 #4
0
    def motion_magic(self, distance: float, speed: float, acc: float, curvature: float = 0):
        """
        Set the talons to drive in an arc or straight at speed, accelerating at acc.
        Only needs to be called once.
        If curvature != 0, the outside wheel goes distance at speed and acc, and the inner wheel speed is decreased.
        :param distance: Distance in feet to travel
        :param speed: Speed (in feet/sec) to cruise at
        :param acc: Acceleration (in feet/sec^2) to accelerate/decelerate at
        :param curvature: 1/radius of turn. If 0, drive straight.
        :return: 
        """
        if curvature == 0:
            ratio = 1
            turn_dir = 1
        else:
            radius = 1 / curvature
            D = self.robot_width / 2
            turn_dir = mathutils.sgn(radius)
            radius = abs(radius)
            ratio = (radius - D) / (radius + D)

        # Change units to what the talons are expecting
        vel_rpm = self.fps_to_rpm(speed)
        acc_rpm = self.fps_to_rpm(acc)  # Works because required unit is rpm/sec for no real good reason.
        dist_revs = self.feet_to_revs(distance)
        print(dist_revs)

        # Don't set encoder position to 0, because that would mess up pose estimation
        # Instead, set to current position, plus however far we want to go
        left_current_pos = self._left_motor.getPosition()
        right_current_pos = self._right_motor.getPosition()


        # Set the talon parameters
        # If turn > 0, left is outside
        if turn_dir > 0:
            self._left_motor.setMotionMagicCruiseVelocity(vel_rpm)
            self._right_motor.setMotionMagicCruiseVelocity(vel_rpm * ratio)
            self._left_motor.setMotionMagicAcceleration(acc_rpm)
            self._right_motor.setMotionMagicAcceleration(acc_rpm * ratio)
            self._left_motor.set(left_current_pos + dist_revs)
            self._right_motor.set(right_current_pos + dist_revs * ratio)
        else:
            self._left_motor.setMotionMagicCruiseVelocity(vel_rpm * ratio)
            self._right_motor.setMotionMagicCruiseVelocity(vel_rpm)
            self._left_motor.setMotionMagicAcceleration(acc_rpm * ratio)
            self._right_motor.setMotionMagicAcceleration(acc_rpm)
            self._left_motor.set(left_current_pos + dist_revs * ratio)
            self._right_motor.set(right_current_pos + dist_revs)
コード例 #5
0
 def radius_drive(self, forward_power, turn_power, power_factor, deadband=0.05):
     if self.is_manual_control_mode():
         if abs(turn_power) < deadband:
             self._set_motor_outputs(forward_power * power_factor, forward_power * power_factor)
             return
         if abs(forward_power) < deadband:
             self._set_motor_outputs(0, 0)
             return
         turn_power = mathutils.signed_power(turn_power, 1/3)
         radius = self.robot_width / 2 + self.max_turn_radius * (1 - abs(turn_power))
         self._radius_turn(forward_power * power_factor,
                           radius * mathutils.sgn(turn_power))
     else:
         warnings.warn("Not in a control mode for Radius Drive", RuntimeWarning)
         self._set_motor_outputs(0, 0)
コード例 #6
0
    def __init__(self, start, end, cruise_speed, acc, frequency=100):
        """
        Generate a trapezoidal motion profile, starting at `start` and ending at `end`
        :param start:
        :param end:
        :param cruise_speed: Magnitude of cruise velocity
        :param acc: Magnitude of acceleration
        :param frequency: Number of points to generate per second
        """
        # https://www.desmos.com/calculator/ponjr7cwze

        # If we're going in reverse we need to flip the sign of speed and acc
        # Although in theory these are vectors, it makes the API easier if they're given as magnitude
        dist = end - start
        cruise_speed = copysign(cruise_speed, dist)
        acc = copysign(acc, dist)

        self.start = start
        self.end = end
        self.displacement = dist

        ramp_time = cruise_speed / acc
        ramp_dist = acc * ramp_time ** 2 / 2
        cruise_dist = dist - 2 * ramp_dist
        cruise_time = cruise_dist / cruise_speed

        if sgn(cruise_dist) != sgn(dist):
            # All ramp, no cruise. Fix parameters to match
            cruise_time = 0
            cruise_dist = 0
            ramp_time = (dist / acc) ** 0.5
            ramp_dist = dist / 2

        time = cruise_time + 2 * ramp_time

        def get_pos(t):
            if t <= ramp_time:
                return start + acc * t ** 2 / 2
            elif t <= ramp_time + cruise_time:
                return start + ramp_dist + (t - ramp_time) * get_vel(ramp_time)
            else:
                tp = (t - ramp_time - cruise_time)
                return start + ramp_dist + cruise_dist + get_vel(ramp_time + cruise_time) * tp - acc * tp ** 2 / 2

        def get_vel(t):
            if t <= ramp_time:
                return get_acc(t) * t
            elif t <= ramp_time + cruise_time:
                return cruise_speed
            else:
                tp = (t - ramp_time - cruise_time)
                return get_vel(ramp_time + cruise_time) - acc * tp

        def get_acc(t):
            if t <= ramp_time:
                return acc
            elif t <= ramp_time + cruise_time:
                return 0
            else:
                return -acc

        self._points = []
        for i in range(int(time * frequency) + 1):
            t = i / frequency
            self._points.append(TrajectoryPoint(position=get_pos(t),
                                                velocity=get_vel(t),
                                                acc=get_acc(t),
                                                time=t))