AMD Schola
AMD Schola 是一个用于在 Unreal Engine 中开发强化学习 (RL) 代理并使用您喜欢的 Python 基础 RL 框架进行训练的库。
在本指南中,我们将演示如何在 Unreal® Engine 中复制一个物理设备,并使用新发布的 AMD Schola v1.3 版本通过强化学习对其进行训练。


Sim-to-real 是指在模拟(虚拟)环境中开发和训练代理(agent),然后将其部署到现实世界中的物理硬件上运行的过程。这种方法在机器人技术和强化学习领域得到广泛应用,因为它可以在早期开发阶段无需承担使用物理硬件的风险和成本,从而实现快速原型设计和测试。
我们使用的物理设备是 SunFounder PiCar-X。请直接查看设备规格以熟悉它。特别是,PiCar-X 的最高速度为 50 厘米/秒(1.8 公里/小时),转弯半径为 29 厘米。我们将使用 Unreal Engine 中的 Chaos Vehicles 模块来复制 PiCar-X,并如稍后所述,使用颜色传感器收集观测值。

目标是利用强化学习训练代理循着地面的线行驶。代理将接收来自模拟颜色传感器的观测值,该传感器可以检测地面的线,然后它会学会向左或向右转向以保持在线上。
模拟环境由一个简单的赛道组成,赛道上有白色地面上的黑线,代理被设置为始终以恒定的速度向前移动。代理使用以下方式进行训练:

训练使用 Unreal Engine 中的 AMD Schola,并结合 Stable Baselines3 (SB3) 库和 Proximal Policy Optimization (PPO) 算法进行。在我们的实验中,代理经过 200 万步训练后达到了良好的性能。

注意:在训练过程中使用 --save-final-policy 和 --export-onnx 标志来保存最终策略并导出为 ONNX 格式。
将 .onnx 文件复制到 PiCar-X,并使用 ONNX Runtime for Raspberry Pi 来运行模型。PiCar-X 将使用训练好的模型根据颜色传感器的观测值做出决策。模型的输出将是转向动作,这些动作将被发送到 PiCar-X 的转向电机。以下是使用 ONNX 模型与 PiCar-X 交互的示例。
import numpy as npimport onnxruntimefrom picarx import Picarximport time
def generate_input_from_sensors(sensor_values): """ Convert grayscale sensor values to ONNX model input format. Sensor values less than 700 are converted to 0, and values greater than or equal to 700 are converted to 1. """ A = 0 if sensor_values[0] > 700 else 1 B = 0 if sensor_values[1] > 700 else 1 C = 0 if sensor_values[2] > 700 else 1 return np.array([[A, A, A, B, B, B, C, C, C]], dtype=np.float32)
def run_inference(session, input_data): """ Run inference on the ONNX model using the provided input data. """ input_feed = {} for input_tensor, data in zip(session.get_inputs(), input_data): input_feed[input_tensor.name] = data
output_name = session.get_outputs()[0].name output = session.run([output_name], input_feed)[0] return output
def map_output_to_steering(output): """ Map the ONNX model output to steering angle. Output range is assumed to be [-1, 1], where -1 is full left and 1 is full right. """ print(f"Output: {output}") return output[0][0] * 90 # Scale to servo angle range (-90 to 90)
if __name__ == "__main__": # Initialize Picarx and ONNX model px = Picarx() model_path = "ppo_final.onnx" session = onnxruntime.InferenceSession(model_path)
try: while True: # Start moving forward px.forward(1)
# Get grayscale sensor values sensor_values = px.get_grayscale_data()
# Generate ONNX model input input_data = [generate_input_from_sensors(sensor_values), np.array([[[0]]], dtype=np.float32)] # State-in is unused
# Run inference output = run_inference(session, input_data)
# Map output to steering angle steering_angle = map_output_to_steering(output)
# Set steering angle px.set_dir_servo_angle(steering_angle) finally: # Stop the robot px.forward(0)我们非常感谢加州大学圣地亚哥分校 ECE 191 课程的 Abhi Sachdeva、Josue Solano、Peter Quawas、Pramesh Singhavi 和 Ryan Luo 的贡献,该课程由 Xinyu Zhang 教授讲授;他们的高级设计项目产生的概念验证激发了此次演示。