Final Project: Car #2
Completed alongside Serena Carson
Completed alongside Serena Carson
My role in this project: Wrote the code, Electrical design, Testing, System Integration, Helping Molex the Circuit
Note: We forgot to add the vive sensor and the battery pack onto the top platform for the nice photo. We also, after taking nice photos in the photobox in the BE lab, moved the robot and added in a servo to test the IR detection. All of the changes are seen above.
During finals week, there was an evacuation due to a gas leak in the engineering building. We left 90% of our stuff but could not leave our car!
By the end of the project, we accomplished 2.5/3 tasks as a team of 2 (every other team was 3-4 people):
Wall Following
Vive Sensor Tracking
(Half of) IR Beacon Detection
Videos of all 3 functions are below.
High Level Approach:
In order to accomplish the tasks of the game we created a car with 2-wheels and a caster, using differential drive for movement. The car had multiple tiers to house the different circuits and components. Our main goal was to focus on car movement using PID control to accomplish wall following and VIVE movement to the police car. Once we found out that our team would be limited to 2 people we made several design decisions to streamline our project from our original proposal in the design reviews. We eliminated the claw mechanism and instead cut a semi-circle section out of the car’s base to account for the IR trophies if we chose to include IR sensing in the project, additionally we switched to a 2-wheel caster design rather than 4-wheel differential drive. We felt that the turning on the 2-wheel caster design would be smoother. We implemented a website that would allow for switching between wall following, movement to the police car, and infrared sensing while maintaining autonomous behaviors.
Approach for functionality:
Feedback: We had initially approached this using PID such as in lab 4, but shied away from it because we were continually having issues with our motors. One of the motors was always significantly weaker- with the same duty cycle, it produced fewer rotations. It felt like which motor was misbehaving switched every few days.
Instead of PID, we implemented a feedback loop based on the difference between the distance to the wall of the time of flight sensors. One was placed towards the front of the car and one towards the back. If there difference was over a certain value, the duty cycle of the wheels would adjust accordingly to assist the car in veering a bit to the left or right, depending on which sensor was greater.
In addition, we had a feedback system for turning the car. For wall following, if the car was a certain distance from the wall as determined by the front ultrasonic sensor, it would begin to turn. It made a turn until the stronger wheel had sensed that 20-25 (varied day to day and on power supply) windows of the encoder had passed. It then sensed if the back of the car was close to a wall and the time of flight sensors were semi aligned to determine if it needed to turn more.
Wall-following: To implement wall following we used 2 TOF-sensors on the side and a ping sensor on the front. To ensure proper attachment we 3-D printed housing for these sensors and secured the attachments to the base. The TOF sensors were meant to keep the car aligned with the wall on the side while the ping sensor was meant to sense when the wall in the front approached, triggering a turn. The code for the TOF sensors was set up to constantly push the car to align so that the TOF sensors would have the same value. For example, with the wall on the left side, if the car is pointing away from the wall the front TOF will read a higher value than the back TOF so the car will make a very small turn towards the wall. The car checks the distance again and will keep making small turns until both TOF sensors have the same value. When they are the same the car will go straight. And if the car is pointing towards the wall it will correct with small turns away from the wall in the same way. Once a ping sensor picks up a distance under a predetermined threshold the car turns right 90º. To ensure the car turned 90º the turn was calibrated using the encoders on the wheels. We counted the number of encoder windows that the interrupter passed. We then designated how many encoder windows needed to pass on one wheel in order to have a proper turn. For example, once the right interrupter read that 25 windows had passed on the encoder, the right turn was complete.
Vive: In order to implement vive we first made the circuit without the car in order to accomplish testing and ensure the angles of rotation that we calculated were correct. For vive, we used two sensors, one placed in front of the other. One sensor was used for the car coordinates and the other was used to find the car heading and angle with respect to the field and the police car. In order to accomplish the movement to the police car we calculated the angle of the car coordinates to the police car coordinates relative to the x-axis of the field. Then we calculated the angle of the first car sensor to the second car sensor in order to determine the heading of the car with respect to the x-axis. These angles were then subtracted in order to find the angle which the car had to rotate.
Car movement was done similar to the control used in wall following. Once the angle of rotation was calculated, whether the angle was positive or negative determined if the car needed to rotate clockwise or counter-clockwise. If the car was meant to rotate clockwise, then it would take a small turn right, and if it was meant to rotate counter-clockwise it would take a small turn left. Once the small turn was accomplished the angle of rotation would be calculated again, once the angle of rotation was found to be 0 the car would go forward and continuously check the angle and make small turns in order to correct to the proper direction.
UDP: UDP was used in order to read in the police car coordinates and assign them to global variables so that they could be used in the angle calculations mentioned above. UDP was also used to transmit the coordinates of our car at a constant frequency.
HTML: An html website was used in order to control which function the robot was following. The website consisted of 3 buttons(Wall following, Police car, and IR Object). When a different button was pressed this changed a variable tracking the state of the robot. State=1 corresponded to wall following, state=2 corresponded to the police car movement, and state=3 corresponded to sensing the IR trophies(although we did not end up implementing IR sensing). Once a button was pressed the state was changed the robot would perform whichever functionality the state designated.
ESP-NOW: Every time a button was pressed on the website, an ESP-now message was transmitted.
Performance:
Feedback: Due to the previously mentioned issues with our motors, it felt like we were adjusting our feedback loops incredibly often. We considered switching back to PID in hopes of minimizing the time spent on this and to increase the consistency of a positive result, but we decided against it due to time constraints. Ultimately, we were able to navigate to the police car and navigate the entire track by wall following, so, while stressful, our feedback loops proved to be successful.
Wall-following: Ultimately we were able to accomplish full wall following (for check off we accomplished ¼ of the circuit but as seen in the video below, we were able to do a full loop). We believe that the issues we had on the field used for check-off were due to the fact that there were a few uneven portions of the wall throwing off the sensors, additionally the room was very noisy while testing which could have potentially interfered with the ping sensor used in the front of the car. We experienced significant noise in the circuit, likely due to the number of sensors. We originally had a ping sensor attached to the back of the robot, as we had intended to implement further sensing if we were to participate in the competition. This extra sensor seemed to be adding noise to the circuit and sensing, due to this and since we would likely not be participating in the competition, we decided to remove the back ping sensor. After this the sensors behaved as intended without issue. Attached is a link to a video of a track we set up in the BE labs (just some MDF sheets and the preexisting walls) where the car was able to complete a full circuit of wall following.
Vive: Overall, the vive sensing worked well and the angle calculations were correct once we figured out the trigonometry necessary. However, the issue that we encountered for the police car had to do with UDP receiving and wheel movement. The UDP receiving worked relatively consistently up until the night before the last check-off. We tested the car previously with the vive sensing and were able to get it to move to the police car well, however that night the UDP receiving stopped working. I believe this was likely due to the amount of people in the lab using UDP and wifi, which prevented us from properly receiving the signal. After some troubleshooting and testing UDP receiving by itself(similar to the code that was provided in lecture) we came to the conclusion that the issue was with UDP receiving. So we tested again by hard coding coordinates(4000, 4000) and the car moved towards the designated coordinates. After this we decided to return to the lab when it was less crowded and were able to have proper UDP receiving and the car moved towards the police car again in the morning. As for wheel movement it took some trouble-shooting and calibration in order to have the car make small turns to the right or left based on the angle of rotation that was calculated. However, once we finished calibrating the movement the car rotated well and moved correctly to the police car. Attached below is a video of the car moving to the police car. In the video the police car was placed slightly outside the field as other teams were also testing at the time. Additionally, only one of us was in GM at the time so the person taking the video is holding their computer, their phone and the separate battery pack that is attached to the car on the cord seen (apologies if the video is a little shaky/poor quality).
UDP/HTML/ESP-NOW: As mentioned above there were some issues with UDP receiving, however UDP sending worked well. Additionally, ESP-NOW sending worked well. For the website the HTML behaved as necessary and was able to properly change states as can be seen in the video attached in the appendix. Here we have the car code running alongside the HTML website with 3 buttons. Print statements are included in order to show the code switching states when a button is pressed on the website.
Lessons learned:
Overall, we learned a lot of lessons from this project. First we learned a lot as we kept changing the design to account for the greater workload that was on our two person team. One particular lesson from this was that we should have considered changing our design sooner. We thought we would be able to stick with our original design however as we continued integrating we realized it would be more efficient to streamline the design. This allowed us to focus more on certain components and made integration easier as we had less different aspects to worry about. Additionally, we learned a lot about integration for this project. We had our circuits and sensors working relatively well separately, however we ran into different issues once we began putting all the components together. When considering the 4-wheel drive vs. 2-wheel drive we found that the 4-wheel drive was not able to get enough torque on all wheels evenly in order to turn well and it was not able to overcome the friction with the ground, so in order to consolidate our circuit and improve turning we switched to 2-wheel drive. Although it was a lot of work it was very helpful to have a soldered circuit for this project. We tended to have more issues with noise in the wall following system than in the vive system as the sensors for the vive were very consistent. However, we ran into more issues with wifi and UDP receiving in this section. With the wall following sensors we experienced more noise and issues with integration.
Look at how happy the little robot is to be driving our car!
Intended Performance:
As mentioned earlier we streamlined some of our design decisions once we realized we were a two-person team. Our car was originally intended to have 4-wheel drive with Ackermann steering and a claw mechanism controlled by a servo. After understanding the math involved in Ackermann steering we decided that we were over complicating the car and that this version of steering would not be able to provide the sharp turning necessary for this project, so we then switched to four wheel differential drive. We did some preliminary testing with the 4-wheel differential drive however the wheels were not able to overcome the friction to turn smoothly. Once we became a two-person team is when we decided on implementing 2-wheel differential drive with a caster. We knew the turning would be sharp and smooth with this version of steering. Additionally, this cut down on the number of pins we needed to use (less motor pins and less interrupter pins) allowing us to fit everything from the car onto the ESP32-S2. This allowed us to eliminate some extra communication that would have been needed between microcontrollers, streamlining our process slightly more. We had used the two-wheel/caster design in lab 4 and had originally wanted to try something new for the final project and thought four wheels would provide the extra grip needed for moving the police car. We decided that the extra grip to move the car was worth trying this version of skid steering as we thought the surface was smooth enough to allow for proper turning. We had also originally avoided using the 2-wheel+caster design as we struggled with moving the car straight due to the limits of the motors and the encoders we used in lab 4. What we did to account for these issues is explained below in the actual performance.
Actual Performance:
The car design we decided on(2-wheel differential drive with caster, and no claw mechanism) performed as we intended. Before building any components of the car we had ruled out ackermann steering as it would be difficult to maneuver sharply, and after initial testing the 4-wheel differential drive was ruled out given that the benefit of added friction for moving the police car was outweighed by there being too much friction between the wheels and the ground. This friction prevented the smooth turning of the car. The design of the car consisted of 2 levels with a semi-circular shape cut out in the front to account for trophy dimensions in case the trophy tracking and movement was something we ended up implementing. 2 motors/wheels were attached in the back while the caster was placed in the front. Housing was made for each sensor and screw holes were made in the platform to align with perfboards and spacers for the next level. In order to account for the issues we encountered in lab 4 with the 2-wheel/caster design mentioned above, we calibrated motors before using them on the car and 3D printed new encoders with smaller gaps between windows. For motor calibration we ran different duty cycles on them and checked the output from the interrupters. If motors were inherently bad motors sometimes the PID would not be enough to make the motors match speeds. By doing this we only used motors on the car that we knew had relatively similar RPM capabilities. Additionally, the new encoders we 3D printed were able to measure motor speeds and correct them to the designated duty cycle more accurately. Additionally, we accounted for any further error in motor speed in the way we implemented code. For example, in wall following and vive we essentially have a second form of feedback control. We make small movements, check sensors, and make small movements again accordingly. This helped us avoid having to make the robot line up to a certain angle and then go straight. We did this given that even with PID if we gave the robot a command to go straight, we expected it would still deviate slightly from the path with the 2-wheel/caster based design.
Lessons learned:
As we iterated through different mechanical designs different lessons were learned. From lab 4 we found it helpful to make an extremely rough draft of the car so we could begin testing car movement as quickly as possible. We continued to use a rough prototype throughout the multiple design iterations we explored which allowed us to quickly test different forms of movement. This was also beneficial to us given that we needed to change our design based on the decisions we made in streamlining our approach. We were able to quickly adjust different prototypes to accommodate this and continue testing. Once we were able to do some preliminary tests with the car we began to add different features and make adjustments as needed, allowing for the mechanical design to be constantly changed and improved based on our needs. Additionally, from mechanical design we learned the need to plan out many aspects of the car ahead of time and account for all different components where needed. For example, with many of the sensors it was important that they be aligned almost perfectly and remain secure while the car moved. When planning our mechanical design we needed to think of where these sensors would go, how they would be attached securely, and how they would fit around other components. Sometimes there would be one small thing that we did not account for and thus would have to recut and reassemble the car.
A demonstration of our beautiful wiring.
Intended Performance:
For the electrical design we intended to have the whole circuit soldered and use Molex to have easy access to wires and the ability to replace if needed. Additionally, we did most low level testing with a 6V battery pack but switched to a lipo battery when we began integrating sensors into the car with the motor control and movement. In lab 4 we switched from the SN754410 to the FAN8100 h-bridge to improve the voltage loss occurring in the other h-bridge. Given that this improved our car performance in lab 4 we continued to use FAN8100 for the final project. Moreover, this reduced the number of pins necessary when compared to the SN754410. With regards to the wall following, we intended to have two-TOF sensors on each side, and one ping sensor on the front and one on the back. For vive we wanted to use two sensors to find location and heading of the car. As the project went on some streamlining decisions were made to complete the necessary functionality, for example the exclusion of the servo and infrared sensors needed for moving towards trophies.
Actual Performance:
We soldered and molexed everything, and left room for additional sensors to be added in the case of wanting to participate in the competition. When we soldered we included space for 2 motor drivers and 4 interrupters in case we kept the 4-wheel design. Additionally, we included space to include 4-TOF sensors and 2-Ping sensors in case we were able to accomplish the minimum functionality and intended to take the car further. Ultimately, we decided on the 2-wheel design and the use of TOF sensors on one side and a ping sensor in the front, this allowed us to complete the wall following in a clockwise direction around the track. The vive circuit stayed the same as intended.
Lessons learned:
Several lessons were learned with regards to electrical design. First off, soldering and molexing was something we had experienced before but not to this extent. In lab 4 we had created a soldered circuit, however it was a smaller circuit and we did not molex the wires. Molexing the wires was something we felt was important, due to the fact that in lab 4 we were not able to easily replace, remove or troubleshoot different aspects of our circuit. We learned to plan out the circuit in detail before soldering, to do so we gathered all components and optimized their placement in order to minimize the necessary soldering while maximizing the space used on the perf board. Another learning curve was dealing with the noise that manifested during integration. Previously, the circuits we had been using were small enough to not cause any issue with noise. However, once we integrated the different circuits and components together noise started to become a problem. In order to solve these problems we pin pointed which sections of the circuit were causing issues and went about fixing them from there. Sometimes the noise wasn’t quite noise but just a loose connection and sometimes the noise required us to rework parts of the circuit in order to correct the problem.
Block Diagram of Code Architecture
Software approach: To implement the software of the car we first went through different iterations and testing of the different components separately. Parallelly, we began working on an integrated version of the code that utilized the html website to switch between the different tasks. Once we knew we were able to accomplish a task such as wall following, we then integrated the wall following to be used with the html. Once we tested and ensured the vive code we then integrated the vive code into the html website. Throughout the coding process we were sure to implement functions so that integration into the html would be smooth and organized.
The software was organized by tracking three states (1: wall following, 2: police car, and 3: IR trophy sensing). Ultimately we did not implement IR sensing however when designing our code we left space in case it was a task we decided on adding. Once a button is pressed on the HTML website the state is changed to correspond to whatever button is pressed. From here the code will follow the functions corresponding to the actions needed for wall following, movement to the police car, and in theory movement towards a trophy.
Within the wall following action the code starts by taking in sensor values, deciding to turn slightly right, slightly left, or going forward, and repeating. Additionally, it constantly checks the front sensor to decide when to make a 90º turn to the right. To do so the side TOF sensor values are recorded. If the front is larger than the back the car is pointing away from the wall, and if the back is larger than the front, the car is pointing towards the wall. The car then adjusts accordingly and repeats. When the front and back TOF sensors are perfectly aligned the car will go straight. The ping sensor attached to the front of the car is constantly being updated, and once the car is too close to the wall in front of it this will trigger a 90º degree turn. This turn is performed as described earlier through the counting of how many encoder windows have passed a wheel, once this number is complete the 90º turn is complete and the duty cycles are once again reset to go straight and the whole cycle repeats.
The vive code performs similar actions. The sensor data is recorded and the UDP from the police car location is received (filtered so that only coordinates from team 00 will be recorded), angle calculations are made, the appropriate small turn is made, and when the car is pointing towards the police car it will go forward. The value of the angle determines the direction. When the rotation angle is positive the car is meant to make a small turn clockwise, and when the rotation angle is negative the car is meant to make a small turn counterclockwise, and when 0 the car will go forward. Once the small movement is made the code repeats in order to constantly correct the car direction and move towards the police car. Given that the car will never actually reach the police car coordinates (since the sensor is at the center of the car) this code would make it so our car will continuously push the police car.
Lessons learned:
Integrating the code was a challenge. Given that we worked on it parallelly and focussed on utilizing functions while testing individual components, it did make the integration process simpler. This was something that was improved upon from lab 4 which is important given that there are many more parts to this project than lab 4. It was very helpful to be consistent with functions and variable naming allowing for smooth integration into the overall program. One aspect that we could improve on slightly is the organization and naming of our files. We shared code by sending it back and forth and did not have a set naming convention. We were able to make it work but using some kind of platform for organizing code in the future could be helpful, especially when it is important that different team members have access to the same code.