Python: Testing Serial Ports for Answer

Python测试串口的回答:

问题 (Question)

I'm trying to build a short code that will test all Serial COM ports (I'm on windows) for reply. For example, I have a Arduino connected on COM3, and when it connects, it sends a serial message.

I want that when I run the python script it automatically detects which is the right COM port to use.

I have the function that lists all the ports, but I can't make it work to test all of them and detect in which the arduino is connected.

Python:

import serial
import time
import _winreg as winreg
import itertools
import datetime

def enumerate_serial_ports():
    """ Uses the Win32 registry to return an
        iterator of serial (COM) ports
        existing on this computer.
    """
    path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
    try:
        key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
    except WindowsError:
        raise IterationError

    for i in itertools.count():
        try:
            val = winreg.EnumValue(key, i)
            yield str(val[1])
        except EnvironmentError:
            break

connected = False

for porta in enumerate_serial_ports():
    print "TRYING PORT: " + porta
    start = datetime.datetime.now()
    delta=0
    ser = serial.Serial(porta,9600,timeout=0)
    if ser.isOpen():
        while ser.isOpen() and delta < 1:
            delta = (datetime.datetime.now()-start).seconds
            r = ser.read()
            if r == None:
                print "connected!"

Arduino Code

void setup(){
  // Open serial connection.
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  Serial.write(6); 
}

void loop(){ 

} 

Thank you!!

我想建立一个短码串行COM端口,将测试所有(我在Windows)的答复。例如,我有一个Arduino连接COM3,当它连接,它发送一个串行消息。

我想,当我运行Python脚本,它会自动检测并正确使用COM端口。

我有功能,列出了所有的港口,但我不能使它工作都测试和检测,Arduino的连接。

Python

import serial
import time
import _winreg as winreg
import itertools
import datetime

def enumerate_serial_ports():
    """ Uses the Win32 registry to return an
        iterator of serial (COM) ports
        existing on this computer.
    """
    path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
    try:
        key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
    except WindowsError:
        raise IterationError

    for i in itertools.count():
        try:
            val = winreg.EnumValue(key, i)
            yield str(val[1])
        except EnvironmentError:
            break

connected = False

for porta in enumerate_serial_ports():
    print "TRYING PORT: " + porta
    start = datetime.datetime.now()
    delta=0
    ser = serial.Serial(porta,9600,timeout=0)
    if ser.isOpen():
        while ser.isOpen() and delta < 1:
            delta = (datetime.datetime.now()-start).seconds
            r = ser.read()
            if r == None:
                print "connected!"

Arduino的代码

void setup(){
  // Open serial connection.
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  Serial.write(6); 
}

void loop(){ 

} 

谢谢你!!

最佳答案 (Best Answer)

This is a common problem in that there is no "connection" for serial ports. As you see, when you open() a serial port, that has no relation to whether something is plugged in on the other end of the wires. All the open() calls are doing is establishing the handles to the serial port hardware inside that machine. The open() guarantees nothing about the other side of the cable.

The concept of "connection" is something you must create. Connections are normally created by some protocol handshake between the two devices that establishes to both that they are talking to who they expect.

Two general approaches are:

  • probe and check for a response
  • listen for a beacon

I warn in this related question that the first approach of pushing bytes at an unknown device is not the safest approach:

Related question

You have chosen the second approach where the Python side passively listens for a beacon. You need something similar to this, where you receive some predefined message and respond when you receive:

// loop for a short time listening for a *
if r != None:
    if r.endswith("*"):
        ser.write("I_hear_you")
        print "connected"

The Arduino side powers up and broadcasts the beacon. It continues to broadcast until someone answers

beaconmode = True;

void loop() {
   if (beaconmode) {
     delay(1000);
     Serial.write("*");
     // Serial.read() and check for "I_hear_you"
     if (someone heard my beacon) {
       beaconmode = false;
       // now the two devices are "connected"
       connectedmode = true;
   }
   if (connectedmode) {
     // do normal stuff
   }
}

If you are seeking to be even more robust, this handshake could be expanded one step. As it is, it only confirms that the Python side heard the Arduino side. The added step would be for the Arduino to acknowledge by transmitting "I heard that you heard me". Then you would have something similar to how the 3 way handshake used to establish TCP connections. .

这是一个共同的问题,没有“串行端口连接”。正如你所看到的,当你open()串行端口,这东西是否是插在导线的另一端没有关系。所有的open()电话所做的是建立在机串口硬件处理。该open()无法保证电缆的另一边。

“连接”就是你要创造的概念。连接通常是由一些握手协议的两个设备之间建立两个,他们是谁他们期望。

一般有两种方法:

  • 探针检查反应
  • 听一个信标

我警告这一相关的问题,在一个未知的设备发送的第一个字节的方法是不安全的方法:

相关问题

你选择了第二种方法在Python侧被动地听一信标。你需要一些类似的事情,你在哪里得到一些预定义消息和回应的时候,你收到:

// loop for a short time listening for a *
if r != None:
    if r.endswith("*"):
        ser.write("I_hear_you")
        print "connected"

Arduino侧的力量和广播信标。它继续播放直到有人回答

beaconmode = True;

void loop() {
   if (beaconmode) {
     delay(1000);
     Serial.write("*");
     // Serial.read() and check for "I_hear_you"
     if (someone heard my beacon) {
       beaconmode = false;
       // now the two devices are "connected"
       connectedmode = true;
   }
   if (connectedmode) {
     // do normal stuff
   }
}

如果你正在寻找更加稳健,这可以扩大一步握手。因为它是,它只能表明Python一边听到Arduino侧。附加步骤是Arduino承认通过发送“我听说你听我的”。然后你会有一些类似于3次握手建立TCP连接。

本文翻译自StackoverFlow,英语好的童鞋可直接参考原文:http://stackoverflow.com/questions/22081560