大疆特洛TELLO手柄盖世小鸡Gamesir-T1D蓝牙连接破解DIY

文章来源于以下博客

感谢大江的工作!!!

文章来源于转载,为了写一系列TT文章,故此加原创

https://www.hsli.top/%E5%A4%A7%E7%96%86%E7%89%B9%E6%B4%9BTELLO%E6%89%8B%E6%9F%84%E7%9B%96%E4%B8%96%E5%B0%8F%E9%B8%A1Gamesir-T1D%E8%93%9D%E7%89%99%E8%BF%9E%E6%8E%A5%E7%A0%B4%E8%A7%A3DIY.html

手头有个大疆TELLO并买了个盖世小鸡Gamesir-T1D遥控器,想着玩够了小飞机还可以用手柄来做DIY小车。。。万万没想到这个遥控器居然是定制的,只能遥控TELLO小飞机。。。电脑和手机都无法通过蓝牙直接连接。遂破解之。

先拆为敬

正面,做工还真是可以,本来手柄的手感就挺好的。可以看到单片机控制板和蓝牙板是单独的两个小板,可能不同遥控用的是同一套底板和不同的蓝牙以及单片机吧。

蓝牙板,芯片名称被磨掉了打上GS-T1d他们自家的标签。看起来像是CC2541方案。单片机和蓝牙之间预留有IIC的测试点。

单片机控制板,同样磨掉了芯片丝印。。

背后貌似预留了串口测试点?

硬件上看不出怎么破,手头没有设备,算了,拆开看一眼装回去。

用BLE调试软件连接,发现并不是用的设想的蓝牙串口方案来遥控,而是真的蓝牙协议。一共有3个Services,其中第三个Service接收的字节流一直不变,第二个变化没有什么规律。第一个UUID开头是00008651的Servie接收的字节流,变化比较有规律。

通过调试发现,在遥控器无动作的时候,第一个Service接收值一直都是C9-C6-86-A1-00-DB-B9-03-01-01-01-0B-01-E1-07-07-06-10-1E-56

有动作的时候,前两个Bytes一直是A1-C5。因此,前两个字节可以用来判断遥控状态。

以下的讨论都是在A1-C5状态下。

最后一个字节是一直自增的,按键按下,放开会使得该字节自增2,一直到0xFF又变回0x00,这个是用来记录按键按下次数的。

10-13字节是按键按下的状态,手柄上每个按键对应一位。实际上只要把这几个字节读取出来,就能和按键一一对应上了。

接下来是摇杆。3-7字节就是摇杆状态,一开始花了挺大劲去猜哪个摇杆对应哪些字节,后来发现其实很好猜的。一共5个字节,2个摇杆共4个方向,所以每个方向就是10bit。一般来说10bit的AD也是相当常见的。

所以只要把这些字节读取出来,然后每10位凑成整数,就可以还原出摇杆的读数了。

在linux上连接读取BLE可以用pyblue模块,可以在树莓派上用了。

下面给出读取的测试代码:

from __future__ import print_functionimport structimport timefrom bluepy.btle import Peripheral
# 来自(https://www.hsli.top)
# 手柄的MAC地址可以通过蓝牙调试软件获得my_gamesir = Peripheral('c6:xx:xx:xx:xx:b9', 'random')
services = my_gamesir.getServices()for service in services: print(service)
control_service = services[3] charac_dics = control_service.getCharacteristics() for charac in charac_dics: print(charac.uuid)

while True: time.sleep(0.01)
charac1, charac2, charac3 = [item.read() for item in charac_dics]
status_code = struct.unpack('H', charac1[:2])[0]
if status_code == 50593: on_press_key = struct.unpack('I', charac1[9:13])[0] press_counter = struct.unpack('B', charac1[-1])[0]
bar_status = struct.unpack('5B', charac1[2:7]) bar_status_bin = ''.join([bin(item).split('b')[1].rjust(8).replace(' ', '0') for item in bar_status])
left_drag = int(bar_status_bin[0:10], 2) left_push = int(bar_status_bin[10:20], 2) right_drag = int(bar_status_bin[20:30], 2) right_push = int(bar_status_bin[30:40], 2)
print("status %s" % status_code, end=' ') print("on_press %s" % on_press_key, end=' ') print("press_counter %s" % press_counter, end=' ') print("left_drag %s" % left_drag, end=' ') print("right_drag %s" % right_drag, end=' ') print("left_push %s" % left_push, end=' ') print("right_push %s" % right_push, end='\r')
# break
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from __future__ import print_function
import struct
import time
from bluepy.btle import Peripheral

# 来自(https://www.hsli.top)

# 手柄的MAC地址可以通过蓝牙调试软件获得
my_gamesir = Peripheral('c6:xx:xx:xx:xx:b9', 'random')

services = my_gamesir.getServices()
for service in services:
print(service)

control_service = services[3]
charac_dics = control_service.getCharacteristics()
for charac in charac_dics:
print(charac.uuid)

while True:
time.sleep(0.01)

charac1, charac2, charac3 = [item.read() for item in charac_dics]

status_code = struct.unpack('H', charac1[:2])[0]

if status_code == 50593:
on_press_key = struct.unpack('I', charac1[9:13])[0]
press_counter = struct.unpack('B', charac1[-1])[0]

bar_status = struct.unpack('5B', charac1[2:7])
bar_status_bin = ''.join([bin(item).split('b')[1].rjust(8).replace(' ', '0') for item in bar_status])

left_drag = int(bar_status_bin[0:10], 2)
left_push = int(bar_status_bin[10:20], 2)
right_drag = int(bar_status_bin[20:30], 2)
right_push = int(bar_status_bin[30:40], 2)

print("status %s" % status_code, end=' ')
print("on_press %s" % on_press_key, end=' ')
print("press_counter %s" % press_counter, end=' ')
print("left_drag %s" % left_drag, end=' ')
print("right_drag %s" % right_drag, end=' ')
print("left_push %s" % left_push, end=' ')
print("right_push %s" % right_push, end='\r')

# break

文章具有很大的指导型意见,注意文章的时间为2020年4月,所以应该是TT还是以前的版本呢?这个就不得为之了,现在属于没有硬件情况下最棒的文章了.

(0)

相关推荐