AirSim多台无人机第一视角键盘控制进阶版

AirSim多台无人机第一视角键盘控制进阶版



本文实现的效果

keyboard ctrl2

前言

本篇文章实现的键盘控制较上一篇主要有三个地方的改进。第一个,更换控制API实现更自由的控制,第二是在该基础上增加图像读取与实时刷新显示功能,第三个是在两台及以上的无人机中自由切换控制对象以及对应的FPV视角。


一、环境依赖

除了上篇文章依赖的pygame库外,还需要安装opencv-python库,用来对AirSim图像API接口返回的数据进行图像编码,以及保存图像。

pip3 install opencv-python
pip3 install pygame

二、图像读取与显示

1.使用的API

python安装的AirSim库中提供了两种获取图像的API,一个是simGetImage,另外一个是simGetImages。对于后者,我们可以对一台无人机同时读取多个摄像头的图像,以及设置是否压缩,多次测试发现使用不压缩的数据类型可以提高图像读取的速率,在读取多个图像时十分管用。在这里为了降低程序阅读门槛,遵循循序渐进的方法,先介绍使用simGetImage接口来读取并处理一帧图像数据。

image = AirSim_client.simGetImage('0', airsim.ImageType.Scene, vehicle_name="Drone1")

第一个参数表示要读取的摄像头编号,'0’号代表的是正前方,此外默认的模型还有左前方右前方,正下方以及正后方的摄像头,具体对应关系如下。

'0': front_center   '1': front_right    '2': front_left    '3': bottom_center   '4': back_center

2.实时显示的一种方法

利用pygame库的图像加载API将实时的第一视角图像读取,然后在pygame主窗口实时更新,对于第一视角的图像使用opencv里面的imwrite函数进行图像保存,基本实现如下。

cv2.imwrite('visual.png', image)
# 利用pygame库加载保存的第一视角图像
screen_image = pygame.image.load("visual.png")

三、键盘控制改进

本次无人机各个方向控制使用了速率量,这样能有更大的自由空间,可以自行调节参数来获得更好的效果。具体请参照代码注释,不懂可留言提问。

import sys
import cv2
import time
import airsim
import pygame

# >------>>>  pygame settings   <<<------< #
pygame.init()
screen = pygame.display.set_mode((320, 240))
pygame.display.set_caption('keyboard ctrl @FPV')
screen.fill((0, 0, 0))

# >------>>>  AirSim settings   <<<------< #
# 这里改为你要控制的无人机名称(settings文件里面设置的)
base_name = "Drone"
vehicle_index = [1, 2]
now_index = vehicle_index[0]

AirSim_client = airsim.MultirotorClient()
AirSim_client.confirmConnection()

AirSim_client.enableApiControl(True, vehicle_name=base_name + str(vehicle_index[0]))
AirSim_client.enableApiControl(True, vehicle_name=base_name + str(vehicle_index[1]))

AirSim_client.armDisarm(True, vehicle_name=base_name + str(vehicle_index[0]))
AirSim_client.armDisarm(True, vehicle_name=base_name + str(vehicle_index[1]))

AirSim_client.takeoffAsync(vehicle_name=base_name + str(vehicle_index[0]))
AirSim_client.takeoffAsync(vehicle_name=base_name + str(vehicle_index[1])).join()

image_types = {
            "scene": airsim.ImageType.Scene,
            "depth": airsim.ImageType.DepthVis,
            "seg": airsim.ImageType.Segmentation,
            "normals": airsim.ImageType.SurfaceNormals,
            "segmentation": airsim.ImageType.Segmentation,
            "disparity": airsim.ImageType.DisparityNormalized
        }

# 基础的控制速率
base_rate = 0.2
# 悬停时的油门
base_throttle = 0.55
# 设置临时加速比例
speedup_ratio = 4.0
# 用来设置临时加速
speedup_flag = False

change_time = 0.0
# 防止来回切换控制对象
enable_change = True
# 用来标记当前是否进行键盘控制
control_iteration = False


while True:
    pitch_rate = 0.0
    yaw_rate = 0.0
    roll_rate = 0.0
    throttle = base_throttle
    control_iteration = False

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    scan_wrapper = pygame.key.get_pressed()

    # 按下空格键加速10倍
    if scan_wrapper[pygame.K_SPACE]:
        scale_ratio = speedup_ratio
    else:
        scale_ratio = speedup_ratio / speedup_ratio
    
    # 切换两秒后方可再次切换
    if time.time() - change_time > 2:
        enable_change = True
    
    # 需要加上enable_change变量判断,否则会来回切换
    if scan_wrapper[pygame.K_LCTRL] and scan_wrapper[pygame.K_c] and enable_change:
        enable_change = False
        change_time = time.time()
        if now_index == vehicle_index[0]:
            now_index = vehicle_index[1]
        else:
            now_index = vehicle_index[0]
        print(f"change to drone{now_index} ···")
        time.sleep(0.2)

    # 根据 'A' 和 'D' 按键来设置偏航速率变量
    if scan_wrapper[pygame.K_a] or scan_wrapper[pygame.K_d]:
        control_iteration = True
        yaw_rate = (scan_wrapper[pygame.K_a] - scan_wrapper[pygame.K_d]) * scale_ratio * base_rate

    # 根据 'UP' 和 'DOWN' 按键来设置pitch轴速率变量(NED坐标系,pitch为机头向前)
    if scan_wrapper[pygame.K_UP] or scan_wrapper[pygame.K_DOWN]:
        control_iteration = True
        pitch_rate = (scan_wrapper[pygame.K_UP] - scan_wrapper[pygame.K_DOWN]) * scale_ratio * base_rate

    # 根据 'LEFT' 和 'RIGHT' 按键来设置roll轴速率变量(NED坐标系,roll为正右方)
    if scan_wrapper[pygame.K_LEFT] or scan_wrapper[pygame.K_RIGHT]:
        control_iteration = True
        roll_rate = -(scan_wrapper[pygame.K_LEFT] - scan_wrapper[pygame.K_RIGHT]) * scale_ratio * base_rate

    # 根据 'W' 和 'S' 按键来设置z轴速率变量(NED坐标系,z轴向上为负,油门为正数)
    if scan_wrapper[pygame.K_w] or scan_wrapper[pygame.K_s]:
        control_iteration = True
        throttle = base_throttle + (scan_wrapper[pygame.K_w] - scan_wrapper[pygame.K_s]) * scale_ratio * base_rate
    
    # 速率需要限幅
    if pitch_rate > 1.0:
        pitch_rate = 1.0
    elif pitch_rate < -1.0:
        pitch_rate = -1.0

    if yaw_rate > 1.0:
        yaw_rate = 1.0
    elif yaw_rate < -1.0:
        yaw_rate = -1.0

    if roll_rate > 1.0:
        roll_rate = 1.0
    elif roll_rate < -1.0:
        roll_rate = -1.0

    if throttle > 1.0:
        throttle = 1.0
    elif throttle < 0.0:
        throttle = 0.0

    # 不控制的时候保持悬停,也可以用于刹车
    if control_iteration:
        # 设置速率控制以及设置偏航控制
        AirSim_client.moveByRollPitchYawrateThrottleAsync(pitch=pitch_rate, roll=roll_rate, yaw_rate=yaw_rate,
                                                          throttle=throttle, duration=0.05,
                                                          vehicle_name=base_name + str(now_index))
    else:
        # 保持当前位置
        AirSim_client.hoverAsync(vehicle_name=base_name + str(now_index))
    
    # 获取正前方的一帧图像
    temp_image = AirSim_client.simGetImage('0', image_types["scene"], vehicle_name=base_name + str(now_index))
    if temp_image is None:
        print("Warning: Failed to read a frame!! ")
        pygame.quit()

    else:
        pass

    # 将图像进行解码,变成像素值为0-255的范围,保存路径自行修改
    image = cv2.imdecode(airsim.string_to_uint8_array(temp_image), cv2.IMREAD_COLOR)
    cv2.imwrite('../data/screen/visual.png', image)

    # 利用pygame库加载保存的第一视角图像,
    screen_image = pygame.image.load("../data/screen/visual.png")
    # 图像坐标系,左上角为(0, 0),在此放置图片
    screen.blit(screen_image, (0, 0))
    pygame.display.flip()
    pygame.display.update()

    # press 'Esc' to quit
    if scan_wrapper[pygame.K_ESCAPE]:
        pygame.quit()
        sys.exit()


总结

本文使用更底层的控制API来实现无人机的运动控制,并使用opencv和pygame结合的方式来实现实时的图像读取与显示,较上一篇文章有更多拓展,只要自己能将各个参数调好,也能达到一种不错的控制效果。下一篇博客将开始使用程序收集图像数据集用于yolov5模型的训练,实现在AirSim中识别无人机以及其它需要识别的目标。

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值