野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 3674|回复: 5

【鲁班猫创意大赛】——Lubancar自平衡小车

[复制链接]
发表于 2023-4-13 04:09:58 | 显示全部楼层 |阅读模式
  大家好,我给大家分享我做的Lubancar自平衡小车,Lubancar只用到了野火鲁班猫(Lubancat ZW)作为主控,纯python语言开发的自平衡小车。Lubancar运行的系统是Debian 10,实现的功能主要有读取mpu6050,卡尔曼滤波,控制直流减速电机转向、转速、读取霍尔编码器、OLED显示、输入中断、PID控制、超声波测距、python多线程、tcp网络通信、串口通信、无线手柄控制、蓝牙通信、Flask+opencv+rknn进行远程监控和图像识别、网页控制等。
  由于作者平时白天要上班,晚上回来要肝毕设、写论文,还要“指导”同学的毕设,而Lubancar这个项目是从2月初才开始搞的,所以时间十分紧张,目前PID参数调得一般,只能使小车基本保持直立或者受到一定干扰也能保持直立,一些通信手段只实现大致框架,没有进行联调。

(补充说明: 1、由于个人能力极其有限,难免有错误的地方,还请大家指正。
        2、作者写本帖的时候还在肝毕设初稿,初稿还没写完,后面还需要按要求修改初稿,所以时间比较紧迫,这个Lubancar项目只作大致说明,详细开源说明和资料发布,待答辩完后再整理发布,可能会是7、8月份。)
一、项目展示
Lubancar:
野火比赛项目——Lubancar自平衡小车_哔哩哔哩_bilibili

解析手柄展示:
野火比赛项目——Lubancar自平衡小车的手柄解析部分展示_哔哩哔哩_bilibili

PCB:

野火论坛202304132310344130..png

二、硬件设计
原理图: Lubancar原理图.zip (43.01 KB, 下载次数: 13)
野火论坛202304130024492052..png
以上是根据V1版实际调试后调整的V2版原理图。
(1)电源部分:
野火论坛202304130029004009..png
Lubancar需要12V电源供电,原因在于电机采用的是12V直流减速电机,对比多种电池后选择12V锂电池进行供电最为合适,支持板载供电、充电,上图中DC电源座子为锂电池充电接口,5.08座子是锂电池供电接口。
(2)稳压部分
野火论坛202304130031416040..png
野火论坛202304130031546283..png
采用的稳压降压芯片为LM2596,LM2596可以驱动最大3A的负载电流,并且具有良好的输出电压线性和负载调节特性。由于鲁班猫ZW启动电流比较大,最大启动电流达到0.75A左右,正常工作电流为0.18A左右,加上其他外设,整体所需要的电流比较大,设计3A及以上最大输出较为合适。
(3)电机及驱动部分
野火论坛202304130045032146..png
采用的电机驱动模块为TB6612FNG,其是一种直流电机驱动器,支持驱动两个电机。可以控制PWM口电压从而控制电机转速、控制AIN、BIN端口逻辑电平从而控制电机转速。
野火论坛202304130047515805..png 野火论坛202304130048147862..png 野火论坛202304130048293545..png
电机采用的是JBG37-520直流减速电机,带霍尔编码器,提供较低的转速和较大的力矩,M+ M-是电机电源接口,VCC是霍尔编码器供电接口,OR选择5V\3.3V是因为编码器供电电压影响编码器A、B相输出,接5V则A、B相逻辑电压为5V、0V,接3.3V则A、B相逻辑电压为3.3V、0V,鲁班猫的IO容压可能达不到5V,这里需要跳帽短接到3.3V。
(3)其余模块部分
野火论坛202304130100053900..png 野火论坛202304130100547470..png 野火论坛202304130101176801..png
野火论坛202304130106278073..png
其余模块部分选择鲁班猫合适引脚对接即可,其余一些设计选择合适IO设计即可。
(4)预留部分
野火论坛202304130102328853..png 野火论坛202304130102498602..png
预留2个舵机控制口,后续可以控制云台,预留spi接口可以接spi屏幕或者其他spi模块。

三、软件部分
(1)读取MPU6050
作者一开始参考野火快速使用手册用python读取和写入MPU6050相关寄存器,成功读取三轴加速度和三轴陀螺仪,通过这种方式完全可以对MPU6050进行读取,但不推荐使用这种方法,因为python有第三方库可以十分方便地进行读取。
python之所以简单,一是本身语法相对简单,二是有非常多的第三方库协助开发。
读取MPU6050的第三库为[color=var(--color-accent-fg)]Adafruit_CircuitPython_MPU6050,其项目地址为https://github.com/adafruit/Adafruit_CircuitPython_MPU6050
野火论坛202304130117233149..png

可以在README.rst文件查看相关说明
野火论坛202304130120359469..png


可以从使用例子看到,加载模块后,使用board.I2C()方法来创建I2C接口的实例对象,然后通过将该对象作为参数传递给adafruit_mpu6050.MPU6050()方法来初始化MPU6050对象,最后访问MPU6050的成员输出相应数据。

野火论坛202304130128147291..png


Lubancar使用I2C_3读取MPU6050,创建I2C接口的实例对象方式为:
i2c = busio.I2C(board.I2C3_SCL, board.I2C3_SDA)
野火论坛202304130132197617..png


野火论坛202304130141242098..png
此处使用了 board和busio模块进行创建,与项目例子稍有差异。


更多python I2c通信说明查看野火教程:https://doc.embedfire.com/linux/rk356x/Python/zh/latest/circuit/i2c_demo.html


(2)卡尔曼滤波
处理MPU6050原始数据,进行姿态解算有几种方式,分别是使用MPU6050的DMP库获取四元数、卡尔曼滤波、互补滤波。DMP库是C库,python下不能直接使用,所以不考虑DMP库,卡尔曼滤波相比互补滤波更加精确,所以采用卡尔曼滤波进行姿态解算,但是卡尔曼滤波相对互补滤波会复杂很多。
卡尔曼滤波概念:卡尔曼滤波(Kalman filtering)一种利用线性系统状态方程,通过系统输入输出观测数据,对系统状态进行最优估计的算法。由于观测数据中包括系统中的噪声和干扰的影响,所以最优估计也可看作是滤波过程。
卡尔曼滤波具体原理本文不作说明,相关文章可以参考:https://www.zhihu.com/search?type=content&q=%E5%8D%A1%E5%B0%94%E6%9B%BC%E6%BB%A4%E6%B3%A2
卡尔曼滤波编程思路笔者参考的是:https://www.bilibili.com/video/BV1sL411F7fu/  ,原视频作者使用的开发平台为arduino,作者参考编程思路和相关代码进行转换,调整。


野火论坛202304130200428490..png
程序代码中卡尔曼滤波部分有较多注释,结合视频理解起来并不困难,主要是先通过def mpu6050_init():初始化相关变量, def mpu6050_Kalman(): 进行卡尔曼滤波,最终得到最优估计的翻滚角(roll)和俯仰角(Pitch)。


野火论坛202304130207042741..png
因为,单靠mpu6050不能准确获取偏航角(Yaw),所以只获取了翻滚角(roll)和俯仰角(Pitch),而在自平衡小车系统中只需要用到 k_roll,所以用卡尔曼滤波进行姿态解算完全可行。
不理解的请结合b站视频和一些文档资料进行理解,时间原因不作过多说明。


(3)控制电机转向
控制电机转向执行控制TB6612FNG的AIN、BIN端口逻辑电平即可。由于Lubancat不能使用树莓派的Rpi.GPIO和WiringPi的python库,但野火教程足足提供了3种方式来控制GPIO,而且都十分简单!不存在脱离树莓派的库,就开发不了的情况,只要稍微学习下就能熟练使用。
野火教程链接:https://doc.embedfire.com/linux/rk356x/Python/zh/latest/circuit/digital_io.html#libgpiod
野火论坛202304130221222419..png


Lubancar程序代码中控制GPIO使用了以上3种方式控制GPIO,证明这三种方式都是可行的,其中控制电机IO部分使用python3-libgpiod。
野火论坛202304130222543580..png


根据教程文档介绍创建对象chipx,设置使用的引脚,然后通过访问request控制GPIO电平即可。


(4)控制电机转速
控制转速需要控制TB6612FNG的PWM引脚的电平,野火教程文档里面有详细使用PWM的说明和例程,如下:
https://doc.embedfire.com/linux/rk356x/Python/zh/latest/circuit/pwm_output.html
Lubancar程序使用python-periphery库控制PWM。
野火论坛202304130238221705..png


野火论坛202304130238333879..png


这部分是初始化PWM,并将PWM占空比为设置为0%,即PWMx.duty_cycle = 1.0,电机默认不转。


野火论坛202304130240097798..png


这部分代码是根据PID算法输出控制PWM的占空比实现调速,该部分也包括根据PID算法输出确定AIN、BIN端口逻辑电平,使用电机转向控制。


(4)读取霍尔编码器
霍尔编码器每个周期内会产生两个相位差为90度的脉冲,通过读取两个通道的输入捕获值,可以确定当前所在的位置,从而计算出电机角度或位移信息。
在stm32中读取霍尔编码器使用定时器的输入捕获功能,但是linux的定时器并没有这个输入捕获功能,(PWM可能有输入捕获功能,没有测试),所以只能考虑中断或者高速扫描的方式。
采用中断的方式读取相对来说肯定比较靠谱,但是python是应用层的,如果没有驱动层支持是不能实现中断,目前Lubancar中IO中断并没有驱动层支持,但野火教程驱动篇有输入中断的教程,可以看教程自行实现。
作者看过一些能实现“中断”的python第三方库的源码,其原理都是轮询的方式,不是真正的中断!这种假中断的方式是不能读取霍尔编码器输出的高速的电平变化,作者对linux驱动层有一定了解,目前板卡中是开启了内核自带的按键驱动的,但没有相关设备树配置,我们可以添加设备树插件来使用内核自带的中断进行测试。
野火论坛202304130258533987..png
野火论坛202304130259043955..png
作者实际测试,用内核自带的这个输入中断驱动读取霍尔编码器发现内存占用率极高,只读取一个电机的霍尔编码器,只是用手转动车轮,cpu占用率高达55%,所以走捷径用内核自带的中断来读取霍尔编码器并不可行。这种高频中断消耗很大,可能需要在驱动层实现,编写特定驱动程序进行处理才行。驱动层开启定时器定时采集、定时上报数据等。作者是很想完成这部分驱动代码编写,但确实没有时间。。。。
既然中断的方式不可行,那只能用高速扫描了,作者测试过必须定时周期要低于0.0003s才能正确读取霍尔编码器,但这样cpu占用率也很高,那怎么办呢?其实不难想到在短时间内加速度是基本不变的,转速变化不大,可以通过短时间高速并间隔读取的方式进行读取,实测这种方式cpu压力可以降到原来的5%以内,但数据比较粗糙,但可以对测速结果进行滤波和离散数据连续化处理。。。


具体实现参考代码的class  Measurement_speed(object):
野火论坛202304130314278213..png


(5)PID控制
PID用的是位置式PID,具体可以参考:https://blog.csdn.net/weixin_44270218/article/details/113665051
程序代码为def lubancar_Vertical_Ring_PD():和def lubancar_Incremental_PI():


野火论坛202304130317492371..png


PID调参可以参考:
https://www.bilibili.com/video/BV1zo4y1D7bx/?buvid=XY579685D8F6F2D557A979629F098AC5922EC&is_story_h5=false&mid=%2B%2BxVYS3aIkTtlKmt74t7gw%3D%3D&p=1&plat_id=114&share_from=ugc&share_medium=android&share_plat=android&share_session_id=ffb38139-a84f-4d13-a999-0e88986a6b5d&share_source=WEIXIN&share_tag=s_i×tamp=1681327150&unique_k=6CccQE3&up_id=286802729


https://www.bilibili.com/video/BV1oW4y1Y7nv/?buvid=XY579685D8F6F2D557A979629F098AC5922EC&is_story_h5=false&mid=%2B%2BxVYS3aIkTtlKmt74t7gw%3D%3D&p=1&plat_id=114&share_from=ugc&share_medium=android&share_plat=android&share_session_id=c411474f-1471-4b6b-b621-60da83790ca1&share_source=WEIXIN&share_tag=s_i×tamp=1681327165&unique_k=Imm0ev0&up_id=472407878


(6)oled显示
OLED显示部分同样使用Adafruit的库,项目地址:https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_SSD1306


野火论坛202304130323503308..png


野火论坛202304130324507312..png


默认不支持中文,作者添加了中文字库,支持显示中文。


野火论坛202304130325559308..png

野火论坛202304132338246825..png

(7)输入中断
使能内核自带的输入中断,编写设备树插件
野火论坛202304130328511101..png


python中使用evdev模块进行解析
野火论坛202304130329477722..png
需要作超时处理


(8)超声波测距
超声波模块有两个引脚:触发引脚和回波引脚。给触发引脚一个至少10us的脉冲信号,当模块接收到触发信号后,会立即向外发射一组超声波。如果这些超声波遇到物体并被反弹回来,模块会将其接收到,并通过回波引脚输出一个高电平信号。通过测量高电平信号的持续时间,就可以得到超声波从发射到返回所用的时间。
野火论坛202304130330529608..png


野火论坛202304130331275010..png
编程思路和上面描述一致。


(9)python多线程

使用threading模块实现多线程
野火论坛202304130333066955..png


(10)tcp网络通信
野火论坛202304130334166523..png
使用socket模块实现网络通信。


(11)串口通信
参考:https://doc.embedfire.com/linux/rk356x/Python/zh/latest/circuit/uart_demo.html
野火论坛202304130336552193..png


(12)无线手柄控制
板卡可能没有相应驱动,笔者的手柄识别为xbox 360,需自行适配驱动
野火论坛202304130338225384..png


野火论坛202304130338323981..png
内核开启现有驱动,编译内核、替换。


手柄解析代码查看test_js.py,运行前需要安装相应库,如果手柄的编码不同程序定义部分需稍作调整


(13)Flask+opencv+rknn
参考:https://doc.embedfire.com/linux/rk356x/Python/zh/latest/example/camera_demo.html
野火论坛202304132342359412..jpg

野火论坛202304130342457809..jpg


四、代码附件
代码.zip (30.46 MB, 下载次数: 3148)




回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-4-20 11:37 , Processed in 0.048387 second(s), 33 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表