用相同的参数初始化两个Python 类,得到不同的结果

Initialize two Python classes with same arguments, get different results

Objective: 理解关于两个 classes 使用相同参数初始化并产生不同结果的奇怪行为。

背景:

我的项目涉及 Raspberry Pi 3 通过串行(通过 USB 端口)通信与 Arduino MEGA 上的各种传感器通信。通讯协议简单

Raspberry Pi发送两个字节:

  1. 传感器的地址(例如'\x04'
  2. 可以包含其他命令的第二个空字节(例如'\x00'

MEGA等待两个字节,然后根据大case/switch树回复请求的信息。

我已经用 Python classes 封装了处理各种传感器的代码。给我带来麻烦的是 Encoder() class。这是一个最小的例子:

import serial

class Encoder(object):
    def __init__(self, hex_name):
        self.hex_name = hex_name

    def value(self):
        temp = self.hex_name + '\x00'
        arduino.write(temp)
        return int(arduino.readline())

if __name__ == '__main__':
    arduino = serial.Serial('/dev/ttyACMO', 115200)

    encoder_one = Encoder('\x03')
    encoder_two = Encoder('\x04')

    print encoder_one.value()
    print encoder_two.value()

Arduino 处理请求如下图:

if(Serial.available() >= 2){
    temp1 = Serial.read();
    temp2 = Serial.read();

    switch(temp1){
        case 1:
          ...
        case 3:
            Serial.println(positionLeft);
            break;
        case 4:
            Serial.println(positionRight);
            break;
        case 5:
         ...
    }
}

问题:

我从编码器中得到了无意义的值。特别令人担忧的是,当我用 same hex_name(即 '\x04')初始化两个编码器时,我从 encoder_one.value() 和 [=21 得到不同的值=].

假设:

  1. class 结构有些错误。

在将它封装到 class 之前,我已经可以正常工作了。我想知道我是否将 encoder_oneencoder_two 分配给同一个对象或类似的愚蠢的东西。

我在 value() 中的 return 之前添加了一行,用于打印 hex_name(即 print self.hex_name)。当我将两个编码器都设置为 '\x04' 时,我打印了相同的非字母数字字符。当我将一个编码器设置为 '\x03' 并将另一个编码器设置为 '\x04' 时,我得到了两个不同的非字母数字字符——一个是之前测试的字符。

  1. 通信中的帧偏移。

MEGA 需要两个字节。它等待两个字节,发送请求的信息,然后清除缓冲区。在我的 Python 程序中将十六进制值存储为字符串是可能的,当它执行 arduino.write() 时会添加一个额外的字节。类似于 \n 或其他不可打印的字符。

结论:

我已经花了大约三个小时研究这个错误,我认为解决它需要一些关于 classes 如何工作的信息,但我不明白。

原来是第二个假设。十六进制字节的连接步骤中显然包含一些不可打印的字符。切换到以下顺序解决了问题。

编辑: 我发现在 write() 之后立即执行 readline() 会出现间歇性错误。我在两个操作之间添加了 10 毫秒的延迟。

旧:

def value(self):
    temp = self.hex_name + '\x00'
    arduino.write(temp)
    return int(arduino.readline())

新:

def value(self):
    arduino.write(self.hex_name)
    arduino.write('\x00')
    time.sleep(0.010)
    return int(arduino.readline())

完整的(现在可用的)示例如下所示。

import serial

class Encoder(object):
    def __init__(self, hex_name):
        self.hex_name = hex_name

    def value(self):
        arduino.write(self.hex_name)
        arduino.write('\x00')
        time.sleep(0.010)
        return int(arduino.readline())

if __name__ == '__main__':
    arduino = serial.Serial('/dev/ttyACMO', 115200)

    encoder_one = Encoder('\x03')
    encoder_two = Encoder('\x04')

    print encoder_one.value()
    print encoder_two.value()