【E392】基于国产 RT-Thread 实时操作系统激光雷达小车

2021-08-20 16:47:40      索炜达电子      986     

项目编号:E392

文件大小:36.5M

源码说明:带中文注释

开发环境:C编译器

简要概述

背景

在做这辆小车之前,正值我大学学习生涯的迷茫期。有关嵌入式的学习,我基本是自学的。自学最大的坏处就是,没有一个系统的学习提纲,你无法充分了解你学习的进度、水平以及未来的方向。你可能会因为一个小成果而觉得自己可以了,也可能会突然有一天遇到一个专业知识更强的同龄人,而自我否定。为了能够接触到新知识,巩固以前所学,我决定做这样一辆小车。


选择操作系统

在这之前我只学过 UCOS,但是 ucos 商用并不免费,一直耿耿于怀。所以趁着这次机会本着学习的目的我选择了 RT-Thread。期间也有考虑过 freertos 等其他实时操作系统但最终还是选择了 RT-Thrad 。


准备阶段

下载 RT-Thread 源码。

激光雷达,作为学生党买淘宝上最便宜。(当初买的时候最便宜的一款也要 499 QAQ,现在好像便宜点了)

PCB的绘制,或者使用最小系统板外加模块。


我选择的是 stm32f429-apollo 因为手头正好有正点原子 F429 的开发板,有好多驱动稍加修改甚至不修改直接就可以用了。


硬件部分

1.主控芯片

stm32f429igt6


因为基础工程是根据 bsp stm32f429-apollo 改的,所以电路原理图上一些引脚的分配我也尽量按照 apollo 开发板的方案设计。


2.电机驱动部分

电机驱动芯片使用 L298N 。控制小车的速度与方向。


电路原理图如下:

【E392】基于国产 RT-Thread 实时操作系统激光雷达小车

电机自带AB相编码器,用于测速(pi闭环控制)。


3.激光雷达

查激光雷达数据手册

【E392】基于国产 RT-Thread 实时操作系统激光雷达小车

激光雷达需要 5v 供电,串口通信,一个 M_SCTP PWM输入口控制转速(M_SCTP可默认拉高省出pwm口)。


【E392】基于国产 RT-Thread 实时操作系统激光雷达小车


4.蓝牙串口

因为使用了 RT-Thread 的组件 FinSH,( FinSH 组件是 RT-Thread 的一大亮点。)为了方便无线调试,我使用两个配对好的蓝牙串口来通信,即插即用。

【E392】基于国产 RT-Thread 实时操作系统激光雷达小车

5.其他

另外我还外加了 mpu9250模块,SDRAM、W25Q128、蜂鸣器、oled屏...等 用于以后的扩展。


程序部分

整体的思路如下:

【E392】基于国产 RT-Thread 实时操作系统激光雷达小车

eaix4线程: 用于对激光雷达数据的处理。

wireless线程: 用于无线传输。

mpu9250线程: 用于9轴姿态传感器数据的处理。

speed线程: 用于速度的闭环控制。

master线程: 作为主线程负责创建其他子线程,以及处理其他子线程发送的传感器信息。

1.激光雷达

查看雷达开发手册


图一: 扫描命令

【E392】基于国产 RT-Thread 实时操作系统激光雷达小车

图二: 扫描命令

【E392】基于国产 RT-Thread 实时操作系统激光雷达小车

当向激光雷达设备发送 [A5 60] 的时候,激光雷达会连续不断的返回扫描到的数据,直到你发送停止扫描命令为止,基于这种特性选择使用 RT-Thread 的消息队列机制。

【E392】基于国产 RT-Thread 实时操作系统激光雷达小车

rt_err_t eaix4_open(const char *name)

{

    rt_err_t res;

    /* 查找系统中的串口设备 */

    eaix4_device = rt_device_find(name);

    /* 查找到设备后将其打开 */

    if (eaix4_device != RT_NULL)

    {

        /* 注册回调函数 eaix4_intput */

        res = rt_device_set_rx_indicate(eaix4_device, eaix4_intput);

        /* 检查返回值 */

        if (res != RT_EOK)

        {

            rt_kprintf("set %s rx indicate error.%d\n", name, res);

            return -RT_ERROR;

        }

        /* 打开设备,以可读写、中断方式 */

        res = rt_device_open(eaix4_device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);

        /* 检查返回值 */

        if (res != RT_EOK)

        {

            rt_kprintf("open %s device error.%d\n", name, res);

            return -RT_ERROR;

        }

    }

    else

    {

        rt_kprintf("can't find %s device.\n", name);

        return -RT_ERROR;

    }

    /* 初始化消息队列对象 */

    rt_mq_init(&Eaix4Mq, "EAIX4", Eaix4Buff, 1, sizeof(Eaix4Buff), RT_IPC_FLAG_FIFO);

    return RT_EOK;

}


/* 串口接收数据回调函数 */

static rt_err_t eaix4_intput(rt_device_t dev, rt_size_t size)

{

    rt_uint8_t ch;

    /* 读取1字节数据 */

    if (rt_device_read(eaix4_device, 0, &ch, 1) == 1)

    {

        /* 将数据发送到消息队列中 */

        rt_mq_send(&Eaix4Mq, &ch, 1);

    }

    return RT_EOK;

}

/* 读取消息队列中的数据 */

rt_uint8_t  eaix4_getchar(void)

{

    rt_uint8_t ch;

    /* 读取消息队列中的数据 */

    rt_mq_recv(&Eaix4Mq, &ch, 1, RT_WAITING_FOREVER);

    return ch;

}

/* 向激光雷达发送数据 */

void eaix4_putchar(const rt_uint8_t c)

{

    rt_size_t len = 0;

    rt_uint32_t timeout = 0;

    do

    {

        len = rt_device_write(eaix4_device, 0, &c, 1);

        timeout++;

    }

    while (len != 1 && timeout < 500);

}


2.添加激光雷达控制命令

#include <finsh.h>

#define stop                    "-s"

#define force_stoppage          "-fs"

#define start_scanning          "-sc"

#define force_start_scanning    "-fsc"

#define get_version_information "-gvf"

#define get_health_status       "-ghs"

void Eaix4Scaning()

{

    eaix4_putchar(0xA5);

    eaix4_putchar(0x60);

}

void Eaix4stop()

{

    eaix4_putchar(0xA5);

    eaix4_putchar(0x65);

}

void Eaix4Version()

{

    eaix4_putchar(0xA5);

    eaix4_putchar(0x90);

}

void Eaix4Health()

{

    eaix4_putchar(0xA5);

    eaix4_putchar(0x91);

}

void eaix4cmd(int argc, char **argv)

{

    if (argc > 1)

    {

        if (!rt_strcmp(argv[1], stop))

        {

            Eaix4stop();

        }

        else if (!rt_strcmp(argv[1], force_stoppage))

        {

            eaix4_putchar(0xA5);

            eaix4_putchar(0x00);

        }

        else if (!rt_strcmp(argv[1], start_scanning))

        {

            Eaix4Scaning();

        }

        else if (!rt_strcmp(argv[1], force_start_scanning))

        {

            eaix4_putchar(0xA5);

            eaix4_putchar(0x61);

        }

        else if (!rt_strcmp(argv[1], get_version_information))

        {

            Eaix4Version();

        }

        else if (!rt_strcmp(argv[1], get_health_status))

        {

            Eaix4Health();

        }

        else

        {

            rt_kprintf("ERROR command !\n");

        }

    }

}

MSH_CMD_EXPORT(eaix4cmd, -s - fs - sc - fsc - gvf - ghs);

MSH_CMD_EXPORT 的作用就是向 msh 中增加命令。

几个主要的命令

【E392】基于国产 RT-Thread 实时操作系统激光雷达小车

命令行演示

【E392】基于国产 RT-Thread 实时操作系统激光雷达小车

实物:

【E392】基于国产 RT-Thread 实时操作系统激光雷达小车

文件列表:

目录│文件列表:

 └ LidarCar

    │ project.uvprojx.lnk

    ├ doc

    │  │ RM-MPU-9250A-00.pdf

    │  │ rtthread_manual.zh.pdf

    │  │ SDRAM布线规则.doc

    │  │ STM32F429IGT6.pdf

    │  │ YDLIDAR X4 使用手册.pdf

    │  │ YDLIDAR X4 开发手册.pdf

    │  └ YDLIDAR X4 数据手册.pdf

    ├ picture

    │  │ bsp选择.png

    │  │ PCB.jpg

    │  │ 俯视图.jpg

    │  │ 命令行操作.gif

    │  │ 扫描命令1.png

    │  │ 扫描命令2.png

    │  │ 效果演示.gif

    │  │ 数据.png

    │  │ 正视图.jpg

    │  │ 激光雷达pcb接口.png

    │  │ 激光雷达接口.png

    │  │ 电机驱动电路.png

    │  │ 硬件架构.png

    │  │ 蓝牙pcb接口.png

    │  └ 软件结构.png

    └ rt-thread

       │ .gitattributes

       │ .gitignore

       │ .travis.yml

       │ AUTHORS

       │ ChangeLog.md

       │ Kconfig

       │ LICENSE

       │ README.md

       │ README_zh.md

       ├ bsp

       │  └ LidarCarBSP

       │     │ .config

       │     │ .gitignore

       │     │ EventRecorderStub.scvd

       │     │ Kconfig

       │     │ LICENSE

       │     │ project.uvoptx

       │     │ project.uvprojx

       │     │ README.md

       │     │ rt-thread_stm32f4xx.BAT

       │     │ rtconfig.h

       │     │ rtconfig.py

       │     │ SConscript

       │     │ SConstruct

       │     │ stm32_rom.icf

       │     │ stm32_rom.ld

       │     │ stm32_rom.sct

       │     ├ applications

       │     │  │ app_beep.c

       │     │  │ app_beep.h

       │     │  │ app_command.c

       │     │  │ app_command.c.orig

       │     │  │ app_command.h

       │     │  │ app_eaix4.c

       │     │  │ app_eaix4.h

       │     │  │ app_motor.c

       │     │  │ app_motor.h

       │     │  │ app_move.c

       │     │  │ app_move.h

       │     │  │ app_mpu9250.c

       │     │  │ app_mpu9250.h

       │     │  │ app_slam.c

       │     │  │ app_slam.c.orig

       │     │  │ app_slam.h

       │     │  │ app_speed.c

       │     │  │ app_speed.h

       │     │  │ app_uart.c

       │     │  │ app_uart.c.orig

       │     │  │ app_uart.h

       │     │  │ app_wirelessuart.c

       │     │  │ app_wirelessuart.h

       │     │  │ event.c

       │     │  │ event.h

       │     │  │ main.c

       │     │  │ main.c.orig

       │     │  │ master_thread.c

       │     │  │ master_thread.h

       │     │  └ SConscript

       │     ├ DebugConfig

       │     │  │ rt-thread_stm32f4xx_STM32F401RCTx.dbgconf

       │     │  └ rt-thread_stm32f4xx_STM32F429IGTx.dbgconf

       │     ├ DMP

       │     │  ├ driver

       │     │  │  ├ eMPL

       │     │  │  │  │ dmpKey.h

       │     │  │  │  │ dmpmap.h

       │     │  │  │  │ inv_mpu.c

       │     │  │  │  │ inv_mpu.h

       │     │  │  │  │ inv_mpu_dmp_motion_driver.c

       │     │  │  │  └ inv_mpu_dmp_motion_driver.h

       │     │  │  ├ include

       │     │  │  │  │ log.h

       │     │  │  │  │ mlinclude.h

       │     │  │  │  │ mlmath.h

       │     │  │  │  │ mlos.h

       │     │  │  │  │ mltypes.h

       │     │  │  │  │ mpu.h

       │     │  │  │  └ stdint_invensense.h

       │     │  │  └ stm32L

       │     │  │     │ log_stm32.c

       │     │  │     └ packet.h

       │     │  ├ eMPL-hal

       │     │  │  │ eMPL_outputs.c

       │     │  │  └ eMPL_outputs.h

       │     │  ├ mllite

       │     │  │  │ data_builder.c

       │     │  │  │ data_builder.h

       │     │  │  │ hal_outputs.c

       │     │  │  │ hal_outputs.h

       │     │  │  │ invensense.h

       │     │  │  │ message_layer.c

       │     │  │  │ message_layer.h

       │     │  │  │ mlmath.c

       │     │  │  │ ml_math_func.c

       │     │  │  │ ml_math_func.h

       │     │  │  │ mpl.c

       │     │  │  │ mpl.h

       │     │  │  │ results_holder.c

       │     │  │  │ results_holder.h

       │     │  │  │ start_manager.c

       │     │  │  │ start_manager.h

       │     │  │  │ storage_manager.c

       │     │  │  └ storage_manager.h

       │     │  └ mpl

       │     │     │ accel_auto_cal.h

       │     │     │ compass_vec_cal.h

       │     │     │ fast_no_motion.h

       │     │     │ fusion_9axis.h

       │     │     │ gyro_tc.h

TAG激光雷达小车
  • 4 次
  • 1 分