树莓派小车无线控制c语言,极客DIY | 如何用无线键盘控制树莓派小车

*本文作者:xutiejun,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。

网上有很多介绍树莓派小车的控制方案,但是搜索了一圈却发现没有无线键盘的控制方案。挑战未知,才更有趣。

0x01 所需材料

1.树莓派小车。(树莓派小车的安装不是本文重点,如果读者不熟悉小车的安装,请自行搜索。)

98710e6d9ba3df95f9811585afb8ca5a.png

2.无线键盘。

a90cdc9385e60e9c1ec83eac8ec8c1d0.png

0x02 方案

在树莓派系统上搭建两个服务:键盘监听服务和小车转向控制服务。

键盘监听服务主要用于监听键盘的按键,并将按键发送给小车转向控制服务。

小车转向控制服务主要用于驱动小车转向。

说明:本文中小车安装的是raspbian系统,是基于linux内核的debian系统。

按键与小车动作映射关系如下:按键事件 小车动作 方向键上按下 小车前进

方向键上抬起 小车停止

方向键下按下 小车后退

方向键下抬起 小车停止

方向键左按下 小车左转

方向键左抬起 小车停止

方向键右按下 小车右转

方向键右抬起 小车停止

0x03 键盘监听服务设计

首先确定键盘对应的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);

}

0x04 小车转向控制服务设计

小车转向控制服务采用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()

控制系统的代码就不粘贴了,只把设计过程中遇到的问题与大家分享下。

控制系统在设计过程中遇到这样一个问题:如果按键一直按下,当按键抬起时小车不会立刻停止,而是过一下才会停止。

导致问题发生的原因:由于按键一直按下会有大量的按键请求发送过来,而小车的动作响应要慢于键盘按键响应,会有大量的按键按下请求堆积在处理线程中,而按键抬起请求处于队列最末尾,是最后执行的,所以当按键抬起时小车才不会立刻停止。

修正方案:按键抬起事件要最优先处理,处理完按键抬起事件后将堆积的按键按下队列清空。

0x05 结束

到此整个小车控制系统就介绍完了。

最后,整套代码已经发到了百度网盘上。

*本文作者:xutiejun,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值