GAZEBO多无人机仿真通信+键盘控制

准备工具

ubuntu18.04

gazebo

PX4+ROS环境配置

xtdrone配置

多无人机仿真

roslaunch px4 multi_uav_mavros_sitl.launch

xtdrone上给出的多无人机启动launch文件,其中默认有三个飞行器,分别为uav0,uav1,uav2

e639c34c131145488ed66bcecfe2dd4b.png

 其中的无人机编号代码部分为

7b4799c1247146b98d235314e2325c11.png

可以 增加无人机在文件最后添加一个组即可(复制以上)

49574145ebc742b9af0f827c0ce13e02.png

其中要修改的有

 <group ns="uav3">

这是命名无人机 ,也是修改话题,服务前缀.

<arg name="ID" value="3"/>
<arg name="fcu_url" default="udp://:24543@localhost:34583"/>

这是无人机ID参数和通信接口,与上一架飞机同参数增加一即可.

其次还有这些,mavlink通信port

<arg name="mavlink_udp_port" value="18573"/>
<arg name="mavlink_tcp_port" value="4563"/>

还有一处

            <arg name="x" value="1"/>
            <arg name="y" value="1"/>
            <arg name="z" value="0"/>
            <arg name="R" value="0"/>
            <arg name="P" value="0"/>
            <arg name="Y" value="0"/>

这里可以改变飞行器初始位置,如果不改的话会和上一个无人机重叠.

这样就添加了一架无人机

ad11e64e6825462c8ef9176ffa7b1898.png

可以随意增加(只要你的电脑内存足够)

像这样

cf16b0bb318141fbba64e1960bcee8a4.png

 是不是很壮观!

查看话题,服务列表后会出现带前缀的

accf49bc8ffc4047b79971f5fafe0e3c.png

无人机键盘控制

首先我这里参考了这位博主的文章

https://blog.csdn.net/cherish1211/article/details/131951664?spm=1001.2014.3001.5502

该博主是在pycharm上编译运行的,我这里要修改一下.

让这个节点在ROS下编译,代码如下

#! /usr/bin/env python
# -*- coding: UTF-8 -*-

import mavros_msgs
import rospy
from mavros_msgs.srv import SetMode,CommandBool

import sys, select, os
#os模块是用于与操作系统进行交互的模块。TTY(teletypewriter)是指终端设备,例如终端窗口、终端控制台或串口终端。
#select 模块:该模块提供了对低级 I/O 多路复用的支持。
#termios模块是Python中用于处理终端IO(Input/Output)的模块,允许我们控制终端的特性(attributes),例如字符的读取方式、输入输出模式等。
import tty, termios
from std_msgs.msg import String

msg2all = """
请输入输入指令:
r   : return home
t/y : arm/disarm
v/n : takeoff/land
b   : offboard
p   : position
s   : stabilized
k   : hover and remove the mask of keyboard control
CTRL-C to quit
"""





def getKey():
    #这行代码使用tty模块的setraw()函数来设置标准输入(sys.stdin)的行为为原始模式。
    #原始模式下,输入不经过缓冲,每次输入一个字符。
    tty.setraw(sys.stdin.fileno())
    #这行代码使用select模块的select()函数来检查是否有可读取的数据。
    #它监视sys.stdin(标准输入),并且等待0.1秒钟。如果在等待期间有数据可读,
    #则select()函数会返回一个非空的可读列表(rlist),否则返回空列表
    rlist, _, _ = select.select([sys.stdin], [], [], 0.1)
    #这段代码检查rlist列表是否非空。如果列表非空,说明在等待期间有数据可读。
    #此时,通过sys.stdin.read(1)读取一个字符,并将其赋值给key变量。
    #如果列表为空,则说明在等待期间没有数据可读,此时将key变量赋值为空字符串。
    if rlist:
        key = sys.stdin.read(1)
    else:
        key = ''
    #这行代码使用termios模块的tcsetattr()函数来恢复标准输入的设置。
    #TCSADRAIN参数表示在所有排队的输出都被传输和处理之后才生效。
    #将标准输入的属性设置为之前保存的settings值。它使用termios.tcsetattr函数来设置终端的属性。
    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)
    #最后,函数返回变量key的值,即读取到的字符(如果有)或空字符串(如果没有读取到字符)。
    return key



def print_msg():
        print(msg2all)


#主函数
if __name__=="__main__":
#设置终端为标准输入流
    settings = termios.tcgetattr(sys.stdin)

    rospy.init_node('my_keyboard_control')
    uav_cmd_pub = rospy.ServiceProxy("/mavros/set_mode",SetMode)
    uav_arm_pub=rospy.ServiceProxy("/mavros/cmd/arming",mavros_msgs.srv.CommandBool)

    #uav_cmd_pub = rospy.ServiceProxy("/uav_0/mavros/set_mode",SetMode)
    #uav_arm_pub = rospy.ServiceProxy("/uav_0/mavros/cmd/arming",mavros_msgs.srv.CommandBool)

    print_msg()
    cmd=""
    while(1):
        key = getKey()#获取读取到的字符
        if key == 'r':
            cmd = 'AUTO.RTL'
            print_msg()
            print('Returning home')
        elif key == 't':
            cmd = 'ARM'
            print_msg()
            print('Arming')
        elif key == 'y':
            cmd = 'DISARM'
            print_msg()
            print('Disarming')
        elif key == 'v':
            cmd = 'AUTO.TAKEOFF'
            print_msg()
            #print('Takeoff mode is disenabled now')
        elif key == 'b':
            cmd = 'OFFBOARD'
            print_msg()
            print('Offboard')
        elif key == 'n':
            cmd = 'AUTO.LAND'
            print_msg()
            print('Landing')
        elif key == 'p':
            cmd = 'POSCTL'
            print_msg()
            print('Position')
        elif key == 's':
            cmd = 'STABILIZED'
            print_msg()
            print('Stabilized')
        elif key in ['k']:
            cmd = 'HOVER'
            print_msg()
            print('Hover')
        elif(key == '\x03'):
                break

        if (cmd=='ARM'):
            uav_arm_pub(True)
        elif (cmd=='DISARM'):
            uav_arm_pub(False)
        else:
            uav_cmd_pub(custom_mode=cmd)


        cmd = ''

    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)

我添加了ROS中python文件的表头,然后增加了两种模式,自稳和悬停模式

然后通过ros节点即可运行

rosrun offboard_nodes key_board.py

 a15a6434c55e4d71a5d84092a2ec06ab.png

记得退出虚拟环境,不然会报错的.

先按t键解锁无人机,再切offboard即可.

多无人机键盘控制

我在上述代码中增加了1-9按键的控制,分别对应1-9号无人机.

添加如下代码

uav_name = 'uav0' 
uav_cmd_pub = rospy.ServiceProxy(uav_name+"/mavros/set_mode",SetMode)
uav_arm_pub=rospy.ServiceProxy(uav_name+"/mavros/cmd/arming",mavros_msgs.srv.CommandBool)

...

if key == '1':
            uav_name = 'uav0'
	    print("开启无人机一号")
        elif key == '2':
            uav_name = 'uav1'
	    print("开启无人机二号")
...

分别是添加话题的前缀,,然后增加数字按键的读取,改变前缀名称.

注:这里前缀名称和你前面launch文件中定义的无人机名称一致,才能控制.

视频效果如下

GAZEBO多无人机通信仿真(键盘控制)

 

 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是基于PX4的无人机定点飞行C++代码示例: ```cpp #include <px4_posix.h> #include <px4_tasks.h> #include <uORB/topics/vehicle_local_position.h> #include <uORB/topics/vehicle_attitude.h> // 定义无人机起飞高度 #define TAKEOFF_ALTITUDE 5.0f // 定义目标位置 #define TARGET_LATITUDE 47.398039f #define TARGET_LONGITUDE 8.545572f #define TARGET_ALTITUDE 10.0f // 定义位置误差阈值 #define POSITION_TOLERANCE 0.5f // 定义姿态误差阈值 #define ATTITUDE_TOLERANCE 0.1f // 定义控制循环间隔时间 #define CONTROL_INTERVAL_US 20000 // 定义无人机状态枚举类型 enum class DroneState { INITIALIZING, TAKEOFF, FLYING, LANDING, LANDED, DISARMED }; // 定义无人机状态变量 static DroneState drone_state = DroneState::INITIALIZING; // 定义无人机位置变量 static struct vehicle_local_position_s local_position; // 定义无人机姿态变量 static struct vehicle_attitude_s attitude; // 定义无人机任务句柄 static px4_task_t control_task_handle = -1; // 定义定点飞行控制函数 void control_task_main(int argc, char *argv[]) { // 初始化本地位置和姿态订阅器 int local_position_sub_fd = orb_subscribe(ORB_ID(vehicle_local_position)); int attitude_sub_fd = orb_subscribe(ORB_ID(vehicle_attitude)); // 开始控制循环 while (true) { // 等待新数据 px4_pollfd_struct_t fds[] = { { .fd = local_position_sub_fd, .events = POLLIN }, { .fd = attitude_sub_fd, .events = POLLIN } }; int poll_ret = px4_poll(fds, 2, CONTROL_INTERVAL_US); // 处理新数据 if (poll_ret == 0) { // 超时 continue; } else if (poll_ret < 0) { // 错误 PX4_ERR("poll error: %d", poll_ret); continue; } // 获取最新的本地位置和姿态数据 orb_copy(ORB_ID(vehicle_local_position), local_position_sub_fd, &local_position); orb_copy(ORB_ID(vehicle_attitude), attitude_sub_fd, &attitude); // 根据当前状态执行相应的控制逻辑 switch (drone_state) { case DroneState::INITIALIZING: { // 等待初始化完成 if (local_position.z > TAKEOFF_ALTITUDE) { drone_state = DroneState::TAKEOFF; } break; } case DroneState::TAKEOFF: { // 起飞 if (local_position.z > TARGET_ALTITUDE - POSITION_TOLERANCE) { drone_state = DroneState::FLYING; } break; } case DroneState::FLYING: { // 到达目标位置 float position_error = sqrtf(powf(local_position.x - TARGET_LATITUDE, 2) + powf(local_position.y - TARGET_LONGITUDE, 2)); if (position_error < POSITION_TOLERANCE && fabsf(attitude.roll) < ATTITUDE_TOLERANCE && fabsf(attitude.pitch) < ATTITUDE_TOLERANCE) { drone_state = DroneState::LANDING; } break; } case DroneState::LANDING: { // 降落 if (local_position.z < POSITION_TOLERANCE) { drone_state = DroneState::LANDED; } break; } case DroneState::LANDED: { // 停止控制循环 return; } default: { // 错误状态 PX4_ERR("invalid drone state: %d", (int)drone_state); drone_state = DroneState::DISARMED; break; } } } } // 定义主函数 int main(int argc, char *argv[]) { // 初始化PX4 px4_main(argc, argv, "px4_posix_app"); // 创建控制任务 control_task_handle = px4_task_spawn_cmd("control_task", SCHED_DEFAULT, SCHED_PRIORITY_MAX - 5, 2000, (px4_main_t)&control_task_main, (char *const *)nullptr); // 等待控制任务结束 px4_task_waitpid(control_task_handle, nullptr, 0); // 退出程序 return 0; } ``` 上述代码实现了基于PX4的无人机定点飞行控制逻辑,其中使用了本地位置和姿态订阅器获取无人机状态信息,使用控制循环实现了状态机控制逻辑。需要注意的是,该代码仅为示例代码,实际应用中需要根据具体情况进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值