安装 rotors_simulator
1. 新建工作空间并初始化(有工作空间的跳过此步骤)
1 | mkdir -p ~/rotors_ws/src |
2. 克隆源代码
1 | cd ~/rotors_ws/src |
3. 初始化wstool,并更新所需库
1 | wstool init |
4. 编译
1 | cd ~/rotors_ws/ |
5. 环境变量
1 | source ./devel/setup.bash |
也可以用下面的方式:
1 | echo "source ~/rotors_ws/devel/setup.bash" >> ~/.bashrc |
6. 测试
1 | roslaunch rotors_gazebo mav_hovering_example.launch mav_name:=firefly world_name:=basic |
如果安装成功,就能启动gazebo
,看到飞机
切换环境和飞机模型
可以在启动时指定参数切换飞机和场景,也可以修改launch
文件。
下面以修改mav_hovering_example_with_vi_sensor.launch
为例,mav_hovering_example_with_vi_sensor.launch
文件位于~/rotors_ws/src/rotors_simulator/rotors_gazebo/launch/
路径下:
mav_hovering_example_with_vi_sensor.launch文件
:
修改launch
文件中的mav_name
切换飞机
打开
launch
文件1
sudo gedit ~/rotors_ws/src/rotors_simulator/rotors_gazebo/launch/mav_hovering_example_with_vi_sensor.launch
第三行参数
firefly
可以改为~/rotors_ws/src/rotors_simulator/rotors_description/urdf
路径中的任意一个飞机名,如iris
,ardrone
等。
修改launch
文件中的world_name
切换场景
- 打开
launch
文件1
sudo gedit ~/rotors_ws/src/rotors_simulator/rotors_gazebo/launch/mav_hovering_example_with_vi_sensor.launch
- 第四行参数
outdoor
可以改为~/rotors_ws/src/rotors_simulator/rotors_gazebo/worlds/
路径中的任意一个文件名,如outdoor
,plane
等。
~/rotors_ws/src/rotors_simulator/rotors_gazebo/worlds/
路径下的文件如下图
测试
修改完之后运行
1 | roslaunch rotors_gazebo mav_hovering_example_with_vi_sensor.launch |
即可查看修改效果
ps. 如果修改的是其他launch
文件,则运行对应的文件查看。
创建直接的 ROS package 来控制飞机
1. 新建 ROS package
1 | cd ~/rotors_ws/src |
如:新建跟踪 package: catkin_create_pkg uav_tracking std_msgs rospy roscpp
2. 修改 uav_tracking/CMakeLists.txt
添加依赖
修改前
1 | find_package(catkin REQUIRED COMPONENTS |
修改后
1 | find_package(catkin REQUIRED COMPONENTS |
- sensor_msgs,添加对ROS官方sensor_msgs消息的依赖,在包的程序中可以使用sensor_msgs/xxx类型的消息;
- geometry_msgs,添加对ROS官方geometry_msgs消息的依赖,在包的程序中可以使用geometry_msgs/xxx类型的消息;
- mav_msgs,添加对mav_msgs消息的依赖,在包的程序中可以使用mav_msgs/xxx类型的消息,该消息的定义在UAV\src\mav_comm包中定义;
- gazebo_msgs添加对ROS官方gazebo_msgs消息的依赖,在包的程序中可以使用gazebo_msgs/xxx类型的消息,主要用于从Gazebo中获取消息.
3. 修改 uav_tracking/package.xml
在 <exec_depend>std_msg</exec_depend>
后添加:
1 | <depend>gazebo_msgs</depend> |
添加后:
4. 新建测试 cpp 文件
在uav_tracking/src/
中新建control_test.cpp
文件并写入下面代码,用于控制飞机:
点击查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
#include <ros/ros.h>
#include <iostream>
#include <chrono>
#include <thread>
#include <geometry_msgs/PointStamped.h>
#include <std_srvs/Empty.h>
#include <Eigen/Core>
#include <mav_msgs/conversions.h>
#include <mav_msgs/default_topics.h>
#include <trajectory_msgs/MultiDOFJointTrajectory.h>
ros::Publisher trajectory_pub;
geometry_msgs::PointStamped current_position;
float linear_smoothing_navigation_step = 2;
bool flag_gps_initialized_OK = false;
bool flag_take_off_OK = false;
int flag_tasks_OK = 0;
Eigen::Vector3d home;
/*
Description:
updateUavPosition(const geometry_msgs::PointStamped& msg)
gps数据更新的回调函数.
Parameters:
msg 位置信息
Return:
无
*/
void updateUavPosition(const geometry_msgs::PointStamped& msg)
{
if (!flag_gps_initialized_OK)
{
flag_gps_initialized_OK= true;
home[0] = msg.point.x;
home[1] = msg.point.y;
home[2] = msg.point.z;
}
current_position = msg;
// std::cout<<"UAV current position is: "<<msg.point.x<< msg.point.y<< msg.point.z<<std::endl;
}
/*
Description:
getDistanceToTarget(const Eigen::Vector3d& target)
获取当前位置到指定位置位置的距离.
Parameters:
target 需要飞达的位置点
Return:
double 当前位置到达目标点的位置
*/
double getDistanceToTarget(const Eigen::Vector3d& target)
{
double temp = 0;
temp += pow((target[0] - current_position.point.x), 2);
temp += pow((target[1] - current_position.point.y), 2);
temp += pow((target[2] - current_position.point.z), 2);
temp = sqrt(temp);
return temp;
}
/*
Description:
reachTargetPosition(const Eigen::Vector3d& target, float max_error)
判定是否到达指定的目标点.
Parameters:
target 需要飞达的位置点
max_error 允许的位置误差阈值,当前位置和目标位置小于该阈值时,判定无人机到达目标点
Return:
bool 到达目标点时返回 true
未到达目标点时返回 false
*/
bool reachTargetPosition(const Eigen::Vector3d& target, float max_error)
{
double temp = getDistanceToTarget(target);
if (temp < max_error)
return true;
return false;
}
/*
Description:
linearSmoothingNavigationTask(const Eigen::Vector3d& target)
控制无人机从当前位置飞向指定位置.
Parameters:
target 需要飞达的位置点
Return:
bool 起飞结束后返回 true
起飞过程中返回 false
*/
bool linearSmoothingNavigationTask(const Eigen::Vector3d& target)
{
trajectory_msgs::MultiDOFJointTrajectory trajectory_msg;
trajectory_msg.header.stamp = ros::Time::now();
if (reachTargetPosition(target,0.2))
return true;
double dist = getDistanceToTarget(target);
Eigen::Vector3d next_step;
if(dist<linear_smoothing_navigation_step)
{
next_step = target;
}
else
{
next_step[0] = current_position.point.x+(target[0]-current_position.point.x)/dist*linear_smoothing_navigation_step;
next_step[1] = current_position.point.y+(target[1]-current_position.point.y)/dist*linear_smoothing_navigation_step;
next_step[2] = current_position.point.z+(target[2]-current_position.point.z)/dist*linear_smoothing_navigation_step;
}
double desired_yaw = 0.0;
mav_msgs::msgMultiDofJointTrajectoryFromPositionYaw(next_step, desired_yaw, &trajectory_msg);
trajectory_pub.publish(trajectory_msg);
return false;
}
/*
Description:
takeOffTask(float height)
起飞函数,调用后无人机从起始位置起飞指定高度.
Parameters:
height 指定的起飞高度
Return:
bool 起飞结束后返回 true
起飞过程中返回 false
*/
bool takeOffTask(float height)
{
trajectory_msgs::MultiDOFJointTrajectory trajectory_msg;
trajectory_msg.header.stamp = ros::Time::now();
static Eigen::Vector3d desired_position(current_position.point.x, current_position.point.y, height);
double desired_yaw = 0.0;
if (reachTargetPosition(desired_position,0.2))
return true;
mav_msgs::msgMultiDofJointTrajectoryFromPositionYaw(desired_position, desired_yaw, &trajectory_msg);
trajectory_pub.publish(trajectory_msg);
return false;
}
/*
Description:
gohome()
反航函数,调用后无人机先沿着当前高度飞到反航点正上方,然后降落.
Parameters:
无
Return:
无
*/
void gohome()
{
static Eigen::Vector3d temp(home[0], home[1], current_position.point.z);
static bool flag_temp = false;
if (!flag_temp)
{
flag_temp = linearSmoothingNavigationTask(temp);
}
else
{
linearSmoothingNavigationTask(home);
}
}
int main(int argc, char** argv) {
ros::init(argc, argv, "UAV_Controler");
ros::NodeHandle nh;
// Create a private node handle for accessing node parameters.
ros::NodeHandle nh_private("~");
std::string uav_name = "";
ros::param::get("~mav_name",uav_name);
// 订阅话题
// /odometry_sensor1/position 无人机位置信息(包含噪声)
ros::Subscriber position_sub = nh.subscribe(std::string("/"+uav_name+"/odometry_sensor1/position").c_str(), 10, &updateUavPosition);
trajectory_pub = nh.advertise<trajectory_msgs::MultiDOFJointTrajectory>(mav_msgs::default_topics::COMMAND_TRAJECTORY, 10);
// 等待5s,让Gazebo可以成功启动.
ros::Duration(5.0).sleep();
// 创建控制Gazebo自动运行的服务,这里自动运行是指让Gazebo自动Play
std_srvs::Empty srv;
bool unpaused = ros::service::call("/gazebo/unpause_physics", srv);
// 尝试让Gazebo自动运行
int i=0;
while (i <= 10 && !unpaused) {
ROS_INFO("Wait for 1 second before trying to unpause Gazebo again.");
std::this_thread::sleep_for(std::chrono::seconds(1));
unpaused = ros::service::call("/gazebo/unpause_physics", srv);
++i;
}
// 判断Gazebo有没有自动运行,没有成功Play则退出
if (!unpaused) {
ROS_FATAL("Could not wake up Gazebo.");
return -1;
} else {
ROS_INFO("Unpaused the Gazebo simulation.");
}
std::vector<Eigen::Vector3d> path;
path.push_back(Eigen::Vector3d(5.f,5.f,5.f));
path.push_back(Eigen::Vector3d(-5.f,5.f,5.f));
path.push_back(Eigen::Vector3d(-5.f,-5.f,5.f));
path.push_back(Eigen::Vector3d(5.f,-5.f,5.f));
path.push_back(Eigen::Vector3d(5.f,5.f,5.f));
std::cout << path.size() << std::endl;
ros::Rate loop_rate(10);
while (ros::ok())
{
if(flag_gps_initialized_OK && !flag_take_off_OK)
{
// ROS_INFO("UAV take off task is running...");
flag_take_off_OK = takeOffTask(3);
}
else if(flag_take_off_OK && flag_tasks_OK<path.size())
{
if(flag_tasks_OK<path.size())
{
bool temp = linearSmoothingNavigationTask(path[flag_tasks_OK]);
if (temp)
flag_tasks_OK ++;
}
}
else if(flag_tasks_OK >= path.size())
{
gohome();
}
ros::spinOnce();
loop_rate.sleep();
}
}
5. 创建launch
文件夹并新建control_test.launch
文件
1 | cd ~/rotors_ws/src/uav_tracking/ |
在control_test.launch
中写入:
1 | <launch> |
6. 在 uav_tracking/CMakeLists.txt
添加编译
在uav_tracking/CMakeLists.txt
文件最下方添加:
1 | add_executable(control_test src/control_test.cpp) |
7. 编译
1 | cd ~/rotors_ws |
8. 运行
重启终端:
1 | source ~/rotors_ws/devel/setup.bash |
如果启动成功,就可以看到程序自动启动仿真,无人机根据control_test.cpp
的代码开始自己运动