This project aimed to create an autonomous driving car using computer vision to lane keep and automatically detect stop signs. We accomplished this using a Raspberry Pi 4B and a Python program that utilized the OpenCV library. OpenCV was used to program the car to move on its own following blue lines making up lanes, and stop automatically when detecting the color orange/red. We used the tutorial here and the projects here and here as a starting point for this project.
User raja_961, "Autonomous Lane-Keeping Car Using Raspberry Pi and OpenCV". Instructables. URL: https://www.instructables.com/Autonomous-Lane-Keeping-Car-Using-Raspberry-Pi-and/
The Nicomobile Hackster Project. URL: https://www.hackster.io/team-youngerwoods/the-nicomobile-83caa9
The Access Code Cybertruck Hackster Project. URL: https://www.hackster.io/497395/access-code-cybertruck-9f8b8cProportional & Derivative Gain, Resolution
Proportional gain determines how aggressively the car reacts to deviation from the lanes. A higher value will cause the car to steer more sharply in response to a deviation, but if set too high, it could lead to oscillations. After trial and error, we decided the best proportional gain to use for our car was kp = 0.2. Derivative gain helps to counteract overshooting caused by proportional gain by considering the rate of change of the deviation. Our final value of kd = 0.5 was also determined experimentally.
The camera resolution needed to balance being high enough to support accurate lane-keeping and stopping abilities, yet low enough for rapid visual data processing. We decided to use a frame of size 320x240, which seemed to balance the two well.
Handling Stop BoxWe used the OpenCV library for color detection and image processing to determine when and where the car should stop. Specifically, the detect_stop_sign() function converts the camera from the BGR color space to HSV to make it easier to isolate colors. It then defines a lower and upper threshold in the HSV color space to filter out colors. The HSV values [0, 40, 60] and [20, 80, 100] are in the red/orange color range since that was the color of the stop box. The function then creates a mask to isolate pixels in that color range and checks if the number of relevant pixels is greater than or equal to 30 (which indicates a stop sign was detected).
def detect_stop_sign(frame):
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_red = np.array([0, 40, 60], dtype = "uint8")
upper_red = np.array([20, 80, 100], dtype="uint8")
mask = cv2.inRange(hsv,lower_red,upper_red)
# detect stop sign
num_red_px = cv2.countNonZero(mask)
print("num_red_px: ", num_red_px)
return num_red_px >= 30
detect_stop_sign() was then called in the main function's while loop, and the car would stop for a few seconds before continuing if encountering the first stop sign or stop permanently if encountering the second stop sign.
# In the main loop
```
if detect_stop_sign(frame):
if (last_stopped == -1):
toggle_throttle(False, True)
print("STOP DETECTED STOP DETECTED STOP DETECTED STOP DETECTED ")
last_stopped = time.time()
while (time.time() - last_stopped < 3):
print("waiting")
elif (time.time() - last_stopped >= 20):
toggle_throttle(False, True)
break
else:
print("not waiting")
```
PlotsWe were unable to generate a plot for error, steering voltage or duty cycle, and speed voltage or duty cycle versus frame number since we had to modify our hardware setup as described below (see the Hardware section).
The following plot shows the error, proportional response, and derivative response versus the frame number for the run. The proportional response seems to follow the error linearly, which matches expectations.
The following images demonstrate how we assembled the hardware components on the RC car:
The base of the car was a standard remote control car. It used a servo for steering and a brushed DC motor for speed. It ran on a 2s battery and was 4-wheel drive. We had wanted to directly control the esc and servo with the Raspberry Pi, but unfortunately, our speed controller was integrated into the radio receiver. The initial plan was to use the remote, desolder the potentiometers for steering and throttle, and use a DAC to give inputs. However, our attempts were unsuccessful and we ended up burning the solder pads.
We decided to go a different route. Since the car used a brushed DC motor, we could control the speed simply by changing the voltage. We wanted a constant speed, so we decided to use a buck converter to reduce the voltage to 3.5 volts (from ~7.8v from the battery). We used a relay controlled by the pi to close the circuit. This way, the pi could make the car go and stop. However, we found that the DC motor had very low torque and would not move if we reduced the voltage below 3.5v and still wanted to go relatively fast. We addressed this by pulsing the motor.
Video DemonstrationThe following video demonstrates how the car momentarily stops at the first detected stop sign and stops permanently at the second/last stop sign:
The following video demonstrates how the car lane keeps and turns:
Referenceshttps://www.instructables.com/Autonomous-Lane-Keeping-Car-Using-Raspberry-Pi-and/
https://www.hackster.io/team-youngerwoods/the-nicomobile-83caa9
https://www.hackster.io/497395/access-code-cybertruck-9f8b8c
Comments
Please log in or sign up to comment.