Our project focuses on adding an Adafruit Time of Flight (TOF) sensor to the Donkey car so that it would be able to autonomously park in 3 modes: straight in parking, parallel parking, and perpendicular parking.
Team 2 Members
(from left to right)
Madatya Nersesian - MAE
Yuansheng Zhang - MAE
Anthony Nguyen - ECE
Tae Ho Kim - CSE
For straight in parking, we have the sensor oriented facing forward and set to stop the DC motor at a specified distance away from an object in front of the car.
For parallel parking, we have the sensor oriented facing sideways on the front, right section of the car. As the car moves forward, the sensor will detect changes in depth to determine the edges of vehicles. We then calculate the time it took our car to read from one edge to another to extrapolate the length of an available spot. If the spot is not big enough, then the car will continue on its path until it finds a suitable space. Once it does, the car will engage in parallel parking mode.
For perpendicular parking, the procedure is similar to parallel parking with a minimal change in the parking algorithm.
Initially, we began our project with the Pololu VL53L0X TOF sensor, but eventually switched to the Adafruit VL53L0X TOF sensor. The actual sensor itself is the same on both boards, but there were some detection complications that arose from the Pololu boards.
With a single TOF sensor, we only needed to connect the V_in, Ground, SDA, and SCL ports to the Raspberry Pi. To confirm that the Raspberry Pi was properly detecting our TOF sensor, we ran the i2cdetect -y 1 command. If it was being properly detected, we should see that address 29 was being occupied along with 40 and 70.
However, with two sensors, we would also need to connect the XSHUTDOWN port (in addition to the previously listed ports) to two different GPIO ports onto the Raspberry Pi. The library that we used would assign two unique addresses -- 2B and 2D -- one for each TOF sensor.
The complete wiring schematic for an Autonomous Parking R/C Vehicle is illustrated below:
Circuit diagram for an Autonomous Rarking R/C Vehicle Using One Adafruit VL53L0X TOF Sensor
Circuit diagram for an Autonomous Rarking R/C Vehicle Using Two Adafruit VL53L0X TOF SensorS
Modeling Equations of Motion
In order to parallel park, we need to first derive the Equations of Motion.
Problem Solving Strategy
Determining Parking Space Length
1) The TOF Sensor will begin to record data once our function starts. We are assuming it starts near a car at a fixed distance. Thus as it drives past the car it has a constant distance.
2) As the TOF passes the car and reaches the gap in the parking space, the TOF sensor will instantaneously detect a large change in distance. We will timestamp this change in distance and call that 't0'.
3) (Assuming we have a TOF sensor in the back of the car as well: ) In a similar fashion, the TOF sensor in the back will detect the large change in distance and timestamp this as 't1'
4) As the car continues to drive, it reads a constant distance of the parking spot.
5) Once the car reaches the next car, the TOF Sensor will timestamp a new change in distance. This time instant at which the front sensor reads the new change in distance can be called 't2'.
6) Now that we have the two separate time instances, we can subtract t2-t0 to get the time it takes to pass the parking space!
7) The car receives a power input which provides a constant velocity, V. From simple physics we can calculate the Length of the parking space! L = V*t We now have the parking space distance L!
Reverse Parking - Finding the Angle to Turn
(Assuming the length L is long enough)
1) Once the algorithm determines the parking space length is long enough, it will shut off the motors instantly. However it will decelerate at a specific rate (discussed later). This final distance from the end of our Car to the beginning of the second car is 'S'. We need to account for this forward distance. The farther we are, the larger the turning radius that will be required. However, the car has a Max Turning Radius in which we need to take into account.
2) The complimentary angle, Alpha, depends on the parking length, turning radius, and S.
3) We can then find the distance to get to the center of turning by finding the angle Beta, or 90-Alpha. This center point is relative to the two tangential circles strategically placed in specific locations (examination of the diagrams will better explain this)
4) From Beta, we can determine the Arc Length, M, which is the distance the car will have to turn to get to the center of turning.
5) Once the car reaches this full distance M, called point P, we call the car to switch the direction of the angle and continue to it's final path.
Perpendicular Reverse Parking We Follow the exact same method to be able to determine the parking space distance L. However, the only difference is that now we only need to turn our wheel's and reverse once! The equations of motion for this were derived from the illustration & assumptions given below.
A PID operator is implemented in our feedback loop to control the speed of the car when the sensor senses an obstacle.
We implemented 3 different parking modes (straight, parallel, and perpendicular) To run the autonomous parking mode, type command
python manage.py park --o=1 (mode1: straight parking)
python manage.py park --o=2 (mode2: parallel parking)
python manage.py park --o=3 (mode3: perpendicular parking)
Mode1: straight in parking
Straight parking part: PARK1 (park1.py)
This part receives distance as an input from the TOF part and returns the throttle as an output. This part calculates the throttle in terms of the remaining distance from the wall.
Mode2: parallel parking
Parallel parking parts: PARK2A, PARK2B (park2a.py, park2b.py)
PARK2A takes care of the first part, which is detecting two edges and figuring out the length of the empty space. It keeps detecting edges until the car finds enough space to park. This part receives distance as an input from the TOF part and returns the throttle, flag (to tell whether the first part is done or not), and the time (it takes to finish the first part) as output.
PARK2B takes care of the second part, actually parking. This part receives the throttle, flag, and time as input from PARK2A part and returns the throttle and angle as output.
Mode3: perpendicular parking
Perpendicular parking parts: PARK3A, PARK3B (park3a.py, park3b.py)
Perpendicular parking is very similar to parallel parking in terms of the process. In PARK3A, it detects two edges and measures the length of the empty space. After that, PARK2B takes care of actual parking.
Most of the analysis is based off of a constant velocity of the car. However, we need to also take into account the acceleration and 'deceleration' of the car. There is an initial acceleration of the car when the power is output to the motors; this will indeed have an impact as it will travel a further distance than expected. Furthermore, when we turn off power to the motors and tell the car to stop, it does not actually stop right away! The power will be yielded from the motors and it will begin to decelerate at a specific value until it comes to a complete stop. Thus we must take these acceleration values into account when implementing our equations of motion.
The acceleration of the vehicle was determined experimentally by running a number of trials at a constant velocity, and determining the time it takes to come to a complete stop after we turn off power input to the motors. The experimental results are displayed below.
2) Calculating Time
In order to determine the linear speed of the car with a specific value of throttle, the built in
.time() function was used which called the internal clock of the Pi. We also used the differences measured by the sensor in order to determine the speed of the car. Acceleration was also a factor which needed to be accounted for.
3) Excess Speed
As described in (1), we know the car moves a further distance after we issue the car to STOP. Because we are not using encoders, and the ESC is completely ran by the Power output, this results in a lot of errors that can only be compensated for by manipulating the code & environment. However, these factors can be better accounted for with the implementation of further hardware.
Because our ESC simply outputs throttle as a function of Power, this can obviously lead to many complications.
Once the battery begins to deplete, we cannot supply the same amount of Voltage to the ESC; so even if we tell the car to move at a specific throttle value, it will not actually move at that speed! It will actually move slower.
Furthermore, if we wanted more accurate speed, implementation of Encoders would allow us to use the motor position and number of encoder counts and change in time to determine an accurate value of speed output of the motor.
Another problem we encountered, was the fact that our vehicle steering was not always straight. Multiple attempts at calibration would not fix this error. The error stemmed from imperfect hardware, namely in the steering tires and axles of the physical R/C car. The only compensation for was this was to include Aluminum suspension system and further manipulation to get the car to steer completely straight.
Final Project Completion (Photos/Videos)
Our autonomous car has found a parkable space and starts parking
Our autonomous car has found several spaces, but only one of them is parkable
Our autonomous car is performing perpendicular parking