diff --git a/src/modules/mc_att_control/mc_att_control.hpp b/src/modules/mc_att_control/mc_att_control.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..850a137124c65c3a8868febea6af2ae461d75d86
--- /dev/null
+++ b/src/modules/mc_att_control/mc_att_control.hpp
@@ -0,0 +1,268 @@
+/****************************************************************************
+ *
+ *   Copyright (c) 2013-2018 PX4 Development Team. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name PX4 nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#include <lib/mathlib/mathlib.h>
+#include <lib/mixer/mixer.h>
+#include <mathlib/math/filter/LowPassFilter2p.hpp>
+#include <systemlib/perf_counter.h>
+#include <px4_config.h>
+#include <px4_defines.h>
+#include <px4_module.h>
+#include <px4_posix.h>
+#include <px4_tasks.h>
+#include <uORB/topics/actuator_controls.h>
+#include <uORB/topics/battery_status.h>
+#include <uORB/topics/manual_control_setpoint.h>
+#include <uORB/topics/multirotor_motor_limits.h>
+#include <uORB/topics/parameter_update.h>
+#include <uORB/topics/rate_ctrl_status.h>
+#include <uORB/topics/sensor_bias.h>
+#include <uORB/topics/sensor_correction.h>
+#include <uORB/topics/sensor_gyro.h>
+#include <uORB/topics/vehicle_attitude.h>
+#include <uORB/topics/vehicle_attitude_setpoint.h>
+#include <uORB/topics/vehicle_control_mode.h>
+#include <uORB/topics/vehicle_rates_setpoint.h>
+#include <uORB/topics/vehicle_status.h>
+
+/**
+ * Multicopter attitude control app start / stop handling function
+ */
+extern "C" __EXPORT int mc_att_control_main(int argc, char *argv[]);
+
+#define MAX_GYRO_COUNT 3
+
+
+class MulticopterAttitudeControl : public ModuleBase<MulticopterAttitudeControl>
+{
+public:
+	MulticopterAttitudeControl();
+
+	virtual ~MulticopterAttitudeControl() = default;
+
+	/** @see ModuleBase */
+	static int task_spawn(int argc, char *argv[]);
+
+	/** @see ModuleBase */
+	static MulticopterAttitudeControl *instantiate(int argc, char *argv[]);
+
+	/** @see ModuleBase */
+	static int custom_command(int argc, char *argv[]);
+
+	/** @see ModuleBase */
+	static int print_usage(const char *reason = nullptr);
+
+	/** @see ModuleBase::run() */
+	void run() override;
+
+private:
+
+	int		_v_att_sub;		/**< vehicle attitude subscription */
+	int		_v_att_sp_sub;			/**< vehicle attitude setpoint subscription */
+	int		_v_rates_sp_sub;		/**< vehicle rates setpoint subscription */
+	int		_v_control_mode_sub;	/**< vehicle control mode subscription */
+	int		_params_sub;			/**< parameter updates subscription */
+	int		_manual_control_sp_sub;	/**< manual control setpoint subscription */
+	int		_vehicle_status_sub;	/**< vehicle status subscription */
+	int		_motor_limits_sub;		/**< motor limits subscription */
+	int		_battery_status_sub;	/**< battery status subscription */
+	int		_sensor_gyro_sub[MAX_GYRO_COUNT];	/**< gyro data subscription */
+	int		_sensor_correction_sub;	/**< sensor thermal correction subscription */
+	int		_sensor_bias_sub;	/**< sensor in-run bias correction subscription */
+
+	unsigned _gyro_count;
+	int _selected_gyro;
+
+	orb_advert_t	_v_rates_sp_pub;		/**< rate setpoint publication */
+	orb_advert_t	_actuators_0_pub;		/**< attitude actuator controls publication */
+	orb_advert_t	_controller_status_pub;	/**< controller status publication */
+
+	orb_id_t _rates_sp_id;	/**< pointer to correct rates setpoint uORB metadata structure */
+	orb_id_t _actuators_id;	/**< pointer to correct actuator controls0 uORB metadata structure */
+
+	bool		_actuators_0_circuit_breaker_enabled;	/**< circuit breaker to suppress output */
+
+	struct vehicle_attitude_s		_v_att;			/**< vehicle attitude */
+	struct vehicle_attitude_setpoint_s	_v_att_sp;		/**< vehicle attitude setpoint */
+	struct vehicle_rates_setpoint_s		_v_rates_sp;		/**< vehicle rates setpoint */
+	struct manual_control_setpoint_s	_manual_control_sp;	/**< manual control setpoint */
+	struct vehicle_control_mode_s		_v_control_mode;	/**< vehicle control mode */
+	struct actuator_controls_s		_actuators;		/**< actuator controls */
+	struct vehicle_status_s			_vehicle_status;	/**< vehicle status */
+	struct battery_status_s			_battery_status;	/**< battery status */
+	struct sensor_gyro_s			_sensor_gyro;		/**< gyro data before thermal correctons and ekf bias estimates are applied */
+	struct sensor_correction_s		_sensor_correction;	/**< sensor thermal corrections */
+	struct sensor_bias_s			_sensor_bias;		/**< sensor in-run bias corrections */
+
+	MultirotorMixer::saturation_status _saturation_status{};
+
+	perf_counter_t	_loop_perf;			/**< loop performance counter */
+	perf_counter_t	_controller_latency_perf;
+
+	math::LowPassFilter2p _lp_filters_d[3];                      /**< low-pass filters for D-term (roll, pitch & yaw) */
+	static constexpr const float initial_update_rate_hz = 250.f; /**< loop update rate used for initialization */
+	float _loop_update_rate_hz;                                  /**< current rate-controller loop update rate in [Hz] */
+
+	math::Vector<3>		_rates_prev;		/**< angular rates on previous step */
+	math::Vector<3>		_rates_prev_filtered;	/**< angular rates on previous step (low-pass filtered) */
+	math::Vector<3>		_rates_sp;		/**< angular rates setpoint */
+	math::Vector<3>		_rates_int;		/**< angular rates integral error */
+	float			_thrust_sp;		/**< thrust setpoint */
+	math::Vector<3>		_att_control;	/**< attitude control vector */
+
+	math::Matrix<3, 3>	_board_rotation = {};	/**< rotation matrix for the orientation that the board is mounted */
+
+	struct {
+		param_t roll_p;
+		param_t roll_rate_p;
+		param_t roll_rate_i;
+		param_t roll_rate_integ_lim;
+		param_t roll_rate_d;
+		param_t roll_rate_ff;
+		param_t pitch_p;
+		param_t pitch_rate_p;
+		param_t pitch_rate_i;
+		param_t pitch_rate_integ_lim;
+		param_t pitch_rate_d;
+		param_t pitch_rate_ff;
+		param_t d_term_cutoff_freq;
+		param_t tpa_breakpoint_p;
+		param_t tpa_breakpoint_i;
+		param_t tpa_breakpoint_d;
+		param_t tpa_rate_p;
+		param_t tpa_rate_i;
+		param_t tpa_rate_d;
+		param_t yaw_p;
+		param_t yaw_rate_p;
+		param_t yaw_rate_i;
+		param_t yaw_rate_integ_lim;
+		param_t yaw_rate_d;
+		param_t yaw_rate_ff;
+		param_t yaw_ff;
+		param_t roll_rate_max;
+		param_t pitch_rate_max;
+		param_t yaw_rate_max;
+		param_t yaw_auto_max;
+
+		param_t acro_roll_max;
+		param_t acro_pitch_max;
+		param_t acro_yaw_max;
+		param_t acro_expo;
+		param_t acro_superexpo;
+		param_t rattitude_thres;
+
+		param_t vtol_wv_yaw_rate_scale;
+
+		param_t bat_scale_en;
+
+		param_t board_rotation;
+
+		param_t board_offset[3];
+
+	}		_params_handles;		/**< handles for interesting parameters */
+
+	struct {
+		matrix::Vector3f attitude_p;					/**< P gain for attitude control */
+		math::Vector<3> rate_p;				/**< P gain for angular rate error */
+		math::Vector<3> rate_i;				/**< I gain for angular rate error */
+		math::Vector<3> rate_int_lim;			/**< integrator state limit for rate loop */
+		math::Vector<3> rate_d;				/**< D gain for angular rate error */
+		math::Vector<3>	rate_ff;			/**< Feedforward gain for desired rates */
+		float yaw_ff;						/**< yaw control feed-forward */
+
+		float d_term_cutoff_freq;			/**< Cutoff frequency for the D-term filter */
+
+		float tpa_breakpoint_p;				/**< Throttle PID Attenuation breakpoint */
+		float tpa_breakpoint_i;				/**< Throttle PID Attenuation breakpoint */
+		float tpa_breakpoint_d;				/**< Throttle PID Attenuation breakpoint */
+		float tpa_rate_p;					/**< Throttle PID Attenuation slope */
+		float tpa_rate_i;					/**< Throttle PID Attenuation slope */
+		float tpa_rate_d;					/**< Throttle PID Attenuation slope */
+
+		float roll_rate_max;
+		float pitch_rate_max;
+		float yaw_rate_max;
+		float yaw_auto_max;
+		math::Vector<3> mc_rate_max;		/**< attitude rate limits in stabilized modes */
+		math::Vector<3> auto_rate_max;		/**< attitude rate limits in auto modes */
+		matrix::Vector3f acro_rate_max;		/**< max attitude rates in acro mode */
+		float acro_expo;					/**< function parameter for expo stick curve shape */
+		float acro_superexpo;				/**< function parameter for superexpo stick curve shape */
+		float rattitude_thres;
+
+		float vtol_wv_yaw_rate_scale;			/**< Scale value [0, 1] for yaw rate setpoint  */
+
+		int32_t bat_scale_en;
+
+		int32_t board_rotation;
+
+		float board_offset[3];
+
+	}		_params;
+
+	/**
+	 * Update our local parameter cache.
+	 */
+	void			parameters_update();
+
+	/**
+	 * Check for parameter update and handle it.
+	 */
+	void		battery_status_poll();
+	void		parameter_update_poll();
+	void		sensor_bias_poll();
+	void		sensor_correction_poll();
+	void		vehicle_attitude_poll();
+	void		vehicle_attitude_setpoint_poll();
+	void		vehicle_control_mode_poll();
+	void		vehicle_manual_poll();
+	void		vehicle_motor_limits_poll();
+	void		vehicle_rates_setpoint_poll();
+	void		vehicle_status_poll();
+
+	/**
+	 * Attitude controller.
+	 */
+	void		control_attitude(float dt);
+
+	/**
+	 * Attitude rates controller.
+	 */
+	void		control_attitude_rates(float dt);
+
+	/**
+	 * Throttle PID attenuation.
+	 */
+	math::Vector<3> pid_attenuations(float tpa_breakpoint, float tpa_rate);
+};
+
diff --git a/src/modules/mc_att_control/mc_att_control_main.cpp b/src/modules/mc_att_control/mc_att_control_main.cpp
index 8371947b1e12b2dfdc129f0b9f4e73ccf4816e3f..ef11870c30229d6fbf9f5e0aa050c7720e3be3b5 100644
--- a/src/modules/mc_att_control/mc_att_control_main.cpp
+++ b/src/modules/mc_att_control/mc_att_control_main.cpp
@@ -35,60 +35,21 @@
  * @file mc_att_control_main.cpp
  * Multicopter attitude controller.
  *
- * Publication documenting this type of Quaternion Attitude Control:
- * Nonlinear Quadrocopter Attitude Control (2013)
- * by Dario Brescianini, Markus Hehn and Raffaello D'Andrea
- * Institute for Dynamic Systems and Control (IDSC), ETH Zurich
- *
  * @author Lorenz Meier		<lorenz@px4.io>
  * @author Anton Babushkin	<anton.babushkin@me.com>
  * @author Sander Smeets	<sander@droneslab.com>
  * @author Matthias Grob	<maetugr@gmail.com>
+ * @author Beat Küng		<beat-kueng@gmx.net>
  *
- * The controller has two loops: P loop for angular error and PD loop for angular rate error.
- * Desired rotation calculated keeping in mind that yaw response is normally slower than roll/pitch.
- * For small deviations controller rotates copter to have shortest path of thrust vector and independently rotates around yaw,
- * so actual rotation axis is not constant. For large deviations controller rotates copter around fixed axis.
- * These two approaches fused seamlessly with weight depending on angular error.
- * When thrust vector directed near-horizontally (e.g. roll ~= PI/2) yaw setpoint ignored because of singularity.
- * Controller doesn't use Euler angles for work, they generated only for more human-friendly control and logging.
- * If rotation matrix setpoint is invalid it will be generated from Euler angles for compatibility with old position controllers.
  */
 
+#include "mc_att_control.hpp"
+
 #include <conversion/rotation.h>
 #include <drivers/drv_hrt.h>
 #include <lib/geo/geo.h>
-#include <lib/mathlib/mathlib.h>
-#include <lib/mixer/mixer.h>
-#include <mathlib/math/filter/LowPassFilter2p.hpp>
-#include <px4_config.h>
-#include <px4_defines.h>
-#include <px4_posix.h>
-#include <px4_tasks.h>
 #include <systemlib/circuit_breaker.h>
 #include <systemlib/param/param.h>
-#include <systemlib/perf_counter.h>
-#include <uORB/topics/actuator_controls.h>
-#include <uORB/topics/battery_status.h>
-#include <uORB/topics/manual_control_setpoint.h>
-#include <uORB/topics/multirotor_motor_limits.h>
-#include <uORB/topics/parameter_update.h>
-#include <uORB/topics/rate_ctrl_status.h>
-#include <uORB/topics/sensor_bias.h>
-#include <uORB/topics/sensor_correction.h>
-#include <uORB/topics/sensor_gyro.h>
-#include <uORB/topics/vehicle_attitude.h>
-#include <uORB/topics/vehicle_attitude_setpoint.h>
-#include <uORB/topics/vehicle_control_mode.h>
-#include <uORB/topics/vehicle_rates_setpoint.h>
-#include <uORB/topics/vehicle_status.h>
-
-/**
- * Multicopter attitude control app start / stop handling function
- *
- * @ingroup apps
- */
-extern "C" __EXPORT int mc_att_control_main(int argc, char *argv[]);
 
 #define MIN_TAKEOFF_THRUST    0.2f
 #define TPA_RATE_LOWER_LIMIT 0.05f
@@ -98,235 +59,45 @@ extern "C" __EXPORT int mc_att_control_main(int argc, char *argv[]);
 #define AXIS_INDEX_YAW 2
 #define AXIS_COUNT 3
 
-#define MAX_GYRO_COUNT 3
-
 using namespace matrix;
 
-class MulticopterAttitudeControl
+
+int MulticopterAttitudeControl::print_usage(const char *reason)
 {
-public:
-	/**
-	 * Constructor
-	 */
-	MulticopterAttitudeControl();
+	if (reason) {
+		PX4_WARN("%s\n", reason);
+	}
 
-	/**
-	 * Destructor, also kills the main task
-	 */
-	~MulticopterAttitudeControl();
+	PRINT_MODULE_DESCRIPTION(
+		R"DESCR_STR(
+### Description
+This implements the multicopter attitude and rate controller. It takes attitude
+setpoints (`vehicle_attitude_setpoint`) or rate setpoints (in acro mode
+via `manual_control_setpoint` topic) as inputs and outputs actuator control messages.
 
-	/**
-	 * Start the multicopter attitude control task.
-	 *
-	 * @return		OK on success.
-	 */
-	int		start();
-
-private:
-
-	bool	_task_should_exit;		/**< if true, task_main() should exit */
-	int		_control_task;			/**< task handle */
-
-	int		_v_att_sub;		/**< vehicle attitude subscription */
-	int		_v_att_sp_sub;			/**< vehicle attitude setpoint subscription */
-	int		_v_rates_sp_sub;		/**< vehicle rates setpoint subscription */
-	int		_v_control_mode_sub;	/**< vehicle control mode subscription */
-	int		_params_sub;			/**< parameter updates subscription */
-	int		_manual_control_sp_sub;	/**< manual control setpoint subscription */
-	int		_vehicle_status_sub;	/**< vehicle status subscription */
-	int		_motor_limits_sub;		/**< motor limits subscription */
-	int		_battery_status_sub;	/**< battery status subscription */
-	int		_sensor_gyro_sub[MAX_GYRO_COUNT];	/**< gyro data subscription */
-	int		_sensor_correction_sub;	/**< sensor thermal correction subscription */
-	int		_sensor_bias_sub;	/**< sensor in-run bias correction subscription */
-
-	unsigned _gyro_count;
-	int _selected_gyro;
-
-	orb_advert_t	_v_rates_sp_pub;		/**< rate setpoint publication */
-	orb_advert_t	_actuators_0_pub;		/**< attitude actuator controls publication */
-	orb_advert_t	_controller_status_pub;	/**< controller status publication */
-
-	orb_id_t _rates_sp_id;	/**< pointer to correct rates setpoint uORB metadata structure */
-	orb_id_t _actuators_id;	/**< pointer to correct actuator controls0 uORB metadata structure */
-
-	bool		_actuators_0_circuit_breaker_enabled;	/**< circuit breaker to suppress output */
-
-	struct vehicle_attitude_s		_v_att;			/**< vehicle attitude */
-	struct vehicle_attitude_setpoint_s	_v_att_sp;		/**< vehicle attitude setpoint */
-	struct vehicle_rates_setpoint_s		_v_rates_sp;		/**< vehicle rates setpoint */
-	struct manual_control_setpoint_s	_manual_control_sp;	/**< manual control setpoint */
-	struct vehicle_control_mode_s		_v_control_mode;	/**< vehicle control mode */
-	struct actuator_controls_s		_actuators;		/**< actuator controls */
-	struct vehicle_status_s			_vehicle_status;	/**< vehicle status */
-	struct battery_status_s			_battery_status;	/**< battery status */
-	struct sensor_gyro_s			_sensor_gyro;		/**< gyro data before thermal correctons and ekf bias estimates are applied */
-	struct sensor_correction_s		_sensor_correction;	/**< sensor thermal corrections */
-	struct sensor_bias_s			_sensor_bias;		/**< sensor in-run bias corrections */
-
-	MultirotorMixer::saturation_status _saturation_status{};
-
-	perf_counter_t	_loop_perf;			/**< loop performance counter */
-	perf_counter_t	_controller_latency_perf;
-
-	math::LowPassFilter2p _lp_filters_d[3];                      /**< low-pass filters for D-term (roll, pitch & yaw) */
-	static constexpr const float initial_update_rate_hz = 250.f; /**< loop update rate used for initialization */
-	float _loop_update_rate_hz;                                  /**< current rate-controller loop update rate in [Hz] */
-
-	math::Vector<3>		_rates_prev;		/**< angular rates on previous step */
-	math::Vector<3>		_rates_prev_filtered;	/**< angular rates on previous step (low-pass filtered) */
-	math::Vector<3>		_rates_sp;		/**< angular rates setpoint */
-	math::Vector<3>		_rates_int;		/**< angular rates integral error */
-	float			_thrust_sp;		/**< thrust setpoint */
-	math::Vector<3>		_att_control;	/**< attitude control vector */
-
-	math::Matrix<3, 3>	_board_rotation = {};	/**< rotation matrix for the orientation that the board is mounted */
-
-	struct {
-		param_t roll_p;
-		param_t roll_rate_p;
-		param_t roll_rate_i;
-		param_t roll_rate_integ_lim;
-		param_t roll_rate_d;
-		param_t roll_rate_ff;
-		param_t pitch_p;
-		param_t pitch_rate_p;
-		param_t pitch_rate_i;
-		param_t pitch_rate_integ_lim;
-		param_t pitch_rate_d;
-		param_t pitch_rate_ff;
-		param_t d_term_cutoff_freq;
-		param_t tpa_breakpoint_p;
-		param_t tpa_breakpoint_i;
-		param_t tpa_breakpoint_d;
-		param_t tpa_rate_p;
-		param_t tpa_rate_i;
-		param_t tpa_rate_d;
-		param_t yaw_p;
-		param_t yaw_rate_p;
-		param_t yaw_rate_i;
-		param_t yaw_rate_integ_lim;
-		param_t yaw_rate_d;
-		param_t yaw_rate_ff;
-		param_t yaw_ff;
-		param_t roll_rate_max;
-		param_t pitch_rate_max;
-		param_t yaw_rate_max;
-		param_t yaw_auto_max;
-
-		param_t acro_roll_max;
-		param_t acro_pitch_max;
-		param_t acro_yaw_max;
-		param_t acro_expo;
-		param_t acro_superexpo;
-		param_t rattitude_thres;
-
-		param_t vtol_wv_yaw_rate_scale;
-
-		param_t bat_scale_en;
-
-		param_t board_rotation;
-
-		param_t board_offset[3];
-
-	}		_params_handles;		/**< handles for interesting parameters */
-
-	struct {
-		Vector3f attitude_p;					/**< P gain for attitude control */
-		math::Vector<3> rate_p;				/**< P gain for angular rate error */
-		math::Vector<3> rate_i;				/**< I gain for angular rate error */
-		math::Vector<3> rate_int_lim;			/**< integrator state limit for rate loop */
-		math::Vector<3> rate_d;				/**< D gain for angular rate error */
-		math::Vector<3>	rate_ff;			/**< Feedforward gain for desired rates */
-		float yaw_ff;						/**< yaw control feed-forward */
-
-		float d_term_cutoff_freq;			/**< Cutoff frequency for the D-term filter */
-
-		float tpa_breakpoint_p;				/**< Throttle PID Attenuation breakpoint */
-		float tpa_breakpoint_i;				/**< Throttle PID Attenuation breakpoint */
-		float tpa_breakpoint_d;				/**< Throttle PID Attenuation breakpoint */
-		float tpa_rate_p;					/**< Throttle PID Attenuation slope */
-		float tpa_rate_i;					/**< Throttle PID Attenuation slope */
-		float tpa_rate_d;					/**< Throttle PID Attenuation slope */
-
-		float roll_rate_max;
-		float pitch_rate_max;
-		float yaw_rate_max;
-		float yaw_auto_max;
-		math::Vector<3> mc_rate_max;		/**< attitude rate limits in stabilized modes */
-		math::Vector<3> auto_rate_max;		/**< attitude rate limits in auto modes */
-		matrix::Vector3f acro_rate_max;		/**< max attitude rates in acro mode */
-		float acro_expo;					/**< function parameter for expo stick curve shape */
-		float acro_superexpo;				/**< function parameter for superexpo stick curve shape */
-		float rattitude_thres;
-
-		float vtol_wv_yaw_rate_scale;			/**< Scale value [0, 1] for yaw rate setpoint  */
-
-		int32_t bat_scale_en;
-
-		int32_t board_rotation;
-
-		float board_offset[3];
-
-	}		_params;
-
-	/**
-	 * Update our local parameter cache.
-	 */
-	void			parameters_update();
+The controller has two loops: a P loop for angular error and a PID loop for angular rate error.
 
-	/**
-	 * Check for parameter update and handle it.
-	 */
-	void		battery_status_poll();
-	void		parameter_update_poll();
-	void		sensor_bias_poll();
-	void		sensor_correction_poll();
-	void		vehicle_attitude_poll();
-	void		vehicle_attitude_setpoint_poll();
-	void		vehicle_control_mode_poll();
-	void		vehicle_manual_poll();
-	void		vehicle_motor_limits_poll();
-	void		vehicle_rates_setpoint_poll();
-	void		vehicle_status_poll();
-
-	/**
-	 * Attitude controller.
-	 */
-	void		control_attitude(float dt);
+Publication documenting the implemented Quaternion Attitude Control:
+Nonlinear Quadrocopter Attitude Control (2013)
+by Dario Brescianini, Markus Hehn and Raffaello D'Andrea
+Institute for Dynamic Systems and Control (IDSC), ETH Zurich
 
-	/**
-	 * Attitude rates controller.
-	 */
-	void		control_attitude_rates(float dt);
+https://www.research-collection.ethz.ch/bitstream/handle/20.500.11850/154099/eth-7387-01.pdf
 
-	/**
-	 * Throttle PID attenuation.
-	 */
-	math::Vector<3> pid_attenuations(float tpa_breakpoint, float tpa_rate);
-
-	/**
-	 * Shim for calling task_main from task_create.
-	 */
-	static void	task_main_trampoline(int argc, char *argv[]);
+### Implementation
+To reduce control latency, the module directly polls on the gyro topic published by the IMU driver.
 
-	/**
-	 * Main attitude control task.
-	 */
-	void		task_main();
-};
+)DESCR_STR");
 
-namespace mc_att_control
-{
+	PRINT_MODULE_USAGE_NAME("mc_att_control", "controller");
+	PRINT_MODULE_USAGE_COMMAND("start");
+	PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
 
-MulticopterAttitudeControl	*g_control;
+	return 0;
 }
 
 MulticopterAttitudeControl::MulticopterAttitudeControl() :
 
-	_task_should_exit(false),
-	_control_task(-1),
-
 	/* subscriptions */
 	_v_att_sub(-1),
 	_v_att_sp_sub(-1),
@@ -482,30 +253,6 @@ _loop_update_rate_hz(initial_update_rate_hz)
 	}
 }
 
-MulticopterAttitudeControl::~MulticopterAttitudeControl()
-{
-	if (_control_task != -1) {
-		/* task wakes up every 100ms or so at the longest */
-		_task_should_exit = true;
-
-		/* wait for a second for the task to quit at our request */
-		unsigned i = 0;
-
-		do {
-			/* wait 20ms */
-			usleep(20000);
-
-			/* if we have given up, kill it */
-			if (++i > 50) {
-				px4_task_delete(_control_task);
-				break;
-			}
-		} while (_control_task != -1);
-	}
-
-	mc_att_control::g_control = nullptr;
-}
-
 void
 MulticopterAttitudeControl::parameters_update()
 {
@@ -1020,13 +767,7 @@ MulticopterAttitudeControl::control_attitude_rates(float dt)
 }
 
 void
-MulticopterAttitudeControl::task_main_trampoline(int argc, char *argv[])
-{
-	mc_att_control::g_control->task_main();
-}
-
-void
-MulticopterAttitudeControl::task_main()
+MulticopterAttitudeControl::run()
 {
 
 	/*
@@ -1067,21 +808,21 @@ MulticopterAttitudeControl::task_main()
 	float dt_accumulator = 0.f;
 	int loop_counter = 0;
 
-	while (!_task_should_exit) {
+	while (!should_exit()) {
 
 		poll_fds.fd = _sensor_gyro_sub[_selected_gyro];
 
 		/* wait for up to 100ms for data */
 		int pret = px4_poll(&poll_fds, 1, 100);
 
-		/* timed out - periodic check for _task_should_exit */
+		/* timed out - periodic check for should_exit() */
 		if (pret == 0) {
 			continue;
 		}
 
 		/* this is undesirable but not much we can do - might want to flag unhappy status */
 		if (pret < 0) {
-			warn("mc att ctrl: poll error %d, %d", pret, errno);
+			PX4_ERR("poll error %d, %d", pret, errno);
 			/* sleep a bit before next try */
 			usleep(100000);
 			continue;
@@ -1276,83 +1017,36 @@ MulticopterAttitudeControl::task_main()
 		perf_end(_loop_perf);
 	}
 
-	_control_task = -1;
 }
 
-int
-MulticopterAttitudeControl::start()
+int MulticopterAttitudeControl::task_spawn(int argc, char *argv[])
 {
-	ASSERT(_control_task == -1);
-
-	/* start the task */
-	_control_task = px4_task_spawn_cmd("mc_att_control",
+	_task_id = px4_task_spawn_cmd("mc_att_control",
 					   SCHED_DEFAULT,
 					   SCHED_PRIORITY_ATTITUDE_CONTROL,
 					   1700,
-					   (px4_main_t)&MulticopterAttitudeControl::task_main_trampoline,
-					   nullptr);
+					   (px4_main_t)&run_trampoline,
+					   (char *const *)argv);
 
-	if (_control_task < 0) {
-		warn("task start failed");
+	if (_task_id < 0) {
+		_task_id = -1;
 		return -errno;
 	}
 
-	return OK;
+	return 0;
 }
 
-int mc_att_control_main(int argc, char *argv[])
+MulticopterAttitudeControl *MulticopterAttitudeControl::instantiate(int argc, char *argv[])
 {
-	if (argc < 2) {
-		warnx("usage: mc_att_control {start|stop|status}");
-		return 1;
-	}
-
-	if (!strcmp(argv[1], "start")) {
-
-		if (mc_att_control::g_control != nullptr) {
-			warnx("already running");
-			return 1;
-		}
-
-		mc_att_control::g_control = new MulticopterAttitudeControl;
-
-		if (mc_att_control::g_control == nullptr) {
-			warnx("alloc failed");
-			return 1;
-		}
-
-		if (OK != mc_att_control::g_control->start()) {
-			delete mc_att_control::g_control;
-			mc_att_control::g_control = nullptr;
-			warnx("start failed");
-			return 1;
-		}
-
-		return 0;
-	}
-
-	if (!strcmp(argv[1], "stop")) {
-		if (mc_att_control::g_control == nullptr) {
-			warnx("not running");
-			return 1;
-		}
-
-		delete mc_att_control::g_control;
-		mc_att_control::g_control = nullptr;
-		return 0;
-	}
-
-	if (!strcmp(argv[1], "status")) {
-		if (mc_att_control::g_control) {
-			warnx("running");
-			return 0;
+	return new MulticopterAttitudeControl();
+}
 
-		} else {
-			warnx("not running");
-			return 1;
-		}
-	}
+int MulticopterAttitudeControl::custom_command(int argc, char *argv[])
+{
+	return print_usage("unknown command");
+}
 
-	warnx("unrecognized command");
-	return 1;
+int mc_att_control_main(int argc, char *argv[])
+{
+	return MulticopterAttitudeControl::main(argc, argv);
 }