예제 #1
0
def sample_x_using_odometry(x,
                            u,
                            variances=[0.01, 0.01, 0.01, 0.01],
                            extents=None):
    """Sample from p(x_t | u_t, x_{t-1}) where u is not a control vector, but
    a measurement of the current and previous states in local coordinates:
                    u = [\bar{x}_{t-1}, \bar{x}_t]^T
    """
    xt = np.empty(3)  # output vector: sampled global pose
    x_prev, y_prev, theta_prev = x  # global pose at time t-1

    du = u[1] - u[0]
    if extents is not None:
        du = wrap(du, extents)

    dx, dy, d_theta = du
    a1, a2, a3, a4 = variances

    drot1 = in2pi(np.arctan2(dy, dx) - u[0][2])
    # drot1 = in2pi(np.arctan2(dy, dx) - theta_prev)
    dtran = np.sqrt(dx**2 + dy**2)
    drot2 = in2pi(d_theta - drot1)

    dr1 = drot1 - np.sqrt(a1 * drot1**2 + a2 * dtran**2) * randn()
    dtr = dtran - np.sqrt(a3 * dtran**2 + a4 * (drot1**2 + drot2**2)) * randn()
    dr2 = drot2 - np.sqrt(a1 * drot2**2 + a2 * dtran**2) * randn()

    xt[0] = x_prev + dtr * np.cos(theta_prev + dr1)
    xt[1] = y_prev + dtr * np.sin(theta_prev + dr1)
    xt[2] = in2pi(theta_prev + dr1 + dr2)

    if extents is not None:
        xt = wrap(xt, extents)

    return xt
예제 #2
0
def main():
    dt = 0.5  # time step
    n_steps = 2000
    extents = (-100, 100)  # map boundaries (square map)
    speed = 20.  # commanded speed in m/s (1 m/s = 2.237 mph)
    N = 500
    particles = []

    # I tried these combinations of variances for odometry sampling:
    # v = [0.1, 0.0, 0.0, 0.0]  # arc
    # v = [0.0, 0.0001, 0.0, 0.0]  # arc
    # v = [0.1, 0.0001, 0.0, 0.0]  # arc
    # v = [0.0, 0.0, 0.01, 0.0]  # straight-ahead line
    # v = [0.1, 0.0, 0.01, 0.0]  # teardrop, ring, line (angle-dependent)
    # v = [0.001, 0.0001, 0.001, 0.0] # banana
    # v = [0.001, 0.0001, 0.01, 0.0]  # textbook
    v = [1e-3, 1e-5, 1e-3, 1e-3]  # compact blob

    # Start in the middle, pointed in a random direction.
    starting_pose = np.array([0, 0, np.random.uniform(0, 2*np.pi)])
    vehicle = Vehicle(wheelbase=0.7,
                      center_of_mass=0.35,
                      initial_state=starting_pose,
                      range_noise=0.1,  # meters
                      bearing_noise=0.01,  # rad
                      sensor_range=50)
    vehicle.t = time()

    # Use control input vector to store odometry info. u_odom is a list of N
    # queue structures. There will be two states in each entry: x_{t-1} and
    # x_t. Each is a state in the local frame of the vehicle (x_bar, y_bar,
    # theta_bar). The starting point is taken to be known; from there, we can
    # only measure changes.
    u_odom = [deque([starting_pose.copy()]) for _ in range(N)]

    # Advance the vehicle one step so we can get an odometry measurement.
    vehicle.move(u=np.array([speed, 0]), dt=dt, extents=extents)
    for j in range(N):
        xbar = vehicle.x - starting_pose + u_odom[j][-1]
        xbar[2] = in2pi(xbar[2])
        u_odom[j].append(xbar)
        particles.append(vehicle.x)

    for i in range(n_steps):
        steer_angle = np.radians(1.0*np.sin(0.5*i/np.pi))

        x_prev = vehicle.x.copy()  # Previous global state
        vehicle.move(u=np.array([speed, steer_angle]), dt=dt, extents=extents)

        for j in range(N):
            u_odom[j].popleft()

            # Simulate a state \bar{x}_t measured by odometry.
            xbar = vehicle.x - x_prev + u_odom[j][-1]
            xbar[2] = in2pi(xbar[2])
            u_odom[j].append(xbar)

            # Update particle position with a new prediction.
            particles[j] = sample_x_using_odometry(particles[j], u_odom[j],
                                                   variances=v, extents=extents)
        sleep(dt)

        pdf = 'motion_pred' if i < 10 else None
        draw(x_prev,
             x_extents=extents,
             y_extents=extents,
             particles=particles,
             fig=pdf,
             )
예제 #3
0
def main():
    dt = 0.05  # time step - 20 Hz updates
    n_steps = 1000
    extents = (-100, 100)  # map boundaries (square map)
    L = extents[1] - extents[0]
    n_landmarks = 5
    speed = 20.0  # commanded speed in m/s (1 m/s = 2.237 mph)
    N = 500  # number of particles
    u_noise = np.array([0.1 * speed, 0.001])  # speed noise, steering noise

    # Start in the middle, pointed in a random direction.
    starting_pose = np.array([0, 0, np.random.uniform(0, 2 * np.pi)])
    vehicle = Vehicle(
        wheelbase=0.7,
        center_of_mass=0.35,
        initial_state=starting_pose,
        range_noise=0.1,  # meters
        bearing_noise=0.01,  # rad
        sensor_range=50,
    )
    vehicle.t = time()

    particles = []
    weights = np.full(shape=(N, ), fill_value=1 / N)
    R = np.diag([vehicle.range_sigma, vehicle.bearing_sigma])

    # Use control input vector to store odometry info. u_odom is a list of N
    # queue structures. There will be two states in each entry: x_{t-1} and
    # x_t. Each is a state in the local frame of the vehicle (x_bar, y_bar,
    # theta_bar). The starting point is taken to be known; from there, we can
    # only measure changes.
    u_odom = [deque([starting_pose.copy()]) for _ in range(N)]

    # Advance the vehicle one step so we can get an odometry measurement.
    vehicle.move(u=np.array([speed, 0]), dt=dt, extents=extents)
    for j in range(N):
        xbar = vehicle.x - starting_pose + u_odom[j][-1]
        xbar[2] = in2pi(xbar[2])
        u_odom[j].append(xbar)

        # Initialize particle distribution
        x0 = np.array([0.1 * L, 0.1 * L, 0.01
                       ]) * np.random.randn(3) + starting_pose
        particles.append(x0)

    # Add landmarks to the map at random.
    landmarks = np.random.uniform(*extents, size=(n_landmarks, 2))

    for i in range(n_steps):
        start = vehicle.t
        steer_angle = np.radians(1.0 * np.sin(i / 100))
        u = np.array([speed, steer_angle])

        # Advance the ground-truth pose
        x_prev = vehicle.x.copy()  # Previous global state
        vehicle.move(u=u, u_noise=u_noise, dt=dt, extents=extents)

        z, in_range = vehicle.observe(landmarks)

        # predict
        for j in range(N):
            u_odom[j].popleft()

            # Simulate a state \bar{x}_t measured by odometry.
            xbar = vehicle.x - x_prev + u_odom[j][-1]
            xbar[2] = in2pi(xbar[2])
            u_odom[j].append(xbar)

            # Update particle position with a new prediction.
            particles[j] = sample_x_using_odometry(
                particles[j],
                u_odom[j],
                variances=np.array([1e-6, 1e-6, 1e-4, 1e-4]),
                extents=extents,
            )

        if len(z) > 0 or i % 10 == 0:
            # update particle weights
            update(np.array(particles), weights, z, landmarks[in_range], R)

            # resample
            if n_effective(weights) < N / 2:
                particles = resample(particles, weights)

        vehicle.t = time()
        if start + dt > vehicle.t:
            sleep(start + dt - vehicle.t)

        # pdf = 'pf-sim' if i < 10 else None
        pdf = None
        draw(
            vehicle.x,
            landmarks=landmarks,
            observations=z,
            x_extents=extents,
            y_extents=extents,
            particles=particles,
            weights=weights,
            fig=pdf,
        )