1.建立一个world里面添加 无人机常用的测试门文件
核心代码:
bash
<!-- ==================== 4 个穿越门(开口2.4m) ==================== -->
<!-- 门1:红色,位置(4,0,2.5),朝向90° -->
<model name='gate_red'>
<static>1</static>
<link name='post_left'>
<visual name='visual'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
<material><ambient>1 0 0 1</ambient><diffuse>1 0 0 1</diffuse></material>
</visual>
<collision name='collision'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
</collision>
<pose>-1.2 0 0 0 0 0</pose>
</link>
<link name='post_right'>
<visual name='visual'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
<material><ambient>1 0 0 1</ambient><diffuse>1 0 0 1</diffuse></material>
</visual>
<collision name='collision'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
</collision>
<pose>1.2 0 0 0 0 0</pose>
</link>
<link name='top_bar'>
<visual name='visual'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
<material><ambient>1 0 0 1</ambient><diffuse>1 0 0 1</diffuse></material>
</visual>
<collision name='collision'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
</collision>
<pose>0 0 1.2 0 1.5708 0</pose>
</link>
<pose>4 0 2.5 0 0 1.5708</pose>
</model>
<!-- 门2:绿色,位置(0,4,2.8),朝向180° -->
<model name='gate_green'>
<static>1</static>
<link name='post_left'>
<visual name='visual'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
<material><ambient>0 1 0 1</ambient><diffuse>0 1 0 1</diffuse></material>
</visual>
<collision name='collision'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
</collision>
<pose>-1.2 0 0 0 0 0</pose>
</link>
<link name='post_right'>
<visual name='visual'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
<material><ambient>0 1 0 1</ambient><diffuse>0 1 0 1</diffuse></material>
</visual>
<collision name='collision'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
</collision>
<pose>1.2 0 0 0 0 0</pose>
</link>
<link name='top_bar'>
<visual name='visual'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
<material><ambient>0 1 0 1</ambient><diffuse>0 1 0 1</diffuse></material>
</visual>
<collision name='collision'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
</collision>
<pose>0 0 1.2 0 1.5708 0</pose>
</link>
<pose>0 4 2.8 0 0 3.1416</pose>
</model>
<!-- 门3:蓝色,位置(-4,0,3.0),朝向-90° -->
<model name='gate_blue'>
<static>1</static>
<link name='post_left'>
<visual name='visual'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
<material><ambient>0 0 1 1</ambient><diffuse>0 0 1 1</diffuse></material>
</visual>
<collision name='collision'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
</collision>
<pose>-1.2 0 0 0 0 0</pose>
</link>
<link name='post_right'>
<visual name='visual'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
<material><ambient>0 0 1 1</ambient><diffuse>0 0 1 1</diffuse></material>
</visual>
<collision name='collision'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
</collision>
<pose>1.2 0 0 0 0 0</pose>
</link>
<link name='top_bar'>
<visual name='visual'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
<material><ambient>0 0 1 1</ambient><diffuse>0 0 1 1</diffuse></material>
</visual>
<collision name='collision'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
</collision>
<pose>0 0 1.2 0 1.5708 0</pose>
</link>
<pose>-4 0 3.0 0 0 -1.5708</pose>
</model>
<!-- 门4:橙色,位置(0,-4,2.6),朝向0° -->
<model name='gate_orange'>
<static>1</static>
<link name='post_left'>
<visual name='visual'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
<material><ambient>1 0.5 0 1</ambient><diffuse>1 0.5 0 1</diffuse></material>
</visual>
<collision name='collision'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
</collision>
<pose>-1.2 0 0 0 0 0</pose>
</link>
<link name='post_right'>
<visual name='visual'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
<material><ambient>1 0.5 0 1</ambient><diffuse>1 0.5 0 1</diffuse></material>
</visual>
<collision name='collision'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
</collision>
<pose>1.2 0 0 0 0 0</pose>
</link>
<link name='top_bar'>
<visual name='visual'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
<material><ambient>1 0.5 0 1</ambient><diffuse>1 0.5 0 1</diffuse></material>
</visual>
<collision name='collision'>
<geometry><cylinder><radius>0.05</radius><length>2.4</length></cylinder></geometry>
</collision>
<pose>0 0 1.2 0 1.5708 0</pose>
</link>
<pose>0 -4 2.6 0 0 0</pose>
</model>
<!-- ==================== 门结束 ==================== -->
四个门东南西北
第二步:多点巡航的程序,核心代码如下,完整代码联系我
python
mavros_msgs::SetMode offb_set_mode;
offb_set_mode.request.custom_mode = "OFFBOARD";
mavros_msgs::SetMode land_set_mode;
land_set_mode.request.custom_mode = "AUTO.LAND";
mavros_msgs::CommandBool arm_cmd;
arm_cmd.request.value = true;
ros::Time last_request = ros::Time::now();
int wp_index = 0;
ros::Time last_wp = ros::Time::now();
bool cruise_started = false; // 是否已开始巡航
bool land_sent = false; // 是否已发降落指令
while(ros::ok()){
// ① 切 offboard 模式
if( current_state.mode != "OFFBOARD" &&
(ros::Time::now() - last_request > ros::Duration(2.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(2.0))){
if( arming_client.call(arm_cmd) &&
arm_cmd.response.success){
ROS_INFO("Vehicle armed");
}
last_request = ros::Time::now();
}
第三步:订阅RVIZ话题的程序
python
void pose_cb(const geometry_msgs::PoseStamped::ConstPtr& msg)
{
if(pts.empty() || dist(msg->pose.position, pts.back().pose.position) > 0.1)
{
pts.push_back(*msg);
cols.push_back(current_color); // 记录该点对应的门颜色
visualization_msgs::Marker m;
m.header.frame_id = "map";
m.header.stamp = ros::Time::now();
m.ns = "gate_traj";
m.id = 0;
m.type = visualization_msgs::Marker::LINE_STRIP;
m.action = visualization_msgs::Marker::ADD;
m.scale.x = 0.12; // 粗线
for(size_t i = 0; i < pts.size(); i++){
m.points.push_back(pts[i].pose.position);
m.colors.push_back(cols[i]);
}
marker_pub.publish(m);
最后一步:在Cmake.list里面添加 编译规则
终端1无人机 终端2订阅RVIZ 终端3.打开RVIZ,这里要选择Marker话题选对 终端4.发布巡航程序
当然也可以进行rosbag记录速度与位置信息
然后如上一篇操作,进行转化成csv格式,把下面代码放入matlab中
python
%% ============ 图1:3D轨迹 + 门 ============
figure('Color','w','Position',[80 80 650 560]);
plot3(x, y, z, '-', 'Color', [0 0.45 0.74], 'LineWidth', lw); hold on;
for i = 1:4
plot3(gx(i), gy(i), gz(i), 's', 'MarkerSize', 15, ...
'MarkerFaceColor', gc(i,:), 'MarkerEdgeColor','k','LineWidth',1.2);
end
hold off;
xlabel('X (m)'); ylabel('Y (m)'); zlabel('Z (m)');
legend([{'Trajectory'},{'Gate1','Gate2','Gate3','Gate4'}], ...
'Location','best','Box','off');
grid on; box on; axis equal; view(40,25);
set(gca,'FontSize',fs,'TickDir','out');
exportgraphics(gcf,'fig1_3d_traj.pdf','ContentType','vector');
%% ============ 图2:位置-时间 ============
figure('Color','w','Position',[80 680 650 400]);
plot(tp,x,'-','Color',[0.85 0.33 0.10],'LineWidth',lw); hold on;
plot(tp,y,'-','Color',[0.47 0.67 0.19],'LineWidth',lw);
plot(tp,z,'-','Color',[0.00 0.45 0.74],'LineWidth',lw); hold off;
xlabel('Time (s)'); ylabel('Position (m)');
legend({'x','y','z'},'Location','best','Box','off','NumColumns',3);
grid on; box on;
set(gca,'FontSize',fs,'TickDir','out');
exportgraphics(gcf,'fig2_position.pdf','ContentType','vector');
%% ============ 图3:速度-时间(平滑)============
figure('Color','w','Position',[780 80 650 400]);
plot(tv,vx_s,'-','Color',[0.85 0.33 0.10],'LineWidth',lw); hold on;
plot(tv,vy_s,'-','Color',[0.47 0.67 0.19],'LineWidth',lw);
plot(tv,vz_s,'-','Color',[0.00 0.45 0.74],'LineWidth',lw); hold off;
xlabel('Time (s)'); ylabel('Velocity (m/s)');
legend({'v_x','v_y','v_z'},'Location','best','Box','off','NumColumns',3);
grid on; box on;
set(gca,'FontSize',fs,'TickDir','out');
exportgraphics(gcf,'fig3_velocity.pdf','ContentType','vector');
%% ============ 图4:总速度 ============
figure('Color','w','Position',[780 560 650 400]);
plot(tv, speed_s, '-', 'Color', [0.20 0.20 0.20], 'LineWidth', lw);
xlabel('Time (s)'); ylabel('Speed |v| (m/s)');
grid on; box on;
set(gca,'FontSize',fs,'TickDir','out');
exportgraphics(gcf,'fig4_speed.pdf','ContentType','vector');