-
Notifications
You must be signed in to change notification settings - Fork 0
Custom Message
altwaitan edited this page Dec 25, 2022
·
2 revisions
This repo shows an example for declaring a erl_quad_states
message in PX4 and sends it to ROS.
- Add
ERLQuadStates.msg
in~/catkin_ws/src/mavros/mavros_msgs/msg
# ERL Quad States
uint64 timestamp # time since system start (microseconds)
float32[3] position # position x, y, z in world-frame
float32[4] orientation # orientation in quaternion [w, x, y, z]
float32[3] velocity # velocity in body-frame
float32[3] angular_velocity # angular velocity in body-frame
float32[4] controls # thrust, torque x, torque y, torque z
float32[4] controls_scaled # thrust, torque x, torque y, torque z (after battery scaling)
- Create
erl_quad_states.cpp
in~/catkin_ws/src/mavros/mavros_extras/src/plugins
#include <mavros/mavros_plugin.h>
#include <mavros_msgs/ERLQuadStates.h>
namespace mavros {
namespace extra_plugins {
class ERLQuadStatesPlugin : public plugin::PluginBase {
public:
ERLQuadStatesPlugin() : PluginBase(),
erl_quad_states_nh("~erl")
{ }
void initialize(UAS &uas_) override
{
PluginBase::initialize(uas_);
erl_quad_states_pub = erl_quad_states_nh.advertise<mavros_msgs::ERLQuadStates>("erl_quad_states", 10);
}
Subscriptions get_subscriptions() override
{
return {
make_handler(&ERLQuadStatesPlugin::handle_erl_quad_states)
};
}
private:
ros::NodeHandle erl_quad_states_nh;
ros::Publisher erl_quad_states_pub;
void handle_erl_quad_states(const mavlink::mavlink_message_t *msg, mavlink::common::msg::ERL_QUAD_STATES &erl_quad_states_msg)
{
auto erl_quad_states = boost::make_shared<mavros_msgs::ERLQuadStates>();
erl_quad_states->timestamp = erl_quad_states_msg.timestamp;
erl_quad_states->position[0] = erl_quad_states_msg.position[0];
erl_quad_states->position[1] = erl_quad_states_msg.position[1];
erl_quad_states->position[2] = erl_quad_states_msg.position[2];
erl_quad_states->orientation[0] = erl_quad_states_msg.orientation[0];
erl_quad_states->orientation[1] = erl_quad_states_msg.orientation[1];
erl_quad_states->orientation[2] = erl_quad_states_msg.orientation[2];
erl_quad_states->orientation[3] = erl_quad_states_msg.orientation[3];
erl_quad_states->velocity[0] = erl_quad_states_msg.velocity[0];
erl_quad_states->velocity[1] = erl_quad_states_msg.velocity[1];
erl_quad_states->velocity[2] = erl_quad_states_msg.velocity[2];
erl_quad_states->angular_velocity[0] = erl_quad_states_msg.angular_velocity[0];
erl_quad_states->angular_velocity[1] = erl_quad_states_msg.angular_velocity[1];
erl_quad_states->angular_velocity[2] = erl_quad_states_msg.angular_velocity[2];
erl_quad_states->controls[0] = erl_quad_states_msg.controls[0];
erl_quad_states->controls[1] = erl_quad_states_msg.controls[1];
erl_quad_states->controls[2] = erl_quad_states_msg.controls[2];
erl_quad_states->controls[3] = erl_quad_states_msg.controls[3];
erl_quad_states->controls_scaled[0] = erl_quad_states_msg.controls_scaled[0];
erl_quad_states->controls_scaled[1] = erl_quad_states_msg.controls_scaled[1];
erl_quad_states->controls_scaled[2] = erl_quad_states_msg.controls_scaled[2];
erl_quad_states->controls_scaled[3] = erl_quad_states_msg.controls_scaled[3];
//! Publish the data
erl_quad_states_pub.publish(erl_quad_states);
}
};
} // namespace extra_plugins
} // namespace mavros
#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(mavros::extra_plugins::ERLQuadStatesPlugin, mavros::plugin::PluginBase)
- Edit
~/catkin_ws/src/mavros/mavros_extras/CMakelists.txt
add_library(mavros_extras
src/plugins/debug_value.cpp
src/plugins/distance_sensor.cpp
...
src/plugins/erl_quad_states.cpp
- Edit
~/catkin_ws/src/mavros/mavros_extras/mavros_plugins.xml
<class name="erl_quad_states" type="mavros::extra_plugins::ERLQuadStatesPlugin" base_class_type="mavros::plugin::PluginBase">
<description>Publish ERL States to ROS.</description>
</class>
- Edit
~/catkin_ws/src/mavros/mavros_msgs/CMakelists.txt
add_message_files(
OnboardComputerStatus.msg
DebugValue.msg
...
ERLQuadStates.msg
- Edit
~/catkin_ws/src/mavlink/message_definitions/v1.0/common.xml
<!-- The message ids 369: ERL Quadrotor States-->
<message id="369" name="ERL_QUAD_STATES">
<description>This message sends quadrotor states and controls</description>
<field type="uint64_t" name="timestamp">time since system start (microseconds)</field>
<field type="float[3]" name="position">position</field>
<field type="float[4]" name="orientation">orientation in quaternion</field>
<field type="float[3]" name="velocity">velocity</field>
<field type="float[3]" name="angular_velocity">angular velocity</field>
<field type="float[4]" name="controls">thrust and torques</field>
<field type="float[4]" name="controls_scaled">thrust and torques after battery scaling</field>
</message>
- Clone PX4 Firmware
$ cd ~
$ git clone https://github.com/PX4/PX4-Autopilot.git
$ cd PX4-Autopilot
$ git checkout e0f016c2b3db160284bbaaadaf70bef84592d81e
- Create uORB message
erl_quad_states.msg
and add it toPX4-Autopilot/msg
# ERL Quad States
uint64 timestamp # time since system start (microseconds)
float32[3] position # position x, y, z in world-frame
float32[4] orientation # orientation in quaternion [w, x, y, z]
float32[3] velocity # velocity in body-frame
float32[3] angular_velocity # angular velocity in body-frame
float32[4] controls # thrust, torque x, torque y, torque z
float32[4] controls_scaled # thrust, torque x, torque y, torque z (after battery scaling)
- Add the message
erl_quad_states.msg
toPX4-Autopilot/msg/CMakeLists.txt
set(msg_files
ekf2_innovations.msg
ekf2_timestamps.msg
ekf_gps_drift.msg
ekf_gps_position.msg
...
erl_quad_states.msg
)
- Build target for
Pixhawk 2 (Cube Black) (FMUv3)
$ cd ~/PX4-Autopilot
$ make px4_fmu-v3_default
- Edit
common.xml
in~/PX4-Autopilot/mavlink/include/mavlink/v2.0/message_definitions
<message id="365" name="STATUSTEXT_LONG">
<description>Status text message (use only for important status and error messages). The full message payload can be used for status text, but we recommend that updates be kept concise. Note: The message is intended as a less restrictive replacement for STATUSTEXT.</description>
<field type="uint8_t" name="severity" enum="MAV_SEVERITY">Severity of status. Relies on the definitions within RFC-5424.</field>
<field type="char[254]" name="text">Status text message, without null termination character.</field>
</message>
...
<!-- The message ids 369: ERL Quadrotor States -->
<message id="369" name="ERL_QUAD_STATES">
<description>This message sends quadrotor states and controls</description>
<field type="uint64_t" name="timestamp">time since system start (microseconds)</field>
<field type="float[3]" name="position">position</field>
<field type="float[4]" name="orientation">orientation in quaternion</field>
<field type="float[3]" name="velocity">velocity</field>
<field type="float[3]" name="angular_velocity">angular velocity</field>
<field type="float[4]" name="controls">thrust and torques</field>
<field type="float[4]" name="controls_scaled">thrust and torques after battery scaling</field>
</message>
-
Delete both
common
andstandard
folders in~/PX4-Autopilot/mavlink/include/mavlink/v2.0/
-
Generate MAVLink files by the following:
$ cd ~/catkin_ws/src/mavlink/
$ python mavgenerate.py
and a pop-up window will appear
xml: ~/PX4-Autopilot/mavlink/include/mavlink/v2.0/message_definitions/standard.xml
out: ~/PX4-Autopilot/mavlink/include/mavlink/v2.0
Language: C
Version: 2.0
Validate
- Go to
~/PX4-Autopilot/.gitmodules
and delete
[submodule "mavlink/include/mavlink/v2.0"]
path = mavlink/include/mavlink/v2.0
url = https://github.com/mavlink/c_library_v2.git
branch = master
- Edit
mavlink_messages.cpp
in~/PX4-Autopilot/src/modules/mavlink
- Add the header file
#include <uORB/topics/differential_pressure.h>
#include <uORB/topics/distance_sensor.h>
...
#include <uORB/topics/erl_quad_states.h>
- Add message class
class MavlinkStreamERLQuadStates : public MavlinkStream
{
public:
const char *get_name() const
{
return MavlinkStreamERLQuadStates::get_name_static();
}
static const char *get_name_static()
{
return "ERL_QUAD_STATES";
}
static uint16_t get_id_static()
{
return MAVLINK_MSG_ID_ERL_QUAD_STATES;
}
uint16_t get_id()
{
return get_id_static();
}
static MavlinkStream *new_instance(Mavlink *mavlink)
{
return new MavlinkStreamERLQuadStates(mavlink);
}
unsigned get_size()
{
return MAVLINK_MSG_ID_ERL_QUAD_STATES_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
}
private:
uORB::Subscription _sub{ORB_ID(erl_quad_states)};
/* do not allow top copying this class */
MavlinkStreamERLQuadStates(MavlinkStreamERLQuadStates &);
MavlinkStreamERLQuadStates& operator = (const MavlinkStreamERLQuadStates &);
protected:
explicit MavlinkStreamERLQuadStates(Mavlink *mavlink) : MavlinkStream(mavlink)
{}
bool send(const hrt_abstime t) override
{
struct erl_quad_states_s _erl_quad_states;
if (_sub.update(&_erl_quad_states)) {
mavlink_erl_quad_states_t _msg_erl_quad_states;
_msg_erl_quad_states.timestamp = _erl_quad_states.timestamp;
_msg_erl_quad_states.position[0] = _erl_quad_states.position[0];
_msg_erl_quad_states.position[1] = _erl_quad_states.position[1];
_msg_erl_quad_states.position[2] = _erl_quad_states.position[2];
_msg_erl_quad_states.orientation[0] = _erl_quad_states.orientation[0];
_msg_erl_quad_states.orientation[1] = _erl_quad_states.orientation[1];
_msg_erl_quad_states.orientation[2] = _erl_quad_states.orientation[2];
_msg_erl_quad_states.orientation[3] = _erl_quad_states.orientation[3];
_msg_erl_quad_states.velocity[0] = _erl_quad_states.velocity[0];
_msg_erl_quad_states.velocity[1] = _erl_quad_states.velocity[1];
_msg_erl_quad_states.velocity[2] = _erl_quad_states.velocity[2];
_msg_erl_quad_states.angular_velocity[0] = _erl_quad_states.angular_velocity[0];
_msg_erl_quad_states.angular_velocity[1] = _erl_quad_states.angular_velocity[1];
_msg_erl_quad_states.angular_velocity[2] = _erl_quad_states.angular_velocity[2];
_msg_erl_quad_states.controls[0] = _erl_quad_states.controls[0];
_msg_erl_quad_states.controls[1] = _erl_quad_states.controls[1];
_msg_erl_quad_states.controls[2] = _erl_quad_states.controls[2];
_msg_erl_quad_states.controls[3] = _erl_quad_states.controls[3];
_msg_erl_quad_states.controls_scaled[0] = _erl_quad_states.controls_scaled[0];
_msg_erl_quad_states.controls_scaled[1] = _erl_quad_states.controls_scaled[1];
_msg_erl_quad_states.controls_scaled[2] = _erl_quad_states.controls_scaled[2];
_msg_erl_quad_states.controls_scaled[3] = _erl_quad_states.controls_scaled[3];
mavlink_msg_erl_quad_states_send_struct(_mavlink->get_channel(), &_msg_erl_quad_states);
return true;
}
return false;
}
};
- Add to
streams_list[]
StreamListItem(&MavlinkStreamERLQuadStates::new_instance, &MavlinkStreamERLQuadStates::get_name_static, &MavlinkStreamERLQuadStates::get_id_static)
- Edit
mavlink_main.cpp
in~/PX4-Autopilot/src/modules/mavlink
switch (_mode) {
case MAVLINK_MODE_NORMAL:
configure_stream_local("ADSB_VEHICLE", unlimited_rate);
...
configure_stream_local("ERL_QUAD_STATES", 100.0f);
for all cases
- Go to
PX4-Autopilot/src/modules/mc_att_control/mc_att_control.hpp
#include <uORB/topics/erl_quad_states.h>
#include <uORB/topics/vehicle_local_position.h>
uORB::SubscriptionCallbackWorkItem _local_pos_sub{this, ORB_ID(vehicle_local_position)}; /**< vehicle local position */
uORB::Publication<erl_quad_states_s> _erl_quad_states_pub{ORB_ID(erl_quad_states)};
struct vehicle_local_position_s _local_pos{}; /**< vehicle local position */
struct erl_quad_states_s _erl_quad_states {}; /**< erl quad states */
- Go to
PX4-Autopilot/src/modules/mc_att_control/mc_att_control_main.cpp
void
MulticopterAttitudeControl::publish_actuator_controls()
{
_actuators.control[0] = (PX4_ISFINITE(_att_control(0))) ? _att_control(0) : 0.0f;
_actuators.control[1] = (PX4_ISFINITE(_att_control(1))) ? _att_control(1) : 0.0f;
_actuators.control[2] = (PX4_ISFINITE(_att_control(2))) ? _att_control(2) : 0.0f;
_actuators.control[3] = (PX4_ISFINITE(_thrust_sp)) ? _thrust_sp : 0.0f;
_actuators.control[7] = (float)_landing_gear.landing_gear;
// note: _actuators.timestamp_sample is set in MulticopterAttitudeControl::Run()
_actuators.timestamp = hrt_absolute_time();
// ERL Quadrotor States
_erl_quad_states.timestamp = _actuators.timestamp;
_erl_quad_states.controls[0] = _actuators.control[3];
_erl_quad_states.controls[1] = _actuators.control[0];
_erl_quad_states.controls[2] = _actuators.control[1];
_erl_quad_states.controls[3] = _actuators.control[2];
/* scale effort by battery status */
if (_param_mc_bat_scale_en.get() && _battery_status.scale > 0.0f) {
for (int i = 0; i < 4; i++) {
_actuators.control[i] *= _battery_status.scale;
}
}
// ERL Quadrotor States
_erl_quad_states.controls_scaled[0] = _actuators.control[3];
_erl_quad_states.controls_scaled[1] = _actuators.control[0];
_erl_quad_states.controls_scaled[2] = _actuators.control[1];
_erl_quad_states.controls_scaled[3] = _actuators.control[2];
_erl_quad_states_pub.publish(_erl_quad_states);
if (!_actuators_0_circuit_breaker_enabled) {
orb_publish_auto(_actuators_id, &_actuators_0_pub, &_actuators, nullptr, ORB_PRIO_DEFAULT);
}
}
void
MulticopterAttitudeControl::Run()
{
if (should_exit()) {
_vehicle_angular_velocity_sub.unregisterCallback();
exit_and_cleanup();
return;
}
perf_begin(_loop_perf);
/* run controller on gyro changes */
vehicle_angular_velocity_s angular_velocity;
if (_vehicle_angular_velocity_sub.update(&angular_velocity)) {
const hrt_abstime now = hrt_absolute_time();
// Guard against too small (< 0.2ms) and too large (> 20ms) dt's.
const float dt = math::constrain(((now - _last_run) / 1e6f), 0.0002f, 0.02f);
_last_run = now;
const Vector3f rates{angular_velocity.xyz};
_actuators.timestamp_sample = angular_velocity.timestamp_sample;
// ERL Quadrotor States
_local_pos_sub.update(&_local_pos);
_erl_quad_states.position[0] = _local_pos.x;
_erl_quad_states.position[1] = _local_pos.y;
_erl_quad_states.position[2] = _local_pos.z;
_erl_quad_states.orientation[0] = _v_att.q[0];
_erl_quad_states.orientation[1] = _v_att.q[1];
_erl_quad_states.orientation[2] = _v_att.q[2];
_erl_quad_states.orientation[3] = _v_att.q[3];
_erl_quad_states.velocity[0] = _local_pos.vx;
_erl_quad_states.velocity[1] = _local_pos.vy;
_erl_quad_states.velocity[2] = _local_pos.vz;
_erl_quad_states.angular_velocity[0] = angular_velocity.xyz[0];
_erl_quad_states.angular_velocity[1] = angular_velocity.xyz[1];
_erl_quad_states.angular_velocity[2] = angular_velocity.xyz[2];
/* run the rate controller immediately after a gyro update */
if (_v_control_mode.flag_control_rates_enabled) {
control_attitude_rates(dt, rates);
publish_actuator_controls();
publish_rate_controller_status();
}
/* check for updates in other topics */
_v_control_mode_sub.update(&_v_control_mode);
_battery_status_sub.update(&_battery_status);
_vehicle_land_detected_sub.update(&_vehicle_land_detected);
_landing_gear_sub.update(&_landing_gear);
vehicle_status_poll();
vehicle_motor_limits_poll();
const bool manual_control_updated = _manual_control_sp_sub.update(&_manual_control_sp);
const bool attitude_updated = vehicle_attitude_poll();
_attitude_dt += dt;
/* Check if we are in rattitude mode and the pilot is above the threshold on pitch
* or roll (yaw can rotate 360 in normal att control). If both are true don't
* even bother running the attitude controllers */
if (_v_control_mode.flag_control_rattitude_enabled) {
_v_control_mode.flag_control_attitude_enabled =
fabsf(_manual_control_sp.y) <= _param_mc_ratt_th.get() &&
fabsf(_manual_control_sp.x) <= _param_mc_ratt_th.get();
}
bool attitude_setpoint_generated = false;
const bool is_hovering = _vehicle_status.vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING
&& !_vehicle_status.in_transition_mode;
// vehicle is a tailsitter in transition mode
const bool is_tailsitter_transition = _vehicle_status.in_transition_mode && _is_tailsitter;
bool run_att_ctrl = _v_control_mode.flag_control_attitude_enabled && (is_hovering || is_tailsitter_transition);
if (run_att_ctrl) {
if (attitude_updated) {
// Generate the attitude setpoint from stick inputs if we are in Manual/Stabilized mode
if (_v_control_mode.flag_control_manual_enabled &&
!_v_control_mode.flag_control_altitude_enabled &&
!_v_control_mode.flag_control_velocity_enabled &&
!_v_control_mode.flag_control_position_enabled) {
generate_attitude_setpoint(_attitude_dt, _reset_yaw_sp);
attitude_setpoint_generated = true;
}
control_attitude();
if (_v_control_mode.flag_control_yawrate_override_enabled) {
/* Yaw rate override enabled, overwrite the yaw setpoint */
_v_rates_sp_sub.update(&_v_rates_sp);
const auto yawrate_reference = _v_rates_sp.yaw;
_rates_sp(2) = yawrate_reference;
}
publish_rates_setpoint();
}
} else {
/* attitude controller disabled, poll rates setpoint topic */
if (_v_control_mode.flag_control_manual_enabled && is_hovering) {
if (manual_control_updated) {
/* manual rates control - ACRO mode */
Vector3f man_rate_sp(
math::superexpo(_manual_control_sp.y, _param_mc_acro_expo.get(), _param_mc_acro_supexpo.get()),
math::superexpo(-_manual_control_sp.x, _param_mc_acro_expo.get(), _param_mc_acro_supexpo.get()),
math::superexpo(_manual_control_sp.r, _param_mc_acro_expo_y.get(), _param_mc_acro_supexpoy.get()));
_rates_sp = man_rate_sp.emult(_acro_rate_max);
_thrust_sp = _manual_control_sp.z;
publish_rates_setpoint();
}
} else {
/* attitude controller disabled, poll rates setpoint topic */
if (_v_rates_sp_sub.update(&_v_rates_sp)) {
_rates_sp(0) = _v_rates_sp.roll;
_rates_sp(1) = _v_rates_sp.pitch;
_rates_sp(2) = _v_rates_sp.yaw;
_thrust_sp = -_v_rates_sp.thrust_body[2];
}
}
}
if (_v_control_mode.flag_control_termination_enabled) {
if (!_vehicle_status.is_vtol) {
_rates_sp.zero();
_rate_control.resetIntegral();
_thrust_sp = 0.0f;
_att_control.zero();
publish_actuator_controls();
}
}
if (attitude_updated) {
// reset yaw setpoint during transitions, tailsitter.cpp generates
// attitude setpoint for the transition
_reset_yaw_sp = (!attitude_setpoint_generated && !_v_control_mode.flag_control_rattitude_enabled) ||
_vehicle_land_detected.landed ||
(_vehicle_status.is_vtol && _vehicle_status.in_transition_mode);
_attitude_dt = 0.f;
}
/* calculate loop update rate while disarmed or at least a few times (updating the filter is expensive) */
if (!_v_control_mode.flag_armed || (now - _task_start) < 3300000) {
_dt_accumulator += dt;
++_loop_counter;
if (_dt_accumulator > 1.f) {
const float loop_update_rate = (float)_loop_counter / _dt_accumulator;
_loop_update_rate_hz = _loop_update_rate_hz * 0.5f + loop_update_rate * 0.5f;
_dt_accumulator = 0;
_loop_counter = 0;
_rate_control.setDTermCutoff(_loop_update_rate_hz, _param_mc_dterm_cutoff.get(), true);
}
}
parameter_update_poll();
}
perf_end(_loop_perf);
}
- Build firmware
$ cd ~/PX4-Autopilot
$ make px4_fmu-v3_default