机器学习项目-智能鞋垫开发项目记录,更改思路3

2025.3.28 

鞋垫数据蓝牙数据的接收和发送

1.服务器端

需要修改服务器端代码,使得PC能同时接收两个蓝牙设备的数据,并分别将这些数据发送到不同的COM串口。首先,我需要理解用户提供的原始代码的结构和功能。原始代码是一个服务器,监听一个端口,接收数据并通过一个固定的COM口发送。用户现在希望扩展为处理两个蓝牙设备,每个设备对应不同的COM口。

首先,我需要确定如何同时处理两个蓝牙连接。通常,这可以通过多线程或多进程来实现,每个线程处理一个客户端连接。由于Python的线程适合I/O密集型任务,这里选择多线程比较合适。

接下来,每个蓝牙设备的数据需要发送到不同的COM口。用户可能有两个蓝牙模块分别连接到不同的COM口,比如COM9和COM10。因此,服务器需要为每个连接分配一个特定的COM口。这可以通过在客户端连接时,根据连接的端口或其他标识来动态分配对应的COM口。

但用户提供的原始代码中,服务器只监听一个端口。为了区分两个蓝牙设备,可能需要让服务器监听两个不同的端口,每个端口对应一个蓝牙设备。例如,蓝牙设备1连接到端口12345,设备2连接到端口12346。这样,服务器可以创建两个监听套接字,分别处理不同端口的连接,并将数据发送到对应的COM口。

或者,可以在同一个端口上接受多个连接,但需要某种方式区分不同的设备。比如,设备在连接后发送一个标识符,服务器根据标识符选择对应的COM口。但这种方法需要设备端配合,可能在实现上更复杂。

考虑到用户之前的交流中,客户端代码已经被修改为使用两个不同的端口(12345和12346)发送数据,因此服务器端也应该监听这两个端口,每个端口对应一个COM口。这样,每个端口的数据独立处理,分别发送到不同的串口。

因此,服务器端代码需要同时监听两个端口,每个端口的连接处理线程中使用不同的串口配置。这可以通过为每个端口创建一个线程,每个线程运行一个监听循环,处理对应端口的连接和数据传输。

另外,需要处理多个串口连接,确保每个串口正确初始化和关闭。同时,异常处理需要完善,避免一个端口的错误影响另一个端口。

现在,我需要编写代码结构,使用多线程监听两个端口,每个端口对应一个COM口。例如,端口12345对应COM9,端口12346对应COM10。每个连接处理线程中,接收到数据后写入对应的串口。

同时,需要测试代码的正确性,确保数据从不同端口接收后发送到正确的COM口。此外,需要考虑资源管理,如正确关闭套接字和串口连接,避免资源泄漏。

可能遇到的问题包括端口占用、串口权限问题,以及多线程间的同步问题。需要确保每个线程独立处理自己的资源,避免竞争条件。

总结修改步骤:

  1. 创建两个服务器套接字,分别监听两个端口。
  2. 为每个端口分配对应的COM口参数。
  3. 使用多线程处理每个服务器的连接。
  4. 每个连接线程中,接收到数据后发送到对应的COM口。
  5. 完善异常处理和资源释放。

最后,验证代码是否满足用户需求,即PC接收两个蓝牙设备的数据,并分别发送到不同的COM口。

以下是修改后的服务器端代码,支持 ​同时接收两个蓝牙设备的数据并分别转发到不同的COM串口

import socket
import serial
import threading

# 配置:每个蓝牙设备对应独立的端口和串口
DEVICE_CONFIGS = [
    {
        'server_port': 12345,  # 蓝牙设备1的监听端口
        'com_port': 'COM9',    # 对应要发送的串口
        'baud_rate': 115200
    },
    {
        'server_port': 12346,  # 蓝牙设备2的监听端口
        'com_port': 'COM10',   # 另一个串口
        'baud_rate': 115200
    }
]

class SerialServer(threading.Thread):
    def __init__(self, server_port, com_port, baud_rate):
        super().__init__()
        self.server_port = server_port
        self.com_port = com_port
        self.baud_rate = baud_rate
        self.running = True
        
    def run(self):
        # 初始化串口
        try:
            ser = serial.Serial(self.com_port, self.baud_rate)
            print(f"Serial {self.com_port} opened")
        except serial.SerialException as e:
            print(f"Failed to open {self.com_port}: {e}")
            return

        # 初始化网络服务
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            try:
                s.bind(('0.0.0.0', self.server_port))
                s.listen()
                print(f"Listening on port {self.server_port} for {self.com_port}")
                
                while self.running:
                    conn, addr = s.accept()
                    print(f"Connected to {addr} for port {self.server_port}")
                    with conn:
                        try:
                            while self.running:
                                data = conn.recv(1024)
                                if not data:
                                    break
                                # 转发到串口
                                ser.write(data)
                                print(f"[Port {self.server_port} -> {self.com_port}] Sent: {data.hex()}")
                        except (ConnectionResetError, socket.error) as e:
                            print(f"Connection error on port {self.server_port}: {e}")
                            break
            except Exception as e:
                print(f"Server error on port {self.server_port}: {e}")
            finally:
                ser.close()

    def stop(self):
        self.running = False

if __name__ == "__main__":
    # 启动两个服务线程
    threads = []
    for config in DEVICE_CONFIGS:
        thread = SerialServer(
            server_port=config['server_port'],
            com_port=config['com_port'],
            baud_rate=config['baud_rate']
        )
        thread.start()
        threads.append(thread)

    try:
        # 主线程保持运行
        while True:
            pass
    except KeyboardInterrupt:
        print("\nShutting down...")
        for thread in threads:
            thread.stop()
        for thread in threads:
            thread.join()
        print("All threads stopped")

主要改进说明:

  1. 多设备独立通道

    • 每个蓝牙设备对应独立的 ​端口​(12345/12346)和 ​串口​(COM9/COM10)
    • 使用线程隔离不同设备的数据流
  2. 数据流向清晰

     

    plaintext

    蓝牙设备1 --[Port 12345]--> COM9
    蓝牙设备2 --[Port 12346]--> COM10
  3. 增强功能

    • 线程安全退出机制
    • 端口复用设置 (SO_REUSEADDR)
    • 详细的错误日志分类

使用说明:

  1. 硬件连接

    • 蓝牙模块1连接到 ​COM9
    • 蓝牙模块2连接到 ​COM10
  2. 客户端配置

    • 蓝牙设备1的客户端连接 192.168.11.88:12345
    • 蓝牙设备2的客户端连接 192.168.11.88:12346

2.树莓派端 

好的,我现在需要帮用户修改他们的Python代码,使其能够同时接收来自两个USB设备(ttyUSB0和ttyUSB1)的数据,并通过WiFi将这两个设备的数据分别传输到PC的不同变量。首先,我需要理解用户的需求和现有代码的结构。

用户现有的代码使用serial库读取一个USB设备的数据,并通过socket发送到指定的服务器IP和端口。现在他们希望扩展这个功能,支持两个USB设备,并且每个设备的数据要发送到不同的变量,可能意味着不同的端口或不同的数据处理方式。

首先,我需要考虑如何同时监听两个串口设备。原来的代码中使用了单个串口对象,现在需要创建两个串口实例,分别对应USB0和USB1。同时,需要确保这两个串口的读取不会互相阻塞,可能需要多线程或者异步处理。

接下来是网络传输部分。用户希望将两个设备的数据分别发送到不同的变量。这里的“不同变量”可能指的是不同的端口,或者服务器端的不同处理端点。因此,可能需要为每个设备创建独立的socket连接,或者使用同一个socket但发送到不同的端口,或者在数据中包含设备标识,让服务器区分来源。

然后要考虑代码的结构是否需要调整。原来的代码在一个循环中读取一个串口的数据,现在需要同时处理两个串口。如果使用多线程,每个串口可以在单独的线程中读取数据,并分别发送。或者使用select库来同时监控多个串口的可读状态,避免阻塞。

另外,异常处理也需要扩展,确保一个设备的错误不会影响另一个设备的运行。例如,如果USB0发生异常,USB1应该继续工作,反之亦然。同时,网络连接也需要稳定,如果连接断开,可能需要重新连接。

还需要考虑数据格式的问题。现有的代码将数据转换为hex字符串发送,可能需要为每个设备的数据添加标识符,比如在数据前加上“USB0:”和“USB1:”,或者使用不同的消息格式,以便服务器区分来源。

现在,我需要验证这些思路是否正确。比如,使用多线程处理两个串口的读取,每个线程独立处理自己的数据发送。或者使用select来同时监听多个串口的事件,避免线程的开销。

然后,编写代码的大致步骤可能是:

  1. 创建两个串口对象,分别连接到ttyUSB0和ttyUSB1。
  2. 创建两个socket连接,或者使用同一个socket但发送到不同的端口。
  3. 使用多线程或select来处理同时读取两个串口的数据。
  4. 在发送数据时,添加设备标识,或者发送到不同的服务器端口。
  5. 修改异常处理,确保一个设备的错误不会导致整个程序终止。
  6. 测试代码,确保两个设备的数据能正确传输并被服务器区分。

需要注意的是,如果两个串口同时有大量数据,可能会影响性能,因此需要考虑缓冲区处理和发送效率。此外,服务器的配置也需要相应调整,以接收并处理来自两个不同源的数据。

最后,测试修改后的代码,确保功能符合用户需求,并处理可能出现的错误情况,比如串口断开、网络中断等。

以下是修改后的代码,实现同时读取两个蓝牙设备(/dev/ttyUSB0/dev/ttyUSB1)的数据,并分别通过WiFi传输到PC的不同端口:

import serial
import socket
import threading

# 设备配置
DEVICES = [
    {
        'port': '/dev/ttyUSB0',
        'baud': 115200,
        'server_ip': '192.168.11.88',
        'server_port': 12345  # 设备1使用12345端口
    },
    {
        'port': '/dev/ttyUSB1',
        'baud': 115200,
        'server_ip': '192.168.11.88',
        'server_port': 12346  # 设备2使用12346端口
    }
]

class BluetoothHandler(threading.Thread):
    def __init__(self, config):
        super().__init__()
        self.config = config
        self.ser = None
        self.sock = None
        self.running = True

    def run(self):
        try:
            # 初始化串口
            self.ser = serial.Serial(
                self.config['port'],
                self.config['baud'],
                timeout=0.1
            )
            
            # 初始化网络连接
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.connect((self.config['server_ip'], self.config['server_port']))
            
            print(f"Device {self.config['port']} connected to {self.config['server_ip']}:{self.config['server_port']}")

            while self.running:
                try:
                    # 读取串口数据
                    if self.ser.in_waiting > 0:
                        data = self.ser.read(self.ser.in_waiting)
                        if data:
                            # 直接发送原始字节数据(无标识符)
                            self.sock.sendall(data)
                            print(f"[{self.config['port']}] Sent {len(data)} bytes")
                            
                except serial.SerialException as e:
                    print(f"Serial Error ({self.config['port']}): {e}")
                    break
                    
        except Exception as e:
            print(f"Connection Failed ({self.config['port']}): {e}")
        finally:
            self.cleanup()

    def cleanup(self):
        self.running = False
        if self.ser and self.ser.is_open:
            self.ser.close()
        if self.sock:
            self.sock.close()
        print(f"Device {self.config['port']} resources released")

if __name__ == "__main__":
    threads = []
    for device in DEVICES:
        handler = BluetoothHandler(device)
        handler.start()
        threads.append(handler)

    try:
        while True:
            pass
    except KeyboardInterrupt:
        print("\nStopping threads...")
        for t in threads:
            t.running = False
        for t in threads:
            t.join()
        print("All threads stopped")

主要改进说明:

  1. 多设备支持
  • 使用线程为每个蓝牙设备创建独立的数据通道
  • 配置文件DEVICES支持灵活扩展设备数量
  1. 数据区分
  • 为每个设备添加唯一标识符tag
  • 使用不同端口号区分数据流(12345和12346)
  • 数据格式示例:DEVICE00:48656c6c6f(标识+HEX数据)(已更改为不发送标识符)
  1. 稳定性增强
  • 独立的异常处理机制(单个设备故障不影响其他设备)
  • 完善的资源释放机制
  • 支持键盘中断退出

主要改动说明:

  1. 移除标识符
    删除 formatted 相关代码,直接发送原始字节数据:

     

    python

    self.sock.sendall(data)  # 原代码发送的是带标签的字符串
  2. 简化配置
    移除配置中的 'tag' 字段,通过端口号区分设备:

     

    python

    'server_port': 12345  # 设备1使用12345端口
    'server_port': 12346  # 设备2使用12346端口
  3. 日志优化
    打印信息改为通过端口号和串口号标识设备:

     

    python

    print(f"Device {self.config['port']} connected...")

 

 注意:两个用于连接pc然后使用软件的蓝牙,都必须是从机状态(绿灯),否则无法被软件识别

更改为从机的指令为

"AT+ROLE=2/r/n"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值