概述
PX4模块设计之三十七:MulticopterRateControl模块
- 1. MulticopterRateControl模块简介
- 2. 模块入口函数
- 2.1 主入口mc_rate_control_main
- 2.2 自定义子命令custom_command
- 3. MulticopterRateControl模块重要函数
- 3.1 task_spawn
- 3.2 instantiate
- 3.3 init
- 3.4 Run
- 4. 总结
- 5. 参考资料
1. MulticopterRateControl模块简介
### Description
This implements the multicopter rate controller. It takes rate setpoints (in acro mode
via `manual_control_setpoint` topic) as inputs and outputs actuator control messages.
The controller has a PID loop for angular rate error.
mc_rate_control <command> [arguments...]
Commands:
start
[vtol]
VTOL mode
stop
status
print status info
注:print_usage函数是具体对应实现。
class MulticopterRateControl : public ModuleBase<MulticopterRateControl>, public ModuleParams, public px4::WorkItem
注:MulticopterRateControl模块采用了ModuleBase和WorkQueue设计。
2. 模块入口函数
2.1 主入口mc_rate_control_main
同样继承了ModuleBase,由ModuleBase的main来完成模块入口。
mc_rate_control_main
└──> return MulticopterRateControl::main(argc, argv)
2.2 自定义子命令custom_command
模块仅支持start/stop/status命令,不支持其他自定义命令。
MulticopterRateControl::custom_command
└──> return print_usage("unknown command")
3. MulticopterRateControl模块重要函数
3.1 task_spawn
这里主要初始化了MulticopterRateControl::task_spawn
对象,后续通过WorkQueue来完成进行轮询。
MulticopterRateControl::task_spawn
├──> bool vtol = false
├──> <argc > 1><strcmp(argv[1], "vtol") == 0>
│
└──> vtol = true
├──> MulticopterRateControl *instance = new MulticopterRateControl(vtol)
├──> <instance>
│
├──> _object.store(instance)
│
├──> _task_id = task_id_is_work_queue
│
└──> <(instance->init()>
│
└──> return PX4_OK
├──> <else>
│
└──> PX4_ERR("alloc failed")
├──> delete instance
├──> _object.store(nullptr)
├──> _task_id = -1
└──> return PX4_ERROR
3.2 instantiate
注:鉴于该模块不采用任务(线程),所以ModuleBase::run_trampoline无需执行,所以可以不实现。
3.3 init
在task_spawn中使用,对_vehicle_angular_velocity_sub成员变量进行事件回调注册(当有vehicle_angular_velocity消息时,会调用SubscriptionCallbackWorkItem::ScheduleNow,再触发MulticopterRateControl::Run过程)。
MulticopterRateControl::init
├──> <!_vehicle_angular_velocity_sub.registerCallback()>
│
├──> PX4_ERR("callback registration failed")
│
└──> return false
└──> return true;
3.4 Run
根据输入参数及业务逻辑计算输出量,并发布消息。
MulticopterRateControl::Run
├──> [优雅退出处理]
├──> <_parameter_update_sub.updated()>
// Check if parameters have changed
│
├──> _parameter_update_sub.copy(¶m_update)
│
├──> updateParams()
│
└──> parameters_updated()
├──> <!_vehicle_angular_velocity_sub.update(&angular_velocity)>
│
└──> return
├──> [grab corresponding vehicle_angular_acceleration immediately after vehicle_angular_velocity copy]
│
├──> vehicle_angular_acceleration_s v_angular_acceleration{}
│
└──> _vehicle_angular_acceleration_sub.copy(&v_angular_acceleration)
├──> const hrt_abstime now = angular_velocity.timestamp_sample
├──> const float dt = math::constrain(((now - _last_run) * 1e-6f), 0.000125f, 0.02f)
//Guard against too small (< 0.125ms) and too large (> 20ms) dt's.
├──> _last_run = now
├──> const Vector3f angular_accel{v_angular_acceleration.xyz}
├──> Vector3f rates{angular_velocity.xyz}
├──> _vehicle_control_mode_sub.update(&_vehicle_control_mode)
//check for updates in other topics
├──> <_vehicle_land_detected_sub.updated()><_vehicle_land_detected_sub.copy(&vehicle_land_detected)>
│
├──> _landed = vehicle_land_detected.landed
│
└──> _maybe_landed = vehicle_land_detected.maybe_landed
├──> _vehicle_status_sub.update(&_vehicle_status)
├──> <_landing_gear_sub.updated()><_landing_gear_sub.copy(&landing_gear)><landing_gear.landing_gear != landing_gear_s::GEAR_KEEP>
│
├──> <landing_gear.landing_gear == landing_gear_s::GEAR_UP && (_landed || _maybe_landed)>
│
│
├──> mavlink_log_critical(&_mavlink_log_pub, "Landed, unable to retract landing geart")
│
│
└──> events::send(events::ID("mc_rate_control_not_retract_landing_gear_landed"), {events::Log::Error, events::LogInternal::Info}, "Landed, unable to retract landing gear")
│
└──> <else>
│
└──>_landing_gear = landing_gear.landing_gear
├──> <_vehicle_control_mode.flag_control_manual_enabled && !_vehicle_control_mode.flag_control_attitude_enabled><_manual_control_setpoint_sub.update(&manual_control_setpoint)>
// manual rates control - ACRO mode
│
├──> const Vector3f man_rate_sp{
│
│
math::superexpo(manual_control_setpoint.y, _param_mc_acro_expo.get(), _param_mc_acro_supexpo.get()),
│
│
math::superexpo(-manual_control_setpoint.x, _param_mc_acro_expo.get(), _param_mc_acro_supexpo.get()),
│
│
math::superexpo(manual_control_setpoint.r, _param_mc_acro_expo_y.get(), _param_mc_acro_supexpoy.get())}
│
├──> _rates_setpoint = man_rate_sp.emult(_acro_rate_max)
│
├──> _thrust_setpoint(2) = -math::constrain(manual_control_setpoint.z, 0.0f, 1.0f)
│
├──> _thrust_setpoint(0) = _thrust_setpoint(1) = 0.f
│
├──> vehicle_rates_setpoint.roll = _rates_setpoint(0)
│
├──> vehicle_rates_setpoint.pitch = _rates_setpoint(1)
│
├──> vehicle_rates_setpoint.yaw = _rates_setpoint(2)
│
├──> _thrust_setpoint.copyTo(vehicle_rates_setpoint.thrust_body)
│
├──> vehicle_rates_setpoint.timestamp = hrt_absolute_time()
│
└──> 【发布vehicle_rates_setpoint消息】_vehicle_rates_setpoint_pub.publish(vehicle_rates_setpoint)
// publish rate setpoint
├──> <else if (_vehicle_rates_setpoint_sub.update(&vehicle_rates_setpoint)><_vehicle_rates_setpoint_sub.copy(&vehicle_rates_setpoint)>
│
├──> _rates_setpoint(0) = PX4_ISFINITE(vehicle_rates_setpoint.roll)
? vehicle_rates_setpoint.roll
: rates(0)
│
├──> _rates_setpoint(1) = PX4_ISFINITE(vehicle_rates_setpoint.pitch) ? vehicle_rates_setpoint.pitch : rates(1)
│
├──> _rates_setpoint(2) = PX4_ISFINITE(vehicle_rates_setpoint.yaw)
? vehicle_rates_setpoint.yaw
: rates(2)
│
└──> _thrust_setpoint = Vector3f(vehicle_rates_setpoint.thrust_body)
├──> <_vehicle_control_mode.flag_control_rates_enabled && !_actuators_0_circuit_breaker_enabled> // run the rate controller
├──> <!_vehicle_control_mode.flag_armed || _vehicle_status.vehicle_type != vehicle_status_s::VEHICLE_TYPE_ROTARY_WING>
│
└──> _rate_control.resetIntegral()
// reset integral if disarmed
├──> control_allocator_status_s control_allocator_status
// update saturation status from control allocation feedback
├──> <_control_allocator_status_sub.update(&control_allocator_status)>
│
├──> <!control_allocator_status.torque_setpoint_achieved>
│
│
└──> <for (size_t i = 0 i < 3 i++)>
│
│
├──> <control_allocator_status.unallocated_torque[i] > FLT_EPSILON>
│
│
│
└──> saturation_positive(i) = true
│
│
└──> <else if (control_allocator_status.unallocated_torque[i] < -FLT_EPSILON>
│
│
└──> saturation_negative(i) = true
│
└──> _rate_control.setSaturationStatus(saturation_positive, saturation_negative)
// TODO: send the unallocated value directly for better anti-windup
├──> const Vector3f att_control = _rate_control.update(rates, _rates_setpoint, angular_accel, dt, _maybe_landed || _landed)
// run rate controller
├──> [publish rate controller status]
│
├──> _rate_control.getRateControlStatus(rate_ctrl_status)
│
├──> rate_ctrl_status.timestamp = hrt_absolute_time()
│
└──> 【发布rate_ctrl_status消息】_controller_status_pub.publish(rate_ctrl_status)
├──> [publish actuator controls]
│
├──> actuators.control[actuator_controls_s::INDEX_ROLL] = PX4_ISFINITE(att_control(0)) ? att_control(0) : 0.0f
│
├──> actuators.control[actuator_controls_s::INDEX_PITCH] = PX4_ISFINITE(att_control(1)) ? att_control(1) : 0.0f
│
├──> actuators.control[actuator_controls_s::INDEX_YAW] = PX4_ISFINITE(att_control(2)) ? att_control(2) : 0.0f
│
├──> actuators.control[actuator_controls_s::INDEX_THROTTLE] = PX4_ISFINITE(_thrust_setpoint(2)) ? -_thrust_setpoint(2) : 0.0f
│
├──> actuators.control[actuator_controls_s::INDEX_LANDING_GEAR] = _landing_gear
│
├──> actuators.timestamp_sample = angular_velocity.timestamp_sample
│
├──> <!_vehicle_status.is_vtol>
│
│
├──> 【发布vehicle_thrust_setpoint消息】publishTorqueSetpoint(att_control, angular_velocity.timestamp_sample)
│
│
└──> 【发布vehicle_torque_setpoint消息】publishThrustSetpoint(angular_velocity.timestamp_sample)
│
├──> <_param_mc_bat_scale_en.get()>
// scale effort by battery status if enabled
│
│
├──><_battery_status_sub.updated()><_battery_status_sub.copy(&battery_status) && battery_status.connected && battery_status.scale > 0.f>
│
│
│
└──> _battery_status_scale = battery_status.scale
│
│
├──> <_battery_status_scale > 0.0f><for (int i = 0 i < 4 i++)>
│
│
│
└──> actuators.control[i] *= _battery_status_scale
│
├──> actuators.timestamp = hrt_absolute_time()
│
├──> 【发布actuator_controls_0消息】_actuator_controls_0_pub.publish(actuators)
│
└──> 【发布actuator_controls_status_0消息】updateActuatorControlsStatus(actuators, dt)
└──> <_vehicle_control_mode.flag_control_termination_enabled><!_vehicle_status.is_vtol> // publish actuator controls
├──> actuator_controls_s actuators{}
├──> actuators.timestamp = hrt_absolute_time()
└──> 【发布actuator_controls_0消息】_actuator_controls_0_pub.publish(actuators)
4. 总结
具体逻辑业务后续再做深入,从模块代码角度:
- 输入
uORB::Subscription _battery_status_sub{ORB_ID(battery_status)};
uORB::Subscription _control_allocator_status_sub{ORB_ID(control_allocator_status)};
uORB::Subscription _landing_gear_sub{ORB_ID(landing_gear)};
uORB::Subscription _manual_control_setpoint_sub{ORB_ID(manual_control_setpoint)};
uORB::Subscription _vehicle_angular_acceleration_sub{ORB_ID(vehicle_angular_acceleration)};
uORB::Subscription _vehicle_control_mode_sub{ORB_ID(vehicle_control_mode)};
uORB::Subscription _vehicle_land_detected_sub{ORB_ID(vehicle_land_detected)};
uORB::Subscription _vehicle_rates_setpoint_sub{ORB_ID(vehicle_rates_setpoint)};
uORB::Subscription _vehicle_status_sub{ORB_ID(vehicle_status)};
uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s};
uORB::SubscriptionCallbackWorkItem _vehicle_angular_velocity_sub{this, ORB_ID(vehicle_angular_velocity)};
- 输出
uORB::Publication<actuator_controls_s>
_actuator_controls_0_pub;
uORB::Publication<actuator_controls_status_s> _actuator_controls_status_0_pub{ORB_ID(actuator_controls_status_0)};
uORB::PublicationMulti<rate_ctrl_status_s> _controller_status_pub{ORB_ID(rate_ctrl_status)};
uORB::Publication<vehicle_rates_setpoint_s> _vehicle_rates_setpoint_pub{ORB_ID(vehicle_rates_setpoint)};
uORB::Publication<vehicle_thrust_setpoint_s> _vehicle_thrust_setpoint_pub{ORB_ID(vehicle_thrust_setpoint)};
uORB::Publication<vehicle_torque_setpoint_s> _vehicle_torque_setpoint_pub{ORB_ID(vehicle_torque_setpoint)};
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
最后
以上就是舒心小蚂蚁为你收集整理的PX4模块设计之三十七:MulticopterRateControl模块1. MulticopterRateControl模块简介2. 模块入口函数3. MulticopterRateControl模块重要函数4. 总结5. 参考资料的全部内容,希望文章能够帮你解决PX4模块设计之三十七:MulticopterRateControl模块1. MulticopterRateControl模块简介2. 模块入口函数3. MulticopterRateControl模块重要函数4. 总结5. 参考资料所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复