ROS2에서 Pixhawk에 올라간 PX4의 PID 파라미터를 바꿀 수 있을까?
결론부터 말하면 가능하다.
다만 여기서 말하는 "ROS2로 변경"은 PX4의 순수 ROS2 인터페이스인 px4_ros_com 또는 uORB bridge만으로 직접 변경한다는 뜻은 아니다.
PX4 파라미터 변경은 ROS2 순수 인터페이스만으로 처리하기보다, MAVLink를 경유하는 MAVROS2를 사용하는 방식이 현실적이다.
PX4 Discuss에서도 PX4의 direct ROS2 interface는 파라미터 변경을 지원하지 않으며, MAVLink와 MAVROS를 사용하라는 답변이 있다. 따라서 구조는 다음과 같이 보는 것이 맞다.
ROS2 node
-> MAVROS2
-> MAVLink
-> PX4 / Pixhawk
PX4 ROS2 Interface와 MAVROS2의 차이
PX4를 ROS2와 연결할 때 흔히 px4_ros_com을 먼저 떠올린다.
이 방식은 PX4의 uORB topic을 ROS2 topic으로 주고받는 데 유용하다.
예를 들어 vehicle odometry, trajectory setpoint, offboard control mode 같은 메시지를 다룰 수 있다.
하지만 PID gain처럼 PX4 내부 파라미터를 바꾸는 문제는 다르다. 파라미터 변경은 단순한 topic publish가 아니라 flight controller 내부 parameter system에 값을 쓰는 작업이다.
px4_ros_com은 offboard 제어 topic을 주고받는 데 적합하지만, PX4 파라미터 쓰기 기능까지 기본 제공한다고 보면 안 된다.
이때 MAVROS2를 사용하면 MAVLink의 parameter protocol을 통해 PX4 파라미터를 읽거나 쓸 수 있다. 즉 ROS2 애플리케이션 입장에서는 MAVROS2 service를 호출하고, MAVROS2가 이를 MAVLink 메시지로 변환해 flight controller에 전달한다.
조절 대상: Multicopter Rate PID
PX4 공식 Multicopter PID tuning guide 기준으로 multicopter rate controller에서 주로 보는 파라미터는 roll, pitch, yaw rate에 대한 P/I/D gain이다.
| Axis | P | I | D |
|---|---|---|---|
| Roll rate | MC_ROLLRATE_P | MC_ROLLRATE_I | MC_ROLLRATE_D |
| Pitch rate | MC_PITCHRATE_P | MC_PITCHRATE_I | MC_PITCHRATE_D |
| Yaw rate | MC_YAWRATE_P | MC_YAWRATE_I | MC_YAWRATE_D |
이 9개는 multicopter rate PID를 조절할 때 직접적으로 확인하게 되는 파라미터다.
여기에 각 축의 global gain에 해당하는 K 파라미터도 함께 존재한다.
| Axis | Global gain |
|---|---|
| Roll rate | MC_ROLLRATE_K |
| Pitch rate | MC_PITCHRATE_K |
| Yaw rate | MC_YAWRATE_K |
PX4 문서에서는 rate controller tuning 관련 파라미터로 P/I/D와 K를 함께 제시한다. 따라서 단순히 P/I/D만 볼 것이 아니라, 현재 기체가 어떤 PID form과 gain 구조를 쓰는지도 함께 확인해야 한다.
PX4 multicopter rate tuning에서는 MC_ROLLRATE_*, MC_PITCHRATE_*, MC_YAWRATE_* 계열 파라미터가 핵심이다.
MAVROS2에서 파라미터 변경하기
MAVROS2를 실행하면 PX4 파라미터를 다루는 service가 노출된다. 환경마다 service 이름이나 type이 다를 수 있으므로 먼저 실제 목록을 확인한다.
ros2 service list | grep param
그 다음 service type을 확인한다.
ros2 service type /mavros/param/set
또는 사용 중인 MAVROS2 버전에 따라 다음처럼 interface를 확인할 수 있다.
ros2 interface show mavros_msgs/srv/ParamSetV2
호출 형태는 대략 다음과 같은 구조가 된다.
ros2 service call /mavros/param/set mavros_msgs/srv/ParamSetV2 "{...}"
최신 MAVROS2의 ParamSetV2는 request에서 rcl_interfaces/ParameterValue를 사용한다.
따라서 실수형 PX4 파라미터를 바꿀 때는 type을 double로 지정하고 double_value에 값을 넣는다.
ros2 service call /mavros/param/set mavros_msgs/srv/ParamSetV2 \
"{force_set: false, param_id: 'MC_ROLLRATE_P', value: {type: 3, double_value: 0.15}}"
여기서 type: 3은 ROS2 parameter type 중 PARAMETER_DOUBLE을 의미한다.
PX4의 rate PID gain은 보통 실수값이므로 double_value를 사용하면 된다.
중요한 점은 예제 명령을 그대로 복사하기 전에 현재 설치된 MAVROS2의 service type을 확인해야 한다는 것이다.
MAVROS2 버전, ROS2 배포판, namespace 설정에 따라 /mavros/param/set 대신 다른 namespace 아래에 service가 있을 수 있다.
예를 들어 multi vehicle simulation에서는 vehicle마다 namespace가 나뉠 수 있다.
/uav1/mavros/param/set
/uav2/mavros/param/set
이 경우 각 vehicle에 대해 독립적으로 service를 호출해야 한다.
실제 적용 예시
예를 들어 roll rate의 P gain을 0.15로 바꾸고 싶다면 다음처럼 호출한다.
ros2 service call /mavros/param/set mavros_msgs/srv/ParamSetV2 \
"{force_set: false, param_id: 'MC_ROLLRATE_P', value: {type: 3, double_value: 0.15}}"
pitch rate P gain도 같은 방식으로 바꾼다.
ros2 service call /mavros/param/set mavros_msgs/srv/ParamSetV2 \
"{force_set: false, param_id: 'MC_PITCHRATE_P', value: {type: 3, double_value: 0.15}}"
yaw rate P gain은 다음과 같다.
ros2 service call /mavros/param/set mavros_msgs/srv/ParamSetV2 \
"{force_set: false, param_id: 'MC_YAWRATE_P', value: {type: 3, double_value: 0.20}}"
force_set은 처음에는 false로 두는 것이 좋다.
force_set: true는 MAVROS2의 일부 check를 우회해서 FCU로 값을 보내는 옵션이므로, 일반적인 튜닝에서는 먼저 false로 시도한다.
응답에서 success: true가 나오면 PX4가 파라미터 변경을 받아들인 것이다.
예상 응답 형태는 다음과 비슷하다.
response:
mavros_msgs.srv.ParamSetV2_Response(
success=True,
value=rcl_interfaces.msg.ParameterValue(...)
)
실제 field 출력은 ROS2 배포판과 MAVROS2 버전에 따라 조금 다를 수 있다.
중요한 것은 success 값이다.
여러 PID 값을 한 번에 바꾸기
반복해서 값을 바꿀 거라면 CLI 명령을 매번 치기보다 작은 ROS2 node를 만드는 편이 낫다.
아래 코드는 MAVROS2의 /mavros/param/set service를 호출해서 여러 PX4 parameter를 순서대로 설정한다.
#!/usr/bin/env python3
import sys
from typing import Dict
import rclpy
from mavros_msgs.srv import ParamSetV2
from rcl_interfaces.msg import ParameterType, ParameterValue
from rclpy.node import Node
class Px4PidParamSetter(Node):
def __init__(self, service_name: str) -> None:
super().__init__("px4_pid_param_setter")
self.client = self.create_client(ParamSetV2, service_name)
def wait_until_ready(self) -> None:
while not self.client.wait_for_service(timeout_sec=1.0):
self.get_logger().info("waiting for MAVROS2 param service...")
def set_double_param(self, name: str, value: float, force_set: bool = False) -> bool:
request = ParamSetV2.Request()
request.force_set = force_set
request.param_id = name
request.value = ParameterValue(
type=ParameterType.PARAMETER_DOUBLE,
double_value=float(value),
)
future = self.client.call_async(request)
rclpy.spin_until_future_complete(self, future)
response = future.result()
if response is None:
self.get_logger().error(f"{name}: no response")
return False
if not response.success:
self.get_logger().error(f"{name}: rejected")
return False
self.get_logger().info(f"{name} = {value}")
return True
def main() -> int:
rclpy.init()
service_name = "/mavros/param/set"
node = Px4PidParamSetter(service_name)
node.wait_until_ready()
params: Dict[str, float] = {
"MC_ROLLRATE_P": 0.15,
"MC_ROLLRATE_I": 0.20,
"MC_ROLLRATE_D": 0.003,
"MC_PITCHRATE_P": 0.15,
"MC_PITCHRATE_I": 0.20,
"MC_PITCHRATE_D": 0.003,
"MC_YAWRATE_P": 0.20,
"MC_YAWRATE_I": 0.10,
"MC_YAWRATE_D": 0.0,
}
ok = True
for name, value in params.items():
ok = node.set_double_param(name, value) and ok
node.destroy_node()
rclpy.shutdown()
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main())
이 코드는 예시값을 넣은 형태이므로 그대로 실기체에 적용하면 안 된다. 실제로는 현재 기체의 기존 값을 먼저 읽고, 한 번에 작은 폭으로만 바꾸는 식으로 사용해야 한다.
multi vehicle 환경이라면 service 이름을 namespace에 맞게 바꾸면 된다.
service_name = "/uav1/mavros/param/set"
또는 launch argument나 ROS parameter로 service name을 받아서 uav1, uav2에 같은 node를 재사용할 수 있다.
실행 전 확인할 것
위 Python 코드는 ROS2 package 안에 넣어서 실행하는 것이 일반적이다.
예를 들어 ament_python package의 executable로 등록한 뒤 다음처럼 실행한다.
ros2 run my_px4_tools px4_pid_param_setter
단독 script로 테스트할 때는 현재 shell에 ROS2와 MAVROS2 workspace가 source되어 있어야 한다.
source /opt/ros/humble/setup.bash
source ~/ros2_ws/install/setup.bash
python3 px4_pid_param_setter.py
MAVROS2 service가 다른 이름으로 떠 있다면 먼저 목록을 확인한다.
ros2 service list | grep param
그리고 코드의 service_name을 실제 service 이름으로 바꾼다.
변경 전 확인 순서
실제 값을 바꾸기 전에는 다음 순서로 확인하는 것이 좋다.
1. MAVROS2 연결 확인
ros2 topic list | grep mavros
ros2 service list | grep mavros
MAVROS2가 PX4와 연결되어 있지 않으면 param service가 보여도 호출이 실패하거나 응답이 정상적으로 오지 않을 수 있다.
2. 파라미터 service 확인
ros2 service list | grep param
ros2 service type /mavros/param/set
service 이름과 type을 먼저 확인한다.
그 다음 ros2 interface show로 request field 구조를 확인한다.
ros2 interface show mavros_msgs/srv/ParamSetV2
3. 바꿀 파라미터 이름 확인
PX4 파라미터 이름은 정확해야 한다. 예를 들어 roll rate P gain을 바꾸려면 다음 이름을 사용한다.
MC_ROLLRATE_P
오타가 있거나 해당 airframe에서 사용하지 않는 파라미터라면 변경이 실패할 수 있다.
4. 기존 값 기록
PID gain은 안정성과 직결된다. 변경 전에는 반드시 기존 값을 기록해 둔다.
MC_ROLLRATE_P = 기존값
MC_ROLLRATE_I = 기존값
MC_ROLLRATE_D = 기존값
문제가 생기면 즉시 원래 값으로 되돌릴 수 있어야 한다.
왜 비행 중 변경이 위험한가
PID gain은 기체의 응답 특성을 직접 바꾼다. P gain이 너무 크면 진동이 커질 수 있고, D gain이 너무 크면 gyro noise가 증폭되어 모터가 불안정하게 반응할 수 있다. I gain이 과하면 누적 오차 때문에 느린 진동이나 예상하지 못한 자세 보정이 생길 수 있다.
PX4 문서에서도 rate tuning은 Acro mode 또는 Stabilized mode에서 단계적으로 수행하는 절차를 설명한다. 특히 rate controller는 기체의 가장 안쪽 제어 루프에 가까우므로 잘못된 gain은 곧바로 자세 안정성 문제로 이어질 수 있다.
실기체에서 PID 파라미터를 바꾸기 전에는 SITL, 고정 상태 테스트, 저출력 테스트를 먼저 거쳐야 한다.
권장 순서는 다음과 같다.
- SITL에서 파라미터 변경 및 응답 확인
- 실제 Pixhawk와 MAVROS2 연결 확인
- 프롭 제거 또는 기체 고정 상태에서 모터 반응 확인
- 안전장치, kill switch, geofence 등 확인
- 저출력 또는 제한된 조건에서 테스트
- 로그 분석 후 다음 gain 변경
한 번에 큰 폭으로 값을 바꾸는 것도 피해야 한다. 작게 바꾸고, 로그를 보고, 다시 조정하는 방식이 안전하다.
적용 범위
여기서 다룬 파라미터는 multicopter rate controller 기준이다. 즉 일반적인 quadrotor, hexacopter, octocopter 같은 multicopter에서 roll, pitch, yaw angular rate를 제어하는 gain이다.
고정익이나 VTOL에서는 제어 구조와 파라미터 이름이 다르다. 따라서 fixed-wing, VTOL transition, position controller, altitude controller를 튜닝하려는 경우에는 해당 기체 타입과 controller 문서를 따로 확인해야 한다.
또한 position control 성능이 나쁘다고 해서 항상 rate PID를 먼저 건드리는 것은 좋은 접근이 아니다. 위치 추종 문제가 trajectory setpoint, estimator, vibration, frame convention, thrust limit, velocity limit에서 오는 경우도 많다.
정리
ROS2에서 Pixhawk/PX4 PID 파라미터를 바꾸는 것은 가능하다.
하지만 px4_ros_com만으로 직접 바꾸는 방식보다는 MAVROS2를 통해 MAVLink parameter protocol을 사용하는 방식이 현실적이다.
핵심 파라미터는 multicopter rate controller 기준으로 다음과 같다.
| Axis | P | I | D | K |
|---|---|---|---|---|
| Roll rate | MC_ROLLRATE_P | MC_ROLLRATE_I | MC_ROLLRATE_D | MC_ROLLRATE_K |
| Pitch rate | MC_PITCHRATE_P | MC_PITCHRATE_I | MC_PITCHRATE_D | MC_PITCHRATE_K |
| Yaw rate | MC_YAWRATE_P | MC_YAWRATE_I | MC_YAWRATE_D | MC_YAWRATE_K |
실제 ROS2 환경에서는 다음 순서로 접근하면 된다.
ros2 service list | grep param
ros2 service type /mavros/param/set
ros2 interface show mavros_msgs/srv/ParamSetV2
그 다음 확인된 service type에 맞춰 /mavros/param/set을 호출한다.
정리하면, ROS2 애플리케이션에서 PX4 PID를 조절하려면 MAVROS2의 parameter service를 통해 PX4 파라미터를 변경하는 방식이 가장 실용적이다.