TA的每日心情  | 怒 2020-3-6 09:52 | 
|---|
 
  签到天数: 13 天 连续签到: 1 天 [LV.3]偶尔看看II 
进士 
 
 
	- 积分
 - 1653
 
 
 
 
 | 
 
 
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  
 
 
 |   
	
 
  
  
  
 
 
 |