Control

Angular speed control

You will likely need to low pass filter the gyroscope values - read up on how we did that with a complementary LPF in Lecture 4, slide 23.

Low pass filter:

const float alpha = 0.1;
float history_gyr = 0.0;

float LPF_gyr(float curr_gyr) {
    float filtered_gyr = alpha * curr_gyr + (1 - alpha) * history_gyr;
    history_gyr = filtered_gyr;
    return filtered_gyr;
}

One way to make the robot spin even slower is to block one set of wheels while turning the others. This means that your robot is now driving in a slight circle (rather than on-axis), which will make post-processing of data slightly more difficult, but allow you to capture data more reliably.

I didn’t use this method. Instead, I always let the left wheel and right wheel spin under opposite control values.

std::pair<int16_t, int16_t> angle_speed_pid(int16_t error) {
		return std::make_pair(-control, control);
}

Please quantify and/or use graphs to document that your PID controller works well, and upload a video that shows how your robot turns.

if (yaw > 400) {
    stop();
    auto_running = false;
}
keepYawSpeed(20, -filtered_gyr);

ttx

Given the slowest speed you are able to achieve, how much does the orientation of the robot change during a single measurement? If you were spinning in the middle of a 4x4m2 empty, square room, what kind of accuracy can you expect?

About 5 degrees

Read data

On every marked point, I collected 2 copy of data,

csvfiles

each csv file looks like this,

csvcontent

Plot Polar Graph

The following code read raw data files and convert yaw angle and distance towards x and y coordinates.

poses = ["-3,-2", "0,0", "0,3", "5,-3", "5,3"]

for pos in poses:
    # create a new polar plot
    fig, ax = plt.subplots(subplot_kw={'polar': True})

    file_path_1 = os.path.join(csv_folder, pos + "-1.csv")
    file_paht_2 = os.path.join(csv_folder, pos + "-2.csv")

    df1 = pd.read_csv(file_path_1)
    df2 = pd.read_csv(file_paht_2)

    degree_angles = df1["yaw"].tolist()
    rad_angles = [elem * -np.pi / 180 for elem in degree_angles]
    distances = df1["distance"].tolist()
    distances = [dist + 40 for dist in distances]

    ax.plot(rad_angles, distances, color="blue")

    degree_angles = df2["yaw"].tolist()
    rad_angles = [elem * -np.pi / 180 for elem in degree_angles]
    distances = df2["distance"].tolist()
    distances = [dist + 40 for dist in distances]
		
    # use two different colors to display two series of data
    ax.plot(rad_angles, distances, color="orange")

    plt.title(pos, loc='center', fontweight='bold')
    plt.show()

The polar plots:

-3-2

00

03

5-3

53

Merge and Plot your readings

I use five different colors to display data that are read from five different positions.

poses = ["-3,-2", "0,0", "0,3", "5,-3", "5,3"]
colors = ["blue", "orange", 'red', 'green', 'purple']
suffixes = ["-1.csv", "-2.csv"]

for pos, curr_color in zip(poses, colors):
    x_base, y_base = list(map(int, pos.split(",")))
    for suffix in suffixes:
        file_path = os.path.join(csv_folder, pos + suffix)
        df = pd.read_csv(file_path)

        degree_angles = df["yaw"].tolist()
        rad_angles = [elem * -np.pi / 180 for elem in degree_angles]

        distances = df["distance"].tolist()
        x_coord = [(dist + 40) * np.cos(rad_angle) + x_base * 304 for dist, rad_angle in zip(distances, rad_angles)]
        y_coord = [(dist + 40) * np.sin(rad_angle) + y_base * 304 for dist, rad_angle in zip(distances, rad_angles)]

        plt.scatter(x_coord, y_coord, color=curr_color)

plt.show()

Graph:

merge

Convert to Line-Based Map

x_wall1 = [-1721, -628, -799, 1895, 2075, 539, 447, -132, -31, -1392, -1721]
y_wall1 = [6, 227, 1248, 1454, -1127, -1319, -543, -656, -1230, -1535, 6]

x_wall2 = [644, 1360, 1404, 728, 644]
y_wall2 = [733, 831, 296, 159, 733]

Line-based map is shown as below,

walls