TA的每日心情 | 怒 2020-3-6 09:52 |
---|
签到天数: 13 天 连续签到: 1 天 [LV.3]偶尔看看II
|
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 结束
到此整个小车控制系统就介绍完了。
最后,整套代码已经发到了百度网盘上。
本文作者:xutiejun,转载自 FreeBuf
|
|