我的惯性导航开发开篇---架构

2019-04-15 13:50发布

    有人问我,学空气动力学到底有什么用?学好了就能玩航模了吗?有些人说,我一点空气动力学知识都没有,可我玩的还是很好啊....
    诸如此类问题,我想大家误解了,其实学好空气动力学是一劳永逸的,是往更高层次发展的基础,学好它,虽然不能很快立竿见影的带来什么,但总之,学则加冕,没坏处的,希望大家正确认识。

    好了,有些人说我理论哥,你做过没?见过没?有本事来点实际的,要不竟是扯淡,没干货一切白瞎。此话,并非无道理。不过在此声明,我不是什么理论哥,我不是科班出身,完全是爱好,自学的,很多专业问题还需大家多指教。

    好了,闲话少说。
    在接下来,我会从零开始,从无到有开发一个简单的IMU惯性导航系统,满足航模级应用,希望对大家有所帮助,也请大家多提建议。
    构思架构:

    CPU:ARM
    MEMS三轴陀螺
    MEMS三轴加速度计


    网上有很多种IMU的硬件方案和软件方案,也有很多很好的开源作品,我为什么还要再多此一举呢?
    原因有二吧:
    1、我本身也是爱好者,希望通过在做的过程中,熟悉各个环节,得到更好的理解与体会;
    2、也希望能对大家在该方面有所帮助,有一个不一样的认识;

    希望大家在当前拿来应用主义极盛的情况下,能更多的深入了解并应用它,因为只有深入其中,才能知道其中的滋味,简单的拿来用,也没什么错,我们想问题的角度或用意关注点不同罢了!
    毕竟现在的系统都是由前辈们从理论从无到有,一点一滴做起来的,一个人的力量也有限的,突然让我们做一个大系统,从经验来讲有很大的难度,更多的时候做项目,以节点为根,成果为本,很难深入弄个明白。
    都说是站在巨人的肩膀上嘛!我们都是应用工程师。

    而我个人而言,我想砸破砂锅问到底。要不然不知道根本就不知道如何提升,从长远来说还是要搞好理论基础,再来搞应用比较实在。所以先搞清楚理论,成为我们不可逾越的坎。好了,说了这么多,我慢慢一一道来,如有什么错误,希望博得同仁们的理解,也希望你们多提建议。在此非常感激。

                                                                        IMU惯性导航模块架构
声明:1、该架构不含操作系统,希望该架构简单,硬件成本低廉,CPU的主频,Flash和RAM较小的情况下也能应用;
         2、本系统嵌入式程序可用C开发,也可以用C++开发,希望大家可以灵活运用。

以下将用C或伪代码来表示:
首先分为几大模块:
1、主程序main;
2、调度模块Schedule;
3、加速度计底层驱动模块ACC_BSP
4、陀螺仪底层驱动模块GYRO_BSP
5、初始化模块Init
6、错误信息处理及记录模块Error
7、系统时钟模块System_Time
8、通信模块Com
9、滤波模块Filter
10、配置模块Config
11、消息模块MSG
12、警告、显示模块 Warn,Display
13、存储模块Flash
14、数学运算模块math
15、异常重构模块 construct

先构想这么多吧,大家可以讨论下,是否合理,可以进行添加或减少。

首先,根据系统需求,估算下该系统会占用多大的CPU资源,Flash和RAM占用情况,模块调度允许周期,计算时间等。
当前我定义Stack:6K,RAM 2K 系统关键线程周期5ms   非关键线程周期20ms,大家也可以根据实际情况自己定义。
今天先写主程序的系统时钟模块吧,这是其他模块允许时基的基础。

声明回调函数:
static void (UserCallback)(void);
定义系统时钟滴答结构体
struct Sys_Tick sys_time;
定义系统时钟计数
static volatile unsigned long SysTick = 0;
系统时钟初始化,返回初始化成功与否
   SINT8 System_Tick_Init(void) 
{
  SysTick_Config(xxxxx);/*根据嵌入式CPU晶振大小进行,系统时钟配置  */
  sys_time.Sys_Ticks_Per_us = SystemCoreClock /xxxx;/*根据系统时钟,计算每us的滴答数  */


SetPriority(xxxx);/*设置系统时钟中断优先级  */




  .......



判断设置初始化成功与否


  if(xxxx)
{
return FAULT;
}
else
return SUCESS;


/*系统时钟中  */
void SysTick_Handler(void)
{
  __disable_irq();/*关闭所有中断  */
Check_SysTick_Underflow();  /*检查系统时钟溢出  */


SysTick++;/*系统时钟计数*/


__enable_irq();   /*打开所有中断*/

UserCallback(); /*调用回调函数*/
}

定义返回当前时间函数

UINT32 micros(void)
{
  do
{
  xxxxxxxx= xxxx; 获取当前值
  asm volatile("nop");/*精确时间调整  */

}
while(!xxxxx);判断时间是否达到
Check_SysTick_Underflow();  /*检查系统时钟溢出  */


  时间转换

  return (timeMs * 1000) + (重新装载值 + 1 - 当前值) / sys_time.Sys_Ticks_Per_us;返回需要的一定单位的时间
}
返回系统时间
UINT32 millis(void)
{
   xxxxxxxxx
}
回调函数
void SysTic_Callback(void (*callback)(void))
{
   UserCallback = callback;
}



定义看们狗,此处用软件方式实现
SINT8 WatchDog(void)
{
  判断看门狗计数值设定值是否超过

  WatchDogCounter = 0;
}


系统时钟部分完成了,我们来写下main主函数,之后验证下。

int main(void)
{

if(Power_On_Task() == SUCESS)//系统执行上电任务,包括我们刚完成的系统时钟设置初始化和各种其他初始化等

给出提示信息
获取系统当前时间
Last_Time = micros();

while(1)
{
  Current_Time = micros(); 获取系统当前时间
Time_Passed = Current_Time - Last_Time;

if(Time_Passed > 5) /*5ms*/  //0.122093  0.14209
{

  启动状态机,调用5ms任务  //0.127093   0.14709 
Small_Period_Loop();
  判断时间,调用大周期任务

xxxxx
WatchDogCounter = 0;看门狗计数清零
Last_Time = Current_Time;

}

}
}


主函数部分和系统时基部分都很简单,经过验证,时间调度周期精确,满足设计要求。
未完待续,敬请关注。