我正在尝试编写一个小代码,以显示通过UDP从游戏(F1 2019)接收的数据。
F1 2019游戏通过UDP发送数据。我已经能够接收数据包,并且已经分离了标头和数据,现在根据使用rawutil模块发送数据的结构来解压缩数据。
发送数据包的结构可以在这里找到: https://forums.codemasters.com/topic/38920-f1-2019-udp-specification/
我只对遥测数据包感兴趣。
import socket
import cdp
import struct
import array
import rawutil
from pprint import pprint
# settings
ip = '0.0.0.0'
port = 20777
# listen for packets
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
listen_socket.bind((ip, port))
while True:
# Receiving data
data, address = listen_socket.recvfrom(65536)
header = data[:20]
telemetry = data[20:]
# decode the header
packetFormat, = rawutil.unpack('<H', header[:2])
gameMajorVersion, = rawutil.unpack('<B', header[2:3])
gameMinorVersion, = rawutil.unpack('<B', header[3:4])
packetVersion, = rawutil.unpack('<B', header[4:5])
packetId, = rawutil.unpack('<B', header[5:6])
sessionUID, = rawutil.unpack('<Q', header[6:14])
sessionTime, = rawutil.unpack('<f', header[14:18])
frameIdentifier, = rawutil.unpack('<B', header[18:19])
playerCarIndex, = rawutil.unpack('<B', header[19:20])
# print all info (just for now)
## print('Packet Format : ',packetFormat)
## print('Game Major Version : ',gameMajorVersion)
## print('Game Minor Version : ',gameMinorVersion)
## print('Packet Version : ',packetVersion)
## print('Packet ID : ', packetId)
## print('Unique Session ID : ',sessionUID)
## print('Session Time : ',sessionTime)
## print('Frame Number : ',frameIdentifier)
## print('Player Car Index : ',playerCarIndex)
## print('\n\n')
#start getting the packet data for each packet starting with telemetry data
if (packetId == 6):
speed, = rawutil.unpack('<H' , telemetry[2:4])
throttle, = rawutil.unpack('<f' , telemetry[4:8])
steer, = rawutil.unpack('<f' , telemetry[8:12])
brake, = rawutil.unpack('<f' , telemetry[12:16])
gear, = rawutil.unpack('<b' , telemetry[17:18])
rpm, = rawutil.unpack('<H' , telemetry[18:20])
print (speed)
UDP规范指出,汽车的速度以km / h为单位发送。但是,当我打开包装袋时,速度是256的倍数,因此10 km / h是2560。
我想知道我是否以错误的方式解压缩数据?还是其他原因导致了这种情况。
例如转向也存在问题。规范说应该在-1.0到1.0之间,但实际值可能很大或很小。
此处抓取屏幕:https://imgur.com/a/PHgdNrx
对此表示感谢。 谢谢。
答案 0 :(得分:1)
我建议您不要使用unpack
方法,因为对于大型结构(例如MotionPacket具有1343字节),您的代码会立即变得非常混乱。
但是,如果您非常想使用它,请仅调用unpack
,例如:
fmt = "<HBBBBQfBB"
size = struct.calcsize(fmt)
arr = struct.unpack("<HBBBBQfBB", header[:size])
或者,查看ctypes
库,尤其是ctypes.LittleEndianStructure
库,您可以在其中将_fields_
属性设置为ctypes
的序列(例如uint8
等等,而不必像解压缩一样将它们翻译成相关符号)。
https://docs.python.org/3.8/library/ctypes.html#ctypes.LittleEndianStructure
或者,看看namedtuples
。
另外,也有很多python
二进制IO库,例如binio
,您可以在其中声明ctypes
的结构,因为无论如何它都是一个薄包装器。
要完全回答您的问题,结构似乎是:
struct PacketHeader
{
uint16 m_packetFormat; // 2019
uint8 m_gameMajorVersion; // Game major version - "X.00"
uint8 m_gameMinorVersion; // Game minor version - "1.XX"
uint8 m_packetVersion; // Version of this packet type, all start from 1
uint8 m_packetId; // Identifier for the packet type, see below
uint64 m_sessionUID; // Unique identifier for the session
float m_sessionTime; // Session timestamp
uint m_frameIdentifier; // Identifier for the frame the data was retrieved on
uint8 m_playerCarIndex; // Index of player's car in the array
};
意味着unpack
的符号序列应为:<H4BQfLB
,因为uint
中的ctypes
实际上是uint32
,您在{{1 }}。
我还用uint8
替换了BBBB
。希望这可以帮助。
答案 1 :(得分:0)
海德我也想从Formula 1 2019中读取车速。我找到了您的问题,从您的问题中得到了一些提示,并解决了我的问题。现在我想我必须还钱。速度乘以256的原因是您从错误的字节开始,并且此数据的格式为little endian。您共享的代码从第22个字节开始读取速度,如果从第23个字节开始读取,则将获得正确的速度数据。