Autonomous Vehicle With Artificial Intelligence — Python AI

Bayram EKER
6 min readDec 18, 2022

--

Autonomous vehicle

Autonomous vehicle is the general name of vehicles with self-driving feature. In short, it is the ability of the vehicle to evaluate the environmental factors while driving and to choose both the safe and the shortest road. If we look at the content of this ability, it is the structure in which the vehicle controls the driving management by controlling the data coming from the sensors inside and outside the vehicle. Although it is aimed to do the driving management with artificial intelligence systems, it should also be controlled by the human eye.

If we consider the decisions that a person makes with his consciousness while driving, and if we assume that we control them with our eyes in general, we do them with a camera in machine learning and artificial intelligence. We transform the frames we take with the camera into formats that we can examine with the help of certain filters. We examine these converted formats with the help of the libraries we have and send certain commands to the control mechanism of the car.

Self driving feature has not been fully implemented yet and it is not completely preferable and there is no legal freedom to go on the road.

Although these vehicle systems have the potential to make our lives easier, they also have great dangers. For example, there are problems such as the sensors not being able to read the data correctly, the sensors working problems and weak connections, and there are many events that cannot be calculated in real life and it is impossible to predict them, so it is not the right behavior to completely rely on the software environment and delegate all possible choices to artificial systems.

In this article, I want to show you in practice with the help of python. You can download and develop the codes of the application on github.

Example Application with Python

We will program our autonomous vehicle with Python pygame to reach the finish line in the simulation environment.

The vehicle will start from a certain pixel point and follow the black colored path and when it reaches the white areas, the vehicle will be removed from the race.

In this environment where we will adjust the fps and vehicle speed, there will be 1000 generations.

The project is open to development.

First of all, let’s look at the libraries we will use

import math
import random
import sys
import os
import neat
import pygame

Let’s determine the values ​​we need to initialize

WIDTH = 1920
HEIGHT = 1080

CAR_SIZE_X = 60
CAR_SIZE_Y = 60

BORDER_COLOR = (255, 255, 255, 255) # Color To Crash on Hit

current_generation = 0 # Generation counter

Let’s create the car class

class Car:

def __init__(self):
# Load Car Sprite and Rotate
self.sprite = pygame.image.load('car.png').convert() # Convert Speeds Up A Lot
self.sprite = pygame.transform.scale(self.sprite, (CAR_SIZE_X, CAR_SIZE_Y))
self.rotated_sprite = self.sprite

# self.position = [690, 740] # Starting Position
self.position = [830, 920] # Starting Position
self.angle = 0
self.speed = 0

self.speed_set = False # Flag For Default Speed Later on

self.center = [self.position[0] + CAR_SIZE_X / 2, self.position[1] + CAR_SIZE_Y / 2] # Calculate Center

self.radars = [] # List For Sensors / Radars
self.drawing_radars = [] # Radars To Be Drawn

self.alive = True # Boolean To Check If Car is Crashed

self.distance = 0 # Distance Driven
self.time = 0 # Time Passed

def draw(self, screen):
screen.blit(self.rotated_sprite, self.position) # Draw Sprite
self.draw_radar(screen) #OPTIONAL FOR SENSORS

def draw_radar(self, screen):
# Optionally Draw All Sensors / Radars
for radar in self.radars:
position = radar[0]
pygame.draw.line(screen, (0, 255, 0), self.center, position, 1)
pygame.draw.circle(screen, (0, 255, 0), position, 5)

def check_collision(self, game_map):
self.alive = True
for point in self.corners:
# If Any Corner Touches Border Color -> Crash
# Assumes Rectangle
if game_map.get_at((int(point[0]), int(point[1]))) == BORDER_COLOR:
self.alive = False
break

def check_radar(self, degree, game_map):
length = 0
x = int(self.center[0] + math.cos(math.radians(360 - (self.angle + degree))) * length)
y = int(self.center[1] + math.sin(math.radians(360 - (self.angle + degree))) * length)

# While We Don't Hit BORDER_COLOR AND length < 300 (just a max) -> go further and further
while not game_map.get_at((x, y)) == BORDER_COLOR and length < 300:
length = length + 1
x = int(self.center[0] + math.cos(math.radians(360 - (self.angle + degree))) * length)
y = int(self.center[1] + math.sin(math.radians(360 - (self.angle + degree))) * length)

# Calculate Distance To Border And Append To Radars List
dist = int(math.sqrt(math.pow(x - self.center[0], 2) + math.pow(y - self.center[1], 2)))
self.radars.append([(x, y), dist])

def update(self, game_map):
# Set The Speed To 20 For The First Time
# Only When Having 4 Output Nodes With Speed Up and Down
if not self.speed_set:
self.speed = 20
self.speed_set = True

# Get Rotated Sprite And Move Into The Right X-Direction
# Don't Let The Car Go Closer Than 20px To The Edge
self.rotated_sprite = self.rotate_center(self.sprite, self.angle)
self.position[0] += math.cos(math.radians(360 - self.angle)) * self.speed
self.position[0] = max(self.position[0], 20)
self.position[0] = min(self.position[0], WIDTH - 120)

# Increase Distance and Time
self.distance += self.speed
self.time += 1

# Same For Y-Position
self.position[1] += math.sin(math.radians(360 - self.angle)) * self.speed
self.position[1] = max(self.position[1], 20)
self.position[1] = min(self.position[1], WIDTH - 120)

# Calculate New Center
self.center = [int(self.position[0]) + CAR_SIZE_X / 2, int(self.position[1]) + CAR_SIZE_Y / 2]

# Calculate Four Corners
# Length Is Half The Side
length = 0.3 * CAR_SIZE_X
left_top = [self.center[0] + math.cos(math.radians(360 - (self.angle + 30))) * length, self.center[1] + math.sin(math.radians(360 - (self.angle + 30))) * length]
right_top = [self.center[0] + math.cos(math.radians(360 - (self.angle + 150))) * length, self.center[1] + math.sin(math.radians(360 - (self.angle + 150))) * length]
left_bottom = [self.center[0] + math.cos(math.radians(360 - (self.angle + 210))) * length, self.center[1] + math.sin(math.radians(360 - (self.angle + 210))) * length]
right_bottom = [self.center[0] + math.cos(math.radians(360 - (self.angle + 330))) * length, self.center[1] + math.sin(math.radians(360 - (self.angle + 330))) * length]
self.corners = [left_top, right_top, left_bottom, right_bottom]

# Check Collisions And Clear Radars
self.check_collision(game_map)
self.radars.clear()

# From -90 To 120 With Step-Size 45 Check Radar
for d in range(-90, 120, 45):
self.check_radar(d, game_map)

def get_data(self):
# Get Distances To Border
radars = self.radars
return_values = [0, 0, 0, 0, 0]
for i, radar in enumerate(radars):
return_values[i] = int(radar[1] / 30)

return return_values

def is_alive(self):
# Basic Alive Function
return self.alive

def get_reward(self):
# Calculate Reward (Maybe Change?)
# return self.distance / 50.0
return self.distance / (CAR_SIZE_X / 2)

def rotate_center(self, image, angle):
# Rotate The Rectangle
rectangle = image.get_rect()
rotated_image = pygame.transform.rotate(image, angle)
rotated_rectangle = rectangle.copy()
rotated_rectangle.center = rotated_image.get_rect().center
rotated_image = rotated_image.subsurface(rotated_rectangle).copy()
return rotated_image

Let’s write our function that starts the simulation

def run_simulation(genomes, config):

# Empty Collections For Nets and Cars
nets = []
cars = []

# Initialize PyGame And The Display
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT), pygame.FULLSCREEN)

# For All Genomes Passed Create A New Neural Network
for i, g in genomes:
net = neat.nn.FeedForwardNetwork.create(g, config)
nets.append(net)
g.fitness = 0

cars.append(Car())

# Clock Settings
# Font Settings & Loading Map
clock = pygame.time.Clock()
generation_font = pygame.font.SysFont("Arial", 30)
alive_font = pygame.font.SysFont("Arial", 20)
game_map = pygame.image.load('map.png').convert() # Convert Speeds Up A Lot

global current_generation
current_generation += 1

# Simple Counter To Roughly Limit Time (Not Good Practice)
counter = 0

while True:
# Exit On Quit Event
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit(0)

# For Each Car Get The Acton It Takes
for i, car in enumerate(cars):
output = nets[i].activate(car.get_data())
choice = output.index(max(output))
if choice == 0:
car.angle += 10 # Left
elif choice == 1:
car.angle -= 10 # Right
elif choice == 2:
if(car.speed - 2 >= 12):
car.speed -= 2 # Slow Down
else:
car.speed += 2 # Speed Up

# Check If Car Is Still Alive
# Increase Fitness If Yes And Break Loop If Not
still_alive = 0
for i, car in enumerate(cars):
if car.is_alive():
still_alive += 1
car.update(game_map)
genomes[i][1].fitness += car.get_reward()

if still_alive == 0:
break

counter += 1
if counter == 30 * 40: # Stop After About 20 Seconds
break

# Draw Map And All Cars That Are Alive
screen.blit(game_map, (0, 0))
for car in cars:
if car.is_alive():
car.draw(screen)

# Display Info
text = generation_font.render("Generation: " + str(current_generation), True, (0,0,0))
text_rect = text.get_rect()
text_rect.center = (900, 450)
screen.blit(text, text_rect)

text = alive_font.render("Still Alive: " + str(still_alive), True, (0, 0, 0))
text_rect = text.get_rect()
text_rect.center = (900, 490)
screen.blit(text, text_rect)

pygame.display.flip()
clock.tick(20) # 60 FPS

let’s run

--

--

Responses (1)