当前位置:   article > 正文

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

microsoft airsim api

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

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

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]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

设置位置控制器增益,用于上层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]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

getRotorStates

返回电机状态

class RotorStates(MsgpackMixin):
    timestamp = np.uint64(0)
    rotors = []
  • 1
  • 2
  • 3

官方示例程序

导入需要使用的包

import setup_path #unused
import airsim

import numpy as np
import os
import tempfile
import pprint
import cv2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

初始化

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

读取传感器数据

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

控制

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))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

拍照并保存

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

重置、上锁、关闭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控制
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

例程运行效果

AirSim官方例程 hello_drone.py

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/541643
推荐阅读
相关标签
  

闽ICP备14008679号