本帖最后由 云天 于 2024-2-19 20:02 编辑
【项目背景】
最近买了两个Xbox手柄,这个手柄支持Bluetooth(蓝牙4.0),行空板也支持蓝牙功能。本项目中,Xbox手柄通过蓝牙连接行空板,控制麦克纳姆轮车。
【行空板启动蓝牙】
蓝牙(Bluetooth)是一个短距离无线通信标准,用于在手机、计算机和其他电子设备之间通信。行空板自带 Linux 系统, 在 Linux 中权威的蓝牙协议栈实现是 BlueZ。其本身自带了很多有用的工具,如bluetoothctl。
1.电脑通过USB线连接上行空板,通过浏览器地址:10.1.2.3,访问行空板,开启终端。
root@unihiker:~#Bluetoothctl 复制代码
复制代码
扫描蓝牙设备,找到Xbox手柄蓝牙地址(40:8E:2C:22:84:31 )
复制代码
【行空板Python连接Xbox】
使用os库的system执行蓝牙连接命令。
import os
import time
result=0
def shellcom(command,wait):
global result
# 调用os模块的system()函数来执行Shell命令
result = os.system(command)
#print(result)
time.sleep(wait)
shellcom("bluetoothctl power on",5)
if result==0:
print("蓝牙已开启")
#shellcom("bluetoothctl scan on",10)
#shellcom("bluetoothctl scan off",2)
shellcom("bluetoothctl agent on",5)
if result==0:
print("代理已开启")
shellcom("bluetoothctl pair 40:8E:2C:22:84:31",10)
if result==0:
print("蓝牙配对已完成")
else:
print("蓝牙配对可能已存在")
shellcom("bluetoothctl connect 40:8E:2C:22:84:31",4)
if result==0:
print("Xbox连接已完成")
else:
print("Xbox连接失败")
复制代码
【读取Xbox手柄各按键】
使用pygame库读取Xbox手柄各按键。
import pygame
pygame.init()
joysticks = []
clock = pygame.time.Clock()
keepPlaying = True
pygame.joystick.init()
# 初始化手柄
joystick = pygame.joystick.Joystick(0)
joystick.init()
while keepPlaying:
clock.tick(60)
for event in pygame.event.get():
print(event)
复制代码
import pygame
pygame.init()
pygame.joystick.init()
# 初始化手柄
joystick = pygame.joystick.Joystick(0)
joystick.init()
while True:
for event in pygame.event.get():
if event.type == pygame.JOYBUTTONDOWN:
if event.button==0:#"A"键
pass
elif event.button==1:#"B"键
pass
elif event.button==4:#"X"键
pass
elif event.button==3:#"Y"键
pass
elif event.button==6:#"RB"键,右肩键:Right Shoulder Button
pass
elif event.button==7:#"LB"键,左肩键:Left Shoulder Button
pass
elif event.button==10:#"View"键
pass
elif event.button==11:#"Menu"键
pass
elif event.button==15:#“共享”按键
pass
elif event.button==12:#“xbox”按键
pass
elif event.type == pygame.JOYHATMOTION:#方向键
if event.hat==0:
print(str(event.value[0])+":"+str(event.value[1]))
if event.value[0]==0:
if event.value[1]==0:#中间位置
print("“中间位置”方向键")
elif event.value[1]==1:#向上
print("“向上”方向键")
elif event.value[1]==-1:#向下
print("“向下”方向键")
elif event.value[0]==-1:#向右
print("“向右”方向键")
elif event.value[0]==1:#向左
print("“向左”方向键")
elif event.type == pygame.JOYAXISMOTION:
#左摇杆按键
if event.axis==0:#左右
if event.value<-0.1:#向左
print("“向左”左摇杆按键")
elif event.value>0.1:#向右
print("“向右”左摇杆按键")
else:
print("左右stop左摇杆按键")
elif event.axis==1:#上下
if event.value<-0.1:#向上
print("“向上”左摇杆按键")
elif event.value>0.1:#向下
print("“向下”左摇杆按键")
else:
print("上下stop左摇杆按键")
#右摇杆按键
if event.axis==2:#左右
if event.value<-0.1:#向右
print("“向右”右摇杆按键")
elif event.value>0.1:#向左
print("“向左”右摇杆按键")
else:
print("“停止”右摇杆按键")
elif event.axis==3:#上下
if event.value<-0.1:#向上
print("“向上”右摇杆按键")
elif event.value>0.1:#向下
print("“向下”右摇杆按键")
elif event.axis==5:#左射击键
if event.value>0:
print("左射击键")
elif event.axis==4:#右射击键
if event.value>0:
print("右射击键")
复制代码
【控制麦克纳姆轮车】
1.电机驱动扩展板初始化
from pinpong.extension.unihiker import *
from pinpong.libs.microbit_motor import DFMotor
from pinpong.board import Board
from pinpong.board import Pin
Board().begin()
p_dfr0548_motor_M1 = DFMotor(1)
p_dfr0548_motor_M2 = DFMotor(2)
p_dfr0548_motor_M3 = DFMotor(3)
p_dfr0548_motor_M4 = DFMotor(4)
复制代码
2.自定义麦克纳姆轮车运动函数
def forward(speed):#带速度参数——前进
p_dfr0548_motor_M1.speed(speed)
p_dfr0548_motor_M1.run(p_dfr0548_motor_M1.CCW)
p_dfr0548_motor_M2.speed(speed)
p_dfr0548_motor_M2.run(p_dfr0548_motor_M2.CCW)
p_dfr0548_motor_M3.speed(speed)
p_dfr0548_motor_M3.run(p_dfr0548_motor_M3.CW)
p_dfr0548_motor_M4.speed(speed)
p_dfr0548_motor_M4.run(p_dfr0548_motor_M4.CW)
def back(speed):#带速度参数——后退
p_dfr0548_motor_M1.speed(speed)
p_dfr0548_motor_M1.run(p_dfr0548_motor_M1.CW)
p_dfr0548_motor_M2.speed(speed)
p_dfr0548_motor_M2.run(p_dfr0548_motor_M2.CW)
p_dfr0548_motor_M3.speed(speed)
p_dfr0548_motor_M3.run(p_dfr0548_motor_M3.CCW)
p_dfr0548_motor_M4.speed(speed)
p_dfr0548_motor_M4.run(p_dfr0548_motor_M4.CCW)
def left(speed):#带速度参数——向左
p_dfr0548_motor_M1.speed(speed)
p_dfr0548_motor_M1.run(p_dfr0548_motor_M1.CW)
p_dfr0548_motor_M2.speed(speed)
p_dfr0548_motor_M2.run(p_dfr0548_motor_M2.CCW)
p_dfr0548_motor_M3.speed(speed)
p_dfr0548_motor_M3.run(p_dfr0548_motor_M3.CCW)
p_dfr0548_motor_M4.speed(speed)
p_dfr0548_motor_M4.run(p_dfr0548_motor_M4.CW)
def right(speed):#带速度参数——向右
p_dfr0548_motor_M1.speed(speed)
p_dfr0548_motor_M1.run(p_dfr0548_motor_M1.CCW)
p_dfr0548_motor_M2.speed(speed)
p_dfr0548_motor_M2.run(p_dfr0548_motor_M2.CW)
p_dfr0548_motor_M3.speed(speed)
p_dfr0548_motor_M3.run(p_dfr0548_motor_M3.CW)
p_dfr0548_motor_M4.speed(speed)
p_dfr0548_motor_M4.run(p_dfr0548_motor_M4.CCW)
def stop():#停止
p_dfr0548_motor_M1.stop()
p_dfr0548_motor_M2.stop()
p_dfr0548_motor_M3.stop()
p_dfr0548_motor_M4.stop()
def Lrotate(speed):#带速度参数——向左原地旋转
p_dfr0548_motor_M1.speed(speed)
p_dfr0548_motor_M1.run(p_dfr0548_motor_M1.CCW)
p_dfr0548_motor_M2.speed(speed)
p_dfr0548_motor_M2.run(p_dfr0548_motor_M2.CCW)
p_dfr0548_motor_M3.speed(speed)
p_dfr0548_motor_M3.run(p_dfr0548_motor_M3.CCW)
p_dfr0548_motor_M4.speed(speed)
p_dfr0548_motor_M4.run(p_dfr0548_motor_M4.CCW)
def Rrotate(speed):#带速度参数——向右原地旋转
p_dfr0548_motor_M1.speed(speed)
p_dfr0548_motor_M1.run(p_dfr0548_motor_M1.CW)
p_dfr0548_motor_M2.speed(speed)
p_dfr0548_motor_M2.run(p_dfr0548_motor_M2.CW)
p_dfr0548_motor_M3.speed(speed)
p_dfr0548_motor_M3.run(p_dfr0548_motor_M3.CW)
p_dfr0548_motor_M4.speed(speed)
p_dfr0548_motor_M4.run(p_dfr0548_motor_M4.CW)
复制代码
3.Xbox按键控制麦克纳姆轮车运动
if event.type == pygame.JOYHATMOTION:#方向键
if event.hat==0:
print(str(event.value[0])+":"+str(event.value[1]))
if event.value[0]==0:
if event.value[1]==0:#中间位置
print("“中间位置”方向键")
stop()
elif event.value[1]==1:#向上
print("“向上”方向键")
forward(200)
elif event.value[1]==-1:#向下
print("“向下”方向键")
back(200)
elif event.value[0]==-1:#向右
print("“向右”方向键")
right(200)
elif event.value[0]==1:#向左
print("“向左”方向键")
left(200)
elif event.type == pygame.JOYAXISMOTION:
#左摇杆按键
if event.axis==0:#左右
if event.value<-0.1:#向左
left(int(abs(event.value)*255))
print("“向左”左摇杆按键")
elif event.value>0.1:#向右
right(int(event.value*255))
print("“向右”左摇杆按键")
else:
stop()
print("左右stop左摇杆按键")
elif event.axis==1:#上下
if event.value<-0.1:#向上
forward(int(abs(event.value)*255))
print("“向上”左摇杆按键")
elif event.value>0.1:#向下
back(int(event.value*255))
print("“向下”左摇杆按键")
else:
stop()
print("上下stop左摇杆按键")
#右摇杆按键
if event.axis==2:#左右
if event.value<-0.1:#向右
Rrotate(int(abs(event.value)*255))
print("“向右”右摇杆按键")
elif event.value>0.1:#向左
Lrotate(int(event.value*255))
print("“向左”右摇杆按键")
else:
stop()
print("“停止”右摇杆按键")
复制代码
4.控制车上灯 (1)控制车底彩灯,共四个LED彩灯,使用NeoPixel库驱动。
if bs==1 and time.time()-time1>0.2:
time1=time.time()
np1.rotate(1)
elif bs==2 and time.time()-time2>0.5:
time2=time.time()
np1.rotate(1)
for event in pygame.event.get():
if event.type == pygame.JOYBUTTONDOWN:
if event.button==0:#"A"键
print("“A”键")
color=0xFF0000
elif event.button==1:#"B"键
print("“B”键")
color=0x00FF00
elif event.button==4:#"Y"键
print("“Y”键")
color=0x0000FF
elif event.button==3:#"X"键
print("“X”键")
color=0xFF00FF
elif event.button==6:#"RB"键,右肩键:Right Shoulder Button
print("“RB”键")
pin14.write_digital(1)
pin15.write_digital(1)
elif event.button==7:#"LB"键,左肩键:Left Shoulder Button
print("“LB”键")
pin14.write_digital(0)
pin15.write_digital(0)
elif event.button==10:#"View"键
print("“View”键")
bs=1
np1.rainbow(0,3,1,360)
elif event.button==11:#"Menu"键
print("“Menu”键")
bs=2
np1.rainbow(0,3,1,360)
elif event.button==15:#“共享”按键
print("“共享”键")
bs=0
np1.clear()
elif event.button==12:#“xbox”按键
print("“xbox”键")
复制代码
(2)控制车前灯,两个LED灯分别接在引脚14、15。
if event.axis==5:#左射击键
if event.value>0:
print("左射击键")
np1.range_color(0,3,color)
elif event.axis==4:#右射击键
if event.value>0:
print("右射击键")
np1.clear()
复制代码
【完整程序】
import pygame
import time
pygame.init()
pygame.joystick.init()
# 初始化手柄
joystick = pygame.joystick.Joystick(0)
joystick.init()
from pinpong.extension.unihiker import *
from pinpong.libs.microbit_motor import DFMotor
from pinpong.board import Board
from pinpong.board import NeoPixel
from pinpong.board import Pin
Board().begin()
pin1 = Pin(Pin.P8)
np1 = NeoPixel(pin1,4)
p_dfr0548_motor_M1 = DFMotor(1)
p_dfr0548_motor_M2 = DFMotor(2)
p_dfr0548_motor_M3 = DFMotor(3)
p_dfr0548_motor_M4 = DFMotor(4)
pin14 = Pin(Pin.P14,Pin.OUT)
pin15 = Pin(Pin.P15,Pin.OUT)
color=0x000000
bs=0
time1=0
time2=0
def forward(speed):#带速度参数——前进
p_dfr0548_motor_M1.speed(speed)
p_dfr0548_motor_M1.run(p_dfr0548_motor_M1.CCW)
p_dfr0548_motor_M2.speed(speed)
p_dfr0548_motor_M2.run(p_dfr0548_motor_M2.CCW)
p_dfr0548_motor_M3.speed(speed)
p_dfr0548_motor_M3.run(p_dfr0548_motor_M3.CW)
p_dfr0548_motor_M4.speed(speed)
p_dfr0548_motor_M4.run(p_dfr0548_motor_M4.CW)
def back(speed):#带速度参数——后退
p_dfr0548_motor_M1.speed(speed)
p_dfr0548_motor_M1.run(p_dfr0548_motor_M1.CW)
p_dfr0548_motor_M2.speed(speed)
p_dfr0548_motor_M2.run(p_dfr0548_motor_M2.CW)
p_dfr0548_motor_M3.speed(speed)
p_dfr0548_motor_M3.run(p_dfr0548_motor_M3.CCW)
p_dfr0548_motor_M4.speed(speed)
p_dfr0548_motor_M4.run(p_dfr0548_motor_M4.CCW)
def left(speed):#带速度参数——向左
p_dfr0548_motor_M1.speed(speed)
p_dfr0548_motor_M1.run(p_dfr0548_motor_M1.CW)
p_dfr0548_motor_M2.speed(speed)
p_dfr0548_motor_M2.run(p_dfr0548_motor_M2.CCW)
p_dfr0548_motor_M3.speed(speed)
p_dfr0548_motor_M3.run(p_dfr0548_motor_M3.CCW)
p_dfr0548_motor_M4.speed(speed)
p_dfr0548_motor_M4.run(p_dfr0548_motor_M4.CW)
def right(speed):#带速度参数——向右
p_dfr0548_motor_M1.speed(speed)
p_dfr0548_motor_M1.run(p_dfr0548_motor_M1.CCW)
p_dfr0548_motor_M2.speed(speed)
p_dfr0548_motor_M2.run(p_dfr0548_motor_M2.CW)
p_dfr0548_motor_M3.speed(speed)
p_dfr0548_motor_M3.run(p_dfr0548_motor_M3.CW)
p_dfr0548_motor_M4.speed(speed)
p_dfr0548_motor_M4.run(p_dfr0548_motor_M4.CCW)
def stop():#停止
p_dfr0548_motor_M1.stop()
p_dfr0548_motor_M2.stop()
p_dfr0548_motor_M3.stop()
p_dfr0548_motor_M4.stop()
def Lrotate(speed):#带速度参数——向左原地旋转
p_dfr0548_motor_M1.speed(speed)
p_dfr0548_motor_M1.run(p_dfr0548_motor_M1.CCW)
p_dfr0548_motor_M2.speed(speed)
p_dfr0548_motor_M2.run(p_dfr0548_motor_M2.CCW)
p_dfr0548_motor_M3.speed(speed)
p_dfr0548_motor_M3.run(p_dfr0548_motor_M3.CCW)
p_dfr0548_motor_M4.speed(speed)
p_dfr0548_motor_M4.run(p_dfr0548_motor_M4.CCW)
def Rrotate(speed):#带速度参数——向右原地旋转
p_dfr0548_motor_M1.speed(speed)
p_dfr0548_motor_M1.run(p_dfr0548_motor_M1.CW)
p_dfr0548_motor_M2.speed(speed)
p_dfr0548_motor_M2.run(p_dfr0548_motor_M2.CW)
p_dfr0548_motor_M3.speed(speed)
p_dfr0548_motor_M3.run(p_dfr0548_motor_M3.CW)
p_dfr0548_motor_M4.speed(speed)
p_dfr0548_motor_M4.run(p_dfr0548_motor_M4.CW)
while True:
if bs==1 and time.time()-time1>0.2:
time1=time.time()
np1.rotate(1)
elif bs==2 and time.time()-time2>0.5:
time2=time.time()
np1.rotate(1)
for event in pygame.event.get():
if event.type == pygame.JOYBUTTONDOWN:
if event.button==0:#"A"键
print("“A”键")
color=0xFF0000
elif event.button==1:#"B"键
print("“B”键")
color=0x00FF00
elif event.button==4:#"Y"键
print("“Y”键")
color=0x0000FF
elif event.button==3:#"X"键
print("“X”键")
color=0xFF00FF
elif event.button==6:#"RB"键,右肩键:Right Shoulder Button
print("“RB”键")
pin14.write_digital(1)
pin15.write_digital(1)
elif event.button==7:#"LB"键,左肩键:Left Shoulder Button
print("“LB”键")
pin14.write_digital(0)
pin15.write_digital(0)
elif event.button==10:#"View"键
print("“View”键")
bs=1
np1.rainbow(0,3,1,360)
elif event.button==11:#"Menu"键
print("“Menu”键")
bs=2
np1.rainbow(0,3,1,360)
elif event.button==15:#“共享”按键
print("“共享”键")
bs=0
np1.clear()
elif event.button==12:#“xbox”按键
print("“xbox”键")
elif event.type == pygame.JOYHATMOTION:#方向键
if event.hat==0:
print(str(event.value[0])+":"+str(event.value[1]))
if event.value[0]==0:
if event.value[1]==0:#中间位置
print("“中间位置”方向键")
stop()
elif event.value[1]==1:#向上
print("“向上”方向键")
forward(200)
elif event.value[1]==-1:#向下
print("“向下”方向键")
back(200)
elif event.value[0]==-1:#向右
print("“向右”方向键")
right(200)
elif event.value[0]==1:#向左
print("“向左”方向键")
left(200)
elif event.type == pygame.JOYAXISMOTION:
#左摇杆按键
if event.axis==0:#左右
if event.value<-0.1:#向左
left(int(abs(event.value)*255))
print("“向左”左摇杆按键")
elif event.value>0.1:#向右
right(int(event.value*255))
print("“向右”左摇杆按键")
else:
stop()
print("左右stop左摇杆按键")
elif event.axis==1:#上下
if event.value<-0.1:#向上
forward(int(abs(event.value)*255))
print("“向上”左摇杆按键")
elif event.value>0.1:#向下
back(int(event.value*255))
print("“向下”左摇杆按键")
else:
stop()
print("上下stop左摇杆按键")
#右摇杆按键
if event.axis==2:#左右
if event.value<-0.1:#向右
Rrotate(int(abs(event.value)*255))
print("“向右”右摇杆按键")
elif event.value>0.1:#向左
Lrotate(int(event.value*255))
print("“向左”右摇杆按键")
else:
stop()
print("“停止”右摇杆按键")
elif event.axis==3:#上下
if event.value<-0.1:#向上
print("“向上”右摇杆按键")
elif event.value>0.1:#向下
print("“向下”右摇杆按键")
elif event.axis==5:#左射击键
if event.value>0:
print("左射击键")
np1.range_color(0,3,color)
elif event.axis==4:#右射击键
if event.value>0:
print("右射击键")
np1.clear()
复制代码
【演示视频】