driving simulator

包括Carla在内的四种驾驶模拟器

ERAF post this 17169 words blog on August 14, 2018

其他驾驶模拟器软件

MATLAB 2017

MATLAB作为一类专业的商业数学软件,用于算法开发、数据可视化、数据分析以及数值计算的高级技术计算语言和交互式环境 ;而针对我们所需要的自主驾驶这个领域,有一个Automated Driving System Toolbox;可以实现一些对于感知层数据的操作,比如:自动从车载摄像头采集到的视频进行物体标注 、为驾驶场景合成传感数据、进行多传感器的融合、设计和模拟视觉系统等;「主要是对感知层的传感数据的处理,比如图片中的目标追踪」

相关的App包括:

  • Ground Truth Labeler : 可以用来进行标记 来验证目标检测的应用;它自动的对道路数据进行自动标记,比如驾驶视频或者图片;可以逐帧对图像中感兴趣的部分进行表明;同时也允许输入算法来自动的标记需要的,同时提供API来对于目标检测结果进行评估;

    包括 道路数据的标注的函数类;对标注结果评估的函数类

  • Object and Lane Boundary Detection: 可以使用机器学习方法来对于图片中的 道路边缘 行人 车辆等 进行检测 识别 分割等;

    包括 基于ML的目标检测;基于DL(各种网络结构)的目标检测;道路边缘检测;

  • Tracking and Sensor Fusion:目标追踪 多传感器信息的融合进而目标追踪,绘制鸟瞰图等;

    包括 多目标的追踪;利用卡尔曼滤波来进行追踪;获取动作模型;绘制鸟瞰图

  • Sensor Configuration and Coordinate System Transforms:相机传感器配置,图像到车辆坐标系统转换,鸟瞰图像变换。

    包括:配置单目传感数据;鸟瞰图的转换

  • Algorithm Validation and Visualization:对于目标和道路检测的结果的评估;还有一系列对于各类图像的处理:鸟瞰图、前向视频、点云图

    有一系列在之前的模块已有的函数,这里把他们提取出来放在一块 方便查阅;

    包括: 目标和道路检测结果的评估; 鸟瞰图的绘制;鸟瞰图视角的相关操作;传感视频的相关操作;视频数据的注释;点云图的相关操作

  • Driving Scenario Generation and Sensor Models:用雷达和相机传感器模型进行综合探测的场景生成。

    1. 借助这个应用中的相关参数,可以用于绘制道路场景
      s = drivingScenario;
      
      roadCenters = [0 0; 50 0];
      roadWidth = 6;
      
      road(s, roadCenters, roadWidth);
      plot(s,'RoadCenters','on','Centerline','on');
    

    1. 我们可用建造简单的车辆模型,进行操作; 下面为一个鸟瞰图 客厅转化为3D图

      s = drivingScenario;
      rav = vehicle(s);
      rav.Position = [0 -2 0]
      plot(s)
      

      比如参看MATLAB中给出的示范,可以创建出来一条交通流,可以完成对于前车的追踪 进而完成避障等实验;「传感器融合、模拟高速路况、车流」

      #首先定义场景路况
      scenario = drivingScenario;
      scenario.SampleTime = 0.01;
            
      #添加一段500米长的双道道路,定义的方式是一系列点 点分别定义了3D空间的中心和道路宽度
      roadCenters = [0 0; 50 0; 100 0; 250 20; 500 40];
      roadWidth = 7.2; % Two lanes, each 3.6 meters
      road(scenario, roadCenters, roadWidth);
            
      #然后定义车辆 包括:本身车辆和周围3辆车辆「默认靠右行驶」,一辆从左边超车、一辆在车前行驶、一辆在车后行驶;然后都在定义车道上行驶 使用路径行驶策略,而超车策略是从右车道移动到左车道再回到右车道;
            
      % 默认车辆,以25m/s的速度
      egoCar = vehicle(scenario, 'ClassID', 1);
      path(egoCar, roadCenters(2:end,:) - [0 1.8], 25); % On right lane
            
      % 默认车辆 周围车辆
      leadCar = vehicle(scenario, 'ClassID', 1);
      path(leadCar, [70 0; roadCenters(3:end,:)] - [0 1.8], 25); % On right lane
            
      % 超车车辆 速度为35m/s 用于超车
      passingCar = vehicle(scenario, 'ClassID', 1);
      waypoints = [0 -1.8; 50 1.8; 100 1.8; 250 21.8; 400 32.2; 500 38.2];
      path(passingCar, waypoints, 35);
            
      % 周围车后车辆
      chaseCar = vehicle(scenario, 'ClassID', 1);
      path(chaseCar, [25 0; roadCenters(2:end,:)] - [0 1.8], 25); % On right lane
      

      定义玩车辆和场景后 我们需要定义雷达和传感器来覆盖三百六十度的场景;本身车辆有着 6 radar sensors and 2 vision sensors ;当然 这里的sensor的范围会有一些重叠和间隙;本身车辆配备了远程雷达传感器和视觉传感器在车辆的前面和后面 ;同时 车辆两侧各有两个短程雷达传感器,每个传感器覆盖90度。 每一侧的两个传感器:一个覆盖了车辆从中间到后面的区域、一个覆盖从前到中间的区域;

      sensors = cell(8,1);
      % Front-facing long-range radar sensor at the center of the front bumper of the car.
      sensors{1} = radarDetectionGenerator('SensorIndex', 1, 'Height', 0.2, 'MaxRange', 174, ...
          'SensorLocation', [egoCar.Wheelbase + egoCar.FrontOverhang, 0], 'FieldOfView', [20, 5]);
            
      % Rear-facing long-range radar sensor at the center of the rear bumper of the car.
      sensors{2} = radarDetectionGenerator('SensorIndex', 2, 'Height', 0.2, 'Yaw', 180, ...
          'SensorLocation', [-egoCar.RearOverhang, 0], 'MaxRange', 174, 'FieldOfView', [20, 5]);
            
      % Rear-left-facing short-range radar sensor at the left rear wheel well of the car.
      sensors{3} = radarDetectionGenerator('SensorIndex', 3, 'Height', 0.2, 'Yaw', 120, ...
          'SensorLocation', [0, egoCar.Width/2], 'MaxRange', 30, 'ReferenceRange', 50, ...
          'FieldOfView', [90, 5], 'AzimuthResolution', 10, 'RangeResolution', 1.25);
            
      % Rear-right-facing short-range radar sensor at the right rear wheel well of the car.
      sensors{4} = radarDetectionGenerator('SensorIndex', 4, 'Height', 0.2, 'Yaw', -120, ...
          'SensorLocation', [0, -egoCar.Width/2], 'MaxRange', 30, 'ReferenceRange', 50, ...
          'FieldOfView', [90, 5], 'AzimuthResolution', 10, 'RangeResolution', 1.25);
            
      % Front-left-facing short-range radar sensor at the left front wheel well of the car.
      sensors{5} = radarDetectionGenerator('SensorIndex', 5, 'Height', 0.2, 'Yaw', 60, ...
          'SensorLocation', [egoCar.Wheelbase, egoCar.Width/2], 'MaxRange', 30, ...
          'ReferenceRange', 50, 'FieldOfView', [90, 5], 'AzimuthResolution', 10, ...
          'RangeResolution', 1.25);
            
      % Front-right-facing short-range radar sensor at the right front wheel well of the car.
      sensors{6} = radarDetectionGenerator('SensorIndex', 6, 'Height', 0.2, 'Yaw', -60, ...
          'SensorLocation', [egoCar.Wheelbase, -egoCar.Width/2], 'MaxRange', 30, ...
          'ReferenceRange', 50, 'FieldOfView', [90, 5], 'AzimuthResolution', 10, ...
          'RangeResolution', 1.25);
            
      % Front-facing camera located at front windshield.
      sensors{7} = visionDetectionGenerator('SensorIndex', 7, 'FalsePositivesPerImage', 0.1, ...
          'SensorLocation', [0.75*egoCar.Wheelbase 0], 'Height', 1.1);
            
      % Rear-facing camera located at rear windshield.
      sensors{8} = visionDetectionGenerator('SensorIndex', 8, 'FalsePositivesPerImage', 0.1, ...
          'SensorLocation', [0.2*egoCar.Wheelbase 0], 'Height', 1.1, 'Yaw', 180);
      

      进而创建一个multiObjectTracker来追踪靠近自我车辆的车辆;首先使用 initSimDemoFilter 这个函数来初始化一个恒速线性卡尔曼滤波器用于生成速度和位置;

      tracker = multiObjectTracker('FilterInitializationFcn', @initSimDemoFilter, ...
          'AssignmentThreshold', 30, 'ConfirmationParameters', [4 5]);
      positionSelector = [1 0 0 0; 0 0 1 0]; % Position selector
      velocitySelector = [0 1 0 0; 0 0 0 1]; % Velocity selector
            
      % Create the display and return a handle to the bird's-eye plot
      BEP = createDemoDisplay(egoCar, sensors);
      

      在完成上面的配置之后,下面开始循环运动车辆,调用传感器模拟,并执行跟踪。

      注意:这里的常见生成和传感器模拟可有着不同的time steps,进而方便高精度建模;

      这里的场景生成为0.01s,而传感器为0.1s;这里 传感器会返回一个标示isValidTime 当传感器的生成被检测到的时候 其为true;于是 追踪器会在此标志有检测时才会被调用。

      同时 传感器可以模拟每个目标的多次探测,特别是当目标非常接近雷达传感器时。因为跟踪器假设每个传感器对每个目标进行一次检测,于是在追踪器处理这些数据之前 需要对其进行cluster;有着专门的函数clusterDetections;

      toSnap = true;
      while advance(scenario) && ishghandle(BEP.Parent)
          % 获取场景时间
          time = scenario.SimulationTime;
            
          % 在自我车辆的坐标系中获取其他车辆的位置
          ta = targetPoses(egoCar);
            
          % 模拟传感器
          detections = {};
          isValidTime = false(1,8);
          for i = 1:8
              [sensorDets,numValidDets,isValidTime(i)] = sensors{i}(ta, time);
              if numValidDets
                  for j = 1:numValidDets
                      % 可视传感检测不能报告SNR「信噪比?」;但跟踪器要求它们具有与雷达探测相同的目标属性。这将把SNR对象属性添加到视觉检测中,并将其设置为NaN。
                      if ~isfield(sensorDets{j}.ObjectAttributes{1}, 'SNR')
                          sensorDets{j}.ObjectAttributes{1}.SNR = NaN;
                      end
                  end
                  detections = [detections; sensorDets]; %#ok<AGROW>
              end
          end
            
            
          % 当追踪器有着新检测的时候进行更新
          if any(isValidTime)
              vehicleLength = sensors{1}.ActorProfiles.Length;
              detectionClusters = clusterDetections(detections, vehicleLength);
              confirmedTracks = updateTracks(tracker, detectionClusters, time);
            
              % 更新鸟瞰图的显示
              updateBEP(BEP, egoCar, detections, confirmedTracks, positionSelector, velocitySelector);
          end
            
          % Snap a figure for the document when the car passes the ego vehicle
          if ta(1).Position(1) > 0 && toSnap
              toSnap = false;
              snapnow
          end
      end
      

      其他的一些支持函数 可以在帮助文档中自行查看;

Carsim

主要是为了验证车辆整车的操作稳定性、动力学特性、舒适性等;参考界面可知

其中的功能模块可以分为三类:模型和工况参数的设置;数学模型的求解;输出和后续处理部分

  • 模型和实况参数的设定: 顾名思义需要对于车辆参数的设定以及车辆测试路况的设置;对于前者首先需要搭建整车模型,包括选定车型 进而对于参数设置来达到对于真实车辆的模拟,主要参数包括三类:转向系「运动学和弹性动力学」、悬架「动力学和弹性动力学」和传动系「发动机 变速器 差速器等」;测试工况的话 设置相关车辆的驾驶环境「初始速度 驾驶员制动模式 转向模式 档位输入等」和相关因素:路面信息和风阻
  • 数学模型求解:求解运算 提供和外界环境的接口 比如simulink等,其实也就是对之前设置的模型的封装成为一个simulink的S函数 设置好输入数据和输出信息 加控制器模块 外部输入信息就完成一个仿真环境;
  • 输出和后续处理:对于仿真结果的显示 可以选取3D动画或者数据绘图方法;

换句话说 当你对车辆动力学有着足够的了解的时候,你可以在carsim里面进行自定义你所需要的车辆,更为准确的说 你可以定义下列这些参数:

同时你可以设置好车辆所在的驾驶环境「初始速度 转向控制等等」参考如下:

此外还可以基于控制理论的方法 建立的驾驶员模型应用其中,如下设置驾驶员的预瞄时间 最大转向角等建立起来基于控制理论的驾驶员模型:

进而完成各类设置后,可以使用carsim和simulink的联合,进行试验;从上面的介绍我们也能看出来 carsim比较偏控制类的方法 涉及的更多是对于车辆动力学的探讨;

Udacity simulator

一个驾驶模拟器,根据驾驶界面 可以知道其分为手动驾驶模式和自主驾驶模式,对于前者可以用于收集数据,进行参考end to end learning for self-driving cars这篇文章里面 进行完成训练模型用于第二种模式的使用;

emmmm 对于驾驶场景数据的收集,然后进行训练模型 看过上面的E2E文章 也就大概知道,这其实就是个训练CNN的过程,最多再加一些图像处理的东西;然后数据生成、模型建立、训练步骤的优化等等就是仁者见仁智者见智的过程了,谁都有着的习惯与风格,这里就不再赘述;

这里说一下关于其中自主驾驶所需要的相关代码;

这里所采取的是python本身socketio库,emmmm 其实相比于后来又封装过的 Flask-SocketIO 来说 其实要更为底层一些的,其实所采用的目的都是一样的:基于flask应用和socketio协议建立起来一个服务器 以实现客户端与服务器之间低延迟的双向通信。

进而如果看过socketio官方文档之后,也就能知道官方给出的示范drive.py里面有关建立服务器的代码其实也是官方的一个例子:使用socketio建立起来server对象,在其中描述需要执行的事件「服务器端需要执行的活动」,然后与flask建立的应用,用middleware进行封装 ,然后选择eventlet.wsgi 这样的事件驱动的服务器类型, 进而建立好了服务器「socketio作为一种传输协议 肯定有server和client,于是首先基于协议建立起来的server对象 和实际使用flask建立起来的server 借助socketio.Middleware封装合并,然后选择服务器的类型 wsgi.server() 设置好监听对应的地址、端口等,将请求传递给 WSGI 中的应用(也就是我们基于flask和socketio建立起来的app)进行处理 进而建立起来server,可以和上面驾驶模拟器这样的客户端进行联动」「站在wsgi.server 的角度来说 就是前面设置好端口,后面基于flask和socketio设置好实现WSGI应用的函数」「待修改」

然后作为server的一端 我们只需要完成计算驾驶转向角和发送控制指令的事件即可;

前者通过解析来自于client的二进制包,得到驾驶场景的图片,进而加载模型进行计算驾驶角度,完成计算后 将控制指令进行发送出去;

@sio.on('telemetry')
def telemetry(sid, data):
    # The current steering angle of the car
    steering_angle = data["steering_angle"]
    # The current throttle of the car
    throttle = data["throttle"]
    # The current speed of the car
    speed = data["speed"]
    # The current image from the center camera of the car
    imgString = data["image"]
    image = Image.open(BytesIO(base64.b64decode(imgString)))
    image_array = np.asarray(image)
    transformed_image_array = image_array[None, :, :, :]
    # This model currently assumes that the features of the model are just the images. Feel free to change this.
    steering_angle = float(model.predict(transformed_image_array, batch_size=1)) * 5.0
    # The driving model currently just outputs a constant throttle. Feel free to edit this.
    speed = float(speed)
    if speed > 15:
        throttle = 0.1
    else:
        throttle = 0.2
    print(steering_angle, throttle)
    send_control(steering_angle, throttle)


def send_control(steering_angle, throttle):
    sio.emit("steer", data={
    'steering_angle': steering_angle.__str__(),
    'throttle': throttle.__str__()
    }, skip_sid=True)

##### 以下为个人使用时候的一些吐槽

  • 数据采集「驾驶员操作」

    这方面封装的比较完善,可以直接借助鼠标键盘等采集驾驶可视数据、转向角度、速度、加速度等参数,而不需要另外借助pygame来封装一个监听键盘按键或者鼠标移动的类 才能收集数据 「说的就是Carla」,同时可以根据按下的时间来产生对应的结果 也就是产生的转向角能够在[-1,1]之间浮动;

  • 自主驾驶

    这方面就不够好,并没有详细封装相关的API ,只是单纯给出一个二进制的包,无论是基于可视数据的预测 还是预测结果输入到client都需要,对这个包进行转化后,而读取或者输入;

    同时进行自主驾驶操作的时候 需要借助socketio建立server,利用flask对于模拟器建立client 进行监听特定接口来收取这个二进制的包 ,建立事件 输入操作指令等等;

    「如果是一个训练好的模型 也就是E2E这样的 基于收集的数据直接训练好不需要借助它的自主驾驶模式来训练,只是单纯的test其实还好;但是如果想基于这个simulator建立一个马尔科夫过程的Env类,来与agent交互 进而训练就成为了一个困难的事情,受限于python中的socketio 库本身的问题 建立的server类 不能自动结束进程,只会一直等待下去 于是关闭的话 只能手动结束进程;这也就给MDP过程带来了很大的难题 毕竟更新agent 需要设置众多episode,每个episode开始的时候都需要手动重启」

    综上 这个驾驶模拟器只适合作为test环境,而不适合用来train;

Carla

对于Carla的介绍分为两部分 一个是对于构造的介绍 方便进行包括测试数据的收集和训练模型使用,另一个就是其中benchmark的使用 可以用于test,或者参照着来写训练过程把;

对于Carla来说,也可以实现上面simulator的两者操作:手动驾驶和自主驾驶两种模式,前者我们可以借助pygame来收集驾驶数据「借助pygame来检测键盘的按键情况 进而转化为对应的控制指令的数值;而驾驶场景图片的获取来自于下面要说的carla_client」;然后是自主驾驶模式 这里从示范代码中也能看出来 :Carla从结构上分为两部分,一个是由simulator构造而成的server,另外一部分是借助python构造而成的client;

Carla的server

Carla的驾驶模拟器包括了两个模式,借助命令:CarlaUE4.exe 来单独的运行这个模拟器,进入模式:standalone mode:得到的就是单纯的驾驶模拟器 可以借助键盘操作; 后面也有一些命令来设置相关参数:如

CarlaUE4.exe /Game/Maps/Town02 -windowed -ResX=800 -ResY=600

就是设置好地图后 窗口化以800x600来运行程序;

而这很明显不能和client产生交互,无法作为env来输出图像和measurement并接受来自client的控制命令。这时候就需要在后面加上-carla-server,这个命令启动 使驾驶模拟器进入server mode; 才能与client产生交互,进而:

CarlaUE4.exe -carla-server /Game/Maps/Town02 -windowed -ResX=800 -ResY=600 

就构成了一个在Town02场景下以窗口化运行800x600的server;

和上面的Udacity的模拟器相比 这里的server封装到了模拟器之中,而Udacity的是是将模拟器和client封装在一起的,所以我们能看到这里的区别之处:Udacity需要在建立server的时候 同时完成 接受来自模拟器「client」的二进制数据转化为图片,来计算控制指令;

而Carla是将模拟器和server封装在一起,于是计算操作指令的操作被放在了后面用python写成的client里面,但和Udacity不同之处在于 这里不需要那一步: 二进制数据的转化步骤 可以直接获取场景图片,同时此外还可以设置图片的素质 视角等等,更重要的是还可以获取来自场景的测量数据等;

对于Carla的服务器来说 会把每一帧的画面和对应的测量数据返回到client; 以下通过对两类返回数据进行介绍:

Image

返回图像的数据需要借助每个episode设置的setting.ini文件 来设置的对于sensor的信息,来得到不同类型的图片,包括:大小 位置 类型,种类,示例如下:

# 默认图片为RGB,PostProcessing = 'SceneFinal'
camera0 = Camera('CameraRGB')
#设置视野 
camera.set(FOV=90.0) #file of view
# 设置图像像素.
camera0.set_image_size(800, 600)
# 设置camera距离车辆的位置米数.
camera0.set_position(0.30, 0, 1.30)
#三姿态角
camera.set_rotation(pitch=0, yaw=0, roll=0)
settings.add_sensor(camera0)

#设置激光雷达
lidar = Lidar('Lidar32')
lidar.set_position(0, 0, 2.50)
lidar.set_rotation(0, 0, 0)
lidar.set(
    hannels=32,
    Range=50,
    PointsPerSecond=100000,
    RotationFrequency=10,
    UpperFovLimit=10,
    LowerFovLimit=-30)
settings.add_sensor(lidar)

Measurement

measurement包括本实验可能所要使用的包括agent的transform「位置信息和姿态信息(滚动角 俯仰角 水平角)」 前向速度、加速度等,「agent就是后面基于client来操作的对象」此外Carla因其还可以设置场景信息 比如其中的行人和其他车辆的参数,于是还可以返回包括:

  • collision_vehicle 和其他车辆的碰撞强度 float
  • collision_pedestrians 和行人碰撞强度 float
  • collision_other 和除了车辆和行人之外的碰撞强度 float
  • intersection_otherlane 车辆变道到其他车道的可能性 float
  • intersection_offroad 车辆脱离车道的可能性 float;

此外相关的Non-player信息也可以设置 虽然本实验用不到:

  • Vehicle Contains its transform, box-extent, and forward speed.
  • Pedestrian Contains its transform, box-extent, and forward speed. (*)
  • Traffic light Contains its transform and state (green, yellow, red).
  • Speed-limit sign Contains its transform and speed-limit.

这里的box-extent是指Carla中所有物体都有bounding box,可准确定位 类似于下图,可以看到车辆有着本体范围大小

carla物体

Carla的client

client被用来设置发送控制信息,同时包括设置文件也可以借助其来配置,可设置参数包括:

  • steer: float [-1.0, 1.0]之间的转向角 throttle: float [ 0.0, 1.0]之间的油门 brake: float [ 0.0, 1.0]之间的刹车 hand_brake: bool 是否开启手动刹车 reverse: bool 车辆是否在倒车

为了效率考虑,最好考虑到client中迭代的每个episode,提前设置好对应的setting文件,用于每个episode读取:

if args.seetings_filepath:
    with open(args.settings_filepath, 'r') as fp:
        settings=fp.read()
#然后把他们读取到server即可,
#server依赖于(scene)场景描述 特别是玩家的初始位置从函数是start_episode()
#唯一的形参是player_start_index就知道了

#提供方式包括两种:提供一个CarlaSetting object
#或者 string的CarlaSetting.ini文件
scene=client.load_settings(settings)
#返回一个包含场景描述的protobuf对象
#这里我们随机选择一个玩家开始的初始位置
number_of_player_starts = len(scene.player_start_spots)
player_start = random.randint(0, max(0, number_of_player_starts - 1))

#告诉服务器想让这个episode开始的玩家位置的索引,
#到此这个函数会阻塞 直到server开始这个episode
print('Starting new episode...')

client.start_episode(player_start)

开启一个新的episode需要的是player的初始位置,设置成同样的参数方便更新策略中所需的多个episode;

以下是一个对于Carla client的实例分析

  1. 定义好运行的episode,和每个episode内部的帧数;
  2. 放在一个with context 管理器里面,借助make_carla_client()创建连接 建立客户端目标 开始连接;

出现问题的时候会抛出异常 借助with这个context manager 在退出的时候会被清理

针对每个episode

  1. 每个episode中,判断是否有设置文件,否则则创建一个设置文件,借助CarlaSetting() 建立一个CarlaSetting object;

参考一个 CarlaSettings.ini解释的很明白

  1. 设置setting中相关需要的参数:包括non-player信息、天气 摄像机等;

    设置需要的摄像机,设置的参数包括图像的名字和类型 参考sensor.py中 Image 的data()部分可以知道,图像的数据类型也就是camera可以捕捉的包括:Depth、SemanticSegmentation、SceneFinal

  1. 建立Camera()对象
  2. 设置图片像素
  3. 设置摄像机位置
  4. 添加到setting里面settings.add_sensor(camera1)
  1. 完成设置设置后 导入设置文件(object)到client中,设置player的初始位置player_start_index;
  client.start_episode(player_start)

至此 完成一个episode的启动工作

  1. 对于该episode中的每一帧,读取来自server的数据 可以输出和保存图片

    measurements, sensor_data = client.read_data()
    print_measurements(measurements)
    if args.save_images_to_disk:
       for name, measurement in sensor_data.items():
           filename = args.out_filename_format.format(episode, name, frame)
           measurement.save_to_disk(filename)
    

    还可以使用numpy形式存取给定图像的编码数据 借助data属性,比如获取像素X,Y处的深度值就直接:

    depth_array = sensor_data['CameraDepth'].data
    value_at_pixel = depth_array[Y, X]
    
  2. 对于其中的发送指令操作,如果是在 synchronous mode下,server会停止 直到我们再次发送control;

    if not args.autopilot:
        client.send_control(
            steer=random.uniform(-1.0, 1.0),
            throttle=0.5,
            brake=0.0,
            hand_brake=False,
            reverse=False)
    else:
        control = measurements.player_measurements.autopilot_control
        control.steer=。。。#一番操作
        client.send_control(control)#发送回去就好
    #控制命令什么的 神经网络的输出,直接在这个run_carla_client里面再加一个形参就是;
    

从上面可以看到,server发送回来的包括每一帧的画面和对应的测量数据返回到客户端,于是我们只需要对这些控制指令进行修改然后返回去就完成了自主驾驶的活动;

Carla的benchmark

看完上面的 应该对于Carla有所了解了,而对于其中的benchmark 其实也就是关于Carla的一种高级封装;

一个 benchmark包括一个确定的agent和一个experiment suite;后者作为一个experiment集合 每个包括一系列的导航的实验,给定好起点和终点;进而还需要设置关于环境的一些参数;agent的话就是和experiment suite交互的了,在该benchmark上被评估的一个;

此外还有 recording module 模块用于保存measurement信息 用于暂停和继续benchmark;The metrics module 可以使用记录的measurement来计算性能度量;具体关系如下图:

详细的可以参考文件benchmark_structure.md

如上图可知,一般包含两个模块:一个是控制器,另外一个就是控制器所要执行的地方「 The agent module, that is a controller which performs in another module: the experiment suite. 」两者都需要一个重定义的抽象类;

如下是一个示范的操作:

# We instantiate a forward agent, a simple policy that just set
# acceleration as 0.9 and steering as zero
#前向运动agent,无转向角
agent = ForwardAgent()

# We instantiate an experiment suite. Basically a set of experiments
# that are going to be evaluated on this benchmark.
#一组环境 相关设置:车辆行人 camera位置等等
experiment_suite = BasicExperimentSuite(city_name)

# Now actually run the driving_benchmark
# Besides the agent and experiment suite we should send
# the city name ( Town01, Town02) the log
#然后就是运行了,除了agent和experiment_suite外,还需要输入city name和log的name
run_driving_benchmark(agent, experiment_suite, city_name,
                      log_name, continue_experiment,
                      host, port)

参考上面也可以知道,agent和experiment suite各需要一个类来定义,然后在一个总函数:run_driving_benchmark里面运行;The summary of the execution, the performance metrics, (执行的总结和性能指标)也都被存储在一个json文件 然后在显示器输出;

定义agent

首先需要定义相关的类,而这个类必须继承相关的基础类,比如下面这个前向agent:

from carla.agent.agent import Agent
from carla.client import VehicleControl

class ForwardAgent(Agent):

首先继承基础的agent类,然后在此基础上进行构造属于自己的agent类;翻看agent类的内容,可以知道 若想进行性能评估 进行运行,就需要重新定义其中的run_step函数,如下 就是设置一个throttle为0.9 转向为0的运动

def run_step(self, measurements, sensor_data, directions, target):
    """
    Function to run a control step in the CARLA vehicle.
    """
    control = VehicleControl()
    control.throttle = 0.9
    return control

可以看到 函数接受来自 相关参数:

  • Measurements: the entire state of the world received by the client from the CARLA Simulator. These measurements contains agent position, orientation, dynamic objects information, etc.「接收到的关于Carla模拟器的测量数据包括:agent的位置 方向 动态目标信息等等」
  • Sensor Data: The measured data from defined sensors, such as Lidars or RGB cameras.「从已定义的传感器得到的测量信息 如lidar和RGB图像等」
  • Directions: Information from the high level planner. Currently the planner sends a high level command from the follwoing set: STRAIGHT, RIGHT, LEFT, NOTHING.「来自于高级规划器的信息;当前规划器发送的高级命令 包括: STRAIGHT, RIGHT, LEFT, NOTHING. 」
  • Target Position: The position and orientation of the target.「目标点的位置和方向信息」

基于以上输入,run_step函数将返回 车辆控制信息 (vehicle control message )包括steering value, throttle value, brake value, etc.

定义 Experiment Suite

创建Experiment Suite class 的话 需要下面步骤:「1.创建继承ExperimentSuite 基准类的自己的类;2.定义要用的test和train的天气环境状况;3.建立 experiment目标 」

1.基于基准类来定义自己的类
from carla.agent_benchmark.experiment import Experiment
from carla.sensor import Camera
from carla.settings import CarlaSettings

from .experiment_suite import ExperimentSuite


class BasicExperimentSuite(ExperimentSuite):
2.定义test和train的环境配置

同样的在BasicExperimentSuite类的设置中

@property
def train_weathers(self):
    return [1]
@property
def test_weathers(self):
    return [1]
3.建立实验向量

The experiments are composed by a task that is defined by a set of poses .换句话说,所谓的实验 其实就是包含了一系列的点组成,然后完成从一个点运行到另一个点的pose任务;借助文件view_start_positions.py 可以看到相关的可设置的点,进而基于需要完成设置任务;

4. 运行

就运行而言 首先的 当然还是 先运行Carla 模拟器来当server,不过这时候其中需要加上一个设置项目

./CarlaUE4.sh /Game/Maps/<Town_name> -windowed -world-port=2000  -benchmark -fps=10

然后同样的运行client,这里没有使用corl2017 而是单纯的至少在town1 和2 中使用BasicExperimentSuite :

./driving_benchmark_example.py -c Town01
./driving_benchmark_example.py -c Town02

而相关的输出 emmmm 是模板化的输出 看样子还是需要翻一波源代码 你才能知道 你想输出的东西 能不能怎么修改得到,

https://github.com/carla-simulator/carla/blob/master/PythonClient/carla/driving_benchmark/driving_benchmark.py

https://github.com/carla-simulator/carla/blob/master/PythonClient/carla/driving_benchmark/results_printer.py: