AirSim学习(4)AirSim的PythonAPI基本操作——MultirotorClient类

AirSim学习笔记汇总

  1. AirSim学习(1)安装Unreal Engine和AirSim
  2. AirSim学习(2)创建UE4项目并添加AirSim插件
  3. AirSim学习(3)AirSim的PythonAPI基本操作——VehicleClient类
  4. AirSim学习(4)AirSim的PythonAPI基本操作——MultirotorClient类
  5. AirSim学习(5)AirSim的C++接口、AirSim与ROS的联合仿真

引言

在上一篇博客中,VehicleClient类已经被详细解读了,这篇博客将会介绍它用于无人机仿真的一个子类MultirotorClient

AirSim中的机体坐标系定义

机体系X轴指向机体正前,Y轴指向机体正左,Z轴指向机体正下方,与ROS和MAVROS中常用的RFU机体坐标系不同。

class MultirotorClient

1. 构造函数

调用父类的构造函数

输入参数

  • ip:字符串,表示连接的IP地址,默认为空字符串。
  • port:整数,表示端口号,默认为41451。
  • timeout_value:整数,表示超时时间,默认为3600秒。

2. 起飞、降落与返航

takeoffAsync

使无人机起飞至起点上方3m的位置

输入参数
  • timeout_sec:整数,起飞至指定高度的超时时间,默认为20秒。
  • vehicle_name:字符串,无人机的名称,默认为空字符串。
输出参数

msgpackrpc.future.Future 对象,表示异步操作的未来结果,调用 .join() 等待操作完成。

landAsync

使无人机降落,输入输出与takeoffAsync相同

goHomeAsync

使无人机返航,输入输出与takeoffAsync相同

3. 上层控制接口

moveByVelocityBodyFrameAsync

在无人机局部NED坐标系中根据给定的速度(vx, vy, vz)移动指定时间 duration

moveByVelocityZBodyFrameAsync

在无人机局部NED坐标系中根据给定的速度 (vx, vy) 和z轴位置移动指定时间 duration

扫描二维码关注公众号,回复: 17474771 查看本文章

moveByVelocityAsync

在世界NED坐标系中根据给定的速度(vx, vy, vz)移动指定时间 duration

moveByVelocityZAsync

在世界NED坐标系中根据给定的速度 (vx, vy) 和z轴位置移动指定时间 duration

moveOnPathAsync

沿着给定的路径path按给定速度velocity移动无人机。

moveToPositionAsync

按给定速度velocity移动到(x, y, z

moveToGPSAsync

按给定速度velocity移动到GPS坐标(latitude, longitude, altitude

moveToZAsync

按给定速度velocity移动到指定高度z

moveByManualAsync

按手动控制移动无人机

输入参数

vx_max:x方向速度上限
vy_max:y方向速度上限
vz_max:z方向速度上限
z_min:世界NED坐标系下允许的无人机最小飞行高度
duration:执行时间,结束后切换回非手动模式

rotateToYawAsync

旋转无人机到指定的偏航角

rotateByYawRateAsync

以指定的偏航角速度旋转无人机,持续duration时间

hoverAsync

使无人机悬停

moveByRC

使用遥控器数据移动无人机,遥控器数据类型如下

class RCData(MsgpackMixin):
    timestamp = 0
    pitch, roll, throttle, yaw = (0.0,)*4 #init 4 variable to 0.0
    switch1, switch2, switch3, switch4 = (0,)*4
    switch5, switch6, switch7, switch8 = (0,)*4
    is_initialized = False
    is_valid = False
    def __init__(self, timestamp = 0, pitch = 0.0, roll = 0.0, throttle = 0.0, yaw = 0.0, switch1 = 0,
                 switch2 = 0, switch3 = 0, switch4 = 0, switch5 = 0, switch6 = 0, switch7 = 0, switch8 = 0, is_initialized = False, is_valid = False):
        self.timestamp = timestamp
        self.pitch = pitch
        self.roll = roll
        self.throttle = throttle
        self.yaw = yaw
        self.switch1 = switch1
        self.switch2 = switch2
        self.switch3 = switch3
        self.switch4 = switch4
        self.switch5 = switch5
        self.switch6 = switch6
        self.switch7 = switch7
        self.switch8 = switch8
        self.is_initialized = is_initialized
        self.is_valid = is_valid

4. 底层控制接口

moveByMotorPWMsAsync

电机PWM控制

moveByRollPitchYawZAsync

姿态角-高度控制

moveByRollPitchYawThrottleAsync

姿态角-推力控制

moveByRollPitchYawrateThrottleAsync

姿态角速度-推力控制

setAngleRateControllerGains

设置角速度控制器增益,输入参数angle_rate_gains类型:

class AngleRateControllerGains():
    """
    Struct to contain controller gains used by angle level PID controller

    Attributes:
        roll_gains (PIDGains): kP, kI, kD for roll axis
        pitch_gains (PIDGains): kP, kI, kD for pitch axis
        yaw_gains (PIDGains): kP, kI, kD for yaw axis
    """
    def __init__(self, roll_gains = PIDGains(0.25, 0, 0),
                       pitch_gains = PIDGains(0.25, 0, 0),
                       yaw_gains = PIDGains(0.25, 0, 0)):
        self.roll_gains = roll_gains
        self.pitch_gains = pitch_gains
        self.yaw_gains = yaw_gains

    def to_lists(self):
        return [self.roll_gains.kp, self.pitch_gains.kp, self.yaw_gains.kp], [self.roll_gains.ki, self.pitch_gains.ki, self.yaw_gains.ki], [self.roll_gains.kd, self.pitch_gains.kd, self.yaw_gains.kd]

setAngleLevelControllerGains

设置姿态控制器增益,该增益用于含有姿态控制的上层控制API,例如moveByRollPitchYawZAsyncmoveByRollPitchYawThrottleAsync等。输入参数angle_level_gains类型

class AngleLevelControllerGains():
    """
    Struct to contain controller gains used by angle rate PID controller

    Attributes:
        roll_gains (PIDGains): kP, kI, kD for roll axis
        pitch_gains (PIDGains): kP, kI, kD for pitch axis
        yaw_gains (PIDGains): kP, kI, kD for yaw axis
    """
    def __init__(self, roll_gains = PIDGains(2.5, 0, 0),
                       pitch_gains = PIDGains(2.5, 0, 0),
                       yaw_gains = PIDGains(2.5, 0, 0)):
        self.roll_gains = roll_gains
        self.pitch_gains = pitch_gains
        self.yaw_gains = yaw_gains

    def to_lists(self):
        return [self.roll_gains.kp, self.pitch_gains.kp, self.yaw_gains.kp], [self.roll_gains.ki, self.pitch_gains.ki, self.yaw_gains.ki], [self.roll_gains.kd, self.pitch_gains.kd, self.yaw_gains.kd]

setVelocityControllerGains

设置速度控制器增益,用于上层APImoveByVelocityAsync,输入参数velocity_gains类型:

class VelocityControllerGains():
    """
    Struct to contain controller gains used by velocity PID controller

    Attributes:
        x_gains (PIDGains): kP, kI, kD for X axis
        y_gains (PIDGains): kP, kI, kD for Y axis
        z_gains (PIDGains): kP, kI, kD for Z axis
    """
    def __init__(self, x_gains = PIDGains(0.2, 0, 0),
                       y_gains = PIDGains(0.2, 0, 0),
                       z_gains = PIDGains(2.0, 2.0, 0)):
        self.x_gains = x_gains
        self.y_gains = y_gains
        self.z_gains = z_gains

    def to_lists(self):
        return [self.x_gains.kp, self.y_gains.kp, self.z_gains.kp], [self.x_gains.ki, self.y_gains.ki, self.z_gains.ki], [self.x_gains.kd, self.y_gains.kd, self.z_gains.kd]

设置位置控制器增益,用于上层APImoveByPositionAsync,输入参数position_gains类型:

class PositionControllerGains():
    """
    Struct to contain controller gains used by position PID controller

    Attributes:
        x_gains (PIDGains): kP, kI, kD for X axis
        y_gains (PIDGains): kP, kI, kD for Y axis
        z_gains (PIDGains): kP, kI, kD for Z axis
    """
    def __init__(self, x_gains = PIDGains(0.25, 0, 0),
                       y_gains = PIDGains(0.25, 0, 0),
                       z_gains = PIDGains(0.25, 0, 0)):
        self.x_gains = x_gains
        self.y_gains = y_gains
        self.z_gains = z_gains

    def to_lists(self):
        return [self.x_gains.kp, self.y_gains.kp, self.z_gains.kp], [self.x_gains.ki, self.y_gains.ki, self.z_gains.ki], [self.x_gains.kd, self.y_gains.kd, self.z_gains.kd]

5. 查询状态

getMultirotorState

查询无人机状态,返回类型:

class MultirotorState(MsgpackMixin):
    collision = CollisionInfo()
    kinematics_estimated = KinematicsState()
    gps_location = GeoPoint()
    timestamp = np.uint64(0)
    landed_state = LandedState.Landed
    rc_data = RCData()
    ready = False
    ready_message = ""
    can_arm = False

getRotorStates

返回电机状态

class RotorStates(MsgpackMixin):
    timestamp = np.uint64(0)
    rotors = []

官方示例程序

导入需要使用的包

import setup_path #unused
import airsim

import numpy as np
import os
import tempfile
import pprint
import cv2

初始化

# connect to the AirSim simulator
client = airsim.MultirotorClient()	# 初始化无人机客户端
client.confirmConnection()	# 确认与UE4的连接
client.enableApiControl(True)	# 使能API控制

读取传感器数据

state = client.getMultirotorState()	# 获取无人机状态
s = pprint.pformat(state)
print("state: %s" % s)

imu_data = client.getImuData()	# 获取IMU数据
s = pprint.pformat(imu_data)
print("imu_data: %s" % s)

barometer_data = client.getBarometerData()	# 获取气压计数据
s = pprint.pformat(barometer_data)
print("barometer_data: %s" % s)

magnetometer_data = client.getMagnetometerData()	# 获取磁力计数据
s = pprint.pformat(magnetometer_data)
print("magnetometer_data: %s" % s)

gps_data = client.getGpsData()	# 获取GPS数据
s = pprint.pformat(gps_data)
print("gps_data: %s" % s)

控制

airsim.wait_key('Press any key to takeoff')
print("Taking off...")
client.armDisarm(True)	# 无人机解锁
client.takeoffAsync().join()	# 无人机起飞

state = client.getMultirotorState()	# 查询无人机状态
print("state: %s" % pprint.pformat(state))

airsim.wait_key('Press any key to move vehicle to (-10, 10, -10) at 5 m/s')
client.moveToPositionAsync(-10, 10, -10, 5).join()	# 位置控制

client.hoverAsync().join()

state = client.getMultirotorState()
print("state: %s" % pprint.pformat(state))

拍照并保存

airsim.wait_key('Press any key to take images')
# get camera images from the car
responses = client.simGetImages([
    airsim.ImageRequest("0", airsim.ImageType.DepthVis),  #depth visualization image
    airsim.ImageRequest("1", airsim.ImageType.DepthPerspective, True), #depth in perspective projection
    airsim.ImageRequest("1", airsim.ImageType.Scene), #scene vision image in png format
    airsim.ImageRequest("1", airsim.ImageType.Scene, False, False)])  #scene vision image in uncompressed RGBA array
print('Retrieved images: %d' % len(responses))

tmp_dir = os.path.join(tempfile.gettempdir(), "airsim_drone")
print ("Saving images to %s" % tmp_dir)
try:
    os.makedirs(tmp_dir)
except OSError:
    if not os.path.isdir(tmp_dir):
        raise

for idx, response in enumerate(responses):

    filename = os.path.join(tmp_dir, str(idx))

    if response.pixels_as_float:
        print("Type %d, size %d" % (response.image_type, len(response.image_data_float)))
        airsim.write_pfm(os.path.normpath(filename + '.pfm'), airsim.get_pfm_array(response))
    elif response.compress: #png format
        print("Type %d, size %d" % (response.image_type, len(response.image_data_uint8)))
        airsim.write_file(os.path.normpath(filename + '.png'), response.image_data_uint8)
    else: #uncompressed array
        print("Type %d, size %d" % (response.image_type, len(response.image_data_uint8)))
        img1d = np.fromstring(response.image_data_uint8, dtype=np.uint8) # get numpy array
        img_rgb = img1d.reshape(response.height, response.width, 3) # reshape array to 4 channel image array H X W X 3
        cv2.imwrite(os.path.normpath(filename + '.png'), img_rgb) # write to png

重置、上锁、关闭API控制

airsim.wait_key('Press any key to reset to original state')

client.reset()	# 重置无人机
client.armDisarm(False)	# 无人机上锁

# that's enough fun for now. let's quit cleanly
client.enableApiControl(False)	# 关闭API控制

例程运行效果

AirSim官方例程 hello_drone.py

猜你喜欢

转载自blog.csdn.net/qq_45709806/article/details/136096432