Pilot Tutorial
Simulate the quadrotor with your dynamic model while using Flightmare to generate sensor data.
Use Gazebo dynamics
Listen to ROS topic and set state
// initialize subscriber call backs
sub_state_est_ = nh_.subscribe("flight_pilot/state_estimate", 1,
&FlightPilot::poseCallback, this);
void FlightPilot::poseCallback(const nav_msgs::Odometry::ConstPtr &msg) {
quad_state_.x[QS::POSX] = (Scalar)msg->pose.pose.position.x;
quad_state_.x[QS::POSY] = (Scalar)msg->pose.pose.position.y;
quad_state_.x[QS::POSZ] = (Scalar)msg->pose.pose.position.z;
quad_state_.x[QS::ATTW] = (Scalar)msg->pose.pose.orientation.w;
quad_state_.x[QS::ATTX] = (Scalar)msg->pose.pose.orientation.x;
quad_state_.x[QS::ATTY] = (Scalar)msg->pose.pose.orientation.y;
quad_state_.x[QS::ATTZ] = (Scalar)msg->pose.pose.orientation.z;
//
quad_ptr_->setState(quad_state_);
if (unity_render_ && unity_ready_) {
unity_bridge_ptr_->getRender(0);
unity_bridge_ptr_->handleOutput();
}
}
Run example
roslaunch flightros rotors_gazebo.launch
Here the full code example
Header
#pragma once
#include <memory>
// ros
#include <nav_msgs/Odometry.h>
#include <ros/ros.h>
// rpg quadrotor
#include <autopilot/autopilot_helper.h>
#include <autopilot/autopilot_states.h>
#include <quadrotor_common/parameter_helper.h>
#include <quadrotor_msgs/AutopilotFeedback.h>
// flightlib
#include "flightlib/bridges/unity_bridge.hpp"
#include "flightlib/common/quad_state.hpp"
#include "flightlib/common/types.hpp"
#include "flightlib/objects/quadrotor.hpp"
#include "flightlib/sensors/rgb_camera.hpp"
using namespace flightlib;
namespace flightros {
class FlightPilot {
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
FlightPilot(const ros::NodeHandle& nh, const ros::NodeHandle& pnh);
~FlightPilot();
// callbacks
void mainLoopCallback(const ros::TimerEvent& event);
void poseCallback(const nav_msgs::Odometry::ConstPtr& msg);
bool setUnity(const bool render);
bool connectUnity(void);
bool loadParams(void);
private:
// ros nodes
ros::NodeHandle nh_;
ros::NodeHandle pnh_;
// publisher
// subscriber
ros::Subscriber sub_state_est_;
// main loop timer
ros::Timer timer_main_loop_;
// unity quadrotor
std::shared_ptr<Quadrotor> quad_ptr_;
std::shared_ptr<RGBCamera> rgb_camera_;
QuadState quad_state_;
// Flightmare(Unity3D)
std::shared_ptr<UnityBridge> unity_bridge_ptr_;
SceneID scene_id_{UnityScene::WAREHOUSE};
bool unity_ready_{false};
bool unity_render_{false};
RenderMessage_t unity_output_;
uint16_t receive_id_{0};
// auxiliary variables
Scalar main_loop_freq_{50.0};
};
} // namespace flightros
Main
#include "flightros/pilot/flight_pilot.hpp"
namespace flightros {
FlightPilot::FlightPilot(const ros::NodeHandle &nh, const ros::NodeHandle &pnh)
: nh_(nh),
pnh_(pnh),
scene_id_(UnityScene::WAREHOUSE),
unity_ready_(false),
unity_render_(false),
receive_id_(0),
main_loop_freq_(50.0) {
// load parameters
if (!loadParams()) {
ROS_WARN("[%s] Could not load all parameters.",
pnh_.getNamespace().c_str());
} else {
ROS_INFO("[%s] Loaded all parameters.", pnh_.getNamespace().c_str());
}
// quad initialization
quad_ptr_ = std::make_shared<Quadrotor>();
// add mono camera
rgb_camera_ = std::make_shared<RGBCamera>();
Vector<3> B_r_BC(0.0, 0.0, 0.3);
Matrix<3, 3> R_BC = Quaternion(1.0, 0.0, 0.0, 0.0).toRotationMatrix();
std::cout << R_BC << std::endl;
rgb_camera_->setFOV(90);
rgb_camera_->setWidth(720);
rgb_camera_->setHeight(480);
rgb_camera_->setRelPose(B_r_BC, R_BC);
quad_ptr_->addRGBCamera(rgb_camera_);
// initialization
quad_state_.setZero();
quad_ptr_->reset(quad_state_);
// initialize subscriber call backs
sub_state_est_ = nh_.subscribe("flight_pilot/state_estimate", 1,
&FlightPilot::poseCallback, this);
timer_main_loop_ = nh_.createTimer(ros::Rate(main_loop_freq_),
&FlightPilot::mainLoopCallback, this);
// wait until the gazebo and unity are loaded
ros::Duration(5.0).sleep();
// connect unity
setUnity(unity_render_);
connectUnity();
}
FlightPilot::~FlightPilot() {}
void FlightPilot::poseCallback(const nav_msgs::Odometry::ConstPtr &msg) {
quad_state_.x[QS::POSX] = (Scalar)msg->pose.pose.position.x;
quad_state_.x[QS::POSY] = (Scalar)msg->pose.pose.position.y;
quad_state_.x[QS::POSZ] = (Scalar)msg->pose.pose.position.z;
quad_state_.x[QS::ATTW] = (Scalar)msg->pose.pose.orientation.w;
quad_state_.x[QS::ATTX] = (Scalar)msg->pose.pose.orientation.x;
quad_state_.x[QS::ATTY] = (Scalar)msg->pose.pose.orientation.y;
quad_state_.x[QS::ATTZ] = (Scalar)msg->pose.pose.orientation.z;
//
quad_ptr_->setState(quad_state_);
if (unity_render_ && unity_ready_) {
unity_bridge_ptr_->getRender(0);
unity_bridge_ptr_->handleOutput();
}
}
void FlightPilot::mainLoopCallback(const ros::TimerEvent &event) {
// empty
}
bool FlightPilot::setUnity(const bool render) {
unity_render_ = render;
if (unity_render_ && unity_bridge_ptr_ == nullptr) {
// create unity bridge
unity_bridge_ptr_ = UnityBridge::getInstance();
unity_bridge_ptr_->addQuadrotor(quad_ptr_);
ROS_INFO("[%s] Unity Bridge is created.", pnh_.getNamespace().c_str());
}
return true;
}
bool FlightPilot::connectUnity() {
if (!unity_render_ || unity_bridge_ptr_ == nullptr) return false;
unity_ready_ = unity_bridge_ptr_->connectUnity(scene_id_);
return unity_ready_;
}
bool FlightPilot::loadParams(void) {
// load parameters
quadrotor_common::getParam("main_loop_freq", main_loop_freq_, pnh_);
quadrotor_common::getParam("unity_render", unity_render_, pnh_);
return true;
}
} // namespace flightros