PX4之commander剖析解读-2

2023-05-16

首先,感谢“阿木社区”小伙伴们在PX4方面做出的贡献。在学习px4的过程中,我也是个小学生,以下作为个人的小心得,纰漏蛮多,还望各位同仁包涵、期待批评指正。但我们的目的只有一个——在想改变一个规则之前,先学会它,打破再立(不破不立)

闲话少絮,书归正文。

Commander文件夹是px4源码中的飞行控制命令切换模块(比如由Stab_Mode,Alti_Mode,Pos_Mode,Auto_Mode在 相互切换的过程)其次,所有模式能不能成功切换,都在这个模块中做了相应的飞行条件检查。

自稳模式的切换,不需要太多的飞行条件。如果是定高,定点,自动模式,需要很多的传感器数据有效的条件,这就需要很多的检查,只有条件满足才能够成功切换。

须知点:

模式切换就是MODE_SW (地面站选择模式切换开关,通常我们的遥控器只有3个档,因此需要3个以上的模式切换,则需要“改造”遥控器了——改装个多档位切换开关):但值得注意的是——Mode_Switch开关除了模式通道定义的模式外,还包含独立模式通道,比如空中停转(brake,return、等等)。

如此种种都是在Commander内完成的内容,最终能不能成功的切换就看各种模式需要的传感器满足条件,和切换间隙、出错问题的判断了。

一 模式基本分类:阿木小伙伴先探过路 + 自己补充一点点

在整个过程中我们需要有明确的思路:这样有助于我们对commander模块的理解。为了能说明白直观理解能上图的地方我尽量少说话(为了截图方便 那就在windows下登着QQ截图,随心所欲啊,包涵了伙伴们),来点小伙伴们没有人提到过的东西。

1、对于Commander函数文件夹内文件之间关系;

这些部分暂时放在这里稍后我会伟伟道来(haha)

2、函数整个基本层次结构。

首先,需要明确:commander.cpp、commander_params.c是关于整个commander模块线程(暂这样叫、道线程是活跃的哦,当然这个需要基于操作系统)的任务调度的入口文件:

int commander_main(int argc, char *argv[])

这函数的“入口和跟进方”法大家都很熟悉了就不累赘了、不过我还是把入口文件附在下面,便于阅读。

int commander_main(int argc, char*argv[])

{

       if (argc <2) {

              usage("missingcommand");

              return 1;

       }

 

       if(!strcmp(argv[1], "start")) {

 

              if(thread_running) {

                     warnx("alreadyrunning");

                     /* this is not anerror */

                     return 0;

              }

 

              thread_should_exit = false;

              daemon_task = px4_task_spawn_cmd("commander",

                                        SCHED_DEFAULT,

                                        SCHED_PRIORITY_DEFAULT + 40,

                                        3600,

                                        commander_thread_main,

                                        (char * const*)&argv[0]);

 

              unsigned constexprmax_wait_us = 1000000;

              unsigned constexprmax_wait_steps = 2000;

 

              unsigned i;

              for (i = 0; i< max_wait_steps; i++) {

                     usleep(max_wait_us /max_wait_steps);

                     if(thread_running) {

                            break;

                     }

              }

 

              return !(i <max_wait_steps);

       }

 

       if(!strcmp(argv[1], "stop")) {

 

              if(!thread_running) {

                     warnx("commanderalready stopped");

                     return 0;

              }

 

              thread_should_exit = true;

              while(thread_running) {

                     usleep(200000);

                     warnx(".");

              }

 

              warnx("terminated.");

 

              return 0;

       }

 

       /* commands needing the app torun below */

       if(!thread_running) {

              warnx("\tcommandernot started");

              return 1;

       }

 

       if(!strcmp(argv[1], "status")) {

              print_status();

              return 0;

       }

 

       if(!strcmp(argv[1], "calibrate")) {

              if (argc >2) {

                     int calib_ret= OK;

                     if(!strcmp(argv[2], "mag")) {

                            calib_ret =do_mag_calibration(&mavlink_log_pub);

                     } else if(!strcmp(argv[2], "accel")) {

                            calib_ret =do_accel_calibration(&mavlink_log_pub);

                     } else if(!strcmp(argv[2], "gyro")) {

                            calib_ret =do_gyro_calibration(&mavlink_log_pub);

                     } else if(!strcmp(argv[2], "level")) {

                            calib_ret =do_level_calibration(&mavlink_log_pub);

                     } else if(!strcmp(argv[2], "esc")) {

                            calib_ret =do_esc_calibration(&mavlink_log_pub, &armed);

                     } else if(!strcmp(argv[2], "airspeed")) {

                            calib_ret =do_airspeed_calibration(&mavlink_log_pub);

                     } else {

                            warnx("argument%s unsupported.", argv[2]);

                     }

 

                     if(calib_ret) {

                            warnx("calibrationfailed, exiting.");

                            return 1;

                     } else {

                            return 0;

                     }

              } else {

                   warnx("missingargument");

              }

       }

 

       if(!strcmp(argv[1], "check")) {

              int checkres =0;

              checkres = preflight_check(&status,&mavlink_log_pub, false, true,&status_flags, &battery, true, false,

hrt_elapsed_time(&commander_boot_timestamp));

              warnx("Preflightcheck: %s", (checkres == 0) ? "OK" : "FAILED");

 

                            checkres = preflight_check(&status,&mavlink_log_pub, true, true,&status_flags, &battery, arm_without_gps,

arm_mission_required, hrt_elapsed_time(&commander_boot_timestamp));

              warnx("Prearmcheck: %s", (checkres == 0) ? "OK" : "FAILED");

 

              return 0;

       }

 

       if(!strcmp(argv[1], "arm")) {

              if (TRANSITION_CHANGED !=arm_disarm(true, &mavlink_log_pub, "commandline")) {

                   warnx("armingfailed");

              }

              return 0;

       }

 

       if(!strcmp(argv[1], "disarm")) {

              if (TRANSITION_DENIED ==arm_disarm(false, &mavlink_log_pub, "commandline")) {

                   warnx("rejecteddisarm");

              }

              return 0;

       }

 

       if(!strcmp(argv[1], "takeoff")) {

 

              /* see if we got ahome position */

              if(status_flags.condition_local_position_valid) {

 

                     if (TRANSITION_DENIED !=arm_disarm(true, &mavlink_log_pub, "commandline")) {

 

                            vehicle_command_s cmd = {};

                            cmd.target_system= status.system_id;

                            cmd.target_component= status.component_id;

 

                            cmd.command =vehicle_command_s::VEHICLE_CMD_NAV_TAKEOFF;

                            cmd.param1 =NAN; /* minimum pitch */

                            /* param2-3 unused */

                            cmd.param2 =NAN;

                            cmd.param3 =NAN;

                            cmd.param4 =NAN;

                            cmd.param5 =NAN;

                            cmd.param6 =NAN;

                            cmd.param7 =NAN;

 

                            orb_advert_t h = orb_advertise_queue(ORB_ID(vehicle_command),&cmd,

vehicle_command_s::ORB_QUEUE_LENGTH);

 

                            (void)orb_unadvertise(h);

 

                     } else {

                            warnx("armingfailed");

                     }

 

              } else {

                     warnx("rejectingtakeoff, no position lock yet. Please retry..");

              }

 

              return 0;

       }

 

       if(!strcmp(argv[1], "land")) {

 

              vehicle_command_s cmd = {};

              cmd.target_system = status.system_id;

              cmd.target_component =status.component_id;

 

              cmd.command = vehicle_command_s::VEHICLE_CMD_NAV_LAND;

              /* param 2-3unused */

              cmd.param2 = NAN;

              cmd.param3 = NAN;

              cmd.param4 = NAN;

              cmd.param5 = NAN;

              cmd.param6 = NAN;

              cmd.param7 = NAN;

 

              orb_advert_t h = orb_advertise_queue(ORB_ID(vehicle_command),&cmd, vehicle_command_s::ORB_QUEUE_LENGTH);

 

              (void)orb_unadvertise(h);

              return 0;

       }

 

       if(!strcmp(argv[1], "transition")) {

 

              vehicle_command_s cmd = {};

              cmd.target_system = status.system_id;

              cmd.target_component =status.component_id;

 

              cmd.command = vehicle_command_s::VEHICLE_CMD_DO_VTOL_TRANSITION;

              /* transition to theother mode */

              cmd.param1 = (status.is_rotary_wing)? vtol_vehicle_status_s::VEHICLE_VTOL_STATE_FW :

vtol_vehicle_status_s::VEHICLE_VTOL_STATE_MC;

              /* param 2-3unused */

              cmd.param2 = NAN;

              cmd.param3 = NAN;

              cmd.param4 = NAN;

              cmd.param5 = NAN;

              cmd.param6 = NAN;

              cmd.param7 = NAN;

 

              orb_advert_t h = orb_advertise_queue(ORB_ID(vehicle_command),&cmd, vehicle_command_s::ORB_QUEUE_LENGTH);

              (void)orb_unadvertise(h);

 

              return 0;

       }

 

       if(!strcmp(argv[1], "mode")) {

               if (argc > 2) {

                uint8_t new_main_state = commander_state_s::MAIN_STATE_MAX;

                if (!strcmp(argv[2], "manual")) {

                     new_main_state = commander_state_s::MAIN_STATE_MANUAL;

                } else if (!strcmp(argv[2], "altctl")) {

                     new_main_state = commander_state_s::MAIN_STATE_ALTCTL;

                } else if (!strcmp(argv[2], "posctl")) {

                     new_main_state = commander_state_s::MAIN_STATE_POSCTL;

                } else if (!strcmp(argv[2], "auto:mission")) {

                     new_main_state = commander_state_s::MAIN_STATE_AUTO_MISSION;

                 } else if (!strcmp(argv[2], "auto:loiter")) {

                     new_main_state = commander_state_s::MAIN_STATE_AUTO_LOITER;

                 } else if (!strcmp(argv[2], "auto:rtl")) {

                     new_main_state = commander_state_s::MAIN_STATE_AUTO_RTL;

                 } else if (!strcmp(argv[2], "acro")) {

                     new_main_state= commander_state_s::MAIN_STATE_ACRO;

                 } else if (!strcmp(argv[2], "offboard")) {

                     new_main_state = commander_state_s::MAIN_STATE_OFFBOARD;

                 } else if (!strcmp(argv[2], "stabilized")) {

                     new_main_state = commander_state_s::MAIN_STATE_STAB;

                 } else if (!strcmp(argv[2], "rattitude")) {

                     new_main_state = commander_state_s::MAIN_STATE_RATTITUDE;

                 } else if (!strcmp(argv[2], "auto:takeoff")) {

                     new_main_state = commander_state_s::MAIN_STATE_AUTO_TAKEOFF;

                 } else if (!strcmp(argv[2], "auto:land")) {

                     new_main_state = commander_state_s::MAIN_STATE_AUTO_LAND;

                 } else {

                     warnx("argument%s unsupported.", argv[2]);

              }

 

                if (TRANSITION_DENIED ==main_state_transition(&status, new_main_state, main_state_prev,  &status_flags,

&internal_state)) {

                            warnx("modechange failed");

              }

             

return 0;

 

           } else {

              warnx("missingargument");

           }

       }

 

       if(!strcmp(argv[1], "lockdown")) {

 

            if (argc < 3) {

              usage("not enougharguments, missing [on, off]");

              return 1;

            }

 

             vehicle_command_s cmd = {};

             cmd.target_system = status.system_id;

             cmd.target_component = status.component_id;

 

             cmd.command = vehicle_command_s::VEHICLE_CMD_DO_FLIGHTTERMINATION;

            /* if the comparison matches for off (== 0) set 0.0f, 2.0f (on)else */

             cmd.param1 = strcmp(argv[2], "off") ? 2.0f :0.0f; /* lockdown */

 

              orb_advert_t h = orb_advertise_queue(ORB_ID(vehicle_command),&cmd, vehicle_command_s::ORB_QUEUE_LENGTH);

             

(void)orb_unadvertise(h);

 

          return 0;

       }

 

usage("unrecognized command");

return 1;

}

由以上代码可以知道,对于commander模块线程能够接受的参数还是蛮多的。

参数不能少于1个:如:

除了“start”“stop”命令参数外,剩下的参数命令可以跟多个参数命令。好了剩下的就是慢慢啃、来分析函数代码了。

我们进入到主函数:int commander_thread_main(int argc, char *argv[])

该函数是整个commander模块线程完成的大loop函数体部分。在读完改函数的过程中,我们比较感兴趣的“问题点3”是比较复杂的。(但是也得啃,啃清楚就明白啦,对吧?那就来吧!!!)

 

3、“相关”数据的“来、去”

这个问题点需要搞懂三个问题:相关数据具体指什么数据,数据来自哪里。完事又去了哪里?

“阿木”伙伴们前期探路让我学习到了一些知识点,对此表示十分感谢。但凡是看过csdn上关于本模块的说明内容后——发现说的不够完全清楚。(读过感觉依旧有一层模糊的窗户纸)

因此,我们还是自己捅了捅窗户。(能力有限,望批评指正)

对于这一模块代码量是比较大而杂的,为了能说明清楚问题,尽量不帖代码(看代码一整就是几大篇,但是重要的代码还是会帖出来一起说说),这里我尽量的提供思路——我们把复杂的事情搞简单。

在这个模块中——软件对提供的数据的“理解范围”还是比较高综合性的。

首先,紧接进入函数int commander_thread_main(int argc, char *argv[])在一进入函数,首先是针对“函数参数”对重要“状态-环节”判断、初始化(标志初始化):

大致骨架梳理:

while(!thread_should_exit)

 {

 

orb_check(param_changed_sub,&updated);

...

orb_check(sp_man_sub,&updated);

...

orb_check(offboard_control_mode_sub,&updated);

...

orb_check(sensor_sub,&updated);

...

orb_check(diff_pres_sub,&updated);

..

orb_check(system_power_sub,&updated);

...

orb_check(safety_sub,&updated);

if (updated){

          bool previous_safety_off = safety.safety_off;

          orb_copy(ORB_ID(safety), safety_sub, &safety);

 

          /* disarmif safety is now on and still armed */

if (status.hil_state == vehicle_status_s::HIL_STATE_OFF &&safety.safety_switch_available && !safety.safety_off&&

armed.armed) {

arming_state_t new_arming_state = (status.arming_state== vehicle_status_s::ARMING_STATE_ARMED ?

vehicle_status_s::ARMING_STATE_STANDBY : vehicle_status_s::ARMING_STATE_STANDBY_ERROR);

if (TRANSITION_CHANGED == arming_state_transition(&status,

&battery,

                                           &safety,

                                           new_arming_state,

                                           &armed,

                                           true /*fRunPreArmChecks */,

                                           &mavlink_log_pub,

                                           &status_flags,

                                           avionics_power_rail_voltage,

                                           arm_without_gps,

arm_mission_required,

hrt_elapsed_time(&commander_boot_timestamp))){

// mavlink_log_info(&mavlink_log_pub, "DISARMEDby safety switch");

arming_state_changed = true;

}

              }

 

                     //Notify the user ifthe status of the safety switch changes

            if (safety.safety_switch_available &&previous_safety_off != safety.safety_off) {

 

              if (safety.safety_off){

               set_tune(TONE_NOTIFY_POSITIVE_TUNE);

 

              } else {

tune_neutral(true);

}

 

             status_changed = true;

          }

}

orb_check(vtol_vehicle_status_sub,&updated);

...

orb_check(global_position_sub,&updated);

...

orb_check(local_position_sub,&updated);

...

orb_check(attitude_sub,&updated);

...

orb_check(land_detector_sub,&updated);

...

orb_check(cpuload_sub,&updated);

...

orb_check(battery_sub,&updated);

...

orb_check(subsys_sub,&updated);

...

 

orb_check(pos_sp_triplet_sub,&updated);

/* 在初始化状态下——试着尝试arming_STANDBY状态 */

if(!status_flags.condition_calibration_enabled && status.arming_state== vehicle_status_s::ARMING_STATE_INIT) {

                     arming_ret = arming_state_transition(&status,

                                          &battery,

                                          &safety,

                                          vehicle_status_s::ARMING_STATE_STANDBY,

                                          &armed,

                                          true /*fRunPreArmChecks */,

                                          &mavlink_log_pub,

                                          &status_flags,

                                           avionics_power_rail_voltage,

                                           arm_without_gps,

                                           arm_mission_required,

                                           hrt_elapsed_time(&commander_boot_timestamp));

 

                     if(arming_ret == TRANSITION_CHANGED) {

                            arming_state_changed= true;

                     } else if (arming_ret== TRANSITION_DENIED) {

                            /* do notcomplain if not allowed into standby */

                            arming_ret = TRANSITION_NOT_CHANGED;

                     }

              }

 

  

...

orb_check(gps_sub,&updated);

...

orb_check(mission_result_sub,&updated);

...

/* 电子围栏 */

orb_check(geofence_result_sub,&updated);

...

 

// revertgeofence failsafe transition if sticks are moved and we werepreviously in a manual mode

          // but only if notin a low battery handling action

          if(rc_override != 0 && !critical_battery_voltage_actions_done &&(warning_action_on &&

            (main_state_before_rtl == commander_state_s::MAIN_STATE_MANUAL ||

                 main_state_before_rtl == commander_state_s::MAIN_STATE_ALTCTL ||

                 main_state_before_rtl == commander_state_s::MAIN_STATE_POSCTL ||

                 main_state_before_rtl == commander_state_s::MAIN_STATE_ACRO ||

                 main_state_before_rtl == commander_state_s::MAIN_STATE_RATTITUDE ||

                 main_state_before_rtl == commander_state_s::MAIN_STATE_STAB))) {

 

                 // transition toprevious state if sticks are touched

                 if((_last_sp_man.timestamp != sp_man.timestamp) &&

                        ((fabsf(sp_man.x -_last_sp_man.x) > min_stick_change) ||

                         (fabsf(sp_man.y - _last_sp_man.y) >min_stick_change) ||

                         (fabsf(sp_man.z - _last_sp_man.z) > min_stick_change)||

                         (fabsf(sp_man.r - _last_sp_man.r) >min_stick_change))) {

 

                     // revert to position control in anycase

                     main_state_transition(&status, commander_state_s::MAIN_STATE_POSCTL,main_state_prev,

&status_flags, &internal_state);

mavlink_log_critical(&mavlink_log_pub,"Autopilotoff, returned control to pilot");

                 }

          }

 

          // abort landing orauto or loiter if sticks are moved significantly

          // but only if notin a low battery handling action

          if(rc_override != 0 && !critical_battery_voltage_actions_done &&

                 (internal_state.main_state== commander_state_s::MAIN_STATE_AUTO_LAND ||

                 internal_state.main_state== commander_state_s::MAIN_STATE_AUTO_MISSION ||

                 internal_state.main_state== commander_state_s::MAIN_STATE_AUTO_LOITER)) {

                 // transition toprevious state if sticks are touched

 

                 if((_last_sp_man.timestamp != sp_man.timestamp) &&

                        ((fabsf(sp_man.x -_last_sp_man.x) > min_stick_change) ||

                         (fabsf(sp_man.y - _last_sp_man.y) > min_stick_change)||

                         (fabsf(sp_man.z - _last_sp_man.z) >min_stick_change) ||

                         (fabsf(sp_man.r - _last_sp_man.r) >min_stick_change))) {

 

                        // revert toposition control in any case

                        main_state_transition(&status, commander_state_s::MAIN_STATE_POSCTL,main_state_prev,

&status_flags,&internal_state);

                        mavlink_log_critical(&mavlink_log_pub,"Autopilotoff, returned control to pilot");

                 }

          }

 

 

          /* Check for missionflight termination */

          if (armed.armed&& _mission_result.flight_termination &&

             !status_flags.circuit_breaker_flight_termination_disabled) {

 

                 armed.force_failsafe = true;

                 status_changed = true;

                 static boolflight_termination_printed = false;

 

                 if(!flight_termination_printed) {

                        mavlink_log_critical(&mavlink_log_pub,"Geofenceviolation: flight termination");

                        flight_termination_printed= true;

                 }

 

                 if (counter %(1000000 / COMMANDER_MONITORING_INTERVAL) == 0) {

                        mavlink_log_critical(&mavlink_log_pub,"Flighttermination active");

                 }

          }

 

          /* Only evaluatemission state if home is set,

           * this prevents false positives for themission

           * rejection. Back off 2 seconds to not overlay

           * home tune.

           */

          if(status_flags.condition_home_position_valid &&

                 (hrt_elapsed_time(&_home.timestamp)> 2000000) &&

                 _last_mission_instance !=_mission_result.instance_count) {

 

                 if(!_mission_result.valid) {

                        /* the mission isinvalid */

                        tune_mission_fail(true);

                        warnx("missionfail");

                 } else if (_mission_result.warning){

                        /* the mission has awarning */

                        tune_mission_fail(true);

                        warnx("missionwarning");

                 } else {

                        /* the mission isvalid */

                        tune_mission_ok(true);

                 }

 

                 /* prevent furtherfeedback until the mission changes */

                 _last_mission_instance =_mission_result.instance_count;

          }

 

          /* RC input check */

          if(!status_flags.rc_input_blocked && sp_man.timestamp != 0 &&

             (hrt_absolute_time() < sp_man.timestamp + (uint64_t)(rc_loss_timeout* 1e6f))) {

                 /* handle the casewhere RC signal was regained */

                 if(!status_flags.rc_signal_found_once) {

                        status_flags.rc_signal_found_once = true;

                        status_changed = true;

 

                 } else {

                        if (status.rc_signal_lost){

                               mavlink_log_info(&mavlink_log_pub,"(xiwei)MANUAL control regained after %llums",

                                                  (hrt_absolute_time() -rc_signal_lost_timestamp) / 1000);

                               status_changed = true;

                        }

                 }

 

 

if(!in_armed_state && status.rc_input_mode != vehicle_status_s::RC_IN_MODE_OFF &&

(stick_in_lower_right|| arm_button_pressed || arm_switch_to_arm_transition) ) {

           if ((stick_on_counter == rc_arm_hyst &&stick_off_counter < rc_arm_hyst) || arm_switch_to_arm_transition) {

if ((internal_state.main_state != commander_state_s::MAIN_STATE_MANUAL) &&

(internal_state.main_state != commander_state_s::MAIN_STATE_ACRO) &&

(internal_state.main_state != commander_state_s::MAIN_STATE_STAB) &&

(internal_state.main_state != commander_state_s::MAIN_STATE_ALTCTL) &&

(internal_state.main_state != commander_state_s::MAIN_STATE_POSCTL) &&

(internal_state.main_state != commander_state_s::MAIN_STATE_RATTITUDE) ) {

print_reject_arm("NOT ARMING: Switch need a manual modefirst.");

              } else if (!status_flags.condition_home_position_valid &&geofence_action == geofence_result_s::GF_ACTION_RTL) {        print_reject_arm("NOTARMING: Geofence RTL requires valid home");

} else if (status.arming_state== vehicle_status_s::ARMING_STATE_STANDBY) {

arming_ret = arming_state_transition( &status,

&battery,

&safety,

vehicle_status_s::ARMING_STATE_ARMED,

&armed,

true /* fRunPreArmChecks */,

&mavlink_log_pub,

&status_flags,

avionics_power_rail_voltage,

arm_without_gps,

arm_mission_required,

hrt_elapsed_time(&commander_boot_timestamp));                             if (arming_ret == TRANSITION_CHANGED) {

arming_state_changed = true;

} else {

usleep(100000);

print_reject_arm("NOT ARMING: Preflight checksfailed");

}

}

}

stick_on_counter++;

} else if(!(arm_switch_is_button == 1 &&

sp_man.arm_switch == manual_control_setpoint_s::SWITCH_POS_ON)) {

        stick_on_counter= 0;

}

_last_sp_man_arm_switch = sp_man.arm_switch;

 

 

 

/* evaluate the main state machine according to mode switches */

bool first_rc_eval = (_last_sp_man.timestamp== 0) && (sp_man.timestamp > 0);

/* 遥控模式输入    */

transition_result_t main_res = set_main_state_rc(&status);

...

 

orb_check(cmd_sub, &updated);

...

 

/* checkif we are disarmed and there is a better mode to wait in */

if (!armed.armed){

       /* if there is no radio control butGPS lock the user might want to fly using

 * just a tablet. Since the RC will force itsmode switch setting on connecting

        *we can as well just wait in a hold mode which enables tablet control.

        */

       if (status.rc_signal_lost&& (internal_state.main_state == commander_state_s::MAIN_STATE_MANUAL)

              &&status_flags.condition_home_position_valid) {

              (void)  main_state_transition (&status,commander_state_s::MAIN_STATE_AUTO_LOITER,

main_state_prev, &status_flags, &internal_state);

                     }

       }

 

       /* handle commands last, as thesystem needs to be updated to handle them */

       orb_check(cmd_sub, &updated);

       if (updated){

       /* got command */

              orb_copy(ORB_ID(vehicle_command),cmd_sub, &cmd);

 

              /* handle it */

              if(handle_command(&status, &safety, &cmd, &armed, &_home,&global_position, &local_position,

                                   &attitude,&home_pub, &command_ack_pub, &command_ack, &_roi,&roi_pub)) {

                     status_changed = true;

              }

      }

 

 

...

 

 

/* now set navigation state according to failsafe andmain state */

   bool nav_state_changed = set_nav_state(&status,                                                                               &armed,                                                                          &internal_state,                                                                     &mavlink_log_pub,                                                                (link_loss_actions_t)datalink_loss_act,                                                     _mission_result.finished,                                                                         _mission_result.stay_in_failsafe,                                                                &status_flags,                                                                       land_detector.landed,                                                              (link_loss_actions_t)rc_loss_act,                                                           offboard_loss_act,                                                                        offboard_loss_rc_act);

 

 

 

      ...

 

 

 

if(main_state_changed || nav_state_changed) {

             status_changed = true;

             main_state_changed = false;

      }

 

/* 我们知道commander不断循环,但是在循环的过程中为20的倍数,因而commandloop的周期,以及set_control_mode函数调用周期也是不固定的但是对于ms运行速度来说,速度至少是5HZ是可以保证的,这使得遥控或者地面站数据外部模式切换是完全够用的 */

     if (counter %(200000 / COMMANDER_MONITORING_INTERVAL(default:1000)) == 0 || status_changed) {

          set_control_mode();

          control_mode.timestamp = now;

          orb_publish(ORB_ID(vehicle_control_mode),control_mode_pub, &control_mode);

 

          status.timestamp = now;

           orb_publish(ORB_ID(vehicle_status),status_pub, &status); // 包含了vtol判断、rcDLinkarm状态、及飞行模式,

          armed.timestamp = now;

 

          /* set prearmedstate if safety is off, or safety is not present and 5 seconds passed */

          if (safety.safety_switch_available){

 

                 /* safetyis off, go into prearmed */

             armed.prearmed = safety.safety_off;

          } else {

          /* safety is notpresent, go into prearmed

          * (all output drivers should bestarted / unlocked last in the boot process

           * when the rest of the system is fullyinitialized)

           */

          armed.prearmed = (hrt_elapsed_time(&commander_boot_timestamp)> 5 * 1000 * 1000);

          }

          orb_publish(ORB_ID(actuator_armed),armed_pub, &armed); // 发布飞机 fmu 、及io的加锁解锁状态

   }

 

...

 

counter++;

/* publishinternal state for logging purposes */

       if(commander_state_pub != nullptr) {

            orb_publish(ORB_ID(commander_state), commander_state_pub,&internal_state);

       } else {

            commander_state_pub = orb_advertise(ORB_ID(commander_state),&internal_state);

       }

 

 

usleep(COMMANDER_MONITORING_INTERVALdefault: 10000);

 

}

 

ret = pthread_join(commander_low_prio_thread,nullptr);

if (ret) {

  warn("join failed: %d", ret);

}

rgbled_set_color_and_mode(led_control_s::COLOR_WHITE, led_control_s::MODE_OFF);

...

 

通过上面“凸显的函数”名我们可以抓住主要“code骨架”,光知道函数骨架——那我们还是太单纯了(函数本身并不复杂,为毛是这样子的骨架么?)(这才是关键)因此,我们来一点点逻辑。

1、函数基本作用

函数

作用

备注

arming_state_transition

解锁判断、执行函数

注意:3 basic state(mode)

set_main_state_rc

RC_input模式切换、判断

Easy

main_state_transition

Mode切换设置

Easy

set_nav_state

导航模式设置

Easy

set_control_mode()

模式设置

逻辑判断 + 结论

StandBy(INIT ture)

ARMING_ERROR( happen and  deal)

 

 

StandBy(ture  && no error)

ARMING  (new arming state)

 

ARMING( now  )

|

|

DISarm、INIT/PREFIGHT

(go back)

 

 

 

基本信息量

safty_sw

sensor_ calibration

system_power

diff_pressure

 

 

 

 

 

 

 


上面罗列了那么多代码,就是为了说清楚这个基本逻辑。源代码中多处用到了函数arming_state_transition——都是按照这个思路来做事的。所以代码还是要看的,毕竟,px4的这帮人还是花了时间的,不管啦,还是老话:在想改变一个规则之前,那就先学会它,打破再制定。

有了这个基本思路,我们在往里看看( ARMING ):

transition_result_t arming_state_transition(       struct vehicle_status_s *status,    //飞机状态数据集

                                                     struct battery_status_s *battery,   // 电量

                                                     const struct safety_s *safety,      //

                                                     arming_state_tnew_arming_state,    // 新状态(期望值)

                                                     struct actuator_armed_s *armed,     // 执行机构(如 电机推力)

                                   boolfRunPreArmChecks,               // 是否进行前期pre-fligt-check

                                                     orb_advert_t*mavlink_log_pub,     ///<uORB handle for mavlink log

                                   status_flags_s*status_flags,

                                                     floatavionics_power_rail_voltage,   //航电 电压等检测

                                                     boolarm_without_gps,                // 是否允许no GPS 下解锁

                                                     boolarm_mission_required,           // mission任务需求bool量标识

                                                 hrt_abstime time_since_boot)         //绝对运行状态值

{

       第一步:

new_arming_state== current_arming_state  // 状态相同。返回

      

       fRunPreArmChecks                  // 是否需要转换前的状态检查bool

Yes

  1、try to disarm if ARMED or to STANDBY_ERROR if ARMED_ERROR  2、manual try to arming

no

1、Go back INIT/PREFLIGTH     2、Standby

 

   //需要pre_flight check的情形:sensor failing 切非 HIL(仿真)状态

如果需要preflight_check (){  fRunPreArmChecks==1

Commander::preflightCheck (mavlink_log_pub,true, true, true, true,checkAirspeed,

(status->rc_input_mode== vehicle_status_s::RC_IN_MODE_DEFAULT),!arm_without_gps,

true,status->is_vtol, reportFailures, prearm, time_since_boot);

其实就是包含了{ bool preflightCheck(orb_advert_t*mavlink_log_pub, bool checkMag, bool checkAcc, bool checkGyro,

                         bool checkBaro,boolcheckAirspeed, bool checkRC, bool checkGNSS, bool checkDynamic, bool isVTOL,

bool reportFailures, bool prearm, hrt_abstimetime_since_boot) }

...

}

第二步:

                              新状态值(期望) 老状态值(current arming state

bool valid_transition =arming_transitions[new_arming_state][status->arming_state];

到这里涉及一个arm_trans_table的东西,其实,模式之间能不能转换,都是已经定义好的,(因为每个模式条件下,涉及的传感器,状态值有所不同,因此需要有所了解)

于是乎我们跳转到state_machine_helper.cpp下的 arming_transition[new][cur]

{

ROW==NEW\ COL==CURR

INIT

STANDBY

ARMED

ARMED_ERROR

STANDBY_ERROR

REBOOT

IN_AIR_RESTORE

ARMING_STATE_INIT

T(1)

T(1)

F(0)

F(0)

T(1)

F(0)

F(0)

ARMING_STATE_STANDBY

T(1)

T(1)

T(1)

T(1)

F(0)

F(0)

F(0)

ARMING_STATE_ARMED

F(0)

T(1)

T(1)

F(0)

F(0)

F(0)

T(1)

ARMING_STATE_ARMED_ERROR

F(0)

F(0)

T(1)

T(1)

F(0)

F(0)

F(0)

ARMING_STATE_STANDBY_ERROR

T(1)

T(1)

T(1)

T(1)

T(1)

F(0)

F(0)

ARMING_STATE_REBOOT

T(1)

T(1)

F(0)

F(0)

T(1)

T(1)

T(1)

ARMING_STATE_IN_AIR_RESTORE

F(0)

F(0)

F(0)

F(0)

F(0)

F(0)

F(0)

值得注意的是:这里虽然定义了转换允许的 Y/ N 但是有些在 True的情况下 附件条件的存在,也会使得转换不成功:

这也就是所谓的 second validation(二次确认)

a、在(row==newARMING_STATE_ARMED && curr != IN_AIR_RESTORE)“栏中尽管转换允许,但如果pre-arm(出错)时,同

样最终转换为失败。再入,安全开关使能但是没按情况下,依旧转换失败。

bstand_by本来就出错了(即就是:自检出错,try arming时候允许转换,但是“二次判断”后再次否决转换)

c、给出最后判断

}

 

if (valid_transition) {

status->arming_state= new_arming_state;

mavlink(“输出信息”);

}

 

第三部:  跟进结论——如果需要:则重置转换反馈信息;

否则:告诉地面站我转换成 后的 目标

}

做完这些总得有个结果:得到这些结果的下一步就是(特殊情况特殊对待的选项):跟据home_position以及可能由于mission特殊情况下,要对某些情况做特殊对待。

比如: 1、在有mission的情况下,转换到mission前是pos_ctrl,刚起飞就碰到misssion_finished状况了,则要直接设定值。

      2、DL、RcGPS 信号灯lost  要立马进行飞行状态的“特殊”处理了。

      3、例外,(例外的例外——就是目标了)当然cmd(RC输入命令的进入,正常切换了)则相应的处理时根本“初衷”。              

因此,需要引出另一个函数:main_state_transition进行模式设置

transition_result_tmain_state_transition(struct vehicle_status_s *status, main_state_tnew_main_state, uint8_t &main_state_prev,

                                         status_flags_s*status_flags, struct commander_state_s*internal_state)

{

switch (new_main_state)

{

case xxx:

case xxx:

}

}

参数:

Satuts:

导航状态,飞行器应该进入的状态

 

new_main_state:

期望切换到的新状态

 

main_state_prev:

之前的状态

 

status_flags:

commander内部的状态标志

 

status_flags:

主状态,用户想要的状态。由遥控器设置,也可以由地面站通过数传控制

 

 

返回值:

 

 

 

ret = TRANSITION_DENIED;

// 表示不满足切换条件,拒绝状态切换

 

ret = TRANSITION_CHANGED;

// 切换到某个状态,不一定是用户想要的目标状态,会根据降级策略,切换至一个最接近的状

 

ret = TRANSITION_NOT_CHANGED;

 

 

解锁成功了、转换逻辑通过确认(这里应该这样称呼才对)了,——>就是该去:模式设置成功了,

bool handle_command( struct vehicle_status_s*status_local,

const struct safety_s*safety_local,       

                  struct vehicle_command_s *cmd,              //飞行器操作cmd

struct actuator_armed_s*armed_local,

                  struct home_position_s *home,

struct vehicle_global_position_s*global_pos,

                  struct vehicle_local_position_s*local_pos,

struct vehicle_attitude_s *attitude,orb_advert_t *home_pub,

                  orb_advert_t*command_ack_pub,

struct vehicle_command_ack_s*command_ack,

                   struct vehicle_roi_s *roi, orb_advert_t *roi_pub)  //飞行器感兴趣的区域(or位置)misssion 有关

{

            ...

unsigned cmd_result= vehicle_command_s::VEHICLE_CMD_RESULT_UNSUPPORTED;

 

       /* request to set different systemmode */

       switch (cmd->command){

       case vehicle_command_s::VEHICLE_CMD_DO_REPOSITION: {

 

              // Just switch theflight mode here, the navigator takes care of

              // doing somethingsensible with the coordinates. Its designed

              // to not requirenavigator and command to receive / process

              // the data at theexact same time.

 

              // Check if a modeswitch had been requested

              if ((((uint32_t)cmd->param2)& 1) > 0)

{

transition_result_t main_ret =main_state_transition(status_local,commander_state_s::MAIN_STATE_AUTO_LOITER,

main_state_prev, &status_flags,&internal_state);

            if ((main_ret!= TRANSITION_DENIED)) {

                     cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED;

 

                    } else {

                     cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED;

                     mavlink_log_critical(&mavlink_log_pub,"Rejectingreposition command");

                    }

              } else {

                   cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED;

              }

}

break;                                                                                         

 

case vehicle_command_s::VEHICLE_CMD_DO_SET_MODE

break;

 ...

 

case vehicle_command_s::VEHICLE_CMD_DO_SET_MODE

break;

 ...

 

answer_command(*cmd,cmd_result, *command_ack_pub, *command_ack);

}

模式确定最后总算在这里肯定了下来(这么称呼比较好说)。

到这里,我们做好了大量工作:

① Arming(允许了)——>

② 模式转换判断(Ture)——>

③ 根据RC、Mavlink(vehile_CMD)——>

④ Mian_state(最后确定模式)并回答给发出CMD的控制的主体——>

⑤ 根据Mode+Cmd/failsafe设定Set_nav_sate()——>因此我们在进入函数

bool set_nav_state(struct vehicle_status_s *status,     // 导航状态数据集,飞行器应该进入的状态

            struct actuator_armed_s *armed,

            struct commander_state_s*internal_state,    //模式CMD值,用户主要状态值

            orb_advert_t *mavlink_log_pub,

            const link_loss_actions_t data_link_loss_act, //地面站数据链丢失

            const bool mission_finished,

             const boolstay_in_failsafe,                  //故障保护数据

            status_flags_s *status_flags,                 //commander内部状态标志

            bool landed,

            const link_loss_actions_t rc_loss_act,

            const int offb_loss_act,

            const int offb_loss_rc_act)

{

//记录old_参数

navigation_state_t nav_state_old = status->nav_state;

...

switch(internal_state->main_state)

{

 case commander_state_s::MAIN_STATE_ACRO:

     case commander_state_s::MAIN_STATE_MANUAL:

     case commander_state_s::MAIN_STATE_RATTITUDE:

     case commander_state_s::MAIN_STATE_STAB:

case commander_state_s::MAIN_STATE_ALTCTL:

/* require RC for all manual modes */

    if (rc_lost&& is_armed) {

          enable_failsafe(status, old_failsafe,mavlink_log_pub, reason_no_rc);

          set_rc_loss_nav_state(status, armed,status_flags, rc_loss_act);

    } else {

           switch(internal_state->main_state) {

          case commander_state_s::MAIN_STATE_ACRO:

                 status->nav_state = vehicle_status_s::NAVIGATION_STATE_ACRO;

                 break;

 

          case commander_state_s::MAIN_STATE_MANUAL:

                 status->nav_state = vehicle_status_s::NAVIGATION_STATE_MANUAL;

                 break;

 

          case commander_state_s::MAIN_STATE_RATTITUDE:

                 status->nav_state = vehicle_status_s::NAVIGATION_STATE_RATTITUDE;

                 break;

 

          case commander_state_s::MAIN_STATE_STAB:

                 status->nav_state = vehicle_status_s::NAVIGATION_STATE_STAB;

                 break;

 

          case commander_state_s::MAIN_STATE_ALTCTL:

                 status->nav_state = vehicle_status_s::NAVIGATION_STATE_ALTCTL;

                 break;

 

          default:

                 status->nav_state = vehicle_status_s::NAVIGATION_STATE_MANUAL;

                 break;

          }

    }

 

break;

...

}

    …

//以下如法炮制

   …

…                                                                                                  

   return status->nav_state != nav_state_old; //设置成功逻辑为1

}

 

返回值:

1

状态改变成功

0

状态未变(失败)

 

一切判断,做完了最后是设置了:那就是函数:

set_control_mode();

这个函数简单就是最后的模式设定了,但是值得注意的是,对于不同的模式在加速度,速度,XY平面内\Z方向上的  速度加速度,tilt、VTOL、转换过程中的有误增稳(加速度\角速度控制)等等都有相应的最后设定,即其设定control_mode.flag_xxx值。

好了,到这个地方基本上算是思路和路子走完了,但是很多代码细节还是要细度分析的。

剩下的就是及时的发布各种平行并列的消息给相应的模块提供指示和参考了。

 

orb_publish(ORB_ID(vehicle_status), status_pub, &status);

orb_publish(ORB_ID(actuator_armed), armed_pub, &armed);

orb_publish(ORB_ID(commander_state), commander_state_pub,&internal_state);

。。。

 

等等,还有件事就是,

rgbled_set_color_and_mode(led_control_s::COLOR_WHITE,led_control_s::MODE_OFF);

它做了—>orb_publish(ORB_ID(led_control),led_control_pub, &led_control);给led驱动模块参考用。

   

基本将commander的顺序理解完了,还有一件大事,耶,对了突然想起来还有个哥们在干活嘞,那就是Low_prio_thread了,你到底是干啥子的嘞。看来还不能休息哈,那我们一口气干完再说休息么。那还是继续…

void *commander_low_prio_loop(void *arg)//指针函数提供posix跨平台api——创建线程入口

{  //这个线程的函数名字为:commander_low_prio

订阅了一个msg // ORB_ID(vehicle_command)

}

可以看到在这个函数中忽略了high_prio command 执行了 低优先级任务:包含:

case vehicle_command_s::VEHICLE_CMD_PREFLIGHT_REBOOT_SHUTDOWN:

case vehicle_command_s::VEHICLE_CMD_PREFLIGHT_CALIBRATION:

case vehicle_command_s::VEHICLE_CMD_START_RX_PAIR:

case vehicle_command_s::VEHICLE_CMD_PREFLIGHT_STORAGE:

低优先级函数到底怎么被调用执行了呢?

很开心的告诉你:地面站mavlink消息很开心的承担了这个函数的“使用权”,为了测试这个函数的调用我加了一点点mavlink进行测试一下:发现

测添加mavlink通话消息:

地面站进行水平校准操作:

截止目前为止,基本上算是走完流程了,剩下的就是细节,。

但是,告诉大家一个不好的消息,对于自动化过程中px4还是需要很多细节要做的,比如,校准问题,就是个大问题,我们在“啪啪啪”在地面站上整了一通校准(整起来麻烦),最后飞了几下,或者炸鸡(希望不要发生吗),再次链接地面站——发现地面站上,耶,NND又不给大爷水平了(或者不准确了,有木有发现)这个就是个基本问题点之一啊,大神们,慢慢来做自己工作吧。

因此,我相信,说道这里,读过代码的——明眼人都懂得了。好了,感谢不厌其烦的 看完了这篇学习记录。水平有限,纰漏之处,望批评指正。

 

我是一只奔跑中的蜗牛,再次感谢,奋斗在同行中的伙伴们读到这里;

联系邮箱:xiwei@adicn.com

联系方式:QQ 344278952

 

L1_control 待续….

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PX4之commander剖析解读-2 的相关文章

  • windows和虚拟机ROS串口通信

    windows和虚拟机ROS串口通信 ROS串口通信步骤1 windows下安装VSPD xff08 虚拟串口工具 xff09 2 VMWare虚拟机添加串口3 Windows下串口通信测试工具设置4 ROS通信代码5 运行结果 最近在学习
  • jsonp原理详解——终于搞清楚jsonp是啥了

    一 JSONP的由来 1 Ajax直接请求普通文件存在跨域无权限访问的问题 xff0c 不管是静态页面 动态页面 web服务 xff0c 只要是跨域请求 xff0c 一律不准 2 不过我们发现 xff0c web页面调用js文件则不受跨域的
  • 无人机分类

    无人机分类方式 一 按飞行平台构型分类 无人机可分为固定翼无人机 多旋翼无人机 无人飞艇 伞翼无人机 扑翼无人机等 固定翼无人机 固定翼 xff0c 顾名思义 xff0c 就是机翼固定不变 xff0c 靠流过机翼的风提供升力 跟我们平时坐的
  • python网络编程smtp协议发送电子邮件

    SMTP协议 SMTP 的全称是 Simple Mail Transfer Protocol xff0c 即简单邮件传输协议 它是一组用于从源地址到目的地址传输邮件的规范 xff0c 通过它来控制邮件的中转方式 SMTP 协议属于 TCP
  • 实时通讯技术Ajax,WebSocket,SSE

    实时通讯技术是一项基于web开发的重要技术 xff0c 网站是需要前后端通讯的 xff0c 因此数据刷新的时间就是获取信息的时间 xff0c 为了能准确而有快速的获取信息需要尽可能的提高信息的刷新效率 常见的实时通讯技术 xff1a 通讯方
  • 当前主流的后端语言,谁能夺得桂冠,果然是后生可畏!

    主流后端语言 如今编程语言遍地开花 xff0c 烟花迷乱 xff0c 小编整理了最流行的几种编程语言如下 xff1a 这几种语言都是经久不衰 xff0c 占领着后端编程界的半壁江山 TIOBE上的语言排名 xff1a C Java pyth
  • CVPR2020 | 中科院VIPL实验室录取论文详解

    编者按 xff1a 近日 xff0c 计算机视觉顶会 CVPR 2020 接收论文结果揭晓 xff0c 从 6656 篇有效投稿中录取了 1470 篇论文 xff0c 录取率约为 22 中科院VIPL实验室共七篇论文录取 xff0c 内容涉
  • 迁移学习:他山之石,可以攻玉【VALSE Webinar】Panel实录

    编者按 xff1a 迁移学习是机器学习与计算机视觉中的重要研究问题之一 xff0c 旨在研究如何将一个领域的知识迁移到另外的领域 xff0c 具有重要的研究意义与应用价值 但迁移学习又会存在哪些局限性 xff1f 在实际应用中的价值是什么
  • 「见微知著」(2) - 细粒度视觉检索特辑【VALSE Webinar】Panel实录

    编者按 xff1a 细粒度图像识别和检索的差异有哪些呢 xff1f 细粒度视觉有哪些重要实际应用及重要场景呢 xff1f 未来细粒度图像分析领域又会如何发展呢 xff1f 为此 xff0c VALSE Webinar 2020 20期邀请了
  • VALSE 2020线上大会学生论坛【VALSE Student Seminar】Panel实录

    首届VALSE Student Seminar于2020年7月31日在VALSE 2020线上大会拉开帷幕 xff0c Student Seminar邀请了6名年轻的研究生 xff1a 张士峰 中国科学院自动化研究所 董胤蓬 清华大学 刘宇
  • 见微知著:语义分割中的弱监督学习

    点击上方 深度学习大讲堂 可订阅哦 xff01
  • 曹汛:计算摄像学研究 | VALSE2017之十六

    点击上方 深度学习大讲堂 可订阅哦 xff01
  • Spring常用注解(绝对经典)

    x1f3c6 作者简介 xff1a 哪吒 xff0c CSDN2022博客之星Top1 CSDN2021博客之星Top2 多届新星计划导师 博客专家 x1f4aa xff0c 专注Java硬核干货分享 xff0c 立志做到Java赛道全网T
  • c++排序方式

    选择排序 第一个数和后面n 1个数比 xff0c 找出最小的数 xff0c 替换第一个数 后面依此类推 include lt bits stdc 43 43 h gt using namespace std const int N 61 1
  • 程明明:面向弱监督的图像理解

    点击上方 深度学习大讲堂 可订阅哦 xff01
  • 白翔:复杂开放场景中的文本理解

    编者按 xff1a 李白的 秋浦歌 中有这样一句诗 xff1a 题诗留万古 xff0c 绿字锦苔生 xff0c 描绘了天执笔 地做纸 苔为墨 xff0c 挥毫题字的豪迈场景 xff0c 也展示了自然场景中文本类型的多样性 xff1b 而另两
  • 深度学习高效计算与处理器设计

    编者按 夫因朴生文 因拙生巧 相因相生 以至今日 在人工智能领域 机器学习研究与芯片行业的发展 即是一个相因相生的过程 自第一个深度网络提出 深度学习历经几次寒冬 直至近年 才真正带来一波AI应用的浪潮 这很大程度上归功于GPU处理芯片的发
  • 华科白翔教授团队ECCV2018 OCR论文:Mask TextSpotter

    本文经授权转自我爱计算机视觉52CV 华中科技大学白翔老师团队在自然场景文本检测与识别领域成果颇丰 xff0c 这篇被ECCV2018接收的论文 Mask TextSpotter An End to End Trainable Neural
  • 【CVPR2019】弱监督图像分类建模

    编者按 xff1a 获取大规模数据集的高置信标注是一个难点问题 xff0c 而解决此问题的弱监督学习更贴近人类对世界的认知机制 已有的弱监督图像分类研究 xff0c 通常局限于单标签或者多标签噪声场景 本文中 xff0c 将为大家介绍中科院
  • 重磅|中科视拓开源SeetaFace2人脸识别算法

    今天 xff0c 来自中科院计算所的人工智能国家队中科视拓宣布 xff0c 开源商用级SeetaFace2人脸识别算法 SeetaFace2采用商业友好的BSD协议 xff0c 这是在2016年9月开源SeetaFace1 0人脸识别引擎之

随机推荐

  • 学习笔记

    八种基本排序及其时间复杂度 https blog csdn net yang03 26 article details 80773280 参照上述文章中快速排序算法的源代码进行验证 在在线编程网站http www bccn net run
  • 杂记

    在线键盘敲击练习 xff1a https www dazima cn flash 127 html 有道云笔记网页网址 xff1a http note youdao com Android使用RenderScript实现图片的高斯模糊效果
  • ubuntu开机后桌面显示空白的问题

    原文 xff1a ubuntu开机只显示空白桌面解决方案 摘自 xff1a http www 2cto com os 201305 214687 html ubuntu开机只显示空白桌面解决方案 重新安装如下 xff1a sudo apt
  • 在ubuntu中安装编译工具mingw

    原文 xff1a Mingw xff1a 在Linux系统下编译Windows的程序 链接 xff1a http www sudu cn info html edu 20071227 87635 html Ubuntu下可以直接安装 xff
  • Spring Boot常用注解(绝对经典)

    x1f3c6 作者简介 xff1a 哪吒 xff0c CSDN2022博客之星Top1 CSDN2021博客之星Top2 多届新星计划导师 博客专家 x1f4aa xff0c 专注Java硬核干货分享 xff0c 立志做到Java赛道全网T
  • linux下deb包如何安装

    原文 xff1a 怎么安装deb软件 链接 xff1a http zhidao baidu com link url 61 w 6LOuxz 97ZrSjEDIZemmLBsQTsseXJCRe1qE5PkmFKhF3o8tRmAkBloU
  • ubuntu下用apt-get时一直报[正在等待报头]

    原文 xff1a ubuntu下用apt get是总是出现0 正在等待报头 链接 xff1a http blog csdn net nevasun article details 6268332 分类 xff1a Linux系统管理 201
  • Android软键盘弹出时把布局顶上去的解决方法

    原文 xff1a 解决Andriod软键盘出现把原来的布局给顶上去的方法 xff08 转 xff09 链接 xff1a http blog sina com cn s blog 9564cb6e0101g2eb html 决方法 xff0c
  • 一个android列表的适配器数据异步加载的问题

    一个android列表的适配器数据异步加载的问题 问题现象 xff1a 当点击一个ListView的子项 xff0c 等更新ListView完成时 xff0c 再点击一下ListView的子项 xff0c 程序运行良好 xff1b 当点击一
  • MHA高可用配置及故障切换

    MHA概述 传统的MySQL主从架构存在问题 单点故障 MHA概述 一套优秀的MySQL高可用环境下故障切换和主从复制的软件 MySQL故障过程中 xff0c MHA能做到0 30秒内自动完成故障切换 MHA的组成 MHA Manager
  • setenforce: SELinux is disabled解决方案

    解决方案 第一步 修改配置文件 root 64 www vi etc selinux config SELINUX 61 disabled 该为SELINUX 61 1 第二步 重启nginx服务 systemctl restart ngi
  • OpenStack

    文章目录 OpenStack概述OpenStack简介什么是云计算IaaSPaaSSaaSDaaS OpenStack发展历程OpenStack发展趋势OpenStack工作流程OpenStack管理流程QEMULibvirt OpenSt
  • 利用wget命令获取FTP资源

    wegt命令作用 xff1a 可以从对方的ftp服务器上直接下载现存的软件包 命令格式 xff1a wget ftp IP 软件包名称 若是防止网站上面现在相关软件包可以使用该命令 xff1a wget http IP 软件包名称 验证 x
  • 部署OpenStack架构

    文章目录 OpenStack环境部署部署思路基础环境配置配置OpenStack系统环境配置 Keystone 组件的搭建小结 Glance组件的搭建 OpenStack环境部署 虚拟机设备信息及需求 控制节点 xff08 ct xff09
  • FTP服务与DNS域名解析服务

    文章目录 FTP原理FTP匿名账户的部署过程 xff1a FTP本地用户的部署过程 xff1a 指定用户的宿主目录路径DNS 域名解析服务 DNS正向解析DNS反向解析DNS主从复制 FTP原理 ftp使用场合 xff1a 用于文件的传输
  • 【Redis 1】Redis基础知识概述

    一 Redis简介 1 Redis xff08 Remote Dictionary Server 远程字段服务 xff09 是一个开源的使用ANSI C语言编写 支持网络 科技与内存亦可持久化的日志型 key value数据库 xff0c
  • PXE高效批量网络装机

    文章目录 PXE概述PXE部署kickstart无人值守部署 PXE概述 PXE批量部署的优点 规模化 xff1a 同时装配多台服务器 自动化 xff1a 安装系统 配置各种服务 远程实现 xff1a 不需要光盘 U盘等安装介质 PXE x
  • Firewalld防火墙基础

    Firewalld概述 Firewalld 支持网络区域所定义的网络链接以及接口安全等级的动态防火墙管理工具 支持IPv IPv6防火墙设置以及以太网桥 支持服务或应用程序直接添加防火墙规则接口 拥有两种配置模式 运行时配置 xff1a 即
  • iptables防火墙

    文章目录 Linux包过滤防火墙概述iptables的表 链结构iptable安装iptables的管理选项规则的匹配条件 Linux包过滤防火墙概述 netfilter 位于Linux内核中的包过滤功能体系 称为Linux防火墙的 内核态
  • PX4之commander剖析解读-2

    首先 xff0c 感谢 阿木社区 小伙伴们在PX4 方面做出的贡献 在学习px4的过程中 xff0c 我也是个小学生 xff0c 以下作为个人的小心得 xff0c 纰漏蛮多 xff0c 还望各位同仁包涵 期待批评指正 但我们的目的只有一个