AirSim 自动驾驶仿真 (3) 飞机控制API和opencv获取图像

官方api

https://microsoft.github.io/AirSim/api_docs/html/

https://zhuanlan.zhihu.com/p/307956920?utm_source=wechat_session

设置摄像机参数和图像参数

修改UE4仿真环境的参数,同样是修改settings.json文件,可以修改AirSim摄像机保存图像的尺寸等参数。示例如下:

{
  "SettingsVersion": 1.2,
  "CameraDefaults": {
      "CaptureSettings": [
        {
          "ImageType": 0,
          "Width": 1920,
          "Height": 1080,
          "FOV_Degrees": 90,
          "AutoExposureSpeed": 100,
          "MotionBlurAmount": 0
        }
    ]
  },
  "SimMode": "ComputerVision"
}

  只是个参考

基本api代码整理

官方自带的测试程序

 自己整理的测试python

1 基本控制移动,两种控制模式

  1-1依靠速度控制.

  1-2依靠坐标位置控制

        备注说明,例如一边拍照一边控制移动,的开个多线程专门处理移动不能影响彩图卡顿。去掉jion函数不会等待动作执行完毕才去执行拍照,就可以做到一边移动一边拍照。

2获取集本数据 gps  position

3获取图像,转化成opencv可以操作的数据

  3-1修改相机编号  下视还是前视,默认下视

  3-2修改画面数据,彩色还是深度图,默认彩色图

# In settings.json first activate computer vision mode: 
# https://github.com/Microsoft/AirSim/blob/master/docs/image_apis.md#computer-vision-mode

#基本集成了飞机所有的控制,图像转换到opencv

#import setup_path 
#导入自己的airsim编译路径
import sys
sys.path.append("/home/dongdong/3Code/Airsim/AirSim/PythonClient")

import airsim

import cv2
import time
import sys

import pprint
import numpy as np
import os
import tempfile

#选择要采集的图像类型
cameraType = "scene" #正常画面 12fps  1920*1080

cameraTypeMap = { 
 "depth": airsim.ImageType.DepthVis,#黑白景深图像
 "segmentation": airsim.ImageType.Segmentation,#彩色目标分割图像
 "seg": airsim.ImageType.Segmentation,#彩色目标分割图像
 "scene": airsim.ImageType.Scene,#正常图像
 "disparity": airsim.ImageType.DisparityNormalized,
 "normals": airsim.ImageType.SurfaceNormals
}

#选择摄像头
'''
---camera_name_val: airsim自带的simple flight,每个无人机自带5个相机,其ID 与相机分别对应如下:
0 = front_center
1 = front_right
2 = front_left
3 = bottom_center #下视画面
4 = back_center
'''
cameraUse="3" 

# 连接到Airsim仿真器
#client = airsim.MultirotorClient()#默认本机
client = airsim.MultirotorClient("192.168.0.1")#局域网主机IP
# 每1秒检查一次连接状态,并在控制台中报告,以便用户可以查看连接的进度(应该是开启了个线程,因为只是调用了一次)
client.confirmConnection()
#开启api控制,默认是false,有的设备不允许用API控制,所以用isApiControlEnabled可以查看是否可以用API控制
client.enableApiControl(True)



#获取无人飞机的所有数据
Flystate = client.getMultirotorState()
#s = pprint.pformat(state)
#print("state: %s" % s)

#从所有数据扣出 position坐标  北偏地坐标系
position1=Flystate.kinematics_estimated.position
#print(position1)
print("position位置")
print(position1.x_val)
print(position1.y_val)
print(position1.z_val) #负为上升,北偏地坐标系

#从所有数据扣出 gps_data数据  经纬度
gps_data=Flystate.gps_location
#print(gps_data)
print("GPS数据")
print(gps_data.altitude)
print(gps_data.latitude)
print(gps_data.longitude)

#单独获取当前位置GPS数据的api
#gps_data = client.getGpsData()
#s = pprint.pformat(gps_data)
#print("gps_data: %s" % s)




#按键等待
airsim.wait_key('安任何按键,开始采集起飞')
#起飞
landed = client.getMultirotorState().landed_state
if landed == airsim.LandedState.Landed:
    print("taking off...")
    client.takeoffAsync().join()
else:
    print("already flying...")
    client.hoverAsync().join()


#悬停
client.hoverAsync().join()

#飞行代码测试 有两种模式 定点飞和恒定速度飞 注销开启测试
'''
----------------------------飞行控制模式1----------------------------------
(1)坐标点控制 
	初始化原点,化点为x,y,z是全局坐标位置,velocity是速度。
	实现的效果是以 1m/s 的速度飞到 (5, 0) 点,3m 高的位置。
	.join() 后缀的意思是程序在这里等待直到任务完成,也就是四旋翼到达目标位置点,同时到达设置的高度。
	如果不加 .join() 后缀,则不用等待任务是否完成,函数直接返回,程序继续往下执行。

'''

'''
airsim.wait_key('Press any key to fly1') 
client.moveToZAsync(-3, 1).join()              # 上升到3m高度
client.moveToPositionAsync(5, 0, -3, 1).join()  # 飞到(5,0)点坐标 高度3米 速度1m/s
client.moveToPositionAsync(5, 5, -3, 1).join()  # 飞到(5,5)点坐标 高度3米 速度1m/s
'''


'''
----------------------------飞行控制模式2----------------------------------
  (2) 速度运动控制模式
	#全局坐标系是北东地坐标系
	vx:全局坐标系下x轴方向上的速度
	vy:全局坐标系下y轴方向上的速度
	z:全局坐标系下的高度
	duration:持续的时间,单位:秒
'''
'''
airsim.wait_key('Press any key to fly2') 
client.moveToZAsync(-6, 1).join()              # 上升到6m高度
client.moveByVelocityZAsync(1, 0, -6, 3).join()     # 第三阶段:以1m/s速度向x前飞3秒钟 -6米高度
client.moveByVelocityZAsync(0, 1, -6, 3).join()     # 第三阶段:以1m/s速度向y前飞3秒钟 -6米高度
'''





#按键等待
airsim.wait_key('按任何按键,开始采集图像,记得修改相机编号和图像类型')
client.moveToZAsync(-10, 10).join()  #飞到10米高      10米速度
#client.moveByVelocityZAsync(0, 1, -10, 9)     # 以y轴1m/s速度向y前飞9秒钟 10米高度  为了移动采集画面,不用等待join() 结束
client.moveByVelocityZAsync(100, 0, -10, 2)   #2米/妙速度  10米高度  飞到 (100 ,0)位置

#---------------------画图输出帧率字体格式------------------
fontFace = cv2.FONT_HERSHEY_SIMPLEX
fontScale = 0.5
thickness = 2
textSize, baseline = cv2.getTextSize("FPS", fontFace, fontScale, thickness)
print (textSize)
textOrg = (10, 10 + textSize[1])
frameCount = 0
startTime=time.clock()
fps = 0
#---------------------画图输出帧率字体格式------------------

cv2.namedWindow("Airsim", cv2.WINDOW_NORMAL)

while True:
    # because this method returns std::vector<uint8>, msgpack decides to encode it as a string unfortunately.
    rawImage = client.simGetImage(cameraUse, cameraTypeMap[cameraType])#获取airsim原始格式视频数据
    if (rawImage == None):
        print("图像为空")
        #sys.exit(0)
        continue
    else:
        png = cv2.imdecode(airsim.string_to_uint8_array(rawImage), cv2.IMREAD_UNCHANGED)#AIRSIM转换数据OPENCV
        cv2.putText(png,'FPS ' + str(fps),textOrg, fontFace, fontScale,(255,0,255),thickness)
        cv2.imshow("Airsim", png)

    frameCount  = frameCount  + 1
    endTime=time.clock()
    diff = endTime - startTime
    if (diff > 1):
        fps = frameCount
        frameCount = 0
        startTime = endTime
    

    key = cv2.waitKey(1) & 0xFF;
    if (key == 27 or key == ord('q') or key == ord('Q')):
        break;

cv2.destroyAllWindows() 
      
#降落
landed = client.getMultirotorState().landed_state
if landed == airsim.LandedState.Landed:
    print("already landed...")
else:
    print("landing...")
    client.landAsync().join()

# 上锁
client.armDisarm(False)
client.reset()
#关闭控制
client.enableApiControl(False)

  

四旋翼飞行控制 API 讲解

AirSim 坐标系定义总结

水平位置控制函数

函数定义:

def moveToPositionAsync(
         self,
         x,          # 位置坐标(北东地坐标系)
         y,
         z,
         velocity,   # 速度
         timeout_sec=3e38,
         drivetrain=DrivetrainType.MaxDegreeOfFreedom,
         yaw_mode=YawMode(),
         lookahead=-1,
         adaptive_lookahead=1,
         vehicle_name="",
     )

  输入参数包括:

 
x,y,z:位置坐标(全局坐标系 - 北东地)
velocity: 飞行速度(m/s)
timeout_sec: 如果没有响应,超时时间
drivetrain,yaw_mode: 设置飞行朝向模式和yaw角控制模式
lookahead, adaptive_lookahead: 设置路径飞行的时候的yaw角控制模式
vehicle_name: 控制的四旋翼名字

x, y, z, velocity 这四个参数是必须要设置的量,指示四旋翼以多大的速度飞往哪个坐标点。后面的几个参数都有其默认值,不用设置也可以。

lookahead 和 adaptive_lookahead 这两个参数是设置当四旋翼飞轨迹的时候的朝向,目前还用不到。

vehicle_name 是将指令发送给哪个四旋翼,当做多个四旋翼协同飞行控制的时候,这个参数就派上用场了,后面会有多机协同编队的教程。

drivetrain 和 yaw_mode 这两个参数的组合可以设置四旋翼的偏航角控制模式,下面详细介绍。

 

2.3 偏航角控制模式详解

drivetrain 参数可以设置为两个量:

  • airsim.DrivetrainType.ForwardOnly: 始终朝向速度方向
  • airsim.DrivetrainType.MaxDegreeOfFreedom:手动设置yaw角度

yaw_mode 必须设置为 YawMode() 类型的变量,这个结构体类型包含两个属性:

  • YawMode().is_rate:True - 设置角速度;False - 设置角度
  • YawMode().yaw_or_rate:可以是任意浮点数

 AirSim 坐标系定义总结

  

Unreal 引擎中的坐标系与 AirSim 定义的坐标系是不同的,甚至长度单位都不同。Unreal的长度单位是厘米,而AirSim的长度单位是米。不过不用担心,AirSim已经非常好的处理了这个问题,你不用管Unreal的坐标系是什么,只需要按照AirSim的坐标系设置即可,AirSim会帮你自动转换的。

 

本文先说明两个坐标系的定义: 全局坐标系、机体坐标系。

全局坐标系是固连到大地的,x,y,z三个坐标轴的指向分别是北,东,地,也就是朝北是x轴的正方向,朝南就是x轴的负方向。全局坐标系的原点位置是大地的某一点(可以在settings文件中设置)。

机体坐标系是固连到四旋翼机身的,x,y,z三个坐标轴的指向分别是前,右,下,也就是飞机的前方是x轴的正方向,飞机后方是x轴的负方向。机体坐标系的原点位置是机体的重心位置。

如果按照1.2节的设置,将 playerStart的旋转都设为0,那么仿真刚开始的时候,四旋翼的机体坐标系与全局坐标系是重合的。

 

暂停和继续的API

可以使用pause(True)实现暂停。可能会遇到这样的情况,特别是在使用强化学习时,会在指定的时间内运行模拟,然后自动暂停。当模拟暂停时,可以执行一些昂贵的计算,发送一个新命令,然后在指定的时间内再次运行模拟。这个也可以使用continueForTime(seconds)实现(非常重要,太关键了),执行一段时间然后暂停。这个例子的使用,可以参考 pause_continue_car.py 和 pause_continue_drone.py.

  

 

原文地址:https://www.cnblogs.com/kekeoutlook/p/14246936.html