29.5.3.4. 최종 믹서 입력값인 3축 회전 모멘트(Torque) 및 병진 추력(Thrust) 명령어 합성 및 유효 범위 정규화 소스

29.5.3.4. 최종 믹서 입력값인 3축 회전 모멘트(Torque) 및 병진 추력(Thrust) 명령어 합성 및 유효 범위 정규화 소스

PX4-Autopilot의 최하위 제어 루프인 mc_rate_control (각속도 제어기)의 최종 임무는 계산된 PID 제어량(토크)과 조종사가 직접 또는 커맨더가 간접적으로 요구한 기체의 수직 방위 추력(Thrust)을 합성하여, 페이로드(Payload) 형태의 하드웨어 액추에이터 제어 신호로 변환하는 것이다.

본 절에서는 각속도 제어기가 PID 연산을 통해 도출해낸 X(Roll), Y(Pitch), Z(Yaw) 축의 무차원 회전 모멘트(Torque)가 어떻게 기체의 Z축 병진 추력(Thrust)과 합쳐져 actuator_controls_s 토픽으로 정규화 및 브로드캐스트(Broadcast)되는지 소스 코드를 통해 분석한다.

1. 토크 및 추력 명령어 합성 체계 (actuator_controls_s)

멀티로터의 물리적 특성상, 프로펠러가 돌면 회전력(가속도)과 양력(추력)이 동시에 발생한다. 따라서 제어 시스템은 순수 회전 제어량과 순수 병진(위로 뜨는) 제어량을 하나의 데이터 구조체에 담아 Control Allocator(모터 믹서)로 넘겨주어야 한다.

// src/modules/mc_rate_control/RateControlMain.cpp 내부 데이터 구조 생성

void RateControl::publish_actuator_controls(const matrix::Vector3f &torque, float thrust_z)
{
    // 최종 출력을 담을 uORB 데이터 구조체 선언
    actuator_controls_s actuator_controls{};
    actuator_controls.timestamp = hrt_absolute_time();

    // 1. 회전 모멘트(Torque) 인가
    // PID 제어기의 결과물인 Roll, Pitch, Yaw 토크 값을 배열 인덱스 0, 1, 2에 매핑
    actuator_controls.control[actuator_controls_s::INDEX_ROLL]  = torque(0);
    actuator_controls.control[actuator_controls_s::INDEX_PITCH] = torque(1);
    actuator_controls.control[actuator_controls_s::INDEX_YAW]   = torque(2);

    // 2. 병진 추력(Thrust) 인가
    // thrust_z는 자세 제어 모델이나 수동(Acro) 모드 스틱에서 Bypass되어 온 기체 프레임 하향식 음수 추력
    // NED(North-East-Down) 좌표계 관례에 따라 Z축 방향(아래)이 양수이므로 위로 뜨는 추력은 음수(-)로 표현됨
    actuator_controls.control[actuator_controls_s::INDEX_THROTTLE] = thrust_z;

    // ... (안전 제약 및 정규화 과정) ...
}

위의 단계에서 torque 벡터는 비례, 적분, 미분 항이 모두 합산된 값이다. 아크로 모드에서 조종사는 스틱(Throttle)을 통해 이 thrust_z 값을 매뉴얼로 제어하며, 제어기는 이 추력을 유지한 채 기체가 원하는 각속도로 돌아가도록 3축 토크를 끊임없이 생성하여 더해준다.

2. 유효 범위 정규화(Normalization 및 Clipping) 로직

제어기에서 도출된 토크 값이 수학적으로 너무 크거나, 추력 값이 모터 하드웨어의 설계 범위를 벗어날 경우 믹서 단계에서 연산 오버플로우가 발생하거나 의도치 않은 거동(예: 모터 컷오프)이 발생할 수 있다. PX4는 actuator_controls 구조체를 발행하기 직전에 철저한 정규화(Normalization, -1.0 \sim 1.0 사이의 범위로 스케일링)를 수행한다.

// 유효 범위 제약(Clipping/Constraining) 적용부

    // Roll, Pitch, Yaw 제어량은 각각 -1.0(반시계 최대한) ~ +1.0(시계 최대한) 범위 제약
    for (int i = 0; i <= 2; ++i) {
        actuator_controls.control[i] = math::constrain(actuator_controls.control[i], -1.0f, 1.0f);
    }

    // Thrust 통제: 멀티로터는 일반적으로 위로 역추력을 낼 수 없으므로 보통 0.0 ~ 1.0 방향으로 제약
    // (단, 3D 곡예 비행 모드나 가변 피치 프로펠러 지원 시스템은 -1.0 ~ 1.0 허용)
    actuator_controls.control[actuator_controls_s::INDEX_THROTTLE] = 
        math::constrain(actuator_controls.control[actuator_controls_s::INDEX_THROTTLE], -1.0f, 1.0f);

    // 최종적으로 Control Allocator 모듈이 수신할 수 있도록 uORB 퍼블리싱
    _actuator_controls_pub.publish(actuator_controls);
}

2.1 아키텍처 단위의 모듈화(Decoupling)와 기체 불가지성(Vehicle Agnostic)

위 함수에서 도출된 actuator_controls_s 토픽은 아직 ‘어떤 모터에 얼마만큼의 전압을 줄 것인가?’ 가 결정되지 않은 상태다. 이 데이터는 완전히 멀티로터 하드웨어 구조 불가지성(Hardware Agnostic) 을 갖는다. 즉, 기체가 쿼드콥터(4개 모터)이든, 헥사콥터(6개 모터)이든, 심지어 틸트로터 VTOL(수직이착륙 고정익)이든 간에 각속도 제어기는 “기체를 X축으로 이만큼, Z축으로 이만큼 밀어 올려라“라는 추상화된 동역학적 명령만을 선언할 뿐이다.

이후의 각 개별 모터 RPM 출력 매핑이나 서보모터 표면 제어 역학은 모두 하단의 Control Allocator (또는 과거의 Mixer) 컴포넌트가 담당하여 기체의 지오메트리(Geometry) 행렬에 맞추어 알아서 배분(Allocation)하게 된다. 이러한 극단적인 관심사 분리(Separation of Concerns) 체계는 Ardupilot 초기의 복합적 프레임 제어 출력 방식에 비해 비행 제어 스택으로서 PX4에 압도적인 소프트웨어 확장성을 부여한다.