在蓝牙套接字上使用pySerialTransfer [英] Using pySerialTransfer over bluetooth sockets

查看:94
本文介绍了在蓝牙套接字上使用pySerialTransfer的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有工作代码,当通过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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆