内容简介:*本文作者:xutiejun,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。网上有很多介绍树莓派小车的控制方案,但是搜索了一圈却发现没有无线键盘的控制方案。挑战未知,才更有趣。1.树莓派小车。(树莓派小车的安装不是本文重点,如果读者不熟悉小车的安装,请自行搜索。)
*本文作者:xutiejun,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。
网上有很多介绍树莓派小车的控制方案,但是搜索了一圈却发现没有无线键盘的控制方案。挑战未知,才更有趣。
0×01 所需材料
1.树莓派小车。(树莓派小车的安装不是本文重点,如果读者不熟悉小车的安装,请自行搜索。)
2.无线键盘。
0×02 方案
在树莓派系统上搭建两个服务:键盘监听服务和小车转向控制服务。
键盘监听服务主要用于监听键盘的按键,并将按键发送给 小车转向控制服务 。
小车转向控制服务主要 用于驱动小车转向。
说明:本文中小车安装的是raspbian系统,是基于 linux 内核的debian系统。
按键与小车动作映射关系如下 :
按键事件 | 小车动作 |
---|---|
方向键上按下 | 小车前进 |
方向键上抬起 | 小车停止 |
方向键下按下 | 小车后退 |
方向键下抬起 | 小车停止 |
方向键左按下 | 小车左转 |
方向键左抬起 | 小车停止 |
方向键右按下 | 小车右转 |
方向键右抬起 | 小车停止 |
0×03 键盘监听服务设计
首先确定键盘对应的event,可以输入如下命令查询。
cat /proc/bus/input/devices
查询结果如下:
省略 …
I: Bus=0003 Vendor=03f0 Product=034a Version=0110
N: Name=”Chicony HP Elite USB Keyboard”
P: Phys=usb-0000:00:14.0-5/input1
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.1/0003:03F0:034A.0003/input/input9
U: Uniq=
H: Handlers=kbd event6
B: PROP=0
B: EV=1f
B: KEY=3f0003007f 0 0 483ffff17aff32d bf54444600000000 1 130f938b17c000 677bfad941dfed 9ed68000004400 10000002
B: REL=40
B: ABS=100000000
B: MSC=10
省略 …
我的设备中键盘对应的是event6(注意:不同设备对应的event号是不同的)。
键盘监听核心代码:
#define KEYSTATUS_IS_UP (0) //键盘按键抬起 void *listenKeyboardThread(void *arg) { int keys_fd; char ret[2]; struct input_event t; keys_fd = open("/dev/input/event6", O_RDWR); if (keys_fd <= 0) { printf("open /dev/input/event6 device error!\n"); return 0; } while (1) { if (read(keys_fd, &t, sizeof (t)) == sizeof (t)) { if (t.type == EV_KEY ) { // printf("\r\nkey:%d %d %d \r\n", t.type, t.code, t.value); // 上键 if ( KEY_UP==t.code&&KEYSTATUS_IS_UP!=t.value) { // 前进 std::cout << "command: CARRUN FORWARD"<< std::endl; DirectionReq *req = new DirectionReq(); req->setValue(DIRECTION_FORWARD); ControlManager::instance()->postActionReq(req); } else if ( KEY_UP==t.code&&KEYSTATUS_IS_UP==t.value) { // 停车 std::cout << "command: CARRUN STOP"<< std::endl; StatusReq *req = new StatusReq(); ControlManager::instance()->postStatusReq(req); } // 下键 if ( KEY_DOWN==t.code&&KEYSTATUS_IS_UP!=t.value) { // 后退 std::cout << "command: CARRUN BACK"<< std::endl; DirectionReq *req = new DirectionReq(); req->setValue(DIRECTION_BACK); ControlManager::instance()->postActionReq(req); } else if ( KEY_DOWN==t.code&&KEYSTATUS_IS_UP==t.value) { // 停车 std::cout << "command: CARRUN STOP"<< std::endl; StatusReq *req = new StatusReq(); ControlManager::instance()->postStatusReq(req); } // 左键 if ( KEY_LEFT==t.code&&KEYSTATUS_IS_UP!=t.value) { // 左转 std::cout << "command: CARRUN LEFT"<< std::endl; DirectionReq *req = new DirectionReq(); req->setValue(DIRECTION_LEFT); ControlManager::instance()->postActionReq(req); } else if ( KEY_LEFT==t.code&&KEYSTATUS_IS_UP==t.value) { // 停车 std::cout << "command: CARRUN STOP"<< std::endl; StatusReq *req = new StatusReq(); ControlManager::instance()->postStatusReq(req); } // 右键 if ( KEY_RIGHT==t.code&&KEYSTATUS_IS_UP!=t.value) { // 右转 std::cout << "command: CARRUN RIGHT"<< std::endl; DirectionReq *req = new DirectionReq(); req->setValue(DIRECTION_RIGHT); ControlManager::instance()->postActionReq(req); } else if ( KEY_RIGHT==t.code&&KEYSTATUS_IS_UP==t.value) { // 停车 std::cout << "command: CARRUN STOP"<< std::endl; StatusReq *req = new StatusReq(); ControlManager::instance()->postStatusReq(req); } } } } close(keys_fd); }
0×04 小车转向控制服务设计
小车转向控制服务采用C++语言和 python 语言混合编程实现。
python语言程序只用于控制小车的动作:前进、后退、左转、右转、停止。
C++语言程序是整个控制系统的核心,用于控制小车动作的逻辑控制。
用python控制小车动作的代码如下:
#!/usr/bin/Python # -*- coding: UTF-8 -*- #引入gpio的模块 import RPi.GPIO as GPIO import time #设置in1到in4接口 IN1 = 12 IN2 = 16 IN3 = 18 IN4 = 22 #初始化接口 def car_init(): #设置GPIO模式 GPIO.setmode(GPIO.BOARD) GPIO.setup(IN1,GPIO.OUT) GPIO.setup(IN2,GPIO.OUT) GPIO.setup(IN3,GPIO.OUT) GPIO.setup(IN4,GPIO.OUT) #前进的代码 def car_forward(): GPIO.output(IN1,GPIO.HIGH) GPIO.output(IN2,GPIO.LOW) GPIO.output(IN3,GPIO.HIGH) GPIO.output(IN4,GPIO.LOW) time.sleep(0.15) GPIO.cleanup() #后退 def car_back(): GPIO.output(IN1,GPIO.LOW) GPIO.output(IN2,GPIO.HIGH) GPIO.output(IN3,GPIO.LOW) GPIO.output(IN4,GPIO.HIGH) time.sleep(0.15) GPIO.cleanup() #左转 def car_left(): GPIO.output(IN1,False) GPIO.output(IN2,False) GPIO.output(IN3,GPIO.HIGH) GPIO.output(IN4,GPIO.LOW) time.sleep(0.15) GPIO.cleanup() #右转 def car_right(): GPIO.output(IN1,GPIO.HIGH) GPIO.output(IN2,GPIO.LOW) GPIO.output(IN3,False) GPIO.output(IN4,False) time.sleep(0.15) GPIO.cleanup() #停止 def car_stop(): GPIO.output(IN1,GPIO.LOW) GPIO.output(IN2,GPIO.LOW) GPIO.output(IN3,GPIO.LOW) GPIO.output(IN4,GPIO.LOW) GPIO.cleanup()
控制系统的代码就不粘贴了,只把设计过程中遇到的问题与大家分享下。
控制系统在设计过程中遇到这样一个问题:
如果按键一直按下,当按键抬起时小车不会立刻停止,而是过一下才会停止。
导致问题发生的原因:
由于按键一直按下会有大量的按键请求发送过来,而小车的动作响应要慢于键盘按键响应,会有大量的按键按下请求堆积在处理线程中,而按键抬起请求处于队列最末尾,是最后执行的,所以当按键抬起时小车才不会立刻停止。
修正方案:
按键抬起事件要最优先处理,处理完按键抬起事件后将堆积的按键按下队列清空。
0×05 结束
到此整个小车控制系统就介绍完了。
最后,整套代码已经发到了百度网盘上。
链接: https://pan.baidu.com/s/1sA8t9mCH_TJegjdE5ggXMg 提取码: w3s2
*本文作者:xutiejun,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。
以上所述就是小编给大家介绍的《使用无线键盘控制树莓派小车》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 【技术分享】现代无线鼠标及键盘的安全性分析报告
- [树莓派]树莓派的入门教程
- 「玩转树莓派」树莓派 3B+ 安装 OpenCv
- 「玩转树莓派」树莓派 3B+ 查询本机IP
- 「玩转树莓派」树莓派 3B+ 配置静态IP
- 「玩转树莓派」树莓派 3B+ 配置无线WiFi
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
C程序设计的抽象思维
Eric S.Roberts / 闪四清 / 机械工业出版社 / 2012-5 / 99.00元
Eric S. Roberts所著的《C程序设计的抽象思维》是一本关于C语言的经典图书。本书共计17章,分为4部分,第一部分概述计算机导论课程中涉及的基本编程概念;第二部分讨论递归算法,其中结合大量示例,有助于读者轻松理解和掌握晦涩的概念;第三部分不仅介绍了用非递归算法实现的抽象数据类型,还提供了一些工具,有助于读者理解数据抽象的概念;第四部分重点介绍采用递归算法实现的抽象数据类型。本书重点突出,......一起来看看 《C程序设计的抽象思维》 这本书的介绍吧!