PWM is used to control the speed of the motors. The higher the pulse width, the faster the wheels spin. However, PWM alone isn’t enough to make the robot drive straight because even if the same exact duty cycle is output to both motors, the actual velocity of the two will always be slightly off.
Because of the limitations of PWM, we had to incorporate the encoders into our design. The encoders provide feedback that tells us exactly how far each wheel has traveled by outputting a tick every time the wheel has turned a certain distance. For our motors, each revolution of the wheel causes the encoder to output 480 ticks. At the start of our program, we set our desired velocity to be 700 ticks per second. We then check what our actual velocity is every 100 milliseconds by counting the number of ticks that has passed over the last 100 milliseconds and then multiplying it by 10 to get the ticks per second. We compare this velocity to our desired velocity and then make any necessary changes to the pulse width.
Proportional and Integral Control
After determining the error between the desired velocity and the actual velocity, the robot needs a way to decide how large of a correction to make. Proportional and integral control are used to decide the correction amount needed to make the robot drive straight. Proportional control is used to make a change to the duty cycle that is proportional to the error amount, while integral control takes into account all of the past errors and uses them to decide how much of a correction to make. We also tested out how straight the robot would go with derivative control, however, it did not seem to make a difference, so we decided to take it out in order to simplify the code.
The feedback from the encoders is used to allow the robot to make very precise turns. Through experimentation, we found that if we program the robot to turn the wheels 245 ticks in opposite directions, it will cause the robot to turn 90 degrees. We then incorporated this code into two different functions called x_degrees_right and x_degrees_left that would allow the robot to make any size turns by passing the number of ticks to turn each wheel by as arguments to the functions.
Distance Sensors for Navigating the Hallway
Distance sensors are incorporated into the design for object avoidance and for more accurate navigation. The distance sensors constantly check to see how close the robot is to the wall in the hallway and whether or not it is about to collide with another object. Each distance corresponds to a voltage that is sampled by the analog to digital converters on the microcontroller. The microcontroller then uses these voltages to make decisions regarding the navigation. If the robot is attempting to follow the wall in the hallway and it samples the readings from the distance sensors and sees that it is too close to the wall, it will do a 30 tick turn to the left. However, if it samples the voltages and sees that it is too far away from the wall, it makes a 30 tick turn to the right. These distance sensors are also used for detecting when the robot is in front of a door. When the robot has reached an open door, the distance sensors on the right side will output a voltage below 0.1 V, letting our robot know that it needs to make a right turn into the door.
Distance Sensors for Navigating the Room
When the robot gets into the room and next to the console, it begins using the distance sensors for object avoidance and to look for open areas to drive into. The robot constantly takes readings from the distance sensors in the front to see if it is about to collide with another object. If it sees something in front of it, it makes a 30 tick turn to the right, which causes it to circle around the console clockwise. To make it less prone to errors, it also constantly samples the voltage from one of the distance sensors on the left to see if there is an open area to its left. If there is, then this means that the robot made too many turns to the right while avoiding obstacles so the robot then makes a 90 degree turn to the left to get back on the right path. This method of looking for open areas on the left and then turning into those open areas also causes the robot to exit the room when it has finished circling the console because after it has driven around the console one time, it sees the open door on the left and then drives into it.
IR vs. Ultrasonic
Initially, we had planned on using only IR distance sensors for the navigation, however, during tests, we noticed that the robot would not see far enough to its sides, causing it to sometimes collide with another object if that object was not directly in front of the sensor. In addition, the robot was not able to see objects that were very close to the sensor or that were small in size. Because of these issues, we decided to incorporate two ultrasonic distance sensors into our design. When testing out the ultrasonic distance sensors, we found that these new sensors enabled the robot to see much further to its sides. In addition, the robot was now able to see small objects, such as the chair legs in the room, and could see an object that was only an inch in front of it.
Navigation without Dead Reckoning
When designing the software for the robot’s navigation, we decided to avoid using dead reckoning and, instead, programmed our robot to rely solely off of data read from the sensors. Our primary reason for not wanting to use dead reckoning was that we wanted our robot to be able to navigate any course, instead of being limited to the course for the competition. In addition, we knew that if we used dead reckoning our robot would be much more prone to errors because any seemingly insignificant changes to the robot’s environment or starting position would quickly accumulate and eventually throw it off course. Even more worrisome, was the fact that a single large error, such as a collision with another robot, would cause the robot to immediately veer off in the wrong direction without the ability to recover from the error. On the other hand, by using only sensors for navigation, we were able to get our robot to navigate much more reliably. For example, during the final round of the competition, both of the competing robots collided with each other and were blocking our robot’s path, however, our robot was able to quickly drive around them because it was able to see the other robots using its sensors, which wouldn’t have been possible using dead reckoning.