在蓝牙套接字上使用pySerialTransfer [英] Using pySerialTransfer over bluetooth sockets
问题描述
我有工作代码,当通过USB电缆连接设备时,可以使用pySerialTransfer从Raspberry Pi向Arduino发送一个结构.但是,我想通过蓝牙而不是使用USB电缆来做到这一点.
I have working code that sends a struct from a Raspberry Pi to an Arduino using pySerialTransfer when the devices are connected via a USB cable. I'd like to do that over bluetooth instead of with a USB cable, however.
我可以使用单独的python代码和单独的Arduino草图独立获得Raspberry Pi& Arduino通过连续的文本或二进制数据流通过蓝牙进行通信.
Independently, using separate python code and a separate Arduino sketch, I've been able to get the Raspberry Pi & Arduino to communicate over bluetooth via a continuous stream of text or binary data.
我的问题是我看不到如何结合这两种方法-即:如果我通过蓝牙发送二进制编码的结构,我看不到如何获得pySerialTransfer/SerialTransfer库的好处它在接收端.我看到了如何手动"解析,寻找特殊的终止字符等,但是我希望避免使用pySerialTransfer.
My issue is that I don't see how to combine the two approaches - i.e.: if I send a binary-encoded structure over bluetooth, I don't see how I get the benefits of the pySerialTransfer / SerialTransfer libraries to parse it on the receiving end. I see how I can do the parsing "manually", looking for special terminating characters, etc., but I was hoping to avoid the need for that with pySerialTransfer.
感谢您提供任何指导/建议/示例.到目前为止,我已经能够构建的所有工作代码都在这里.
Thanks for any pointers / suggestions / examples. All the working code I've been able to construct so far is here.
#include "SerialTransfer.h"
SerialTransfer myTransfer;
int const ONBOARD_LED_PIN = 13;
struct POSITION {
int id;
float azimuth;
float altitude;
} position;
void Blink(int n) {
for (int i=0; i<n; i++) {
digitalWrite(ONBOARD_LED_PIN, HIGH);
delay(75);
digitalWrite(ONBOARD_LED_PIN, LOW);
delay(75);
}
delay(150);
}
void setup()
{
Serial.begin(115200);
myTransfer.begin(Serial);
pinMode(ONBOARD_LED_PIN, OUTPUT);
digitalWrite(ONBOARD_LED_PIN, LOW);
}
void loop()
{
if(myTransfer.available())
{
//////////////////////////////////////////////
// handle call from Python
myTransfer.rxObj(position, sizeof(position));
//////////////////////////////////////////////
//////////////////////////////////////////////
// send response
myTransfer.txObj(position, sizeof(position));
myTransfer.sendData(sizeof(position));
//////////////////////////////////////////////
}
else if(myTransfer.status < 0)
{
Serial.print("ERROR: ");
if(myTransfer.status == -1)
Serial.println(F("CRC_ERROR"));
else if(myTransfer.status == -2)
Serial.println(F("PAYLOAD_ERROR"));
else if(myTransfer.status == -3)
Serial.println(F("STOP_BYTE_ERROR"));
}
}
有效的Raspberry Pi序列号
import time
import struct
from pySerialTransfer import pySerialTransfer
def StuffObject(txfer_obj, val, format_string, object_byte_size, start_pos=0):
"""Insert an object into pySerialtxfer TX buffer starting at the specified index.
Args:
txfer_obj: txfer - Transfer class instance to communicate over serial
val: value to be inserted into TX buffer
format_string: string used with struct.pack to pack the val
object_byte_size: integer number of bytes of the object to pack
start_pos: index of the last byte of the float in the TX buffer + 1
Returns:
start_pos for next object
"""
val_bytes = struct.pack(format_string, *val)
for index in range(object_byte_size):
txfer_obj.txBuff[index + start_pos] = val_bytes[index]
return object_byte_size + start_pos
if __name__ == '__main__':
try:
link = pySerialTransfer.SerialTransfer('/dev/cu.usbmodem14201', baud=115200)
link.open()
time.sleep(2) # allow some time for the Arduino to completely reset
base = time.time()
while True:
sent = (4, 1.2, 2.5)
format_string = '<lff'
format_size = 4+4+4
StuffObject(link, sent, format_string, format_size, start_pos=0)
link.send(format_size)
start_time = time.time()
elapsed_time = 0
while not link.available() and elapsed_time < 2:
if link.status < 0:
print('ERROR: {}'.format(link.status))
else:
print('.', end='')
elapsed_time = time.time()-start_time
print()
response = bytearray(link.rxBuff[:link.bytesRead])
response = struct.unpack(format_string, response)
print('SENT: %s' % str(sent))
print('RCVD: %s' % str(response))
print(' ')
except KeyboardInterrupt:
link.close()
蓝牙通信
正在工作的Arduino蓝牙通信
#include "SerialTransfer.h"
// Connect the HC-05 TX to Arduino pin 2 RX.
// Connect the HC-05 RX to Arduino pin 3 TX through a voltage divider.
//
long n = 0;
struct POSITION {
float azimuth=5;
float altitude=10;
};
SerialTransfer myTransfer;
void setup()
{
Serial.begin(9600);
// HC-06 default serial speed for communcation mode is 9600
Serial1.begin(9600);
myTransfer.begin(Serial1);
}
void loop()
{
n++;
POSITION x;
x.azimuth=n;
x.altitude=n+1;
myTransfer.txObj(x, sizeof(x));
myTransfer.sendData(sizeof(x));
if(Serial1.available() > 0){ // Checks whether data is comming from the serial port
Serial.println(Serial1.read());} // Reads the data from the serial port
delay(1000);
}
正在工作的python蓝牙通信
import bluetooth
sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
bd_addr = '98:D3:11:FC:42:16'
port = 1
sock.connect((bd_addr, port))
d = sock.recv(10240000)
print(d)
sock.send("hello")
推荐答案
我无法使套接字连接持续超过几个小时(请参阅);鉴于使用pySerialTransfer的最终目标,也许我的套接字尝试是技术的不正确或至少不必要的组合.回到串行,我最终得以使此代码适用于我的Raspberry Pi和Arduino之间通过蓝牙进行的双向RFCOMM串行通信.
I could not get the socket connection to last more than a few hours (see Detecting and recovering from "hanging" bluetooth python connection ); perhaps my socket attempt was an incorrect or at least unnecessary combination of technologies given ultimate goal of using pySerialTransfer. Falling back to just serial, I ultimately was able to get this code working for bidirectional RFCOMM serial communication between my Raspberry Pi and Arduino over bluetooth.
#!/usr/bin/python3
import datetime
import sys
import time
import subprocess
from pySerialTransfer import pySerialTransfer
COMMAND_START_CHAR = '<'
COMMAND_END_CHAR = '>'
LOGFILE = 'bt.log'
def Log(s):
"""Appends message s to the logfile."""
with open(LOGFILE, 'a') as f:
f.write('%s\n' % s)
def Time(epoch):
"""Converts epoch to easy-to-read string."""
return datetime.datetime.fromtimestamp(epoch).strftime('%Y-%m-%d %H:%M:%S')
def ConnectBluetoothRetry(attempts=1):
"""Attempts to make connections for a number of attempts, exiting program on fail."""
attempt = 1
while attempt <= attempts:
try:
ser = pySerialTransfer.SerialTransfer('/dev/rfcomm1', 9600)
except pySerialTransfer.InvalidSerialPort as e:
Log('ERROR: Unbound; will attempt to bind: %s' % e)
cmd = 'sudo rfcomm bind 1 98:D3:11:FC:42:16 1'
conn = subprocess.Popen(cmd, shell=True)
if conn.returncode is None:
Log('ERROR: Unable to bind')
sys.exit()
else:
Log('Connection bound with return code %s' % conn.returncode)
if attempt == attempts:
attempts += 1
Log('Allowing one more attempt to connect')
if ser:
Log('Connected after %d attempts' % attempt)
return ser
attempt += 1
if attempt < attempts:
time.sleep(1)
Log('ERROR: Failed to connect after %d attempts' % attempt)
sys.exit()
def ReconnectOnError(ser, error=None):
"""Close and reopen the serial."""
if error:
Log('ERROR: %s' % error)
ser.close()
ser = ConnectBluetoothRetry(10)
return ser
def Parse(s):
"""Returns the string encapsulated between COMMAND_START_CHAR and COMMAND_END_CHAR."""
if COMMAND_START_CHAR in s:
start_char = s.find(COMMAND_START_CHAR)
else:
return None
if COMMAND_END_CHAR in s:
end_char = s.rfind(COMMAND_END_CHAR)
else:
return None
return s[start_char + len(COMMAND_START_CHAR): end_char - len(COMMAND_END_CHAR) + 1]
def Read(ser):
"""Non-blocking read on an open Bluetooth pySerialTransfer."""
recv = ''
if ser.available():
if ser.status < 0:
if ser.status == -1:
Log('ERROR: CRC_ERROR')
elif ser.status == -2:
Log('ERROR: PAYLOAD_ERROR')
elif ser.status == -3:
Log('ERROR: STOP_BYTE_ERROR')
else:
for index in range(ser.bytesRead):
recv += chr(ser.rxBuff[index])
if recv:
command = Parse(recv)
if command is not None:
command = recv[len(COMMAND_START_CHAR):-len(COMMAND_END_CHAR)]
return command
Log('ERROR: malformed %s' % recv)
return None
def Write(ser, command):
"""Sends the encapsulated string command on an open Bluetooth pySerialTransfer."""
send = COMMAND_START_CHAR+str(command)+COMMAND_END_CHAR
byte_count = ser.tx_obj(send)
ser.send(byte_count)
Log('Sent %s' % send)
def main():
"""Sends sequential numbers over bluetooth, and receives & parses anything sent."""
sys.stderr = open(LOGFILE, 'a')
start = time.time()
last_write = start
Log('Started at %s' % Time(start))
ser = ConnectBluetoothRetry(10)
x = 0
while True:
try:
command = Read(ser)
except Exception as e:
ser = ReconnectOnError(ser, 'Failed to receive: %s' % e)
if command is not None:
Log('Recd: %s; runtime: %.3f hours' % (command, (time.time() - start) / 60**2))
if time.time() - last_write > 1:
last_write = time.time()
try:
Write(ser, x)
except Exception as e:
ser = ReconnectOnError(ser, 'Failed to send: %s' % e)
x += 1
time.sleep(.1)
if __name__ == "__main__":
main()
Arduino代码
#include "SerialTransfer.h"
// Connect the HC-05 TX to Arduino pin 2 RX.
// Connect the HC-05 RX to Arduino pin 3 TX through a voltage divider.
//
SerialTransfer myTransfer;
char number[12];
unsigned long n = 1;
long last_mesg_received = 0;
long last_mesg_sent = 0;
void(* resetFunc) (void) = 0; //declare reset function @ address 0
void setup()
{
Serial.begin(9600);
// HC-05 default serial speed for communcation mode is 9600
Serial1.begin(9600);
myTransfer.begin(Serial1);
last_mesg_received = millis();
}
void Read(){
if(myTransfer.available())
{
Serial.print("Recd: ");
for(byte i = 0; i < myTransfer.bytesRead; i++)
Serial.write(myTransfer.rxBuff[i]);
Serial.println();
}
else if(myTransfer.status < 0)
{
Serial.print("ERROR: ");
if(myTransfer.status == -1)
Serial.println(F("CRC_ERROR"));
else if(myTransfer.status == -2)
Serial.println(F("PAYLOAD_ERROR"));
else if(myTransfer.status == -3)
Serial.println(F("STOP_BYTE_ERROR"));
}
}
void Write(){
sprintf(number, "<%d>", n);
int len = strlen(number) + 1;
for(int x; x<len; x++){
myTransfer.txBuff[x+1] = number[x];
}
Serial.print("Sent: ");
Serial.println(number);
myTransfer.sendData(len);
}
void loop()
{
Read();
if (millis() - last_mesg_sent > 1000){
Write();
last_mesg_sent = millis();
n++;
}
delay(100);
}
这将产生如下输出:
Started at 2020-05-05 09:04:47
Connected after 1 attempts
Sent <0>
Sent <1>
Sent <2>
Recd: <1; runtime: 0.001 hours
Recd: <1; runtime: 0.001 hours
Recd: <2; runtime: 0.001 hours
Recd: <3; runtime: 0.001 hours
Sent <3>
Recd: <4; runtime: 0.001 hours
Sent <4>
Recd: <5; runtime: 0.002 hours
Sent <5>
Recd: <6; runtime: 0.002 hours
Sent <6>
Sent <7>
Recd: <7; runtime: 0.002 hours
Sent <8>
Recd: <8; runtime: 0.003 hours
Sent <9>
Recd: <9; runtime: 0.003 hours
Sent <10>
Recd: <10; runtime: 0.003 hours
Sent <11>
Recd: <11; runtime: 0.003 hours
Sent <12>
Recd: <12; runtime: 0.004 hours
Sent <13>
Recd: <13; runtime: 0.004 hours
Sent <14>
Recd: <14; runtime: 0.004 hours
Sent <15>
Recd: <15; runtime: 0.005 hours
Sent <16>
Recd: <16; runtime: 0.005 hours
Sent <17>
Arduino串行监视器
09:04:49.591 -> Sent: <1>
09:04:50.564 -> Sent: <2>
09:04:51.368 -> Recd: <0>
09:04:51.477 -> Recd: <1>
09:04:51.583 -> Recd: <2>
09:04:51.687 -> Sent: <3>
09:04:52.080 -> Recd: <3>
09:04:52.777 -> Sent: <4>
09:04:52.997 -> Recd: <4>
09:04:53.804 -> Sent: <5>
09:04:54.096 -> Recd: <5>
09:04:54.896 -> Sent: <6>
09:04:55.083 -> Recd: <6>
09:04:55.995 -> Sent: <7>
09:04:56.104 -> Recd: <7>
09:04:56.970 -> Sent: <8>
09:04:57.073 -> Recd: <8>
09:04:58.084 -> Recd: <9>
09:04:58.084 -> Sent: <9>
09:04:59.106 -> Recd: <10>
09:04:59.174 -> Sent: <10>
09:05:00.087 -> Recd: <11>
09:05:00.197 -> Sent: <11>
09:05:01.111 -> Recd: <12>
09:05:01.291 -> Sent: <12>
09:05:02.091 -> Recd: <13>
09:05:02.380 -> Sent: <13>
09:05:03.103 -> Recd: <14>
09:05:03.390 -> Sent: <14>
09:05:04.087 -> Recd: <15>
09:05:04.518 -> Sent: <15>
09:05:05.091 -> Recd: <16>
09:05:05.607 -> Sent: <16>
这篇关于在蓝牙套接字上使用pySerialTransfer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!