PX4模块设计之四十:FrskyTelemetry模块

Posted lida2003

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PX4模块设计之四十:FrskyTelemetry模块相关的知识,希望对你有一定的参考价值。

PX4模块设计之四十:FrskyTelemetry模块

1. FrskyTelemetry模块简介

FrSky Telemetry support. Auto-detects D or S.PORT protocol.

frsky_telemetry <command> [arguments...]
 Commands:
   start
     [-d <val>]  Select Serial Device
                 values: <file:dev>, default: /dev/ttyS6
     [-t <val>]  Scanning timeout [s] (default: no timeout)
                 default: 0
     [-m <val>]  Select protocol (default: auto-detect)
                 values: sport|sport_single|sport_single_invert|dtype, default:
                 auto

   stop

   status

注1:usage函数是具体对应实现。
注2:FrskyTelemetry模块采用了纯C语言代码实现。

2. 模块入口函数

2.1 主入口frsky_telemetry_main

模块仅支持start/stop/status命令,不支持其他自定义命令。

frsky_telemetry_main
 ├──> <argc < 2>
 │   ├──> PX4_ERR("missing command")
 │   ├──> usage()
 │   └──> return -1
 ├──> <!strcmp(argv[1], "start")>
 │   ├──> <thread_running>
 │   │   ├──> PX4_INFO("frsky_telemetry already running")
 │   │   └──> return 0
 │   ├──> thread_should_exit = false
 │   ├──> frsky_task = px4_task_spawn_cmd("frsky_telemetry",SCHED_DEFAULT,SCHED_PRIORITY_DEFAULT + 4,1400,frsky_telemetry_thread_main,(char *const *)argv)
 │   ├──> <while (!thread_running)>
 │   │   └──> usleep(200)
 │   └──> return 0
 ├──> <!strcmp(argv[1], "stop")>
 │   ├──> <!thread_running>
 │   │   ├──> PX4_WARN("frsky_telemetry already stopped")
 │   │   └──> return 0
 │   ├──> thread_should_exit = true
 │   ├──> <while (thread_running)>
 │   │   ├──> usleep(1000000)
 │   │   └──> PX4_INFO(".")
 │   ├──> PX4_INFO("terminated.")
 │   ├──> device_name = NULL
 │   └──> return 0
 ├──> <!strcmp(argv[1], "status")><thread_running><switch (frsky_state)>
 │   ├──> <case SCANNING>
 │   │   ├──> PX4_INFO("running: SCANNING")
 │   │   ├──> PX4_INFO("port: %s", device_name)
 │   │   └──> break
 │   ├──> <case SPORT>
 │   │   ├──> PX4_INFO("running: SPORT")
 │   │   ├──> PX4_INFO("port: %s", device_name)
 │   │   ├──> PX4_INFO("packets sent: %ld", sentPackets)
 │   │   └──> break
 │   ├──> <case SPORT_SINGLE_WIRE>
 │   │   ├──> PX4_INFO("running: SPORT (single wire)")
 │   │   ├──> PX4_INFO("port: %s", device_name)
 │   │   ├──> PX4_INFO("packets sent: %ld", sentPackets)
 │   │   └──> break
 │   ├──> <case SPORT_SINGLE_WIRE_INVERT>
 │   │   ├──> PX4_INFO("running: SPORT (single wire, inverted)")
 │   │   ├──> PX4_INFO("port: %s", device_name)
 │   │   ├──> PX4_INFO("packets sent: %ld", sentPackets)
 │   │   └──> break
 │   ├──> <case DTYPE>
 │   │   ├──> PX4_INFO("running: DTYPE")
 │   │   ├──> PX4_INFO("port: %s", device_name)
 │   │   ├──> PX4_INFO("packets sent: %ld", sentPackets)
 │   │   └──> break
 │   └──> return 0
 ├──> <PX4_ERR("unrecognized command")
 ├──> <usage()
 └──> return 0

2.2 自定义子命令custom_command

注:该模块采用了纯C语言代码实现,在main函数中直接执行命令,无需ModuleBase的custom_command重载实现。

2.3 模块状态print_status【重载】

注:该模块采用了纯C语言代码实现,在main函数中直接执行usage函数,无需ModuleBase的模块状态print_status重载实现。

3. FrskyTelemetry模块重要函数

3.1 task_spawn/instantiate/Run

注:该模块采用了纯C语言代码实现,无需ModuleBase的模块状态task_spawn/instantiate/Run重载实现。

3.2 frsky_telemetry_thread_main

这个是FrskyTelemetry模块任务入口函数,在任务内部会循环执行,直到条件不满足才退出循环任务。

frsky_telemetry_thread_main
 ├──> device_name = "/dev/ttyS6" /* default USART8 */
 ├──> [frsky状态机及变量初始化]
 ├──> [frsky telemetry参数解析]
 │   ├──> <case 'd'>
 │   │   ├──> device_name = myoptarg
 │   │   └──> break
 │   ├──> <case 't'>
 │   │   ├──> scanning_timeout_ms = strtoul(myoptarg, nullptr, 10) * 1000
 │   │   └──> break
 │   ├──> <case 'm'>
 │   │   ├──> <!strcmp(myoptarg, "sport")>
 │   │   │   └──> frsky_state = baudRate = SPORT
 │   │   ├──> <!strcmp(myoptarg, "sport_single")>
 │   │   │   └──> frsky_state = baudRate = SPORT_SINGLE_WIRE
 │   │   ├──> <!strcmp(myoptarg, "sport_single_invert")>
 │   │   │   └──> frsky_state = baudRate = SPORT_SINGLE_WIRE_INVERT
 │   │   ├──> <!strcmp(myoptarg, "dtype")>
 │   │   │   └──> frsky_state = baudRate = DTYPE
 │   │   ├──> <!strcmp(myoptarg, "auto")>
 │   │   │   └──> frsky_state = baudRate = DTYPE
 │   │   ├──> < else >
 │   │   │   ├──> usage()
 │   │   │   └──> return -1
 │   │   └──> break
 │   └──> <default:
 │       ├──> usage()
 │       └──> return -1
 ├──> [Open UART]
 │   ├──> const int uart = sPort_open_uart(device_name, &uart_config, &uart_config_original)
 │   └──> <uart < 0>
 │       ├──> device_name = NULL
 │       └──> return -1
 ├──> [poll descriptor]
 │   ├──> struct pollfd fds[1]
 │   ├──> fds[0].fd = uart
 │   └──> fds[0].events = POLLIN
 ├──> thread_running = true
 ├──> [Auto Detect FrSky (D8 mode, DTYPE) or SmartPort (D16 mode, SPORT/SPORT_SINGLE_WIRE/SPORT_SINGLE_WIRE_INVERT)]
 ├──> <frsky_state == SPORT || frsky_state == SPORT_SINGLE_WIRE || frsky_state == SPORT_SINGLE_WIRE_INVERT>
 │   ├──> [UART Initialization]
 │   ├──> [sPort Topic subscribe]
 │   ├──> <while (!thread_should_exit)>  // send S.port telemetry
 │   │   ├──> [Wait bus master to put 0x7E flag]
 │   │   ├──> [Read ID flag for pulling]
 │   │   ├──> sPort_update_topics  // update subscribed topic
 │   │   └──> <switch (ID flag)>
 │   │       ├──> <case SMARTPORT_POLL_1><now_ms - lastBATV_ms > 1000> //report BATV at 1Hz
 │   │       │   ├──> lastBATV_ms = now_ms
 │   │       │   └──> sPort_send_BATV(uart)  //send battery voltage
 │   │       ├──> <case SMARTPORT_POLL_2><now_ms - lastCUR_ms > 200>  //report battery current at 5Hz
 │   │       │   ├──> lastCUR_ms = now_ms
 │   │       │   └──> sPort_send_CUR(uart)  //send battery current
 │   │       ├──> <case SMARTPORT_POLL_3><now_ms - lastALT_ms > 200> //report altitude at 5Hz
 │   │       │   ├──> lastALT_ms = now_ms
 │   │       │   └──> sPort_send_ALT(uart) //send altitude
 │   │       ├──> <case SMARTPORT_POLL_4><now_ms - lastSPD_ms > 200> //report speed at 5Hz
 │   │       │   ├──> lastSPD_ms = now_ms
 │   │       │   └──> sPort_send_SPD(uart)  //send speed
 │   │       ├──> <case SMARTPORT_POLL_5><now_ms - lastFUEL_ms > 1000> //report fuel at 1Hz
 │   │       │   ├──> lastFUEL_ms = now_ms
 │   │       │   └──> sPort_send_FUEL(uart) //send fuel
 │   │       ├──> <case SMARTPORT_POLL_6><now_ms - lastVSPD_ms > 100>  //report vertical speed at 10Hz
 │   │       │   ├──> uint32_t dt = now_ms - lastVSPD_ms
 │   │       │   ├──> float speed  = (filtered_alt - last_baro_alt) / (1e-3f * (float)dt)  //estimate vertical speed using first difference and delta t
 │   │       │   ├──> last_baro_alt = filtered_alt  //save current alt and timestamp
 │   │       │   ├──> lastVSPD_ms = now_ms
 │   │       │   └──> sPort_send_VSPD(uart, speed)
 │   │       ├──> <case SMARTPORT_POLL_7><now_ms - lastGPS_ms > 100><switch (elementCount)>  //report GPS data elements at 5*5Hz
 │   │       │   ├──> <elementCount 0>:sPort_send_GPS_LON(uart)
 │   │       │   ├──> <elementCount 1>:sPort_send_GPS_LAT(uart)
 │   │       │   ├──> <elementCount 2>:sPort_send_GPS_CRS(uart)
 │   │       │   ├──> <elementCount 3>:sPort_send_GPS_ALT(uart)
 │   │       │   ├──> <elementCount 4>:sPort_send_GPS_SPD(uart)
 │   │       │   └──> <elementCount 5>:sPort_send_GPS_TIME(uart)
 │   │       ├──> <case SMARTPORT_POLL_8>
 │   │       │   ├──> <now_ms - lastNAV_STATE_ms > 500>  // report nav_state as DIY_NAVSTATE 2Hz
 │   │       │   │   ├──> lastNAV_STATE_ms = now_ms
 │   │       │   │   └──> sPort_send_NAV_STATE(uart)  // send T1
 │   │       │   └──> <now_ms - lastGPS_FIX_ms > 500>  //report satcount and fix as DIY_GPSFIX at 2Hz
 │   │       │       ├──> lastGPS_FIX_ms = now_ms
 │   │       │       └──> sPort_send_GPS_FIX(uart)  // send T2
 │   │       └──> <case SMARTPORT_SENSOR_ID_SP2UR>
 │   │           ├──> <case 0>
 │   │           │   └──> sPort_send_flight_mode(uart)
 │   │           └──> default:
 │   │               └──> sPort_send_GPS_info(uart)
 │   ├──> PX4_DEBUG("freeing sPort memory")
 │   └──> sPort_deinit()
 ├──> <frsky_state == DTYPE>
 │   ├──> [detected D type telemetry: reconfigure UART]
 │   ├──> [frsky_init() Topic subscribe]
 │   ├──> <while (!thread_should_exit)> //send D8 mode telemetry
 │   │   ├──> [frsky_parse_host, parse incoming data]
 │   │   ├──> frsky_update_topics // update subscribed topic
 │   │   ├──> <sentPackets++>: frsky_send_frame1(uart)  //Send frame 1 (every 200ms): acceleration values, altitude (vario), temperatures, current & voltages, RPM
 │   │   ├──> <sentPackets++>: frsky_send_frame2(uart)  //Send frame 2 (every 1000ms): course, latitude, longitude, speed, altitude (GPS), fuel level
 │   │   └──> <sentPackets++>: frsky_send_frame3(uart)  //Send frame 3 (every 5000ms): date, time
 │   └──> frsky_deinit()
 ├──> tcsetattr(uart, TCSANOW, &uart_config_original)  //Reset the UART flags to original state
 ├──> close(uart)
 ├──> device_name = NULL
 ├──> thread_running = false
 └──> return 0C
frsky_telemetry_thread_main
 ├──> device_name = "/dev/ttyS6"; /* default USART8 */
 ├──> [frsky状态机及变量初始化]
 ├──> [frsky telemetry参数解析]
 │   ├──> <case 'd'>
 │   │   ├──> device_name = myoptarg;
 │   │   └──> break;
 │   ├──> <case 't'>
 │   │   ├──> scanning_timeout_ms = strtoul(myoptarg, nullptr, 10) * 1000;
 │   │   └──> break;
 │   ├──> <case 'm'>
 │   │   ├──> <!strcmp(myoptarg, "sport")>
 │   │   │   └──> frsky_state = baudRate = SPORT;
 │   │   ├──> <!strcmp(myoptarg, "sport_single")>
 │   │   │   └──> frsky_state = baudRate = SPORT_SINGLE_WIRE;
 │   │   ├──> <!strcmp(myoptarg, "sport_single_invert")>
 │   │   │   └──> frsky_state = baudRate = SPORT_SINGLE_WIRE_INVERT;
 │   │   ├──> <!strcmp(myoptarg, "dtype")>
 │   │   │   └──> frsky_state = baudRate = DTYPE;
 │   │   ├──> <!strcmp(myoptarg, "auto")>
 │   │   │   └──> frsky_state = baudRate = DTYPE;
 │   │   ├──> < else >
 │   │   │   ├──> usage();
 │   │   │   └──> return -1;
 │   │   └──> break;
 │   └──> <default:
 │       ├──> usage();
 │       └──> return -1;
 ├──> [Open UART]
 │   ├──> const int uart = sPort_open_uart(device_name, &uart_config, &uart_config_original);
 │   └──> <uart < 0>
 │       ├──> device_name = NULL;
 │       └──> return -1;
 ├──> [poll descriptor]
 │   ├──> struct pollfd fds[1];
 │   ├──> fds[0].fd = uart;
 │   └──> fds[0].events = POLLIN;
 ├──> thread_running = true;
 ├──> [Auto Detect FrSky (D8 mode, DTYPE) or SmartPort (D16 mode, SPORT/SPORT_SINGLE_WIRE/SPORT_SINGLE_WIRE_INVERT)]
 ├──> <frsky_state == SPORT || frsky_state == SPORT_SINGLE_WIRE || frsky_state == SPORT_SINGLE_WIRE_INVERT>
 │   ├──> [UART Initialization]
 │   ├──> [sPort Topic subscribe]
 │   ├──> <while (!thread_should_exit)>  // send S.port telemetry
 │   │   ├──> [Wait bus master to put 0x7E flag]
 │   │   ├──> [Read ID flag for pulling]
 │   │   ├──> sPort_update_topics  // update subscribed topic
 │   │   └──> <switch (ID flag)>
 │   │       ├──> <case SMARTPORT_POLL_1><now_ms - lastBATV_ms > 1000> //report BATV at 1Hz
 │   │       │   ├──> lastBATV_ms = now_ms;
 │   │       │   └──> sPort_send_BATV(uart);  //send battery voltage
 │   │       ├──> <case SMARTPORT_POLL_2><now_ms - lastCUR_ms > 200>  //report battery current at 5Hz
 │   │       │   ├──> lastCUR_ms = now_ms;
 │   │       │   └──> sPort_send_CUR(uart);  //send battery current
 │   │       ├──> <case SMARTPORT_POLL_3><now_ms - lastALT_ms > 200> //report altitude at 5Hz
 │   │       │   ├──> lastALT_ms = now_ms;
 │   │       │   └──> sPort_send_ALT(uart); //send altitude
 │   │       ├──> <case SMARTPORT_POLL_4><now_ms - lastSPD_ms > 200> //report speed at 5Hz
 │   │       │   ├──> lastSPD_ms = now_ms;
 │   │       │   └──> sPort_send_SPD(uart);  //send speed
 │   │       ├──> <case SMARTPORT_POLL_5><now_ms - lastFUEL_ms > 1000> //report fuel at 1Hz
 │   │       │   ├──> lastFUEL_ms = now_ms;
 │   │       │   └──> sPort_send_FUEL(uart); //send fuel
 │   │       ├──> <case SMARTPORT_POLL_6><now_ms - lastVSPD_ms > 100>  //report vertical speed at 10Hz
 │   │       │   ├──> uint32_t dt = now_ms - lastVSPD_ms;
 │   │       │   ├──> float speed  = (filtered_alt - last_baro_alt) / (1e-3f * (float)dt);  //estimate vertical speed using first difference and delta t
 │   │       │   ├──> last_baro_alt = filtered_alt;  //save current alt and timestamp
 │   │       │   ├──> lastVSPD_ms = now_ms;
 │   │       │   └──> sPort_send_VSPD(uart, speed);
 │   │       ├──> <case SMARTPORT_POLL_7><now_ms - lastGPS_ms > 100><switch (elementCount)>  //report GPS data elements at 5*5Hz
 │   │       │   ├──> <elementCount 0>:sPort_send_GPS_LON(uart);
 │   │       │   ├──> <elementCount 1>:sPort_send_GPS_LAT(uart);
 │   │       │   ├──> <elementCount 2>:sPort_send_GPS_CRS(uart);
 │   │       │   ├──> <elementCount 3>:sPort_send_GPS_ALT(uart);
 │   │       │   ├──> <elementCount 4>:sPort_send_GPS_SPD(uart);
 │   │       │   └──> <elementCount 5>:sPort_send_GPS_TIME(uart);
 │   │       ├──> <case SMARTPORT_POLL_8>
 │   │       │   ├──> <now_ms - lastNAV_STATE_ms > 500>  // report nav_state as DIY_NAVSTATE 2Hz
 │   │       │   │   ├──> lastNAV_STATE_ms = now_ms;
 │   │       │   │   └──> sPort_send_NAV_STATE(uart);  // send T1
 │   │       │   └──> <now_ms - lastGPS_FIX_ms > 500>  //report satcount and fix as DIY_GPSFIX at 2Hz
 │   │       │       ├──> lastGPS_FIX_ms = now_ms;
 │   │       │       └──> sPort_send_GPS_FIX(uart);  // send T2
 │   │       └──> <case SMARTPORT_SENSOR_ID_SP2UR>
 │   │           ├──> <case 0>
 │   │           │   └──> sPort_send_flight_mode(uart);
 │   │           └──> default:
 │   │               └──> sPort_send_GPS_info(uart);
 │   ├──> PX4_DEBUG("freeing sPort memory");
 │   └──> sPort_deinit();
 ├──> <frsky_state == DTYPE>
 │   ├──> [detected D type telemetry: reconfigure UART]
 │   ├──> [frsky_init() Topic subscribe]
 │   ├──> <while (!thread_should_exit)> //send D8 mode telemetry
 │   │   ├──> [frsky_parse_host, parse incoming data]
 │   │   ├──> frsky_update_topics // update subscribed topic
 │   │   ├──> <sentPackets++>: frsky_send_frame1(uart)  //Send frame 1 (every 200ms): acceleration values, altitude (vario), temperatures, current & voltages, RPM
 │   │   ├──> <sentPackets++>: frsky_send_frame2(uart)  //Send frame 2 (every 1000ms): course, latitude, longitude, speed, altitude (GPS), fuel level
 │   │   └──> <sentPackets++>: frsky_send_frame3(uart);  //Send frame 3 (every 5000ms): date, time
 │   └──> frsky_deinit();
 ├──> tcsetattr(uart, TCSANOW, &uart_config_original);  //Reset the UART flags to original state
 ├──> close(uart);
 ├──> device_name = NULL;
 ├──> thread_running = false;
 └──> return 0;

4. 总结

1. FrSky硬件连接图,如下所示

2. 从模块代码角度,输入输出项如下所示

  • 输入
uORB::SubscriptionData<battery_status_s> battery_status_subORB_ID(battery_status);
uORB::SubscriptionData<vehicle_acceleration_s> vehicle_acceleration_subORB_ID(vehicle_acceleration);
uORB::SubscriptionData<vehicle_air_data_s> vehicle_air_data_subORB_ID(vehicle_air_data);
uORB::SubscriptionData<vehicle_local_position_s> vehicle_local_position_subORB_ID(vehicle_local_position);
uORB::SubscriptionData<vehicle_global_position_s> vehicle_global_position_subORB_ID(vehicle_global_position);
uORB::SubscriptionData<vehicle_gps_position_s> vehicle_gps_position_subORB_ID(vehicle_gps_position);
uORB::SubscriptionData<vehicle_status_s> vehicle_status_subORB_ID(vehicle_status);
  • 输出
    通过串行口输出到Rx模块,最终到遥控Tx模块。
void sPort_send_data(int uart, uint16_t id, uint32_t data)

3. 具体逻辑业务就是期望将飞控上的数据展示到遥控器上,如下图所示

5. 参考资料

【1】PX4开源软件框架简明简介
【2】PX4模块设计之十一:Built-In框架
【3】PX4模块设计之十二:High Resolution Timer设计
【4】PX4模块设计之十三:WorkQueue设计
【5】PX4模块设计之十七:ModuleBase模块
【6】PX4模块设计之三十:Hysteresis类
【7】PX4 modules_main
【8】frsky-protocols-made-simple

以上是关于PX4模块设计之四十:FrskyTelemetry模块的主要内容,如果未能解决你的问题,请参考以下文章

PX4模块设计之四十五:param模块

PX4模块设计之四十六:dataman模块

PX4模块设计之四十六:dataman模块

PX4模块设计之四十二:ATXXXX模块

PX4模块设计之四十七:mavlink模块

PX4模块设计之四十七:mavlink模块