Donkey模拟器

Donkey Gym项目是一个OpenAI Gym的包装器,用于连接Self Driving Sandbox Donkey模拟器(sdsandbox)。

该模拟器基于Unity游戏平台构建,使用其内部的物理和图形系统,并连接到一个Donkey Python进程,以使用我们训练好的模型来控制模拟的Donkey车。

我的虚拟Donkey

根据您的目标,有许多使用模拟器的方式。您可以将模拟器视为虚拟硬件,使用它来了解和使用标准的Donkeycar驱动/训练/测试循环。您将使用与实际机器人相同的命令来收集数据、驾驶和训练。我们将首先介绍这种用法。

sim_screen_shot

安装

  • Donkey Gym Release下载并解压适用于您的主机平台的模拟器。
  • 将模拟器放置在您喜欢的位置。以本示例为例,将其放置在~/projects/DonkeySimLinux目录下。根据平台的不同,您的目录名称将不同。
  • 完成所有步骤以在主机PC上安装Donkey
  • 设置DonkeyGym:
cd ~/projects
git clone https://github.com/tawnkramer/gym-donkeycar
cd gym-donkeycar
conda activate donkey
pip install -e .[gym-donkeycar]
  • 您可以使用现有的~/mycar Donkey应用程序,或者开始一个新的应用程序。在这里,我们将从头开始:
donkey createcar --path ~/mysim
cd ~/mysim
  • 编辑您的myconfig.py文件以启用Donkey Gym模拟器包装器,请替换<user-name>和路径的其他部分:
DONKEY_GYM = True
DONKEY_SIM_PATH = "/home/<user-name>/projects/DonkeySimLinux/donkey_sim.x86_64"
DONKEY_GYM_ENV_NAME = "donkey-generated-track-v0"

注意:根据平台和用户的不同,可执行文件的路径会有所不同。

  • Windows: DonkeySimWin/donkey_sim.exe
  • Mac OS: DonkeySimMac/donkey_sim.app/Contents/MacOS/donkey_sim
  • Linux: DonkeySimLinux/donkey_sim.x86_64

驾驶

您可以使用所有常规的 manage.py 命令来进行操作。例如:

python manage.py drive

这将启动模拟器并自动连接到它。默认情况下,您将拥有一个用于控制Donkey的Web界面。请访问 http://localhost:8887/drive 查看控制页面。

在Ubuntu Linux上,您可以连接您选择的游戏手柄。如果它被挂载为 /dev/input/js0,那么它很有可能可以工作。修改 myconfig.py 指示您的游戏手柄型号,并使用 --js 参数来运行。

python manage.py drive --js

在您驾驶的过程中,这将像往常一样在您的数据目录中创建一个记录的数据集。

训练

您不需要将数据进行 rsync,因为它已经被记录并保存在本地。您可以像往常一样进行训练:

donkey train --tub ./data --model models/mypilot.h5

测试

您可以像往常一样使用该模型:

python manage.py drive --model models/mypilot.h5

然后导航到Web控制页面。将“模式和驾驶员”设置为“本地驾驶员(d)”。汽车应该开始行驶。

样本驾驶数据

这是一些示例驾驶数据,可帮助您入门。下载此文件 并将其解压缩到您的数据目录中。这应该训练出一个速度较慢但稳定的驾驶程序。


API

以下是与模拟服务器通信的API信息。创建一个TCP客户端并连接到模拟器正在运行的主机上的9091端口。服务器发送和接收UTF-8编码的JSON数据包。每个消息必须有一个“msg_type”字段。模拟器会在每个JSON数据包的末尾添加换行符以作为终止符。当向服务器发送消息时,您不必在每个数据包末尾添加换行符。但是,如果发送的消息过多,可能会出现问题。如果遇到问题,请检查播放器日志文件以查找JSON解析错误。


获取协议版本

客户端=>模拟器。请求协议的版本。将帮助了解这些消息何时发生更改。

字段:

示例:

    {
    "msg_type" : "get_protocol_version" 
    }

协议版本

模拟器=>客户端. 回复协议的版本。当前版本为2。

Fields:

  • version : string integer

Example:

    {
    "msg_type" : "protocol_version",
    "version" : "2",
    }

场景选择准备就绪

模拟器=>客户端。当菜单场景加载完成时,将发送此消息。在此之后,模拟器可以响应场景加载消息。(仅菜单)

字段:

示例:

    {
    "msg_type" : "scene_selection_ready" 
    }

获取场景名称

客户端=>模拟器。询问可以加载的场景的名称。(仅菜单)

字段:

示例:

    {
    "msg_type" : "get_scene_names" 
    }

场景名称

模拟器=>客户端。模拟器将回复一个场景名称列表。

字段:

  • scene_names:场景名称数组

示例:

    {
    "msg_type" : "scene_names" 
    "scene_names" : [ "generated_road", "warehouse", "sparkfun_avc". "generated_track" ]
    }

加载场景

客户端=>模拟器。请求模拟器从菜单屏幕加载其中一个场景。(仅菜单)

字段:

scene_namegenerated_road | warehouse | sparkfun_avc | generated_track(或模拟器从get_scene_names返回的列表)

示例:

    {
        "msg_type" : "load_scene",
        "scene_name" : "generated_track"
    }

场景加载完成

模拟器=>客户端。一旦场景加载完成,你将收到以下回复:

    {
        "msg_type" : "scene_loaded"
    }

车辆加载完成

模拟器=>客户端。一旦模拟器完成加载你的车辆,它将发送此消息。在场景加载完成后,当有活动的客户端连接时,车辆将自动加载给你。或者客户端建立连接。

字段:

示例:

    {
    "msg_type" : "car_loaded" 
    }

车辆配置

客户端=>模拟器。一旦加载完成,你可以配置车辆的可视细节(仅场景)

字段:

  • body_styledonkey | bare | car01 | cybertruck | f1
  • body_r:0-255之间的整数字符串值
  • body_g:0-255之间的整数字符串值
  • body_b:0-255之间的整数字符串值
  • car_name:要在车辆上显示的字符串值车辆名称。多行可接受换行符。
  • font_size:10-100之间的整数字符串值,用于设置车辆名称文本的大小

示例:

    {
        "msg_type" : "car_config",
        "body_style" : "car01",
        "body_r" : "128",
        "body_g" : "0",
        "body_b" : "255",
        "car_name" : "Your Name",
        "font_size" : "100"
    }

摄像头配置

客户端=>仿真器。一旦场景加载完成,您可以配置汽车相机传感器的详细信息。

字段:

  • fov:浮点数字符串,范围在10到200之间。设置相机的视野角度。
  • fish_eye_x:浮点数字符串,范围在0到1之间。在x轴上引起畸变变形。
  • fish_eye_y:浮点数字符串,范围在0到1之间。在y轴上引起畸变变形。
  • img_w:整数字符串,范围在16到512之间。设置相机传感器图像的宽度。
  • img_h:整数字符串,范围在16到512之间。设置相机传感器图像的高度。
  • img_d:整数字符串,值为1或3。设置相机传感器图像的深度。在值为1的情况下,您将获得3个通道,但所有通道都是相同的,模拟器上进行了灰度转换。
  • img_enc:图像数据的编码格式 JPG | PNG | TGA
  • offset_x:浮点数字符串。将相机在左右轴上移动。
  • offset_y:浮点数字符串。将相机上下移动。
  • offset_z:浮点数字符串。将相机前后移动。
  • rot_x:浮点数字符串。以度为单位。围绕X轴旋转相机。

示例:

    {
    "msg_type" : "cam_config",
    "fov" : "150", 
    "fish_eye_x" : "1.0",
    "fish_eye_y" : "1.0",
    "img_w" : "255",
    "img_h" : "255",
    "img_d" : "1",
    "img_enc" : "PNG",
    "offset_x" : "0.0",
    "offset_y" : "3.0",
    "offset_z" : "0.0",
    "rot_x" : "90.0"
    }

注意: 您可以通过将msg_type更改为"cam_config_b"来添加另一个相机。


控制车辆

客户端=>仿真器。控制油门和转向。

字段:

  • steering:浮点数字符串,范围在-1到1之间。映射到完全向左或向右,与中心相差16度。
  • throttle:浮点数字符串,范围在-1到1之间。将扭矩完全施加到前进或倒车的车轮。
  • brake:浮点数字符串,范围在0到1之间。

示例:

    {
    "msg_type" : "control",
    "steering" : "0.0",
    "throttle" : "0.3",
    "brake" : "0.0"
    }

遥测数据

仿真器=>客户端。仿真器发送此消息,包含相机图像和有关车辆状态的详细信息。这些消息以仿真器中设置的固定速率发送,通常约为20Hz。

字段:

  • steering_angle:上次应用的转向角度。为什么不直接使用"steering",我不知道。
  • throttle:上次应用的油门。
  • speed:线速度的大小。
  • image:二进制图像的BinHex编码。使用PIL.Image.open(BytesIO(base64.b64decode(imgString)))来打开图像。
  • imageb:(可选)第二个相机的图像,与上述相同。
  • lidar:(可选)激光雷达点的列表,格式如下:{d: 距离物体的距离, rx: 射线X轴旋转, ry: 射线Y轴旋转}
  • hit:最后撞击物体的名称。如果没有撞击物体,则为None。
  • accel_x:车辆的x轴加速度。
  • accel_y:车辆的y轴加速度。
  • accel_z:车辆的z轴加速度。
  • gyro_x:x轴陀螺加速度。
  • gyro_y:y轴陀螺加速度。
  • gyro_z:z轴陀螺加速度。
  • gyro_w:w轴陀螺加速度。
  • pitch:车辆的俯仰角(以度为单位)。
  • roll:车辆的横滚角(以度为单位)。
  • yaw:车辆的偏航角(以度为单位)。
  • activeNode:在赛道上的进度(目前与多车不正常工作)。
  • totalNodes:赛道上的节点数。
  • pos_x:(仅用于训练)车辆的世界坐标x。
  • pos_y:(仅用于训练)车辆的世界坐标y。
  • pos_z:(仅用于训练)车辆的世界坐标z。
  • vel_x:(仅用于训练)车辆的x轴速度。
  • vel_y:(仅用于训练)车辆的y轴速度。
  • vel_z:(仅用于训练)车辆的z轴速度。
  • cte:(仅用于训练)横向误差。车辆到最右车道中心线或赛道中心线的距离(取决于赛道)。

示例:

    {
    "msg_type" : "telemetry",
    "steering_angle" : "0.0",
    "throttle" : "0.0",
    "speed" : "1.0",
    "image" : "0x123...",
    "hit" : "None",
    "pos_x" : "0.0",
    "pos_y" : "0.0",
    "pos_z" : "0.0",
    "accel_x" : "0.0",
    "accel_y" : "0.0",
    "accel_z" : "0.0",
    "gyro_x" : "0.0",
    "gyro_y" : "0.0",
    "gyro_z" : "0.0",
    "gyro_w" : "0.0",
    "pitch" : "0.0",
    "roll" : "0.0",
    "yaw" : "0.0",
    "activeNode" : "5",
    "totalNodes" : "26",
    "cte" : "0.5"
    }

重置车辆

客户端=>仿真器。将车辆返回到起点。

字段:

示例:

    {
    "msg_type" : "reset_car"
    }

设置车辆位置

客户端=>模拟器。将车辆移动到指定位置(仅用于训练)

字段:

  • pos_x:x世界坐标。
  • pos_y:y世界坐标。
  • pos_z:z世界坐标。
  • qx:(可选)四元数x分量。
  • qy:(可选)四元数y分量。
  • qz:(可选)四元数z分量。
  • qw:(可选)四元数w分量。

示例:

{
    "msg_type" : "set_position",
    "pos_x" : "0.0",
    "pos_y" : "0.0",
    "pos_z" : "0.0"
}

或者:

{
    "msg_type" : "set_position",
    "pos_x" : "0.0",
    "pos_y" : "0.0",
    "pos_z" : "0.0",
    "qx" : "0.0",
    "qy" : "0.2",
    "qz" : "0.0",
    "qw" : "1.0"
}

获取节点位置和旋转

客户端=>模拟器。请求一个node_position数据包

字段:

  • index:节点索引

示例:

{
    "msg_type": "node_position",
    "index": "0"
}

节点位置和旋转

模拟器=>客户端。node_position数据包(在发送node_position数据包后收到)

字段:

  • pos_x:x世界坐标。
  • pos_y:y世界坐标。
  • pos_z:z世界坐标。
  • qx:(可选)四元数x分量。
  • qy:(可选)四元数y分量。
  • qz:(可选)四元数z分量。
  • qw:(可选)四元数w分量。

示例:

{
    "msg_type": "node_position",
    "Qx": "0",
    "Qy": "0",
    "Qz": "0",
    "Qw": "1",
    "pos_x": "0",
    "pos_y": "0",
    "pos_z": "0"
}

退出场景

客户端=>模拟器。离开场景,返回主菜单屏幕。

字段:

示例:

{
    "msg_type" : "exit_scene"
}

退出应用

客户端=>模拟器。关闭模拟器应用程序(仅限菜单)。

字段:

示例:

{
    "msg_type" : "quit_app"
}