赞
踩
我们这里用话题mavros/setpoint_raw/local
来发布控制命令。mavros/setpoint_raw/local
的消息内容可见官方文档:
http://docs.ros.org/en/api/mavros_msgs/html/msg/PositionTarget.html
用话题mavros/cmd/arming
和mavros/set_mode
来设定无人机的状态(解锁)和模式(OFFBOARD)。
其中进入OFFBOARD模式需要以>=2HZ的频率向无人机发送消息,否则无人机会回退到OFFBOARD模式之前所在的模式。
我们要发布无人机的目标位置,其中发布目标位置的消息将分为x坐标、y坐标和z坐标,因此我们需要写出圆圈的参数方程。
{
x
=
r
c
o
s
(
θ
)
y
=
r
s
i
n
(
θ
)
−
r
s
t
.
−
π
2
≤
θ
≤
3
π
2
st. -\frac{\pi}{2}\leq\theta\leq\frac{3\pi}{2}
st.−2π≤θ≤23π
无人机速度为
v
x
=
−
r
s
i
n
(
θ
)
v_x=-rsin(\theta)
vx=−rsin(θ)
v
y
=
r
c
o
s
(
θ
)
v_y= rcos(\theta)
vy=rcos(θ)
无人机的偏航角为
θ
=
a
r
c
t
a
n
(
v
y
x
x
)
\theta = arctan(\frac{v_y}{x_x})
θ=arctan(xxvy)
创建cpp文件offb_node.cpp
#include <ros/ros.h> #include <geometry_msgs/PoseStamped.h> #include <mavros_msgs/CommandBool.h> #include <mavros_msgs/SetMode.h> #include <mavros_msgs/State.h> #include <geometry_msgs/Twist.h> #include <mavros_msgs/PositionTarget.h> #define RATE 20 // 20hz #define r 2.5 // radius #define cycle_s 15 #define STEP (cycle_s * RATE) #define PI 3.14 mavros_msgs::State current_state; void state_cb (const mavros_msgs::State::ConstPtr& msg){ current_state = *msg; } geometry_msgs::PoseStamped local_pos; void local_pos_cb(const geometry_msgs::PoseStamped::ConstPtr& msg){ local_pos = *msg; } int main(int argc, char **argv) { ros::init(argc, argv, "offb_cfx"); ros::NodeHandle nh; // 订阅无人机当前状态 ros::Subscriber state_sub = nh.subscribe<mavros_msgs::State> ("mavros/state", 10, state_cb); // 发布无人机本地位置(控制) ros::Publisher target_pub = nh.advertise<mavros_msgs::PositionTarget>("mavros/setpoint_raw/local", 10); // 服务的客户端(设定无人机的模式、状态) ros::ServiceClient arming_client = nh.serviceClient<mavros_msgs::CommandBool> ("mavros/cmd/arming"); ros::ServiceClient set_mode_client = nh.serviceClient<mavros_msgs::SetMode> ("mavros/set_mode"); //the setpoint publishing rate MUST be faster than 2Hz ros::Rate rate(RATE); mavros_msgs::PositionTarget Target_P; Target_P.coordinate_frame = mavros_msgs::PositionTarget::FRAME_LOCAL_NED; Target_P.type_mask = mavros_msgs::PositionTarget::IGNORE_VX | mavros_msgs::PositionTarget::IGNORE_VY | mavros_msgs::PositionTarget::IGNORE_VZ | mavros_msgs::PositionTarget::IGNORE_AFX | mavros_msgs::PositionTarget::IGNORE_AFY | mavros_msgs::PositionTarget::IGNORE_AFZ | mavros_msgs::PositionTarget::IGNORE_YAW_RATE; Target_P.position.x = 0; Target_P.position.y = 0; Target_P.position.z = 0; Target_P.velocity.x = 0; Target_P.velocity.y = 0; Target_P.velocity.z = 0; Target_P.acceleration_or_force.x = 0; Target_P.acceleration_or_force.y = 0; Target_P.acceleration_or_force.z = 0; Target_P.yaw = 0; Target_P.yaw_rate = 0; // wait for FCU connection while(ros::ok() && !current_state.connected){ ros::spinOnce(); rate.sleep(); } //send a few setpoints before starting for(int i = 100; ros::ok() && i > 0; --i){ target_pub.publish(Target_P); ros::spinOnce(); rate.sleep(); } // 设定无人机工作模式 offboard mavros_msgs::SetMode offb_set_mode; offb_set_mode.request.custom_mode = "OFFBOARD"; // 无人机解锁 mavros_msgs::CommandBool arm_cmd; arm_cmd.request.value = true; // 记录当前时间 ros::Time last_request = ros::Time::now(); // 用于走圈的变量 int step = 0; int sametimes = 0; int i = 0; double theta = -PI/2; while(ros::ok()){ // 无人机状态设定与判断 // 进入while循环后,先循环5s,然后再向客户端发送无人机状态设置的消息 // set_mode_client.call arming_client.call if( current_state.mode != "OFFBOARD" && (ros::Time::now() - last_request > ros::Duration(5.0))){ if( set_mode_client.call(offb_set_mode) && offb_set_mode.response.mode_sent){ ROS_INFO("Offboard enabled"); } last_request = ros::Time::now(); } else { if( !current_state.armed && (ros::Time::now() - last_request > ros::Duration(5.0))){ if( arming_client.call(arm_cmd) && arm_cmd.response.success){ ROS_INFO("Vehicle armed"); } last_request = ros::Time::now(); } else // 无人机 Offboard enabled && Vehicle armed 后 { switch (step) { case 0: Target_P.position.z = 2.0; if(local_pos.pose.position.z >1.95 && local_pos.pose.position.z <2.05) step = 1; break; case 1: theta += 2*PI/STEP; Target_P.position.x = r*cos(theta); Target_P.position.y = r*sin(theta) + r; Target_P.position.z = 2.0; Target_P.velocity.x = -r*sin(theta); Target_P.velocity.y = r*cos(theta); Target_P.velocity.z = 0; Target_P.acceleration_or_force.x = -r*cos(theta); Target_P.acceleration_or_force.y = -r*sin(theta); Target_P.acceleration_or_force.x = 0; Target_P.yaw = atan2(Target_P.velocity.y, Target_P.velocity.x = -r*sin(theta)); i ++; if(i > STEP) { i = 1; step = 2; } break; case 2: if(sametimes < 40) { sametimes ++; } else { offb_set_mode.request.custom_mode = "AUTO.LAND"; if (current_state.mode != "AUTO.LAND" && (ros::Time::now() - last_request > ros::Duration(5.0))) { if (set_mode_client.call(offb_set_mode) && offb_set_mode.response.mode_sent) { ROS_INFO("AUTO.LAND enabled"); step = 3; } last_request = ros::Time::now(); } } break; default: break; } } } // 发布位置控制信息 target_pub.publish(Target_P); ros::spinOnce(); rate.sleep(); // 影响消息发布与更新的周期 } return 0; }
其中,代码中
Target_P.type_mask = mavros_msgs::PositionTarget::IGNORE_VX |
mavros_msgs::PositionTarget::IGNORE_VY |
mavros_msgs::PositionTarget::IGNORE_VZ |
mavros_msgs::PositionTarget::IGNORE_AFX |
mavros_msgs::PositionTarget::IGNORE_AFY |
mavros_msgs::PositionTarget::IGNORE_AFZ |
mavros_msgs::PositionTarget::IGNORE_YAW_RATE;
把速度和加速度以及偏航角速度忽略了,本质上来讲还是位置控制。
在CmakeList中添加
cmake_minimum_required(VERSION 3.0.2) project(off_node) find_package(catkin REQUIRED COMPONENTS geometry_msgs mavros_msgs roscpp std_msgs ) catkin_package() include_directories( ${catkin_INCLUDE_DIRS} ) add_executable(offb_node src/offb_node.cpp) target_link_libraries(offb_node ${catkin_LIBRARIES})
创建脚本offb.sh
#!/bin/zsh
source ~/.zshrc
gnome-terminal --window -e 'zsh -c "roscore; exec zsh"' \
--tab -e 'zsh -c "sleep 5; roslaunch px4 mavros_posix_sitl.launch; exec zsh"' \
--tab -e 'zsh -c "sleep 5; source ~/catkin_ws/devel/setup.zsh; rosrun off_node offb_node; exec zsh"' \
这里我用的终端是zsh的,如果是bash可以自行将zsh换成bash即可。
https://zhuanlan.zhihu.com/p/476941058
https://zhuanlan.zhihu.com/p/440996013?utm_id=0
第二篇文章有速度闭环控制(但是是画矩形)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。