58#include <gz/sim/Server.hh>
59#include <gz/sim/ServerConfig.hh>
60#include <gz/sim/System.hh>
61#include <gz/sim/Model.hh>
62#include <gz/sim/Link.hh>
63#include <gz/sim/World.hh>
64#include <gz/sim/components/Gravity.hh>
65#include <gz/sim/components/MagneticField.hh>
66#include <gz/sim/components/SphericalCoordinates.hh>
67#include <gz/math/Pose3.hh>
68#include <gz/math/Quaternion.hh>
69#include <gz/math/Vector3.hh>
70#include <gz/msgs/image.pb.h>
71#include <gz/transport/Node.hh>
78#include "generated/airframe.h"
79#include "generated/flight_plan.h"
103#ifndef NPS_MT9F002_SENSOR_RES_DIVIDER
104#define NPS_MT9F002_SENSOR_RES_DIVIDER 1
115static std::unique_ptr<gz::transport::Node>
gz_node;
122#ifndef NPS_GAZEBO_WORLD
123#define NPS_GAZEBO_WORLD "empty.world"
125#ifndef NPS_GAZEBO_AC_NAME
126#define NPS_GAZEBO_AC_NAME "bebop"
145 gz::math::Pose3d pose;
146 gz::math::Vector3d linear_vel;
147 gz::math::Vector3d angular_vel;
149 gz::math::Vector3d magnetic_field;
150 double heading_offset;
168 public gz::sim::ISystemConfigure,
169 public gz::sim::ISystemPreUpdate,
170 public gz::sim::ISystemPostUpdate
174 const std::shared_ptr<const sdf::Element> &,
175 gz::sim::EntityComponentManager &
ecm,
176 gz::sim::EventManager &)
override
182 void PreUpdate(
const gz::sim::UpdateInfo &info, gz::sim::EntityComponentManager &
ecm)
override
184 if (
model_ == gz::sim::kNullEntity) {
193 auto pose = link.WorldPose(
ecm);
197 gz::math::Vector3d force = pose->Rot().RotateVector(gz::math::Vector3d(0, 0,
gz_cmd.thrusts[i]));
198 gz::math::Vector3d
torque = pose->Rot().RotateVector(gz::math::Vector3d(0, 0,
gz_cmd.torques[i]));
203 void PostUpdate(
const gz::sim::UpdateInfo &info,
const gz::sim::EntityComponentManager &
ecm)
override
205 if (
model_ == gz::sim::kNullEntity) {
209 auto pose =
body.WorldPose(
ecm);
210 auto vel =
body.WorldLinearVelocity(
ecm);
211 auto ang_vel =
body.WorldAngularVelocity(
ecm);
212 if (!pose || !vel || !ang_vel) {
221 auto mag =
ecm.Component<gz::sim::components::MagneticField>(
world_);
222 gz_state.magnetic_field = mag ? mag->Data() : gz::math::Vector3d::Zero;
223 auto sphere =
ecm.Component<gz::sim::components::SphericalCoordinates>(
world_);
226 gz_state.sim_time = std::chrono::duration<double>(info.simTime).count();
243 fprintf(
stderr,
"NPS gz: link '%s' not found in model '%s'\n",
250 body.EnableVelocityChecks(
ecm,
true);
257 gz::sim::Entity
world_{gz::sim::kNullEntity};
258 gz::sim::Entity
model_{gz::sim::kNullEntity};
263static std::unique_ptr<gz::sim::Server>
server;
275 return gz::math::Quaterniond(0, 0,
gz_state.heading_offset -
M_PI);
321#ifdef NPS_ACTUATOR_TIME_CONSTANTS
327#ifdef NPS_ACTUATOR_MAX_ANGULAR_MOMENTUM
351#if NPS_SIMULATE_VIDEO
373 const char *home = getenv(
"PAPARAZZI_HOME");
379 const std::string
dirs[] = {
pprz_home +
"/conf/simulator/gazebo/",
pprz_home +
"/sw/ext/tudelft_gazebo_models/" };
382 for (
const std::string &
dir :
dirs) {
383 sdf::addURIPath(
"model://",
dir +
"models/");
384 sdf::addURIPath(
"world://",
dir +
"world/");
388 sdf::addURIPath(
"model://",
pprz_home +
"/conf/simulator/gazebo/models_gz/");
391 const char *
env_path = getenv(
"GZ_SIM_RESOURCE_PATH");
416 sdf::ElementPtr world =
world_sdf->Root()->GetElement(
"world");
417#if NPS_SIMULATE_VIDEO
421 if (!world->HasElement(
"plugin")) {
423 "<sdf version='1.6'><world name='plugins'>"
424 "<plugin filename='gz-sim-physics-system' name='gz::sim::systems::Physics'/>"
425 "<plugin filename='gz-sim-user-commands-system' name='gz::sim::systems::UserCommands'/>"
426 "<plugin filename='gz-sim-scene-broadcaster-system' name='gz::sim::systems::SceneBroadcaster'/>"
427 "<plugin filename='gz-sim-sensors-system' name='gz::sim::systems::Sensors'>"
428 "<render_engine>ogre2</render_engine></plugin>"
435 world->InsertElement(
plugin->Clone());
438 fprintf(
stderr,
"NPS gz: the world has its own plugins, make sure it loads the Sensors system for the cameras\n");
441 world->InsertElement(
vehicle_sdf->Root()->GetFirstElement());
443 world->GetElement(
"physics")->GetElement(
"max_step_size")->Set(
fdm.
init_dt);
447 gz::sim::ServerConfig config;
450 config.SetHeadlessRendering(getenv(
"DISPLAY") ==
NULL);
451 server = std::make_unique<gz::sim::Server>(config);
454 fprintf(
stderr,
"NPS gz: could not add the paparazzi system\n");
471#ifdef MOTOR_MIXING_YAW_COEF
482#if NPS_SIMULATE_VIDEO
485#if NPS_SIMULATE_LASER_RANGE_ARRAY
486 fprintf(
stderr,
"NPS gz: laser range array simulation is not supported yet\n");
504 const gz::math::Pose3d &pose =
gz_state.pose;
505 const gz::math::Vector3d &vel =
gz_state.linear_vel;
512 gz::math::Vector3d accel = (
time_prev >= 0. && dt > 0.) ? (vel -
vel_prev) / dt : gz::math::Vector3d::Zero;
524 for (
int i = 0; i < 3 * 3; i++) {
596#ifdef NPS_ACTUATOR_TIME_CONSTANTS
604#ifdef NPS_ACTUATOR_MAX_ANGULAR_MOMENTUM
609 gz_cmd.thrusts[i] = thrust;
614#if NPS_SIMULATE_VIDEO
618 return std::string(
"/nps/camera/") + dev_name;
632 for (sdf::ElementPtr link =
model->GetElement(
"link"); link; link = link->GetNextElement(
"link")) {
634 if (link->Get<std::string>(
"name") !=
cameras[i]->
dev_name || !link->HasElement(
"sensor")) {
637 sdf::ElementPtr
sensor = link->GetElement(
"sensor");
638 std::string name =
sensor->Get<std::string>(
"name");
640 sensor->GetElement(
"always_on")->Set(
true);
641 sdf::ElementPtr camera =
sensor->GetElement(
"camera");
642 if (name ==
"mt9f002") {
644 sdf::ElementPtr
image = camera->GetElement(
"image");
647 if (camera->HasElement(
"lens") && camera->GetElement(
"lens")->HasElement(
"env_texture_size")) {
648 sdf::ElementPtr
env = camera->GetElement(
"lens")->GetElement(
"env_texture_size");
655 }
else if (name ==
"mt9v117") {
660 sdf::ElementPtr
image = camera->GetElement(
"image");
661 int w =
image->Get<
int>(
"width");
662 int h =
image->Get<
int>(
"height");
667 cam->output_size.h =
h;
668 cam->sensor_size.w = w;
669 cam->sensor_size.h =
h;
673 cam->camera_intrinsics.focal_x = w / 2.0f;
674 cam->camera_intrinsics.center_x = w / 2.0f;
675 cam->camera_intrinsics.focal_y =
h / 2.0f;
676 cam->camera_intrinsics.center_y =
h / 2.0f;
677 if (name ==
"mt9f002") {
686 cam->camera_intrinsics = {
693 }
else if (name ==
"mt9v117") {
696 cam->camera_intrinsics = {
705 printf(
"NPS gz: camera %s (%s) %dx%d on %s\n",
cam->dev_name, name.c_str(), w,
h,
719 gz_node = std::make_unique<gz::transport::Node>();
725 std::function<
void(
const gz::msgs::Image &)> cb = [
gcam](
const gz::msgs::Image &
msg) {
726 std::lock_guard<std::mutex> lock(
gcam->mutex);
743 const int w =
msg.width();
744 const int h =
msg.height();
745 const int step =
msg.step() ?
msg.step() : 3 * w;
767 if (
x_yuv % 2 == 0) {
775 img->ts.tv_sec =
msg.header().stamp().sec();
776 img->ts.tv_usec =
msg.header().stamp().nsec() / 1000;
777 img->pprz_ts =
msg.header().stamp().sec() * 1000000 +
msg.header().stamp().nsec() / 1000;
788 std::lock_guard<std::mutex> lock(
gcam->mutex);
795 if (
msg.pixel_format_type() != gz::msgs::PixelFormatType::RGB_INT8) {
796 fprintf(
stderr,
"NPS gz: camera %s: unsupported pixel format %d\n",
cameras[i]->dev_name,
msg.pixel_format_type());
static void h(const real32_T x[7], const real32_T q[4], real32_T y[6])
struct pprz_autopilot autopilot
Global autopilot structure.
Core autopilot interface common to all firmwares.
bool motors_on
motor status
gz-sim System that connects NPS with the simulation.
void PostUpdate(const gz::sim::UpdateInfo &info, const gz::sim::EntityComponentManager &ecm) override
void PreUpdate(const gz::sim::UpdateInfo &info, gz::sim::EntityComponentManager &ecm) override
gz::sim::Entity body_link_
void FindModel(gz::sim::EntityComponentManager &ecm)
gz::sim::Entity motor_links_[NPS_COMMANDS_NB]
void Configure(const gz::sim::Entity &entity, const std::shared_ptr< const sdf::Element > &, gz::sim::EntityComponentManager &ecm, gz::sim::EventManager &) override
void cv_run_device(struct video_config_t *device, struct image_t *img)
Computer vision framework for onboard processing.
static pthread_mutex_t mutex
void double_quat_of_eulers(struct DoubleQuat *q, struct DoubleEulers *e)
struct EcefCoor_d ecef
origin of local frame in ECEF
double gc_of_gd_lat_d(double gd_lat, double hmsl)
void ecef_of_ned_vect_d(struct EcefCoor_d *ecef, struct LtpDef_d *def, struct NedCoor_d *ned)
void lla_of_ecef_d(struct LlaCoor_d *lla, struct EcefCoor_d *ecef)
void ecef_of_ned_point_d(struct EcefCoor_d *ecef, struct LtpDef_d *def, struct NedCoor_d *ned)
definition of the local (flat earth) coordinate system
vector in North East Down coordinates Units: meters
static float pprz_isa_pressure_of_height(float height, float ref_p)
Get pressure in Pa from height (using simplified equation).
#define PPRZ_ISA_SEA_LEVEL_PRESSURE
ISA sea level standard atmospheric pressure in Pascal.
struct LtpDef_f ned_origin_f
Definition of the local (flat earth) coordinate system.
Simple high pass filter with double precision.
static void init_first_order_high_pass(struct FirstOrderHighPass *filter, float tau, float sample_time, float value)
Init first order high pass filter.
static float update_first_order_high_pass(struct FirstOrderHighPass *filter, float value)
Update first order high pass filter state with a new value.
First order high pass filter structure.
uint8_t msg[10]
Buffer used for general comunication over SPI (out buffer)
void image_free(struct image_t *img)
Free the image.
void image_create(struct image_t *img, uint16_t width, uint16_t height, enum image_type type)
Create a new image.
Image helper functions like resizing, color filter, converters...
@ IMAGE_YUV422
UYVY format (uint16 per pixel)
static const Vector3f gravity(0.f, 0.f, 9.81f)
Simple first order low pass filter with bilinear transform.
static void init_first_order_low_pass(struct FirstOrderLowPass *filter, float tau, const float sample_time, float value)
Init first order low pass filter.
static float update_first_order_low_pass(struct FirstOrderLowPass *filter, const float value)
Update first order low pass filter state with a new value.
First order low pass filter structure.
static const int32_t yaw_coef[MOTOR_MIXING_NB_MOTOR]
#define MOTOR_MIXING_YAW_COEF
Initialization and configuration of the MT9F002 CMOS Chip.
uint16_t offset_x
Offset from left in pixels.
#define CFG_MT9F002_PIXEL_ARRAY_WIDTH
uint16_t offset_y
Offset from top in pixels.
#define MT9F002_OUTPUT_WIDTH
#define CFG_MT9F002_PIXEL_ARRAY_HEIGHT
#define MT9F002_TARGET_FPS
#define MT9F002_OUTPUT_HEIGHT
Initialization and configuration of the MT9V117 CMOS Chip.
#define MT9V117_TARGET_FPS
static float sign(float x)
sign function
#define NPS_COMMANDS_NB
Number of commands sent to the FDM of NPS.
double aoa
angle of attack in rad
struct NedCoor_d ltpprz_ecef_vel
velocity in ltppprz frame, wrt ECEF frame
double pressure_sl
pressure at sea level in Pascal
struct DoubleQuat ltpprz_to_body_quat
struct EcefCoor_d ecef_pos
struct NedCoor_d ltpprz_pos
struct LlaCoor_d lla_pos_pprz
struct DoubleVect3 body_inertial_accel
acceleration in body frame, wrt ECI inertial frame
struct DoubleRates body_inertial_rotvel
double airspeed
equivalent airspeed in m/s
struct NedCoor_d ltp_ecef_vel
velocity in LTP frame, wrt ECEF frame
struct NedCoor_d ltpprz_ecef_accel
accel in ltppprz frame, wrt ECEF frame
struct DoubleVect3 body_ecef_vel
velocity in body frame, wrt ECEF frame
double dynamic_pressure
dynamic pressure in Pascal
struct DoubleEulers ltp_to_body_eulers
struct EcefCoor_d ecef_ecef_accel
acceleration in ECEF frame, wrt ECEF frame
double pressure
current (static) atmospheric pressure in Pascal
struct DoubleQuat ltp_to_body_quat
struct DoubleRates body_ecef_rotvel
struct EcefCoor_d ecef_ecef_vel
velocity in ECEF frame, wrt ECEF frame
struct DoubleVect3 body_ecef_accel
acceleration in body frame, wrt ECEF frame
double temperature
current temperature in degrees Celcius
struct DoubleEulers ltpprz_to_body_eulers
double sideslip
sideslip angle in rad
struct DoubleVect3 body_accel
acceleration in body frame as measured by an accelerometer (incl.
struct LlaCoor_d lla_pos_geoc
struct DoubleVect3 wind
velocity in m/s in NED
struct LlaCoor_d lla_pos_geod
struct NedCoor_d ltp_ecef_accel
acceleration in LTP frame, wrt ECEF frame
static gazebo::physics::ModelPtr model
void nps_fdm_set_wind_ned(double wind_north, double wind_east, double wind_down)
struct FirstOrderLowPass lowpass[NPS_COMMANDS_NB]
void nps_fdm_init(double dt)
NPS FDM rover init.
static struct DoubleVect3 vect_ned_of_enu(const gz::math::Vector3d &enu)
static std::unique_ptr< gz::sim::Server > server
static struct gazebo_actuators_t gazebo_actuators
void nps_fdm_run_step(bool launch, double *act_commands, int commands_nb)
Minimum complexity flight dynamic model In legacy Paparazzi simulator, was implemented in OCaml and c...
struct FirstOrderHighPass highpass[NPS_COMMANDS_NB]
double thrusts[NPS_COMMANDS_NB]
static void gazebo_write(double act_commands[], int commands_nb)
Compute the motor thrusts and torques from the normalized commands [0, 1], with NPS_ACTUATOR_THRUSTS ...
string names[NPS_COMMANDS_NB]
double max_ang_momentum[NPS_COMMANDS_NB]
void nps_fdm_set_temperature(double temp, double h)
Set temperature in degrees Celcius at given height h above MSL.
static struct @367 gz_state
Simulation state, written in PaparazziSystem::PostUpdate (gz local frame, FLU body)
static void gazebo_read(void)
Fill the fdm struct from the gz state.
static struct DoubleRates rates_frd_of_flu(const gz::math::Vector3d &flu)
static struct @368 gz_cmd
Actuator commands in the body frame of each motor link, read in PaparazziSystem::PreUpdate.
static gz::math::Quaterniond local_to_enu(void)
double torques[NPS_COMMANDS_NB]
void nps_fdm_set_turbulence(double wind_speed, int turbulence_severity)
static void init_gazebo(void)
Start an embedded gz-sim server.
static struct DoubleEulers eulers_ned_of_enu(const gz::math::Quaterniond &q_enu)
NED to FRD euler angles from the ENU to FLU attitude.
#define NPS_GAZEBO_AC_NAME
static struct NedCoor_d ned_of_enu(const gz::math::Vector3d &enu)
void nps_fdm_set_wind(double speed, double dir)
void nps_fdm_run_init_step(void)
struct NpsFdm fdm
Holds all necessary NPS FDM state information.
static std::shared_ptr< PaparazziSystem > pprz_system
static struct DoubleVect3 frd_of_flu(const gz::math::Vector3d &flu)
Paparazzi double precision floating point algebra.
Paparazzi double-precision floating point math for geodetic calculations.
float alt
in meters (normally above WGS84 reference ellipsoid)
float hmsl
Height above mean sea level in meters.
struct FloatRMat ltp_of_ecef
rotation from ECEF to local frame
struct EcefCoor_f ecef
origin of local frame in ECEF
struct LlaCoor_f lla
origin of local frame in LLA
Paparazzi atmospheric pressure conversion utilities.
API to get/set the generic vehicle states.
struct img_size_t output_size
Output image size.
char * dev_name
path to device
#define VIDEO_THREAD_MAX_CAMERAS
static struct video_config_t * cameras[VIDEO_THREAD_MAX_CAMERAS]
This header gives NPS access to the list of added cameras.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.