- 前言
1.1 对于51单片机裸奔式的编程,只有一个main函数,main函数中只有一个while死循环,即最后烧入的固件只有一个可执行程序,这个可执行程序的入口函数即main函数。
1.2 对stm32来说,可以采用51单片机传统的编程方式,采用一个main函数,但是也可以先运行一个RTOS,然后通过该操作系统来运行多个可执行程序。每一个可执行程序都有自己的main函数,一般取名为appname_main(char argc , char *argv[] ) ,即该可执行程序的入口函数。 - 编译工作的不同
51单片机式的只会将多个.c和.h文件make成一个可执行程序,该可执行程序的入口函数为main()
运行了操作系统的stm32会,例如,会将a.c a.h b.c b.h 编译成app1.exe,该可执行程序的入口函数appnme_main()在a.c或b.c中。同理可将其他文件make成app2.exe。然后再同个RTOS的启动脚本或手动执行想要运行的app。
对于操作系统来说,可执行程序被看作是系统的命令(command),如系统自带的ls cp等实质上是可执行程序。 - 在nuttxx下运行某个可执行程序(app)的过程详析
注意:在nuttx下执行某个app并不意味着在操作系统中启动了该进程。而且,操作系统执行了某个可执行程序,意味着该程序会被循环运行,只有进程才会被循环运行(因为进程的入口函数里面有while循环)。
举个例子:
可执行程序mc_att_control的入口函数在arducopter\modules\PX4Firmware\src\modules\mc_att_control\mc_att_control_main.cpp中,
函数名为int mc_att_control_main(int argc, char *argv[]),一般位置会在.cpp文件的末尾,因为其他被它调用的函数或变量都要放在它前面作为声明。
int mc_att_control_main(int argc, char argv[])
{
//若执行该程序时参数不对则报错
if (argc < 2) { …}
//若参数为 start , 则向任务管理器创建一个进程(task),并告诉任务管理器该进程的名字,句柄(pid),优//先级,运行频率,最大运行时间,进程的入口函数(task_main())等信息
if (!strcmp(argv[1], “start”))
{
…
mc_att_control::g_control = new MulticopterAttitudeControl; //创建一个对象
if (OK != mc_att_control::g_control->start()) //start()函数负责创建进程(task)
{
delete mc_att_control::g_control; //删除对象
mc_att_control::g_control = nullptr;
warnx(“start failed”);
return 1;
}
return 0;
}
if (!strcmp(argv[1], “stop”))
{
…
}
…
}
下面看start()函数
MulticopterAttitudeControl::start()
{
ASSERT(_control_task == -1);
/ start the task */
_control_task = px4_task_spawn_cmd(“mc_att_control”,
SCHED_DEFAULT,
SCHED_PRIORITY_MAX - 5,
1500,
(px4_main_t)&MulticopterAttitudeControl::task_main_trampoline,
nullptr);
if (_control_task < 0)
{
warn(“task start failed”);
return -errno;
}
return OK;
}
可知,该进程的名字为mc_att_control,句柄保存在任务创建函数px4_task_spawn_cmd的返回值_control_task中,任务(进程)的入口函数为task_main_trampoline。
所以下面看task_main_trampoline函数:
void
MulticopterAttitudeControl::task_main_trampoline(int argc, char *argv[])
{
mc_att_control::g_control->task_main();
}
所以最后执行的是task_main(),该函数的定义如下:
void
MulticopterAttitudeControl::task_main()
{
//do subscriptions
…
…
//initialize parameters cache
…
// wakeup source: vehicle attitude
…
…
//下面就是我们最终要找的while循环,终于让我给找到了,可谓是非了九牛二虎之力
//while循环中要执行的,也就是我们要重复执行的代码,算法。
while (!_task_should_exit) {
/* wait for up to 100ms for data */
int pret = px4_poll(&fds[0], (sizeof(fds) / sizeof(fds[0])), 100);
/* timed out - periodic check for _task_should_exit */
if (pret == 0) {
continue;
}
/* this is undesirable but not much we can do - might want to flag unhappy status */
if (pret < 0) {
warn("mc att ctrl: poll error %d, %d", pret, errno);
/* sleep a bit before next try */
usleep(100000);
continue;
}
perf_begin(_loop_perf);
/* run controller on attitude changes */
if (fds[0].revents & POLLIN) {
static uint64_t last_run = 0;
float dt = (hrt_absolute_time() - last_run) / 1000000.0f;
last_run = hrt_absolute_time();
/* guard against too small (< 2ms) and too large (> 20ms) dt's */
if (dt < 0.002f) {
dt = 0.002f;
} else if (dt > 0.02f) {
dt = 0.02f;
}
/* copy attitude and control state topics */
orb_copy(ORB_ID(control_state), _ctrl_state_sub, &_ctrl_state);
/* check for updates in other topics */
parameter_update_poll();
vehicle_control_mode_poll();
arming_status_poll();
vehicle_manual_poll();
vehicle_status_poll();
vehicle_motor_limits_poll();
/* Check if we are in rattitude mode and the pilot is above the threshold on pitch
* or roll (yaw can rotate 360 in normal att control). If both are true don't
* even bother running the attitude controllers */
if (_vehicle_status.main_state == vehicle_status_s::MAIN_STATE_RATTITUDE) {
if (fabsf(_manual_control_sp.y) > _params.rattitude_thres ||
fabsf(_manual_control_sp.x) > _params.rattitude_thres) {
_v_control_mode.flag_control_attitude_enabled = false;
}
}
if (_v_control_mode.flag_control_attitude_enabled) {
if (_ts_opt_recovery == nullptr) {
// the tailsitter recovery instance has not been created, thus, the vehicle
// is not a tailsitter, do normal attitude control
control_attitude(dt);
} else {
vehicle_attitude_setpoint_poll();
_thrust_sp = _v_att_sp.thrust;
math::Quaternion q(_ctrl_state.q[0], _ctrl_state.q[1], _ctrl_state.q[2], _ctrl_state.q[3]);
math::Quaternion q_sp(&_v_att_sp.q_d[0]);
_ts_opt_recovery->setAttGains(_params.att_p, _params.yaw_ff);
_ts_opt_recovery->calcOptimalRates(q, q_sp, _v_att_sp.yaw_sp_move_rate, _rates_sp);
/* limit rates */
for (int i = 0; i < 3; i++) {
_rates_sp(i) = math::constrain(_rates_sp(i), -_params.mc_rate_max(i), _params.mc_rate_max(i));
}
}
/* publish attitude rates setpoint */
_v_rates_sp.roll = _rates_sp(0);
_v_rates_sp.pitch = _rates_sp(1);
_v_rates_sp.yaw = _rates_sp(2);
_v_rates_sp.thrust = _thrust_sp;
_v_rates_sp.timestamp = hrt_absolute_time();
if (_v_rates_sp_pub != nullptr) {
orb_publish(_rates_sp_id, _v_rates_sp_pub, &_v_rates_sp);
} else if (_rates_sp_id) {
_v_rates_sp_pub = orb_advertise(_rates_sp_id, &_v_rates_sp);
}
//}
} else {
/* attitude controller disabled, poll rates setpoint topic */
if (_v_control_mode.flag_control_manual_enabled) {
/* manual rates control - ACRO mode */
_rates_sp = math::Vector<3>(_manual_control_sp.y, -_manual_control_sp.x,
_manual_control_sp.r).emult(_params.acro_rate_max);
_thrust_sp = math::min(_manual_control_sp.z, MANUAL_THROTTLE_MAX_MULTICOPTER);
/* publish attitude rates setpoint */
_v_rates_sp.roll = _rates_sp(0);
_v_rates_sp.pitch = _rates_sp(1);
_v_rates_sp.yaw = _rates_sp(2);
_v_rates_sp.thrust = _thrust_sp;
_v_rates_sp.timestamp = hrt_absolute_time();
if (_v_rates_sp_pub != nullptr) {
orb_publish(_rates_sp_id, _v_rates_sp_pub, &_v_rates_sp);
} else if (_rates_sp_id) {
_v_rates_sp_pub = orb_advertise(_rates_sp_id, &_v_rates_sp);
}
} else {
/* attitude controller disabled, poll rates setpoint topic */
vehicle_rates_setpoint_poll();
_rates_sp(0) = _v_rates_sp.roll;
_rates_sp(1) = _v_rates_sp.pitch;
_rates_sp(2) = _v_rates_sp.yaw;
_thrust_sp = _v_rates_sp.thrust;
}
}
if (_v_control_mode.flag_control_rates_enabled) {
control_attitude_rates(dt);
/* publish actuator controls */
_actuators.control[0] = (PX4_ISFINITE(_att_control(0))) ? _att_control(0) : 0.0f;
_actuators.control[1] = (PX4_ISFINITE(_att_control(1))) ? _att_control(1) : 0.0f;
_actuators.control[2] = (PX4_ISFINITE(_att_control(2))) ? _att_control(2) : 0.0f;
_actuators.control[3] = (PX4_ISFINITE(_thrust_sp)) ? _thrust_sp : 0.0f;
_actuators.timestamp = hrt_absolute_time();
_actuators.timestamp_sample = _ctrl_state.timestamp;
_controller_status.roll_rate_integ = _rates_int(0);
_controller_status.pitch_rate_integ = _rates_int(1);
_controller_status.yaw_rate_integ = _rates_int(2);
_controller_status.timestamp = hrt_absolute_time();
if (!_actuators_0_circuit_breaker_enabled) {
if (_actuators_0_pub != nullptr) {
orb_publish(_actuators_id, _actuators_0_pub, &_actuators);
perf_end(_controller_latency_perf);
} else if (_actuators_id) {
_actuators_0_pub = orb_advertise(_actuators_id, &_actuators);
}
}
/* publish controller status */
if (_controller_status_pub != nullptr) {
orb_publish(ORB_ID(mc_att_ctrl_status), _controller_status_pub, &_controller_status);
} else {
_controller_status_pub = orb_advertise(ORB_ID(mc_att_ctrl_status), &_controller_status);
}
}
}
perf_end(_loop_perf);
}
_control_task = -1;
return;
}