02 Crazyflie Source Preview

Crazyflie源码分析

一、源代码结构

./              | Root, contains the Makefile
 + init         | 主文件目录,很简单 Contains the main.c
 + config       | 配置文件,包括系统任务配置文件,freertos配置文件, stm32配置文件 Configuration files
 + drivers      | 传感器底层访问驱动 Hardware driver layer
 |  + src       |  Drivers source code
 |  + interface |  Drivers header files. Interface to the HAL layer
 + hal          | 硬件抽象层  Hardware abstraction layer 主要包括sensors
 |  + src       | HAL source code
 |  + interface | HAL header files. Interface with the other parts of the program
 + modules      | 主要飞控代码 Firmware operating code and headers 角度计算 pid 等
 |  + src       | Firmware tasks source code and main.c
 |  + interface | Operating headers. Configure the firmware environment
 + utils        | CRC校验 IIR滤波器等 Utils code. Implement utility block like the console.
 |  + src       | Utils source code
 |  + interface | Utils header files. Interface with the other parts of the program
 + platform     | 平台信息 Platform specific files. Not really used yet
 + tools        | Misc. scripts for LD, OpenOCD, make, version control, ...
 |              | *** The two following folders contains the unmodified files ***
 + lib          | Libraries
 |  + FreeRTOS  | Source FreeRTOS folder. Cleaned up from the useless files
 |  + STM32...  | STM32外设库 Library folders of the ST STM32 peripheral libs
 |  + CMSIS     | ARM标准库 Core abstraction layer

二、运行任务

系统启动时主要运行的任务有,adcTask,crtpTxTask,crtpRxTask,eskylinkTask,infoTask,logTask,memTask,paramTask,pmTask,stabilizerTask,syslinkTask,systemTask,prvIdleTask,prvTimerTask和usblinkTask等任务.分析链接

Adc_f103.c (drivers\src):  xTaskCreate(adcTask, (const signed char * const)"ADC",
Crtp.c (modules\src):  xTaskCreate(crtpTxTask, (const signed char * const)CRTP_TX_TASK_NAME,
Crtp.c (modules\src):  xTaskCreate(crtpRxTask, (const signed char * const)CRTP_RX_TASK_NAME,
Eskylink.c (hal\src):  xTaskCreate(eskylinkTask, (const signed char * const)ESKYLINK_TASK_NAME,
Info.c (modules\src):  xTaskCreate(infoTask, (const signed char * const)"Info",
Log.c (modules\src):  xTaskCreate(logTask, (const signed char * const)LOG_TASK_NAME,
Mem.c (modules\src):  xTaskCreate(memTask, (const signed char * const)MEM_TASK_NAME,
Nrf24link.c (hal\src):  xTaskCreate(nrf24linkTask, (const signed char * const)NRF24LINK_TASK_NAME,
Param.c (modules\src):    xTaskCreate(paramTask, (const signed char * const)PARAM_TASK_NAME,
Pidctrl.c (modules\src):  xTaskCreate(pidCrtlTask, (const signed char * const)"PIDCrtl",
Pm_f103.c (hal\src):  xTaskCreate(pmTask, (const signed char * const)PM_TASK_NAME,
Pm_f405.c (hal\src):  xTaskCreate(pmTask, (const signed char * const)PM_TASK_NAME,
Stabilizer.c (modules\src):  xTaskCreate(stabilizerTask, (const signed char * const)STABILIZER_TASK_NAME,
Syslink.c (hal\src):  if (xTaskCreate(syslinkTask, (const signed char * const)SYSLINK_TASK_NAME,
System.c (modules\src):  xTaskCreate(systemTask, (const signed char * const)SYSTEM_TASK_NAME,
Task.h (lib\freertos\include): * Type by which tasks are referenced.  For example, a call to xTaskCreate
Task.h (lib\freertos\include): portBASE_TYPE xTaskCreate(
Task.h (lib\freertos\include): * xTaskCreate() can only be used to create a task that has unrestricted
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include): * \defgroup xTaskCreate xTaskCreate
Task.h (lib\freertos\include):#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) )
Task.h (lib\freertos\include): * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include): * At least one task should be created via a call to xTaskCreate ()
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
Task.h (lib\freertos\include): * xTaskCreate() and xTaskCreateRestricted() macros.
Tasks.c (lib\freertos):        xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle );
Tasks.c (lib\freertos):        xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL );
Timers.c (lib\freertos):            xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, &xTimerTaskHandle );
Timers.c (lib\freertos):            xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, NULL);
Usblink.c (hal\src):  xTaskCreate(usblinkTask, (const signed char * const)USBLINK_TASK_NAME,

三、源码风格总结

Crazyflie项目中有很多巧妙的类型定义,可以很方便的解决问题,也可能是本人才疏学浅表示第一看看到这么用

1. 两种方式检索同一区域(union)

以下可以实现两种检索方式检索同一片内存区域,可以使用

 typedef union {
   struct {
         float x;
         float y;
         float z;
   };
   float axis[3];
 } Axis3f;

2. 使用枚举类型计数

以下枚举类型成员SensorImplementation_COUNT,始终可以代表枚举类型中成员的个数.巧妙利用了枚举类型第一个成员默认为0的特点

typedef enum {  
  #ifdef SENSOR_INCLUDED_BMI088_BMP388
  SensorImplementation_bmi088_bmp388,
  #endif

  #ifdef SENSOR_INCLUDED_BMI088_SPI_BMP388
  SensorImplementation_bmi088_spi_bmp388,
  #endif

  #ifdef SENSOR_INCLUDED_MPU9250_LPS25H
  SensorImplementation_mpu9250_lps25h,
  #endif

  #ifdef SENSOR_INCLUDED_MPU6050_HMC5883L_MS5611
  SensorImplementation_mpu6050_HMC5883L_MS5611,
  #endif

  #ifdef SENSOR_INCLUDED_BOSCH
  SensorImplementation_bosch,
  #endif

  SensorImplementation_COUNT,
} SensorImplementation_t;

3. 紧凑的数据类型

struct cppmEmuPacket_s {
  struct {
      uint8_t numAuxChannels : 4;   // Set to 0 through MAX_AUX_RC_CHANNELS
      uint8_t reserved : 4;
  } hdr;
  uint16_t channelRoll;
  uint16_t channelPitch;
  uint16_t channelYaw;
  uint16_t channelThrust;
  uint16_t channelAux[MAX_AUX_RC_CHANNELS];
} __attribute__((packed));

attribute ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,是GCC特有的语法.这个功能是跟操作系统没关系,跟编译器有关,gcc编译器不是紧凑模式的,我在windows下,用vc的编译器也不是紧凑的,用tc的编译器就是紧凑的.例如:

在TC下:struct my{ char ch; int a;} sizeof(int)=2;sizeof(my)=3;(紧凑模式)
在GCC下:struct my{ char ch; int a;} sizeof(int)=4;sizeof(my)=8;(非紧凑模式)
在GCC下:struct my{ char ch; int a;}__attrubte__ ((packed)) sizeof(int)=4;sizeof(my)=5

4. git工程中如何引用其他仓库

使用将其他仓库一起clone

git submodule init
git submodule update

5. 在makefile中添加宏定义

在Crazyflie的固件代码中,宏一般都定义在文件Makefile中.可以使用CFLAGS += -D的方式配置固件功能

# Flag that can be added to config.mk
CFLAGS += -DUSE_UART_CRTP        # Set CRTP link to UART
CFLAGS += -DUSE_ESKYLINK         # Set CRTP link to E-SKY receiver
CFLAGS += -DENABLE_UART          # To enable the uart
CFLAGS += -DDEBUG_PRINT_ON_UART  # Redirect the console output to the UART
CFLAGS += -DTOSH_DATA_LENGTH=114

相当于编译时

gcc -DTOSH_DATA_LENGTH=114 xx.c

相当于文件中添加

#define TOSH_DATA_LENGTH 114

最后更新于