Adafruit LoRa RFM96W分块传输numpy数组后重塑失败求助
分块传输numpy数组时的接收异常解决方法
问题场景
我有一个shape为(8,64)的numpy数组,经array.tobytes()转换后长度为512字节,但adafruit_rfm9x库的send()函数存在252字节的payload限制。尝试分块传输后,接收端抛出异常:
ValueError: cannot reshape array of size 8 into shape (8,64)
错误原因
当前的传输逻辑存在两个核心问题:
- 接收端仅通过当前数据包长度是否小于252判断传输结束,若出现丢包(比如只收到最后一块8字节的数据包),会提前终止接收,导致数据不完整。
- 无线传输可能出现丢包、乱序,现有逻辑没有块序号和总块数标识,无法确认是否收齐所有数据。
修复方案:添加块序号与总块数标识
在每个数据包中嵌入总块数和当前块序号,让接收端明确知道需要接收的块数量,同时通过字典存储块解决乱序问题,结合ACK机制确保每块传输可靠。
1. 发送端代码修改
预留2字节用于存储块信息(总块数+当前块序号),将有效数据块大小设为250,确保整个数据包(2+250=252)不超过payload限制,并添加重试逻辑:
import time def send_message(key, value): print(f"Sending {key} to Dev 2...") if not isinstance(value, bytes): value = bytes(value, 'utf-8') MAX_CHUNK_SIZE = 250 # 预留2字节头部,有效数据块设为250 total_len = len(value) num_chunks = (total_len + MAX_CHUNK_SIZE - 1) // MAX_CHUNK_SIZE # 向上取整计算总块数 for i in range(num_chunks): chunk_data = value[i * MAX_CHUNK_SIZE: (i + 1) * MAX_CHUNK_SIZE] # 构造头部:第1字节总块数,第2字节当前块序号(从1开始) header = bytes([num_chunks, i+1]) packet = header + chunk_data # 发送并等待ACK,失败则重试 success = rfm9x.send_with_ack(packet) if not success: print(f"Chunk {i+1} send failed, retrying...") i -= 1 time.sleep(0.5) continue print(f"Sent chunk {i+1}/{num_chunks}") print(f"{key} has been sent")
2. 接收端代码修改
解析每个数据包的头部信息,用字典按序号存储块,确认收齐所有块后再合并数据:
def receive_message(key): print(f"Receiving {key} from Dev 1 ...") MAX_CHUNK_SIZE = 250 received_chunks = {} total_chunks = None while True: data = rfm9x.receive(with_ack=True) if data is not None and len(data) >= 2: # 解析头部信息 total_chunks = data[0] current_chunk_idx = data[1] chunk_data = data[2:] # 仅存储有效范围内的块 if 1 <= current_chunk_idx <= total_chunks: received_chunks[current_chunk_idx] = chunk_data print(f"Received chunk {current_chunk_idx}/{total_chunks}") # 检查是否收齐所有块 if len(received_chunks) == total_chunks: # 按序号排序合并数据 received_data = b'' for idx in range(1, total_chunks+1): received_data += received_chunks[idx] print(f"Received {key} completely") return received_data time.sleep(0.1)
3. 验证步骤
- 发送端执行:
send_message("Data", nparray.tobytes()) - 接收端执行:
Data = receive_message("Data") result = np.frombuffer(Data, dtype=np.int8).reshape(8, 64)
此时接收端能完整获取512字节数据,正常重构为(8,64)的numpy数组。
内容的提问来源于stack exchange,提问作者a15600712
相关产品推荐
相关产品推荐

