Thrust to throttle in /mavros/setpoint_raw/attitude

I think it could be better to find the exact mapping. Maybe this How are pwm values set after controllers outputs are calculated for quadrotors? would be useful for you.

Thanks man.

But we are not sure the mapping is linear, right? I am not sure about that. That is why I am stepping inside of the px4 and mavros codes trying finding out the exact relation.

@robin-ecn The actuator commands corresponds to the PWM values commanded on the ESCs. The nonlinearity is not that high and I believe the performance will not be too bad even if you assume that it is linear. Given that the thrust values will not vary too much around the hovering value of the thrust commands.

Even if you manage to model the nonlinearity between the pwm and thrust generation, this will no longer hold when the drone starts to move dynamically as the thrust generated by the rotors will vary on the load and speed.

There are a lot of people testing motors and measuring thrust vs pwm values on benches so this could be a good reference for you

Thanks so much for you reply. I agree even with the correct model, it is not the case when the drone moves dynamically.

Check the actuator_control in mavros
I believe it is useful.

@robin-ecn are you by chance talking about this topic (Control Multicopter via thrust f and moments M)?

It was me as well.:joy:

Hi, Jaeyoung.

I have a question. When you said “The actuator commands corresponds to the PWM values commanded on the ESCs.”, you mean “actuator_control provided by MAVROS are actually the PWM of the motors”?

Now I am trying to control the motors directly, do you have some good reference on that.

Thanks very much

@robin-ecn You can look into how the mixer works :

The actuator control message goes through the mixer as you can see here:

Hi, Jaeyong.

In order to control each motor directly, I have read the webpages that you recommand and thank for that.

Now my idea is I receive the pose information from mocap in my conputor and I compute the required force and torques to track a trajectory. Then, I can mapping the force and torques into angular velocity for each motor. Then I just need to send those commands to /actuator_control.

I still have two questions in terms of mixer for quadrotors.

(1) I need to write a new simple mixer using tag M instead of R?

(2) I find the quad+x.main.mix to understand how the mixer maps the roll, pitch, yaw and thrust into the actuator commands. But there is only one line

R: 4+ 10000 10000 10000 0

I can not understand how this is transformed to the actuator_control.

Could you give me some help? Thanks

@robin-ecn It is because it is a multirotor mixer, geometry of 4+. It is explained in the document

@Jaeyoung-Lim yes, is it possible to find out how those roll, pitch, yaw and thrust commandes are transformed into actuator commandes, like PWM?

This is because I try to understand how this works before writing my mixer file. Maybe it is not necessary?

@robin-ecn So the purpose of a mixer file is to use actuator commands without knowing how exactly the geometry of the drone is. If you want to look into the multirotor mixer you can look here

The attitude controller simply commands angular moments and thrust and this translates to the actuator inputs according to the geometry of the mixer. This enables same attitude controller be applied to various airframes.

Hello everyone,

I am also trying to send thrust and attitude values to the drone with setpoint_raw but I end up with a problem which I think is related to the mode. The problem is that when I arm the drone and then publish a setpoint_raw message, it activates a failsafe saying: no RC and no Offboard. I am currently in the Offboard mode and I wanted to ask you which mode I should use to send thrust commands and not position commands. Thank you in advance.

@pedro27 You need to be sending setpoints before you arm the drone and before you enter offboard mode

@Jaeyoung-Lim that is actually what I did. Then once the drone was armed, I stoped sending position setpoints and tried to send only thrust and attitude commands and that’s when I got the Failsafe activated.

@pedro27 why did you need to switch? It should work if you stream the attitude setpoints at a fixed rate

@Jaeyoung-Lim You mean that before arming and entering offboard mode I should send attitude setpoints? No position setpoints? Because it looks like in order to arm and takeoff it needs a position setpoint but I might be wrong.

@pedro27 It should also work if you send attitude setpoints and no position setpoints. It is more important you send valid setpoints before the timeout

My code is the following:

#include <ros/ros.h>

#include <geometry_msgs/PoseStamped.h>
#include <mavros_msgs/CommandBool.h>
#include <mavros_msgs/SetMode.h>
#include <mavros_msgs/State.h>
#include <mavros_msgs/Thrust.h>
#include <mavros_msgs/AttitudeTarget.h>
#include <gazebo_msgs/ModelStates.h>

mavros_msgs::State current_state;
void state_cb(const mavros_msgs::State::ConstPtr& msg){
current_state = *msg;

int main(int argc, char **argv)
ros::init(argc, argv, “offb_node”);
ros::NodeHandle nh;

ros::Subscriber state_sub = nh.subscribe<mavros_msgs::State>
        ("mavros/state", 10, state_cb);
ros::Publisher local_pos_pub = nh.advertise<geometry_msgs::PoseStamped>
        ("mavros/setpoint_position/local", 10);
ros::ServiceClient arming_client = nh.serviceClient<mavros_msgs::CommandBool>
ros::ServiceClient set_mode_client = nh.serviceClient<mavros_msgs::SetMode>

ros::Publisher thrust_pub = nh.advertise<mavros_msgs::AttitudeTarget>

//the setpoint publishing rate MUST be faster than 2Hz
ros::Rate rate(100.0);

// wait for FCU connection
while(ros::ok() && !current_state.connected){

mavros_msgs::AttitudeTarget attitude_wanted;

double mag = sqrt(0.08*0.08 + 1);

attitude_wanted.orientation.x = 0;
attitude_wanted.orientation.y = 0.08/mag;
attitude_wanted.orientation.z = 0;
attitude_wanted.orientation.w = 1/mag;

attitude_wanted.thrust = 0.3;

//send a few setpoints before starting
for(int i = 100; ros::ok() && i > 0; --i){

mavros_msgs::SetMode offb_set_mode;
offb_set_mode.request.custom_mode = “OFFBOARD”;

mavros_msgs::CommandBool arm_cmd;
arm_cmd.request.value = true;

ros::Time last_request = ros::Time::now();

if( current_state.mode != “OFFBOARD” &&
(ros::Time::now() - last_request > ros::Duration(5.0))){
if( &&
ROS_INFO(“Offboard enabled”);
last_request = ros::Time::now();
} else {
if( !current_state.armed &&
(ros::Time::now() - last_request > ros::Duration(5.0))){
if( &&
ROS_INFO(“Vehicle armed”);
last_request = ros::Time::now();



return 0;


It is pretty simple but I now keep getting:

I did as you said @Jaeyoung-Lim and I don’t know where it blocks. Thank you a lot for your help!