Xbox360 手柄通过网络远程控制树莓派

49 篇文章 11 订阅
14 篇文章 0 订阅

前言


本文基于如下博客基础:

  1. Windows 安装pygame 模块
  2. 树莓派 与 Xbox360手柄 的一次美丽邂逅
  3. Python >>> TCP 网络编程
  4. Python >>> UDP 网络编程

大家都知道,我们一般的游戏手柄是不提供网络连接功能的,只有蓝牙2.4G无线连接等连接方式,而这就限制了手柄的有效连接距离。
例如我的八爪鱼手柄,连接距离最远才10m,这对于远程控制来说是远远不够的,所以,我就想为我的手柄赋予网络的远距离控制能力(虽然是间接赋予 😃 )

有了如上博客的基础,我再简单介绍一下:

  1. 首先我们在Windows 主机上安装了python(上述pygame 安装教程有讲解);
  2. 并在Windows 上通过pygame 获取到了手柄的数据(程序和树莓派的一样,见上述第二篇博客);
  3. 然后实现了TCP 网络连接的服务器端和客户端程序的构建;
  4. 最后也实现了UDP 网络连接的服务器端和客户端程序的构建。

开始

如此一来,整合一下,手柄远程控制的代码就出来了:
(关键点均有注释)

TCP 版

1. 服务器端

我把树莓派作为服务器,用来接收数据,其IP地址是192.168.0.200,端口我开的是9999

#coding:utf-8
import socket
import threading
import time

# 建立Socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('192.168.0.200', 9999))

# 开始监听端口
s.listen(5)
print('Waiting for connection...')

def tcplink(sock, addr):
    print('Accept new connection from %s:%s...' % addr)
    # 发送数据
    sock.send(b'Welcome!')
    # 接收数据
    while True:
        # 指定最大接收量
        data = sock.recv(1024)
        print data
        if not data or data.decode('utf-8') == 'exit':
            break
    # 关闭Socket
    sock.close()
    print('Connection from %s:%s closed.' % addr)

# 等待连接
while True:
    sock, addr = s.accept()
    # 建立新进程
    t = threading.Thread(target=tcplink, args=(sock, addr))
    t.start()

2. 客户端

我的Windows 笔记本是客户端,读取手柄数据并发送给服务器端(树莓派)

#coding:utf-8
import pygame
import socket

# 模块初始化
pygame.init()
pygame.joystick.init()

# 若只连接了一个手柄,此处带入的参数一般都是0
joystick = pygame.joystick.Joystick(0)
# 手柄对象初始化
joystick.init()

buttons = joystick.get_numbuttons()
axes = joystick.get_numaxes()
hats = joystick.get_numhats()

done = False

# 建立连接
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.0.200', 9999))

print(s.recv(1024).decode('utf-8'))

while not done:
    for event_ in pygame.event.get():
		# 退出事件
        if event_.type == pygame.QUIT:
            done = True
		# 按键按下或弹起事件
        elif event_.type == pygame.JOYBUTTONDOWN or event_.type == pygame.JOYBUTTONUP:
			# 获取所有按键状态信息
            for i in range(buttons):
                button = joystick.get_button(i)
                if button:
                    s.send(bytes(("Button " + str(i) +" was pressed"), encoding="utf-8"))
		# 轴转动事件
        elif event_.type == pygame.JOYAXISMOTION:
			# 获取所有轴状态信息
            for i in range(axes):
                axis = joystick.get_axis(i)
                s.send(bytes(("axis " + str(i) + " " + str(axis) + "\n\r"), encoding="utf-8"))
		# 方向键改变事件
        elif event_.type == pygame.JOYHATMOTION:
			# 获取所有方向键状态信息
            for i in range(hats):
                hat = joystick.get_hat(i)
                if hat[0] == -1:
                    s.send(bytes('Left', encoding="utf-8"))
                if hat[0] == 1:
                    s.send(bytes('Right', encoding="utf-8"))
                if hat[1] == -1:
                    s.send(bytes('Down', encoding="utf-8"))
                if hat[1] == 1:
                    s.send(bytes('Up', encoding="utf-8"))
	
pygame.quit()
s.send(b'exit')

# 关闭连接
s.close()

3. 结果

上面是笔记本,下面是树莓派
在这里插入图片描述

UDP 版

1. 服务器端

#coding=utf-8
import socket
import time
import threading

# 创建连接
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定端口
s.bind(('192.168.0.200', 9999))

print('Waiting for connection...')
while True:
    # 无数据接收则线程挂起,等待数据
    data, addr = s.recvfrom(1024)
    print('Received from %s:%s.' % addr)
    print(data)

2. 客户端

我的Windows 笔记本是客户端,读取手柄数据并发送给服务器端(树莓派)

#coding:utf-8
import pygame
import socket

# 模块初始化
pygame.init()
pygame.joystick.init()

# 若只连接了一个手柄,此处带入的参数一般都是0
joystick = pygame.joystick.Joystick(0)
# 手柄对象初始化
joystick.init()

buttons = joystick.get_numbuttons()
axes = joystick.get_numaxes()
hats = joystick.get_numhats()

done = False

# 创建连接
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

while not done:
    for event_ in pygame.event.get():
		# 退出事件
        if event_.type == pygame.QUIT:
            done = True
		# 按键按下或弹起事件
        elif event_.type == pygame.JOYBUTTONDOWN or event_.type == pygame.JOYBUTTONUP:
			# 获取所有按键状态信息
            for i in range(buttons):
                button = joystick.get_button(i)
                if button:
                    s.sendto(bytes(("Button " + str(i) +" was pressed"), encoding="utf-8"), ('192.168.0.200', 9999))
		# 轴转动事件
        elif event_.type == pygame.JOYAXISMOTION:
			# 获取所有轴状态信息
            for i in range(axes):
                axis = joystick.get_axis(i)
                s.sendto(bytes(("axis " + str(i) + " " + str(axis) + "\n\r"), encoding="utf-8"), ('192.168.0.200', 9999))
		# 方向键改变事件
        elif event_.type == pygame.JOYHATMOTION:
			# 获取所有方向键状态信息
            for i in range(hats):
                hat = joystick.get_hat(i)
                if hat[0] == -1:
                    s.sendto(bytes('Left', encoding="utf-8"), ('192.168.0.200', 9999))
                if hat[0] == 1:
                    s.sendto(bytes('Right', encoding="utf-8"), ('192.168.0.200', 9999))
                if hat[1] == -1:
                    s.sendto(bytes('Down', encoding="utf-8"), ('192.168.0.200', 9999))
                if hat[1] == 1:
                    s.sendto(bytes('Up', encoding="utf-8"), ('192.168.0.200', 9999))
	
pygame.quit()
s.sendto(b'exit', ('192.168.0.200', 9999))

s.close()

3. 结果

在这里插入图片描述

TCP 和UDP

当我们只是按下手柄的Button 时,TCP 连接能够满足快速传输的要求,但是当快速摇动控制杆时,TCP 有时会出现传输滞后的情况,但UDP 的传输质量能够一直保持相对较高的水平。

所以,对于手柄控制,我们完全可以使用UDP 进行传输,就算偶尔出现丢包也不影响整体控制。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诺亚方包

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值