在蓝牙插座上使用pySerialTransfer。

问题描述 投票:0回答:1

我有一段工作代码,当设备通过USB电缆连接时,使用pySerialTransfer将一个结构体从Raspberry Pi发送到Arduino。但是,我想通过蓝牙而不是USB线来实现。

独立地,使用单独的python代码和单独的Arduino草图,我已经能够让Raspberry Pi & Arduino通过蓝牙通过连续的文本或二进制数据流进行通信。

我的问题是,我不知道如何将这两种方法结合起来--即:如果我通过蓝牙发送一个二进制编码的结构,我不知道如何获得pySerialTransfer串行传输库的好处,在接收端解析它。 我看到我可以 "手动 "进行解析,寻找特殊的终止符等,但我希望通过pySerialTransfer避免这种需要。

谢谢你的任何指点建议和例子。到目前为止,我能够构建的所有工作代码都在这里。

pySerialTransfer

工作的Arduino C序列代码

#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")
python bluetooth pyserial
1个回答
0
投票

pySerialTransfer SerialTransfer将安排数据包格式与CRC,所以它快速和安全的方式通过串行通信。

事实上,没有特殊的字符来终止数据包,因为二进制数据可以是任何字符从0x00到0xFF覆盖所有的ASCII码。


0
投票

我无法让socket连接持续超过几个小时(见 检测和恢复 "挂起 "的蓝牙Python连接。); 也许我的套接字尝试是一个不正确的或至少是不必要的技术组合,因为使用pySerialTransfer的最终目标。回归到仅仅是串行,我最终能够让这个代码在我的Raspberry Pi和Arduino之间通过蓝牙进行双向RFCOMM串行通信。

Python代码

#!/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);

}

这将产生类似下面的输出。

Python bt.log

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>
© www.soinside.com 2019 - 2024. All rights reserved.