Cu toți suntem fascinați de mașinile autonome. Cu siguranță, unii dintre noi chiar visează să-și construiască una. Din păcate avem de-a face cu costuri mari pentru realizarea unui astfel de proiect, riscuri și autorizări în ceea ce privește testarea lor. Simulatorul CARLA rezolvă toate aceste probleme prin oferirea unei soluții virtuale unde vă veți putea testa algoritmii, folosi și testa camere video, senzori lidar sau de detecție a obstacolelor. În rândurile care urmează, veți descoperi moduri de instalare a simulatorului și de încărcare a anumitor hărți, precum și principiile de bază ale controlului automobilului. La final, va fi prezentat un exemplu complet în care se va implementa frânarea de urgență.
Descărcați ultima versiune a simulatorului și lansați CarlaUE4. În cazul în care folosiți Windows instalați python 3.7 pentru rularea exemplelor. De asemenea, va trebui să instalați câteva pachete folosind utilitarul pip. Verificați și versiunea pip pe care o aveți instalată. Menționăm că ar fi bine să vă faceți un update înainte de a porni tot procesul de setup.
Tips & Tricks: Pentru rularea tuturor exemplelor pe window s-ar putea să fie nevoie să înlocuiți localhost cu 127.0.0.1
în sursele python ale acestora.
Avem de a face cu o arhitectură server - client. Serverul afișează harta 3D folosind engine-ul Unreal. Aplicațiile client se conectează la acesta pe portul 2000 și transmit comenzile. Rulăm un prim exemplu din folderul /Carla/PythonAPI/examples
:
python3 client_bounding_boxes.py
Vom începe cu un exemplu în care vom încărca o hartă specifică:
import carla
def main():
client = carla.Client('localhost',2000);
print ("Available maps:");
print(client.get_available_maps());
world=client.load_world('Town02');
if __name__ == '__main__':
main()
Creăm un obiect client prin conectarea la server pe portul 2000. Se afișează hărțile disponibile și încărcăm harta Town02
. În cazul în care se dorește revenirea la harta inițială, se va încărca Town10HD
.
Odată încărcată o hartă, putem să adăugăm obiecte, în cazul nostru va fi vorba, bineînțeles, de câteva mașini. Acestea sunt obținute din librăria globală în felul următor: world.get_blueprint_library()
. În funcție de modelul de care avem nevoie o putem interoga astfel: blueprint_lib.filter('vehicle.tesla.model3')
.
Următorul pas este să stabilim exact locul în care va fi adăugată mașina pe hartă. Un mod rapid este să obținem un punct aleatoriu astfel:
random.choice(world.get_map().get_spawn_points())
Alternativa este să definim exact locul în care aceasta va apărea așa cum se va putea vedea în exemplul următor.
Modelul mașinii împreună cu locul în care va apărea aceasta ne permite să adăugăm mașina pe hartă cu ajutorul metodei world.spawn_actor(car, transform)
.
world.spawn_actor(car, transform).
def main():
client = carla.Client('localhost',2000);
world=client.load_world('Town04');
world=client.get_world();
blueprint_lib=world.get_blueprint_library();
tesla3_bp=blueprint_lib.filter(
'vehicle.tesla.model3');
spawn_car(world, tesla3_bp[0],
carla.Transform(carla.Location(
x=-60.149902, y=33.856983, z=10.458009),
carla.Rotation(pitch=0.972154, yaw=0.076826,
roll=0.000000)));
spawn_car(world, tesla3_bp[0],
carla.Transform(carla.Location(x=-60.149902,
y=29.756983, z=10.458009),
carla.Rotation(pitch=0.972154, yaw=0.076826,
roll=0.000000)));
spawn_car(world, tesla3_bp[0],
carla.Transform(carla.Location(x=-60.149902,
y=37.356983, z=10.458009),
carla.Rotation(pitch=0.972154, yaw=0.076826,
roll=0.000000)));
spawn_car(world, tesla3_bp[0],
carla.Transform(carla.Location(x=-60.149902,
y=26.256983, z=10.458009),
carla.Rotation(pitch=0.972154, yaw=0.076826,
roll=0.000000)));
client.set_timeout(20.0);
def spawn_car(world, car, transform):
print('transform=',transform);
tesla3_auto=world.spawn_actor(car, transform);
Se observă apelarea metodei set_timeout()
care definește în secunde durata de existență a clientului.
Vom prezenta acum un exemplu complet pornind de la informațiile prezentate până acum. Este vorba de implementarea unui algoritm de frânare în două etape, în funcție de distanța detectată până la obstacol:
mai puțin de 80 de metri - vom opri accelerația și vom frâna;
Vor fi pornite patru mașini. Precizăm că în fața uneia dintre ele va fi un obstacol reprezentat de un automobil aflat în staționare.
import carla
import random;
import time;
sensor=[];
cars=[];
def main():
client = carla.Client('localhost',2000);
world=client.load_world('Town04');
world=client.get_world();
blueprint_lib=world.get_blueprint_library();
tesla3_bp=blueprint_lib.filter(
'vehicle.tesla.model3');
for x in range(4):
cars.append(spawn_car(world, tesla3_bp[0], x));
sensor.append(set_sensor(world,cars[x]));
print('car=',cars[x]);
#add obstacle car
transform=carla.Transform(
carla.Location(x=300.149902, y=26.756983,
z=10.458009), carla.Rotation(pitch=0.972154,
yaw=0.076826, roll=0.000000))
stoped_car=world.spawn_actor(tesla3_bp[0],
transform);
for x in range(4):
cars[x].apply_control(
carla.VehicleControl(throttle=1.0, steer=0.0))
while True:
time.sleep(60);
client.set_timeout(20.0);
def process_sensor(data, car):
lidar_data=data;
print("distance:",data.distance);
if (data.distance<40):
print("Stop !!!!");
car.apply_control(
carla.VehicleControl(hand_brake=True))
else:
if (data.distance<80):
print("Stop accelrating !!!!");
car.apply_control(
carla.VehicleControl(throttle=0.0,
brake=1.0))
def set_sensor(world, car):
blueprint_obstacle =
world.get_blueprint_library().
find("sensor.other.obstacle");
print('obstacle=',blueprint_obstacle);
blueprint_obstacle.
set_attribute('distance','100');
transform = carla.Transform(carla.Location(x=1.0,
z=1.8));
sens= world.spawn_actor(blueprint_obstacle,
transform, attach_to=car);
sens.listen(lambda data: process_sensor(data,
car));
return sens;
def spawn_car(world, car, index):
transform=carla.Transform(
carla.Location(x=-60.149902,
y=(26.256983+3.5*index), z=10.458009),
carla.Rotation(pitch=0.972154, yaw=0.076826,
roll=0.000000))
print('transform=',transform);
tesla3_auto=world.spawn_actor(car, transform);
return tesla3_auto;
if __name__ == '__main__':
main()
Fiecare mașină are atașat un senzor de detecție a obstacolelor obținut din librăria CARLA: sensor.other.obstacle
. Acestuia îi este stabilită distanța de detecție începând cu 100 m, fiind generat prin atașarea la fiecare automobil. Datele procesate de acesta sunt trimise printr-un callback la metoda process_data
împreună cu obiectul car
la care este atașat.
sens.listen(lambda data: process_sensor(data, car));
Controlul mașinilor este realizat prin metoda apply_control
care poate primi o listă de parametri cu valori între 0.0 și 1.0: trotthle
, steer
, brake
și hand_brake
, de tip boolean.
Sperăm ca prin acest articol v-am deschis apetitul pentru simularea conducerii unui automobil. Putem ajunge chiar la un algoritm de autonomous driving și - de ce nu ?- să îl folosim ulterior pentru testare pe o mașină reală.