def update_encoders(left_prev, right_prev, mu_prev):
    """Odometry Sensor Integration

    Integration of wheel encoder information to provide a continuous update of
     internal position. This state is never intended to be updated with other
     sensor information. Per 5.4 Odometry Motion Model - this is the function
     that will be reporting relative motion information such as advancement.

    :param left_prev: prior left encoder
    :param right_prev: prior right encoder
    :param mu_prev: prior internal pose - x_bar_t-1
    TODO: Add relative advancement in x and y to the return
     y_bar_prime - y_bar
     x_bar_prime - x_bar
     theta_bar_prime - theta_bar
    :return: current internal pose - x_bar_t
    """
    # Initialize data needed
    new_reading = get_reading(read_mag=False)

    # Update Encoders
    scale = 0.0577
    left_delta = new_reading.get('left_enc') - left_prev
    right_delta = new_reading.get('right_enc') - right_prev

    r = scale * (left_delta + right_delta) / 2

    rotation_scale = 5.5
    theta_delta = (left_delta - right_delta) / rotation_scale
    x_delta = math.sin((mu_prev[2] + theta_delta) * np.pi / 180) * r
    y_delta = math.cos((mu_prev[2] + theta_delta) * np.pi / 180) * r

    mu = mu_prev + np.array([x_delta, y_delta, theta_delta]).T

    return new_reading.get('left_enc'), new_reading.get('right_enc'), mu
def update_position(left_prev, right_prev, theta_prev, time_prev):
    new_reading = get_reading()

    # Update Encoders
    left_delta = new_reading.get('left_enc') - left_prev
    right_delta = new_reading.get('right_enc') - right_prev

    # Scale factor to go from encoder to centimeter -
    scale = 0.0577

    # Distance traveled in scaled units
    lr_avg = (left_delta + right_delta) / 2 * scale
    # translation in a straight line (distance in cm - r) is lr_avg
    # translational_vel = lr_avg / delta_time * delta_theta

    # Update theta based upon gyroscope
    delta_time = (new_reading.get('time') - time_prev).total_seconds()
    theta = theta_prev - new_reading.get('gyro_y') * delta_time

    delta_x = math.sin(theta * 0.0174533) * lr_avg
    delta_y = math.cos(theta * 0.0174533) * lr_avg
    return new_reading.get('left_enc'), new_reading.get(
        'right_enc'), delta_x, delta_y, theta, new_reading.get('time')
from drive.utils import get_reading

gpg = EasyGoPiGo3()
gpg.reset_encoders()
atexit.register(gpg.stop)


def drive_instructions():
    process_name = multiprocessing.current_process().name
    print("Starting Drive Process {}".format(process_name))
    gpg.drive_cm(10)
    gpg.turn_degrees(90)
    gpg.drive_cm(20)
    gpg.turn_degrees(-90)
    gpg.drive_cm(10)
    gpg.stop()


drive_process = multiprocessing.Process(name='drive',
                                        target=drive_instructions)
drive_process.start()
num = 30
while num > 0:
    time.sleep(.10)
    measurements = get_reading()
    # pprint(measurements)
    print("Bearing: {}".format(measurements.get('euler_x')))
    num -= 1

drive_process.join()
def update_position(left_prev, right_prev, mu_prev, cov, time_prev):
    theta_prev = mu_prev[2, 0]
    # Initialize data needed
    new_reading = get_reading(read_mag=False)
    delta_time = (new_reading.get('time') - time_prev).total_seconds()

    # Get 'r' from encoders and scale to centimeters
    scale = 0.0577
    left_delta = new_reading.get('left_enc') - left_prev
    right_delta = new_reading.get('right_enc') - right_prev
    # scale * average encoder advancement / time_elapsed
    nu = scale * (left_delta + right_delta) / 2 / delta_time

    # Update theta based upon gyroscope
    omega = new_reading.get('gyro_y') * np.pi / 180
    vt_omega = omega if np.abs(omega) > 10e-8 else 10e-8
    theta_new = theta_prev - omega * delta_time
    r = nu / omega if np.abs(omega) > 10e-6 else nu / 10e-6

    G_t = np.array([[1, 0, r * (np.cos(theta_new) - np.cos(theta_prev))],
                    [0, 1, r * (np.sin(theta_new) - np.sin(theta_prev))],
                    [0, 0, 1]])

    V_t = np.array(
        [[(-np.sin(theta_prev) + np.sin(theta_new)) / vt_omega,
          nu * (np.sin(theta_prev) - np.sin(theta_new)) / vt_omega**2 +
          (r * np.cos(theta_new) * delta_time)],
         [(np.cos(theta_prev) - np.cos(theta_new)) / vt_omega,
          -nu * (np.cos(theta_prev) - np.cos(theta_new)) / vt_omega**2 +
          (r * np.sin(theta_new) * delta_time)], [0, delta_time]])

    # What to plugin to alpha 1-4?
    alpha_1, alpha_2, alpha_3, alpha_4 = 10e-7, 15e-7, 5e-7, 20e-7
    M_t_1_1 = alpha_1 * nu**2 + alpha_2 * omega**2
    M_t_2_2 = alpha_3 * nu**2 + alpha_4 * omega**2
    M_t = np.array([[M_t_1_1, 0], [0, M_t_2_2]])

    try:
        Sigma = G_t.dot(cov).dot(G_t.T) + V_t.dot(M_t).dot(V_t.T)
    except:
        Sigma = G_t.dot(cov).dot(G_t.T)
        print("Unexpected error:", sys.exc_info()[0])
        print(vt_omega)
        print(theta_prev)
        print(theta_new)

    mu_new = mu_prev + np.array([[
        r * (np.sin(theta_new) - np.sin(theta_prev))
    ], [r * (np.cos(theta_prev) - np.cos(theta_new))], [omega * delta_time]])
    if i % 10 == 0:
        print(mu_prev)
        print(mu_new)
        print(nu)
        print(omega)
        pprint(M_t)
        print(G_t)
        pprint(V_t)
        pprint(Sigma)

    return new_reading.get('left_enc'), new_reading.get(
        'right_enc'), mu_new, Sigma, new_reading.get('time')
        print(nu)
        print(omega)
        pprint(M_t)
        print(G_t)
        pprint(V_t)
        pprint(Sigma)

    return new_reading.get('left_enc'), new_reading.get(
        'right_enc'), mu_new, Sigma, new_reading.get('time')


# Initialize Measurements for drive
i = 0
data = []
pose = np.array([[init_x], [init_y],
                 [get_reading().get('euler_x') * np.pi / 180]])
cov = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
left_prev = 0
right_prev = 0
curr_time = datetime.now()

# Start Driving
drive_process.start()

# Measure while driving loop
while i < 100:
    # mu is 3 x 1 pose
    left_prev, right_prev, pose, cov, curr_time = update_position(
        left_prev, right_prev, pose, cov, curr_time)
    # print("x= %2.2f, y=%2.2f, theta==%2.2f " % (pose[0], pose[1], pose[2]))
    # print(pose)
    theta = theta_prev - new_reading.get('gyro_y') * delta_time

    delta_x = math.sin(theta * 0.0174533) * lr_avg
    delta_y = math.cos(theta * 0.0174533) * lr_avg
    return new_reading.get('left_enc'), new_reading.get(
        'right_enc'), delta_x, delta_y, theta, new_reading.get('time')


# Initialize Measurements for drive
i = 0
data = []
left_prev = 0
right_prev = 0
x_total = init_x
y_total = init_y
theta = get_reading().get('euler_x')
curr_time = datetime.now()

# Start Driving
drive_process.start()

# Measure while driving loop
while i < 100:
    left_prev, right_prev, delta_x, delta_y, theta, curr_time = update_position(
        left_prev, right_prev, theta, curr_time)
    x_total = x_total + delta_x
    y_total = y_total + delta_y
    print("x= %2.2f, y=%2.2f, theta==%2.2f " %
          (x_total / 44, y_total / 44, theta))
    data.append({"t": str(curr_time), "x": x_total, "y": y_total})
# Setup Standard Drive
q = multiprocessing.Queue()
drive_process = multiprocessing.Process(name='drive',
                                        target=test_drive_instr,
                                        args=(q, ))

# drive_process.start()

i = 0
data = []
while i < 200:
    # if i == 100:
    #     drive_process.start()

    reading = get_reading(read_mag=False)
    reading['drive name'] = drive_name
    data.append(reading)
    i += 1
    while not q.empty():
        print(q.get())
    time.sleep(.0625)

# Wrap up processes, print and save
# drive_process.join()
pprint(data)
print('done')

if saving_data:
    output_file_name = os.path.join(os.getcwd(), 'offline', 'data', file_out)
    # keys = data[0].keys()
Example #8
0
def update_position(left_prev, right_prev, vel_prev, mu_control_prev,
                    mu_sensor_prev, cov, time_prev):
    """Update position using two sources of information; control and sensors.
    The sensor data comes from the imu/gyroscope and the control comes from the
    odometers.

    nu is translational velocity in cm per second
    omega is Rotational Velocity in radians per second

    scales is a tuned parameter that turns the incoming odometer units to
    centimeters.

    :param left_prev:
    :param right_prev:
    :param vel_prev:
    :param mu_control_prev:
    :param mu_sensor_prev:
    :param cov:
    :param time_prev:
    :return:
    """
    # Get new measurements
    new_reading = get_reading(read_mag=False)
    # pprint(new_reading)
    delta_time = (new_reading.get('time') - time_prev).total_seconds()

    # Initialize
    # Get 'r' from encoders and scale to centimeters
    theta_control_prev = mu_control_prev[2, 0]
    theta_sensor_prev = mu_sensor_prev[2, 0]
    scale = 0.0577 * 2 * 10e-3  # Odometer units to centimeters, 20e-3 is magic number
    left_delta = new_reading.get('left_enc') - left_prev
    right_delta = new_reading.get('right_enc') - right_prev
    # scale * average encoder advancement / time_elapsed
    nu_control = scale * (left_delta + right_delta) / (2 * delta_time
                                                       )  # should be cm/s

    # TODO: Test the below decompositions, then refactor
    # Calibration from 7/19 [0.554, -0.235, 1.755]
    accel_forward = (new_reading.get('accel_z') - 1.755)
    accel_side = (new_reading.get('accel_x') - 0.554)

    vel_now = vel_prev + delta_time * np.array([
        accel_forward * np.sin(theta_sensor_prev) + accel_side *
        np.cos(theta_sensor_prev), accel_forward * np.cos(theta_sensor_prev) +
        accel_side * np.sin(theta_sensor_prev)
    ])

    # TODO: Decompose back to velocity in forward direction
    # Total velocity is L2 Norm
    # nu_sensor?
    # nu_sensor = np.sqrt(vel_now[0]**2 + vel_now[1]**2)
    nu_sensor = np.abs(np.sin(theta_sensor_prev) * vel_now[0]) + np.abs(
        np.cos(theta_sensor_prev) * vel_now[1])

    # Theta from Odometer
    rotation_scale = 5.5
    theta_delta_control = (left_delta - right_delta) / rotation_scale
    theta_control_new = theta_control_prev + theta_delta_control
    omega_control = theta_delta_control * np.pi / (180 * delta_time)

    # Theta from Gyroscope
    omega_sensor = -1 * new_reading.get('gyro_y') * np.pi / 180
    theta_delta_sensor = omega_sensor * delta_time
    theta_sensor_new = theta_sensor_prev + theta_delta_sensor

    if np.abs(omega_control) > 10e-4:
        omega_control_star = omega_control
        theta_control_new_star = theta_control_prev + theta_delta_control
    else:
        omega_control_star = 10e-4
        theta_control_new_star = theta_control_prev + 10e-4 * delta_time

    r_control = nu_control / omega_control_star

    if np.abs(omega_sensor) > 10e-4:
        omega_sensor_star = omega_sensor
        theta_sensor_new_star = theta_sensor_prev + theta_delta_sensor
    else:
        omega_sensor_star = 10e-4
        theta_sensor_new_star = theta_sensor_prev + 10e-4 * delta_time

    r_sensor = nu_sensor / omega_sensor_star

    # r_control = nu_control / omega_control_star if np.abs(omega_control) > 10e-6 else nu_control / 10e-6
    # r_sensor = nu_sensor / omega_sensor if np.abs(omega_sensor) > 10e-6 else nu_sensor / 10e-6
    # r_control = nu_control * delta_time
    # r_sensor = nu_sensor * delta_time

    mu_control_new = mu_control_prev + np.array(
        [[
            r_control *
            (np.sin(theta_control_new_star) - np.sin(theta_control_prev))
        ],
         [
             r_control *
             (np.cos(theta_control_prev) - np.cos(theta_control_new_star))
         ], [omega_control * delta_time]])

    mu_sensor_new = mu_sensor_prev + np.array([[
        r_sensor * (np.sin(theta_sensor_new_star) - np.sin(theta_sensor_prev))
    ], [
        r_sensor * (np.cos(theta_sensor_prev) - np.cos(theta_sensor_new_star))
    ], [omega_sensor * delta_time]])

    if i % 10 == 0:
        print("Control", nu_control, omega_control)
        print(mu_control_prev, mu_control_new)

        print("Sensor", nu_sensor, omega_sensor)
        print(mu_sensor_prev, mu_sensor_new)

    velocities = {
        'nu_control': nu_control,
        'omega_control': omega_control,
        'nu_sensor': nu_sensor,
        'omega_sensor': omega_sensor,
    }

    return (
        new_reading.get('left_enc'),
        new_reading.get('right_enc'),
        vel_now,
        mu_control_new,
        mu_sensor_new,
        cov,  # Sigma
        new_reading.get('time'),
        velocities)
    rotation_scale = 5.5
    theta_delta = (left_delta - right_delta) / rotation_scale
    x_delta = math.sin((mu_prev[2] + theta_delta) * np.pi / 180) * r
    y_delta = math.cos((mu_prev[2] + theta_delta) * np.pi / 180) * r

    mu = mu_prev + np.array([x_delta, y_delta, theta_delta]).T

    return new_reading.get('left_enc'), new_reading.get('right_enc'), mu


# Initialize Measurements for drive
i = 0
t1 = datetime.now()
data = []
int_pose = np.array([init_x, init_y, 0]).T
left_enc = get_reading().get('left_enc')
right_enc = get_reading().get('right_enc')

# Start Driving
drive_process.start()

# Measure while driving loop
while i < 100:
    t2 = datetime.now()
    left_enc, right_enc, int_pose = update_encoders(left_enc, right_enc,
                                                    int_pose)
    print(int_pose)

    data.append({
        "t": str(t2),
        "x": int_pose[0],