!REDIRECT “https://docs.px4.io/master/ko/middleware/mavlink.html

MAVLink 메세징

MAVLink는 드론 생태계에서 활용하려 설계한 초경량 메세지 프로토콜입니다.

PX4는 QGroundControl(그리고 기타 지상 통제 장치)과의 통신, 그리고 보조 컴퓨터, MAVLink 기능을 갖춘 카메라 등 비행체 제어 장치 외의 드론 구성요소 연결을 위한 통합 매커니즘 용도로 MAVLink 를 활용합니다.

프로토콜은 데이터 교환 목적의 표준 메세지마이크로서비스를 정의합니다(여러가지가 있으나, PX4 용도로의 메시지/서비스를 전부 구현하진 못했습니다).

이 자습서에서는 새 “개별 정의” 메시지를 PX4 지원에 추가하는 방법을 알려드리겠습니다.

Note 이 자습서에서는 이미 msg/ca_trajectory.msgcustom uORB ca_trajectory 메세지를 정의하고, 개별 MAVLink ca_trajectory메세지를 mavlink/include/mavlink/v2.0/custom_messages/mavlink_msg_ca_trajectory.h 에 정의했음을 가정합니다.

MAVLink 개별 메세지 정의

MAVLink 개발자 안내서에서는 프로그래밍 영역의 라이브러리에 새 메세지 정의하고 빌드하는 방법을 설명합니다:

MAVLink 2 메세지는 C 라이브러리로 만들어야합니다. 일단 MAVLink를 설치하면, 아래 명령으로 명령행에서 메세지 정의 및 빌드를 처리할 수 있습니다:

  1. python -m pymavlink.tools.mavgen --lang=C --wire-protocol=2.0 --output=generated/include/mavlink/v2.0 message_definitions/v1.0/custom_messages.xml

For your own use/testing you can just copy the generated headers into PX4-Autopilot/mavlink/include/mavlink/v2.0.

기존의 다른 요소와 바뀐 내용을 쉽게 시험해보려면, https://github.com/mavlink/c_library_v2 저장소를 가져온 소스트리에 새로 만든 헤더를 추가하는 방법이 가장 바람직한 접근 방안이라 볼 수 있습니다. PX4 developers can then update the submodule to your fork in the PX4-Autopilot repo before building.

MAVLink 개별 메시지 송신

이 절에서는 uORB 개별 설정 메세지를 활용하여 MAVLink 메세지에 실어 보내는 방법을 설명합니다.

Add the headers of the MAVLink and uORB messages to mavlink_messages.cpp

  1. #include <uORB/topics/ca_trajectory.h>
  2. #include <v2.0/custom_messages/mavlink.h>

Create a new class in mavlink_messages.cpp

  1. class MavlinkStreamCaTrajectory : public MavlinkStream
  2. {
  3. public:
  4. const char *get_name() const
  5. {
  6. return MavlinkStreamCaTrajectory::get_name_static();
  7. }
  8. static const char *get_name_static()
  9. {
  10. return "CA_TRAJECTORY";
  11. }
  12. static uint16_t get_id_static()
  13. {
  14. return MAVLINK_MSG_ID_CA_TRAJECTORY;
  15. }
  16. uint16_t get_id()
  17. {
  18. return get_id_static();
  19. }
  20. static MavlinkStream *new_instance(Mavlink *mavlink)
  21. {
  22. return new MavlinkStreamCaTrajectory(mavlink);
  23. }
  24. unsigned get_size()
  25. {
  26. return MAVLINK_MSG_ID_CA_TRAJECTORY_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
  27. }
  28. private:
  29. MavlinkOrbSubscription *_sub;
  30. uint64_t _ca_traj_time;
  31. /* do not allow top copying this class */
  32. MavlinkStreamCaTrajectory(MavlinkStreamCaTrajectory &);
  33. MavlinkStreamCaTrajectory& operator = (const MavlinkStreamCaTrajectory &);
  34. protected:
  35. explicit MavlinkStreamCaTrajectory(Mavlink *mavlink) : MavlinkStream(mavlink),
  36. _sub(_mavlink->add_orb_subscription(ORB_ID(ca_trajectory))), // make sure you enter the name of your uORB topic here
  37. _ca_traj_time(0)
  38. {}
  39. bool send(const hrt_abstime t)
  40. {
  41. struct ca_traj_struct_s _ca_trajectory; //make sure ca_traj_struct_s is the definition of your uORB topic
  42. if (_sub->update(&_ca_traj_time, &_ca_trajectory)) {
  43. mavlink_ca_trajectory_t _msg_ca_trajectory; //make sure mavlink_ca_trajectory_t is the definition of your custom MAVLink message
  44. _msg_ca_trajectory.timestamp = _ca_trajectory.timestamp;
  45. _msg_ca_trajectory.time_start_usec = _ca_trajectory.time_start_usec;
  46. _msg_ca_trajectory.time_stop_usec = _ca_trajectory.time_stop_usec;
  47. _msg_ca_trajectory.coefficients =_ca_trajectory.coefficients;
  48. _msg_ca_trajectory.seq_id = _ca_trajectory.seq_id;
  49. mavlink_msg_ca_trajectory_send_struct(_mavlink->get_channel(), &_msg_ca_trajectory)
  50. }
  51. return true;
  52. }
  53. };

Finally append the stream class to the streams_list at the bottom of mavlink_messages.cpp

  1. StreamListItem *streams_list[] = {
  2. ...
  3. new StreamListItem(&MavlinkStreamCaTrajectory::new_instance, &MavlinkStreamCaTrajectory::get_name_static, &MavlinkStreamCaTrajectory::get_id_static),
  4. nullptr
  5. };

Then make sure to enable the stream, for example by adding the following line to the startup script (e.g. /ROMFS/px4fmu_common/init.d-posix/rcS on NuttX or ROMFS/px4fmu_common/init.d-posix/rcS) on SITL. 참고로, -r 인자로 스트리밍 전송율을 설정하고 -u 인자로 UDP 포트 14556의 MAVLink 채널을 식별합니다.

  1. mavlink stream -r 50 -s CA_TRAJECTORY -u 14556

Tip uorb top [<message_name>] 명령을 활용하여 메시지 송신 여부와 전송율을 실시간으로 확인할 수 있습니다(uORB 메세징 참고). 이 방법으로 uORB 토픽을 내보내는 메시지 수신을 시험해볼 수 있습니다(다른 메시지에 대해서는 SITL에서 코드와 테스트에 printf를 사용해야 합니다).

QGroundControl에서 메세지를 보려면 MAVLink 라이브러리를 빌드하고 MAVLink 검사 위젯(또는 다른 MAVLink 도구)으로 수신 메시지를 확인해야 합니다.

MAVLink 개별 메시지 수신

이 절에서는 MAVLink 메시지 수신 및 uORB 대상 송신 방법을 설명합니다.

Add a function that handles the incoming MAVLink message in mavlink_receiver.h

  1. #include <uORB/topics/ca_trajectory.h>
  2. #include <v2.0/custom_messages/mavlink_msg_ca_trajectory.h>

Add a function that handles the incoming MAVLink message in the MavlinkReceiver class in mavlink_receiver.h

  1. void handle_message_ca_trajectory_msg(mavlink_message_t *msg);

Add an uORB publisher in the MavlinkReceiver class in mavlink_receiver.h

  1. orb_advert_t _ca_traj_msg_pub;

Implement the handle_message_ca_trajectory_msg function in mavlink_receiver.cpp

  1. void MavlinkReceiver::handle_message_ca_trajectory_msg(mavlink_message_t *msg)
  2. {
  3. mavlink_ca_trajectory_t traj;
  4. mavlink_msg_ca_trajectory_decode(msg, &traj);
  5. struct ca_traj_struct_s f;
  6. memset(&f, 0, sizeof(f));
  7. f.timestamp = hrt_absolute_time();
  8. f.seq_id = traj.seq_id;
  9. f.time_start_usec = traj.time_start_usec;
  10. f.time_stop_usec = traj.time_stop_usec;
  11. for(int i=0;i<28;i++)
  12. f.coefficients[i] = traj.coefficients[i];
  13. if (_ca_traj_msg_pub == nullptr) {
  14. _ca_traj_msg_pub = orb_advertise(ORB_ID(ca_trajectory), &f);
  15. } else {
  16. orb_publish(ORB_ID(ca_trajectory), _ca_traj_msg_pub, &f);
  17. }
  18. }

and finally make sure it is called in MavlinkReceiver::handle_message()

  1. MavlinkReceiver::handle_message(mavlink_message_t *msg)
  2. {
  3. switch (msg->msgid) {
  4. ...
  5. case MAVLINK_MSG_ID_CA_TRAJECTORY:
  6. handle_message_ca_trajectory_msg(msg);
  7. break;
  8. ...
  9. }

MAVLink 개별 메세지 생성 대안

때로는 완전히 정의하지 못한 내용이 담긴 MAVLink 개별 메세지가 필요할 경우가 있습니다.

예를 들어 PX4와 내장된 디바이스의 인터페이스를 MAVLink로 사용할 때 자동조종장치와 그 디바이스는 안전화되기 전에 여러번의 메시지를 교환할 것입니다. 이 과정은 오류에 취약한 MAVLink 헤더를 다시 만들고 장치간 프로토콜 버전의 동일 여부를 확인하는데 시간을 소요할 수 있습니다.

임시 대안책은 디버깅 메시지의 목적 전환입니다. MAVLink 개별 메세지 CA_TRAJECTORY를 만드는 대신, CA_TRAJ 문자열 키와 x, y, z 필드에 데이터를 담은 DEBUG_VECT 메세지를 보낼 수 있습니다. 이 자습서를 살펴보십시오. 디버깅 메시지 사용 예제가 들어있습니다.

Note 이 방법은 문자열을 네트워크로 보내면서 문자열 비교과정에 관여하므로 그다지 효율적이지 않습니다. 개발용으로만 활용하십시오!

일반

스트리밍 전송율 설정

개별 토픽의 스트리밍 전송율을 늘리는 방법이 좋을 때가 있습니다(QGC 에서의 상태 검사). 셸에 다음 명령을 입력해서 처리할 수 있습니다:

  1. mavlink stream -u <port number> -s <mavlink topic name> -r <rate>

(다른 내용과 함께) transport protocol: UDP (<port number>)를 출력하는 mavlink status 명령으로 포트 번호를 알 수 있습니다. 예제는 다음과 같습니다:

  1. mavlink stream -u 14556 -s OPTICAL_FLOW_RAD -r 300