Well, this lab wasn't a success. This lab's purpose was to have the robot navigate through a set of waypoints on the canonical map seen in the past two labs. I was not able to finish it in the time completed. For anyone reading this in the future, I want to offer some advice to avoid repeating the mistakes I've made to get to this point, as well as report what I had done. Time wasn't really the issue, per se. Suffice it to say, don't expect the robot to not break down at the worst time! I expected to finish the lab the day before returning home to Chicago, but a combination of multiple failures prevented me from finishing on time.
I would recommend anyone planning for this class to carefully consider how long any lab should take. Then take that number and multiply it by two. Life is chaos! So anything can break for any reason. At some point after pushing code to my robot, I noticed the the right wheels began to turn erroneously. On further inspection, the motor driver for the right motor began heating up beyond what was normal. I decided to shut off the robot to avoid more potential damage, and replaced the motor driver. Despite that, I couldn't get the motors working in time. The replaced motor driver still didn't work as expected, with a pin controlling the motor most likely dead on the Artemis. Below is a video showing a funny but frustrating demonstration of the failing motor.
It seems that a control pin on the Artemis got fried, so when the "stop" command was made on the robot, the right motors instead got driven in one way, as only one of the control pins could be set high. In addition, I was the only one in the room who could stop the motors by laying my finger on the board, since my fingers apparently had the lowest resistance in the room, and I was shorting the control pins.
I tried borrowing the robot of a friend of mine, but at that point I was risking missing my bus and had to cut it short. In addition, one of the distance sensors failed after two different connections on it snapped. Seeing that these events happened around 11PM on Tuesday, and my bus to the Syracuse airport was at 7AM the next day, this was a problem! I want this section to not completely read like an airing of grievances, but as something that people can learn from. Definitely this isn't the defining experience of the class, but there is something to be learned here! Keep in mind that for the majority of this report, the robot is not functional and I can't demonstrate its navigation.
Let me explain what I was trying to do. I was working on essentially doing a hardcoded path for the robot, executing single turn-x-degrees, go-for-y-millimeters commands, while using localization at each waypoint to adjust the path to account for the imprecision of the robot. The localization and adjustment served to correct extreme deviations from the preset path. To get the absolute heading of the robot, I decided to use sensor fusion with the accelerometer and the net angle turned in the PID control, as well as the starting position. The following code shows how I got the magnetometer angle, which involved some manual calibration, and average many values, as the data from the sensor varies significantly.
The 0° of the magnetometer won't line up with the 0° bearing on the robot, so the first magnetometer reading will be discard and that particular reading will be used to orient the magnetometer so that N lines up with 0° from the net PID rotation angle. The function below accomplishes this using an additional pair of variables.
During calibration of the magnetometer, I found it to be accurate within ±2° if I averaged 100 magnetometer readings. Calibration itself is rotating the robot and finding the minimum/maximum magnetometer readings in the x-y directions (maximum x corresponds to north, for example), and scaling the readings so that they fall in the range of ±1.0, then finding the angle using tan-1(|mag_y| / |mag_x|). (|| indicating a reading normalized to be in the range ±1.0). The PID turning in practice is never able to get angles to exactly the desired angle, and achieves an angle ±1° of the setpoint. This fact means that basically the magnetometer won't be used unless the robot becomes significantly off of the set angle (I'm saying significantly being 5° off).
This brearing data was going to be used by the "RealRobot" class in a Jupyter notebook that will command the robot. The notebook is responsible for commanding the robot, taking in odometry data, and planning its route; the robot will simply perform turn-go operations and send back odometry and position information. Here is the code for getting the robot's pose. Since absolute position data isn't available, getPose() will return x and y coordinates based on odometry and an angle return from the robot potentially with magnetometer correction.
I then implemented the turn-go command execution on the robot, as well as adding a command to the Jupyter notebook.
On the board, turn operations were executed in the same manner that I've been doing for the past labs: orientation control plus adding a "kick." The straight motion was done in a striclty "P" controller. What I mean is that the motors were driven at a speed proportional to the difference of measured distance and a "target" point.
This was tested on the robot. The following code shows the way I tested the robot's ability to follow basic odometry instructions.
The video below is an attempt to execute a command that should have placed it on the next step of the trajectory.
The robot overshot the distance to travel multiple times, but otherwise did what what it was supposed to: execute an odometry command from the list, perform an observation loop to know where it is, repeat. It was at this point that the robot broke down, and every part of the robot began to fail.
Everything after this point are things I would do if I had a working robot. First, the erronous sensor measurement was due to the limit of the sensor range, seeming to cap at around 2 meters. To remedy this, the alpha sensor was moved from the side of the robot to the back. This way it could reference the wall behind it, which will somethimes be closer. The back sensor is used if it's closer to a wall and if the "target" distance is within its readable range (set to 1.5m). The following code shows the edit to the odometry-based control on the board.
This should have made movement fairly precise. However, in the case of slight deviations from the path, the commands send by the Jupyter notebook were supposed to respond to the actual odometry on the robot. The following code shows a simple pathfinding algorithm between points I would have used, that simply calculates the odometry between two points, where the starting position may have its angle adjusted according to odometry data.
I'd like to say thanks to all the great people who have made this class possible, and to anyone who has ever read this site! Best of luck to all you guys!