How to calculate Total Thrust of iris model

Model SDF

GCOPTER 에서 magnitudeBoundsminThrust, maxThrust 를 요구하기 때문에 tracking 가능한 경로 (or dynamically feasible) 를 만들기 위해 계산이 필요하다.

Iris SDF 파일에 나와있는 maxRotVelocitymotorConstant 에 따르면 motor constant 이고 maximum rotor velocity 이다.

위 수식 에 대입해보면 한 모터 당 정도 나오고 quadrotor 기준 이다.

>>> k = 5.84 * 10 ** -6
>>> w = 1100 * 2 * math.pi / 60
>>> T = k * w ** 2
>>> T
0.0774917472665087
>>> 4 * T
0.3099669890660348 (N)

그러나 SDF 에 나와있는 무게가 이므로 중력 가속도 를 곱해주면 위 모터 출력으로 호버링할 수 없게된다. (약 필요)

Bug

  • 아래 섹션에서 다루지만 위 계산 방식은 잘못되었음

Analyze ROS topics

PX4 에서는 0과 1 사이의 normalized thrust 를 사용한다. 따라서 기체가 호버링하는 값을 찾으면 그때의 thrust 가 라는 의미이고, 가속도 에 근접한다. [Reference]

따라서 이를 mavros_controllers 에 구현된 제어기를 통해 구해볼 수 있다.

이 geometric controller 는 Iris 기체에 적용되어 있고 호버링이나 원형 궤적을 잘 tracking 할 수 있게 튜닝되어 있다.

처음 높이로 호버링할 때는 ~/setpoint_raw/attitude 의 normalized thrust 값은 0.7 이고, thrust 를 scaling 하기 위한 수식은 아래와 같이 적용되어 있다.

즉, 의 thrust 일 때 호버링하고 있고 처음 이륙하기 전에 내보내는 thrust 값은 약 이었다.

Warning

이를 바탕으로 iris 기체의 질량을 계산하면 대략 임을 알 수 있다. 하지만 iris 를 호버링시키는 normalized thrust 0.7 이 되도록 scaling 한 것이므로 모델의 무게가 반영된 것으로 보이지는 않는다.

여기에서 유일하게 고려된 dynamics 는 최대 가속도 이고 이는 파라미터로 적용되어 있다.

// Position Controller
const Eigen::Vector3d a_fb = poscontroller(pos_error, vel_error);
  
// Rotor Drag compensation
const Eigen::Vector3d a_rd = R_ref * D_.asDiagonal() * R_ref.transpose() * target_vel; // Rotor drag
  
// Reference acceleration
const Eigen::Vector3d a_des = a_fb + a_ref - a_rd - gravity_;
 
// ...
Eigen::Vector3d geometricCtrl::poscontroller(){
	Eigen::Vector3d a_fb = 
		Kpos_.asDiagonal() * pos_error + Kvel_.asDiagonal() * vel_error; // feedforward term for trajectory error
	
	if (a_fb.norm() > max_fb_acc_)
		a_fb = (max_fb_acc_ / a_fb.norm()) * a_fb; // Clip acceleration if reference is too large
	
	return a_fb;
}

위와 같이 최대 가속도로 제한된 a_fbgravity_ 빼서 연산하므로 이륙할 때 내던 최대 thrust 도 의 결과이다.

Motor PWM and Accelerations

결국 호버링하는 normalized thrust 는 0.7 이고 최대 normalized thrust 는 1.0 이므로 실제로 낼 수 있는 최대 thrust 가 더 크더라도 scaling 의 영향을 받는 것을 알 수 있다.

그래서 normalized thrust 가 0.7 과 1.0 일 때의 각각 모터 출력값과 가속도를 살펴보았다.

호버링할 때 각 모터에서 내는 출력값 토픽 ~/rc/out 은 아래와 같다.

$ rostopic echo /mavros/rc/out
header: 
  seq: 391
  stamp: 
    secs: 886
    nsecs: 195000000
  frame_id: ''
channels: [1708, 1709, 1706, 1704, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900]
---
header: 
  seq: 392
  stamp: 
    secs: 886
    nsecs: 295000000
  frame_id: ''
channels: [1707, 1705, 1707, 1706, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900]
---
# ...
---
header: 
  seq: 401
  stamp: 
    secs: 887
    nsecs: 196000000
  frame_id: ''
channels: [1704, 1703, 1704, 1703, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900]
---
header: 
  seq: 402
  stamp: 
    secs: 887
    nsecs: 295000000
  frame_id: ''
channels: [1705, 1703, 1705, 1705, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900]
 

4 개의 모터에서 모두 대략 1700 의 pwm 을 내는 것으로 보인다.

이륙 시부터 호버링까지 ~/imu/data_raw 의 가속도값과 ~/rc/out 을 측정해본 결과 최댓값인 2000 의 모터 출력을 낼 때 기체의 가속도는 대략 15.6 ~ 17.0 을 내고 있었다.

Calculations

Iris 의 최대 가속도 라고 하고 질량 라고 하자. 이는 SDF 파일에 있는 질량을 모두 더한 것이다.

그렇다면 호버링 할 때 필요한 thrust 는 이고, 최대 thrust 는 이다.

이를 각각 normalize thrust 0.7 과 1 에 mapping 하기 위한 상수 를 구하자.

방정식을 풀어내면 이다.

Increase the mass of iris until the drone can not offboard

최대 Thrust 를 구할 수 있는 다른 방법이 있다. normalized thrust 가 1임을 이용하여 SDF 파일의 모델 무게를 이륙하지 못할 때 까지 조금씩 증가시키는 것이다. [Reference]

임을 이용하는 것이다.

이전 계산 에서 을 최대 thrust 로 구하였으므로 이를 로 나누어 SDF 파일을 수정하여 테스트해보자.

우선 으로 가정하여 <mass>2.412</mass> 로 iris.sdf 수정 이륙 성공

그대로 계산하여 <mass>2.469</mass> 로 수정 이륙 실패

0.01 씩 조절해본 결과, 2.41 일 때 이륙 성공하고 2.42 일 때 이륙 실패하였다.

0.001 씩 다시 늘려본 결과 normalized thrust 가 굉장히 값이 많이 바뀌므로 이전 2.412 일 때 이륙 성공하고 2.413 일 때 이륙 실패하였다.

딱 떨어지는 값을 갖는 것을 보아 iris 기체의 Total Thrust 는 이다. 그러므로 최대 가속도 가 된다.

Calculations

위 계산대로 다시 진행해보면, 호버링 할 때 필요한 thrust 는 이고, 최대 thrust 는 이다.

방정식을 풀어내면 이다.

Todo

  • geometric controller 에서 만드는 Thrust 는 실제 값보다 작게 나오고 있다. (호버링 시 이 나오도록 연산되어야 하지만 이 나오고 있음.)
  • poscontroller 에서 Kpos_Kvel_ 로 P-control 되고 있으므로 이를 튜닝.
  • 호버링 시 이 0.7 로, 이륙 시 최대 이 1 로 mapping 될 수 있도록 scaling factor 를 로 수정

Gazebo Motor Plugin

PX4 시뮬레이션에서 SDF 의 모터를 직접 처리하는 gazebo_motor_model.cpp 를 참고하였다.

이전 Model SDF 에서 계산한 방식이 잘못되었다. maxRotVelocity 가 RPM 이 아닌지 값 그대로 계산되었다. VelocityCallback 을 보면 force 를 계산하는데 들어가는 real_motor_velocity 과 같은 단위를 사용하고 있다.

그러므로 motor constant 과 maximum rotor velocity 를 다시 계산해보자.

한 모터 당 이고 quadrotor 기준 이다.

이는 위에서 계산한 에 약 15 오차가 있다. 실제 계산에서는 도 같이 고려되고, 직접 날려보며 적용하였으므로 대략 맞는다고 여겨진다.

gazebo_motor_model.cpp 의 주요 부분은 아래와 같다.

void GazeboMotorModel::VelocityCallback(CommandMotorSpeedPtr &rot_velocities) {
	if(rot_velocities->motor_speed_size() < motor_number_) {
		std::cout << "You tried to access index " << motor_number_
		<< " of the MotorSpeed message array which is of size " << rot_velocities->motor_speed_size() << "." << std::endl;
	} else ref_motor_rot_vel_ = std::min(static_cast<double>(rot_velocities->motor_speed(motor_number_)), static_cast<double>(max_rot_velocity_));
}
  
void GazeboMotorModel::UpdateForcesAndMoments() {
	motor_rot_vel_ = joint_->GetVelocity(0);
	if (motor_rot_vel_ / (2 * M_PI) > 1 / (2 * sampling_time_)) {
		gzerr << "Aliasing on motor [" << motor_number_ << "] might occur. Consider making smaller simulation time steps or raising the rotor_velocity_slowdown_sim_ param.\n";
	}
	double real_motor_velocity = motor_rot_vel_ * rotor_velocity_slowdown_sim_;
	double force = real_motor_velocity * std::abs(real_motor_velocity) * motor_constant_;
	if(!reversible_) {
		// Not allowed to have negative thrust.
		force = std::abs(force);
	}
	  
	// scale down force linearly with forward speed
	// XXX this has to be modelled better
	//
	ignition::math::Vector3d body_velocity = ignitionFromGazeboMath(link_->GetWorldLinearVel());
	ignition::math::Vector3d joint_axis = ignitionFromGazeboMath(joint_->GetGlobalAxis(0));
	  
	ignition::math::Vector3d relative_wind_velocity = body_velocity - wind_vel_;
	ignition::math::Vector3d velocity_parallel_to_rotor_axis = (relative_wind_velocity.Dot(joint_axis)) * joint_axis;
	double vel = velocity_parallel_to_rotor_axis.Length();
	double scalar = 1 - vel / 25.0; // at 25 m/s the rotor will not produce any force anymore
	scalar = ignition::math::clamp(scalar, 0.0, 1.0);
	// Apply a force to the link.
	link_->AddRelativeForce(ignition::math::Vector3d(0, 0, force * scalar));
	  
	// Forces from Philppe Martin's and Erwan Salaün's
	// 2010 IEEE Conference on Robotics and Automation paper
	// The True Role of Accelerometer Feedback in Quadrotor Control
	// - \omega * \lambda_1 * V_A^{\perp}
	ignition::math::Vector3d velocity_perpendicular_to_rotor_axis = relative_wind_velocity - (relative_wind_velocity.Dot(joint_axis)) * joint_axis;
	ignition::math::Vector3d air_drag = -std::abs(real_motor_velocity) * rotor_drag_coefficient_ * velocity_perpendicular_to_rotor_axis;
	// Apply air_drag to link.
	link_->AddForce(air_drag);
	// Moments
	// Getting the parent link, such that the resulting torques can be applied to it.
	physics::Link_V parent_links = link_->GetParentJointsLinks();
	// The tansformation from the parent_link to the link_.th::Pose3d pose_difference = ignitionFromGazeboMath(link_->GetWorldCoGPose() - parent_links.at(0)->GetWorldCoGPose());
	
	ignition::math::Vector3d drag_torque(0, 0, -turning_direction_ * force * moment_constant_);
	// Transforming the drag torque into the parent frame to handle arbitrary rotor orientations.
	ignition::math::Vector3d drag_torque_parent_frame = pose_difference.Rot().RotateVector(drag_torque);
	parent_links.at(0)->AddRelativeTorque(drag_torque_parent_frame);
	  
	ignition::math::Vector3d rolling_moment;
	// - \omega * \mu_1 * V_A^{\perp}
	rolling_moment = -std::abs(real_motor_velocity) * turning_direction_ * rolling_moment_coefficient_ * velocity_perpendicular_to_rotor_axis;
	parent_links.at(0)->AddTorque(rolling_moment);
	// Apply the filter on the motor's velocity.
	double ref_motor_rot_vel;
	ref_motor_rot_vel = rotor_velocity_filter_->updateFilter(ref_motor_rot_vel_, sampling_time_);  
	
	joint_->SetVelocity(0, turning_direction_ * ref_motor_rot_vel / rotor_velocity_slowdown_sim_);
	
	#endif /* if 0 */
}

And so on…

Control Allocator

SDF 파일에 나와있는 모터 값들 외에 PX4 내부에서 설정하는 값을 찾기 위해 여러 자료들을 찾음.

이전에는 Mixer 로 관리되던 Control Allocation 과 관련이 있었다. normalized thrust 를 어떤 모델에도 적용하기 위해 필요한 내용으로 자세한 내용은 공식 문서 에 잘(?) 나와있다.

v1.13 이후로는 control allocator 로 바뀌면서 소스코드 위치가 바뀌었고, 일부 문서 링크도 깨져있다. 현재 control allocator 의 소스코드 링크는 src/modules/control_allocator 이다.

여기에 있는 module.yaml 파일에 airframe 에 정의되는 값들의 기본값 및 설명이 들어있다. (Multirotor 이 외는 모두 생략)

__max_num_mc_motors: &max_num_mc_motors 12
__max_num_servos: &max_num_servos 8
__max_num_tilts: &max_num_tilts 4
 
module_name: Control Allocation
 
parameters:
    - group: Geometry
      definitions:
        CA_AIRFRAME:
            description:
                short: Airframe selection
                long: |
                  Defines which mixer implementation to use.
                  Some are generic, while others are specifically fit to a certain vehicle with a fixed set of actuators.
 
                  'Custom' should only be used if noting else can be used.
            type: enum
            values:
                0: Multirotor
                1: Fixed-wing
                2: Standard VTOL
                3: Tiltrotor VTOL
                4: Tailsitter VTOL
                5: Rover (Ackermann)
                6: Rover (Differential)
                7: Motors (6DOF)
                8: Multirotor with Tilt
                9: Custom
                10: Helicopter (tail ESC)
                11: Helicopter (tail Servo)
                12: Helicopter (Coaxial)
            default: 0
 
        CA_METHOD:
            description:
                short: Control allocation method
                long: |
                  Selects the algorithm and desaturation method.
                  If set to Automtic, the selection is based on the airframe (CA_AIRFRAME).
            type: enum
            values:
                0: Pseudo-inverse with output clipping
                1: Pseudo-inverse with sequential desaturation technique
                2: Automatic
            default: 2
 
        # Motor parameters
        CA_R_REV:
            description:
                short: Bidirectional/Reversible motors
                long: |
                  Configure motors to be bidirectional/reversible. Note that the output driver needs to support this as well.
            type: bitmask
            bit:
                0: Motor 1
                1: Motor 2
                2: Motor 3
                3: Motor 4
                4: Motor 5
                5: Motor 6
                6: Motor 7
                7: Motor 8
                8: Motor 9
                9: Motor 10
                10: Motor 11
                11: Motor 12
            default: 0
        CA_R${i}_SLEW:
            description:
                short: Motor ${i} slew rate limit
                long: |
                  Minimum time allowed for the motor input signal to pass through
                  the full output range. A value x means that the motor signal
                  can only go from 0 to 1 in minimum x seconds (in case of
                  reversible motors, the range is -1 to 1).
 
                  Zero means that slew rate limiting is disabled.
            type: float
            decimal: 2
            increment: 0.01
            num_instances: *max_num_mc_motors
            min: 0
            max: 10
            default: 0.0
 
        # Servo params
        CA_SV${i}_SLEW:
            description:
                short: Servo ${i} slew rate limit
                long: |
                  Minimum time allowed for the servo input signal to pass through
                  the full output range. A value x means that the servo signal
                  can only go from -1 to 1 in minimum x seconds.
 
                  Zero means that slew rate limiting is disabled.
            type: float
            decimal: 2
            increment: 0.05
            num_instances: *max_num_servos
            min: 0
            max: 10
            default: 0.0
 
 
        # (MC) Rotors
        CA_ROTOR_COUNT:
            description:
                short: Total number of rotors
            type: enum
            values:
                0: '0'
                1: '1'
                2: '2'
                3: '3'
                4: '4'
                5: '5'
                6: '6'
                7: '7'
                8: '8'
                9: '9'
                10: '10'
                11: '11'
                12: '12'
            default: 0
        CA_ROTOR${i}_PX:
            description:
                short: Position of rotor ${i} along X body axis relative to center of gravity
            type: float
            decimal: 2
            increment: 0.1
            unit: m
            num_instances: *max_num_mc_motors
            min: -100
            max: 100
            default: 0.0
        CA_ROTOR${i}_PY:
            description:
                short: Position of rotor ${i} along Y body axis relative to center of gravity
            type: float
            decimal: 2
            increment: 0.1
            unit: m
            num_instances: *max_num_mc_motors
            min: -100
            max: 100
            default: 0.0
        CA_ROTOR${i}_PZ:
            description:
                short: Position of rotor ${i} along Z body axis relative to center of gravity
            type: float
            decimal: 2
            increment: 0.1
            unit: m
            num_instances: *max_num_mc_motors
            min: -100
            max: 100
            default: 0.0
 
        CA_ROTOR${i}_AX:
            description:
                short: Axis of rotor ${i} thrust vector, X body axis component
                long: Only the direction is considered (the vector is normalized).
            type: float
            decimal: 2
            increment: 0.1
            num_instances: *max_num_mc_motors
            min: -100
            max: 100
            default: 0.0
        CA_ROTOR${i}_AY:
            description:
                short: Axis of rotor ${i} thrust vector, Y body axis component
                long: Only the direction is considered (the vector is normalized).
            type: float
            decimal: 2
            increment: 0.1
            num_instances: *max_num_mc_motors
            min: -100
            max: 100
            default: 0.0
        CA_ROTOR${i}_AZ:
            description:
                short: Axis of rotor ${i} thrust vector, Z body axis component
                long: Only the direction is considered (the vector is normalized).
            type: float
            decimal: 2
            increment: 0.1
            num_instances: *max_num_mc_motors
            min: -100
            max: 100
            default: -1.0
 
        CA_ROTOR${i}_CT:
            description:
                short: Thrust coefficient of rotor ${i}
                long: |
                  The thrust coefficient if defined as Thrust = CT * u^2,
                  where u (with value between actuator minimum and maximum)
                  is the output signal sent to the motor controller.
            type: float
            decimal: 1
            increment: 1
            num_instances: *max_num_mc_motors
            min: 0
            max: 100
            default: 6.5
 
        CA_ROTOR${i}_KM:
            description:
                short: Moment coefficient of rotor ${i}
                long: |
                  The moment coefficient if defined as Torque = KM * Thrust.
 
                  Use a positive value for a rotor with CCW rotation.
                  Use a negative value for a rotor with CW rotation.
            type: float
            decimal: 3
            increment: 0.01
            num_instances: *max_num_mc_motors
            min: -1
            max: 1
            default: 0.05
        CA_ROTOR${i}_TILT:
            description:
                short: Rotor ${i} tilt assignment
                long: If not set to None, this motor is tilted by the configured tilt servo.
            type: enum
            values:
                0: 'None'
                1: 'Tilt 1'
                2: 'Tilt 2'
                3: 'Tilt 3'
                4: 'Tilt 4'
            num_instances: *max_num_mc_motors
            instance_start: 0
            default: 0
 
# Mixer
mixer:
    actuator_types:
        motor:
            functions: 'Motor'
            actuator_testing_values:
                min: 0
                max: 1
                default_is_nan: true
            per_item_parameters:
              - name: 'CA_R_REV'
                label: 'Bidirectional'
                show_as: 'bitset'
                index_offset: 0
                advanced: true
              - name: 'CA_R${i}_SLEW'
                label: 'Slew Rate'
                index_offset: 0
                advanced: true
        servo:
            functions: 'Servo'
            actuator_testing_values:
                min: -1
                max: 1
                default: 0
            per_item_parameters:
              - name: 'CA_SV${i}_SLEW'
                label: 'Slew Rate'
                index_offset: 0
                advanced: true
        DEFAULT:
            actuator_testing_values:
                min: -1
                max: 1
                default: -1
 
    config:
        param: CA_AIRFRAME
        types:
            0: # Multirotor
                type: 'multirotor'
                title: 'Multirotor'
                actuators:
                  - actuator_type: 'motor'
                    count: 'CA_ROTOR_COUNT'
                    per_item_parameters:
                        standard:
                            position: [ 'CA_ROTOR${i}_PX', 'CA_ROTOR${i}_PY', 'CA_ROTOR${i}_PZ' ]
                        extra:
                          - name: 'CA_ROTOR${i}_KM'
                            label: 'Direction CCW'
                            function: 'spin-dir'
                            show_as: 'true-if-positive'
                          - name: 'CA_ROTOR${i}_AX'
                            label: 'Axis X'
                            function: 'axisx'
                            advanced: true
                          - name: 'CA_ROTOR${i}_AY'
                            label: 'Axis Y'
                            function: 'axisy'
                            advanced: true
                          - name: 'CA_ROTOR${i}_AZ'
                            label: 'Axis Z'
                            function: 'axisz'
                            advanced: true
 
            7: # Motors (6DOF)
                actuators:
                  - actuator_type: 'motor'
                    count: 'CA_ROTOR_COUNT'
                    per_item_parameters:
                        standard:
                            position: [ 'CA_ROTOR${i}_PX', 'CA_ROTOR${i}_PY', 'CA_ROTOR${i}_PZ' ]
                        extra:
                          - name: 'CA_ROTOR${i}_AX'
                            label: 'Axis X'
                            function: 'axisx'
                          - name: 'CA_ROTOR${i}_AY'
                            label: 'Axis Y'
                            function: 'axisy'
                          - name: 'CA_ROTOR${i}_AZ'
                            label: 'Axis Z'
                            function: 'axisz'
                          - name: 'CA_ROTOR${i}_KM'
                            label: "Moment\nCoefficient"
 
            8: # Multirotor with Tilt
                title: 'Multirotor with Tilt'
                actuators:
                  - actuator_type: 'motor'
                    count: 'CA_ROTOR_COUNT'
                    per_item_parameters:
                        standard:
                            position: [ 'CA_ROTOR${i}_PX', 'CA_ROTOR${i}_PY', 'CA_ROTOR${i}_PZ' ]
                        extra:
                          - name: 'CA_ROTOR${i}_KM'
                            label: 'Direction CCW'
                            function: 'spin-dir'
                            show_as: 'true-if-positive'
                          - name: 'CA_ROTOR${i}_TILT'
                            label: 'Tilted by'
                  - actuator_type: 'servo'
                    group_label: 'Tilt Servos'
                    count: 'CA_SV_TL_COUNT'
                    item_label_prefix: 'Tilt ${i}'
                    per_item_parameters:
                        extra:
                          - name: 'CA_SV_TL${i}_MINA'
                            label: "Angle at Min\nTilt"
                          - name: 'CA_SV_TL${i}_MAXA'
                            label: "Angle at Max\nTilt"
                          - name: 'CA_SV_TL${i}_TD'
                            label: 'Tilt Direction'
                          - name: 'CA_SV_TL${i}_CT'
                            label: 'Use for Control'

여기에 자신의 모델을 정의하여 파라미터를 정해주면 된다.

ROMFS/px4fmu_common/init.d/rc.mc_defaults

#!/bin/sh
#
# Multicopter default parameters.
#
# NOTE: Script variables are declared/initialized/unset in the rcS script.
#
 
set VEHICLE_TYPE mc
 
# MAV_TYPE_QUADROTOR 2
param set-default MAV_TYPE 2
 
if param compare IMU_GYRO_RATEMAX 400
then
	param set-default IMU_GYRO_RATEMAX 800
fi
 
param set-default NAV_ACC_RAD 2
 
param set-default RTL_RETURN_ALT 30
param set-default RTL_DESCEND_ALT 10
 
param set-default GPS_UBX_DYNMODEL 6

ROMFS/px4fmu_common/init.d-posix/airframes/10015_gazebo-classic_iris

#!/bin/sh
#
# @name 3DR Iris Quadrotor SITL
#
# @type Quadrotor Wide
#
# @maintainer Julian Oes <julian@oes.ch>
#
 
. ${R}etc/init.d/rc.mc_defaults
 
 
param set-default CA_AIRFRAME 0
 
param set-default CA_ROTOR_COUNT 4
param set-default CA_ROTOR0_PX 0.1515
param set-default CA_ROTOR0_PY 0.245
param set-default CA_ROTOR0_KM 0.05
param set-default CA_ROTOR1_PX -0.1515
param set-default CA_ROTOR1_PY -0.1875
param set-default CA_ROTOR1_KM 0.05
param set-default CA_ROTOR2_PX 0.1515
param set-default CA_ROTOR2_PY -0.245
param set-default CA_ROTOR2_KM -0.05
param set-default CA_ROTOR3_PX -0.1515
param set-default CA_ROTOR3_PY 0.1875
param set-default CA_ROTOR3_KM -0.05
 
param set-default PWM_MAIN_FUNC1 101
param set-default PWM_MAIN_FUNC2 102
param set-default PWM_MAIN_FUNC3 103
param set-default PWM_MAIN_FUNC4 104

주요한 부분은 위치값인 PX PYKM (moment coefficient) 이다. 그렇다면 나머지는 기본 값이 들어간다는 의미이고, CA_ROTOR${i}_CT (thrust coefficient) 는 6.5 라는 의미이다.

CA_ROTOR${i}_CT:
	description:
		short: Thrust coefficient of rotor ${i}
		long: |
		  The thrust coefficient if defined as Thrust = CT * u^2,
		  where u (with value between actuator minimum and maximum)
		  is the output signal sent to the motor controller.
	type: float
	decimal: 1
	increment: 1
	num_instances: *max_num_mc_motors
	min: 0
	max: 100
	default: 6.5

Mixing

이전 버전에서 사용하던 mixer 값이 그대로 옮겨왔을 것 같은데, 현재는 소스코드 경로가 바뀌어서 이전 버전 문서와 소스코드를 살펴보았다.

PX4 공식 문서

두 번째 링크에 output scaling 값이 지정되어 있어 multirotor (혹은 iris)에 기본으로 적용되고 있는 파일을 찾으면 PWM 에서 Thrust 변환에 지정된 값을 알 수 있어보인다.

PX4-Autopilot

v1.10 까지 사용되던 mixer_multirotor.cpp 도 참고해도 괜찮아 보인다.

References