首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用pymodbus作为串行/RTU主机运行ArduinoModbus的Modbus丢失字节错误

使用pymodbus作为串行/RTU主机运行ArduinoModbus的Modbus丢失字节错误
EN

Stack Overflow用户
提问于 2022-11-24 05:25:53
回答 1查看 50关注 0票数 0

我面临一些与Modbus RTU实现有关的问题。我有2x Arduino MKR和RS485 hats/扩展作为我的2个从设备(使用ArduinoModbus库)。我正在尝试使用python和pymodbus库轮询我的个人电脑(Windows)上的设备,运行速度为9600波特。

我可以成功地传输数据。最初的理智测试是一个简单的analogRead()在一个Arduino(传感器1)上,写入它的内部保持寄存器,然后进行pymodbus主投票/注册请求。

我现在连接了第二个Arduino (传感器2),它有一个I2C连接到一个流传感器。arduino正在运行,通过I2C读取传感器,并用数据更新5倍的保存寄存器。主机(PC)一个接一个地轮询Arduino(传感器1和传感器2)。它总是成功地获取传感器1的数据(只有一个寄存器),但间歇性地失败了获取传感器2的数据(5个寄存器)。python控制台如下所示:

代码语言:javascript
复制
Sensor 2: 0,25000,0,0, 0
Sensor 2: 0,25000,0,0, 0
Modbus Error: [Input/Output] No Response received from the remote unit/Unable to decode response
Modbus Error: [Input/Output] No Response received from the remote unit/Unable to decode response
Sensor 2: 0,25000,0,0, 0
Modbus Error: [Input/Output] No Response received from the remote unit/Unable to decode response
Sensor 2: 0,25000,0,0, 0
Modbus Error: [Input/Output] No Response received from the remote unit/Unable to decode response

对日志进行更深入的研究就会发现,这个问题并不是所有Bytes人都在解决的问题,如下所示:

代码语言:javascript
复制
11/24/2022 03:52:59 PM Running transaction 4
11/24/2022 03:52:59 PM SEND: 0x1 0x3 0x0 0x0 0x0 0x5 0x85 0xc9
11/24/2022 03:52:59 PM Changing state to IDLE - Last Frame End - 1669265577.447308, Current Time stamp - 1669265579.457942
11/24/2022 03:52:59 PM New Transaction state "SENDING"
11/24/2022 03:52:59 PM Changing transaction state from "SENDING" to "WAITING FOR REPLY"
11/24/2022 03:52:59 PM {msg_start} received, Expected 15 bytes Received 11 bytes !!!!
11/24/2022 03:52:59 PM Changing transaction state from "WAITING FOR REPLY" to "PROCESSING REPLY"
11/24/2022 03:52:59 PM RECV: 0x1 0x3 0xa 0x0 0x0 0x61 0xa8 0x0 0x0 0x0 0x0
11/24/2022 03:52:59 PM Frame - [b'\x01\x03\n\x00\x00a\xa8\x00\x00\x00\x00'] not ready
11/24/2022 03:52:59 PM Getting transaction 1
11/24/2022 03:52:59 PM Changing transaction state from "PROCESSING REPLY" to "TRANSACTION_COMPLETE"
11/24/2022 03:52:59 PM Modbus Error: [Input/Output] No Response received from the remote unit/Unable to decode response
11/24/2022 03:53:01 PM Current transaction state - TRANSACTION_COMPLETE

现在,我已经完全删除了向传感器1请求数据,并且我的python脚本只能从传感器2(问题传感器)请求,但问题仍然存在,我的python脚本如下所示:

代码语言:javascript
复制
import serial
import time
import logging
from pymodbus.client import ModbusSerialClient
from pymodbus.transaction import ModbusRtuFramer

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler('main.log', 'w', 'utf-8')
handler.setFormatter(logging.Formatter(fmt='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p'))
logger.addHandler(handler)

client = ModbusSerialClient("COM12", ModbusRtuFramer, baudrate=9600, timeout=10, reset_socket=False)
client.connect()

while(1):

    c2 = client.read_holding_registers(0,5,1)
    if c2.isError():
        logger.error(msg=c2)
        print(c2)
    else:    
        print(f"Sensor 2: {c2.getRegister(0)},{c2.getRegister(1)},{c2.getRegister(2)},{c2.getRegister(3)}, {c2.getRegister(4)}")
    
    time.sleep(2)

我不太确定什么是失火..。我可以很好地使用像QModMaster这样的图形用户界面来处理传感器2的数据,我知道它在引擎盖下使用libmodbus。我应该使用python库pylibmodbus吗?它需要本地编译的libmodbus,这对Windows来说有点麻烦.

我是不是漏掉了一个能帮上忙的pymodbus设置?

我已经尝试过更改pymodbus超时,但没有起作用。我尝试降低流量传感器的采样率,以降低频率,并确保Arduino是免费的/可用于Modbus请求。这是行不通的,事实上,减少它使问题变得更糟。

我尝试向python代码(time.sleep(2))添加基本延迟,以减缓Modbus请求的速度,但这对错误没有影响。

希望有人知道发生了什么,因为我已经花了很长时间在网上搜索资源,以找到答案,但没有用。如果我最后需要更多的澄清,我可以提供:)

谢谢!

P.S. Arduino代码,供参考

代码语言:javascript
复制
#include <Arduino.h>
#include <ArduinoRS485.h>
#include <ArduinoModbus.h>
#include <Wire.h>

/**
 * Modbus slave/server
*/

#define SAMPLE_RATE 50

const int ADDRESS = 0x08; // Sensor I2C Address
const float SCALE_FACTOR_FLOW = 500.0; // Scale Factor for flow rate measurement
const float SCALE_FACTOR_TEMP = 200.0; // Scale Factor for temperature measurement

int count = 0;
unsigned long startMillis;
unsigned long currentMillis;

enum error_types{
  no_error,
  write_mode_error, 
  read_error
  };

enum error_types error; 

// Protoypes
int stop_continuous_measurement();
int start_continous_measurement();

void setup() {
  int ret;

  // Start Serial and I2C
  Serial.begin(9600); // initialize serial communication
  Wire.begin();       // join i2c bus (address optional for master)

  // Set up MODBUS
  if (!ModbusRTUServer.begin(0x01,9600)) {
    Serial.println("Could not begin ModbusRTU server...");
    while(1);
  }

  // configure holding registers at address 0x00, 4 registers for data
  ModbusRTUServer.configureHoldingRegisters(0x00, 5);

  // start sensor
  do {
    // Soft reset the sensor
    Wire.beginTransmission(0x00);
    Wire.write(0x06);
    ret = Wire.endTransmission();
    if (ret != 0) {
      Serial.println("Error while sending soft reset command, retrying...");
      delay(500); // wait long enough for chip reset to complete
    }
  } while (ret != 0);

  delay(50); // wait long enough for chip reset to complete

  // To perform a measurement, first send 0x3608 to switch to continuous
  if(start_continous_measurement() !=0) {
    error = write_mode_error;
  }

  startMillis = millis();
}

void loop() {

  ModbusRTUServer.poll();

  uint16_t aux_value;
  uint16_t sensor_flow_value;
  uint16_t sensor_temp_value;
  int16_t signed_flow_value;
  int16_t signed_temp_value;
  float scaled_flow_value;
  float scaled_temp_value;
  byte aux_crc;
  byte sensor_flow_crc;
  byte sensor_temp_crc;

  // measurement mode (H20 calibration), then read 3x (2 bytes + 1 CRC byte) from the sensor.
  // To perform a IPA based measurement, send 0x3615 instead.
  // Check datasheet for available measurement commands.

  error = no_error;

  currentMillis = millis();

  if(currentMillis - startMillis > SAMPLE_RATE){
    Wire.requestFrom(ADDRESS, 9);
    if (Wire.available() < 9) {
      error = read_error;
    }
    else{
      sensor_flow_value  = Wire.read() << 8; // read the MSB from the sensor
      sensor_flow_value |= Wire.read();      // read the LSB from the sensor
      sensor_flow_crc    = Wire.read();
      sensor_temp_value  = Wire.read() << 8; // read the MSB from the sensor
      sensor_temp_value |= Wire.read();      // read the LSB from the sensor
      sensor_temp_crc    = Wire.read();
      aux_value          = Wire.read() << 8; // read the MSB from the sensor
      aux_value         |= Wire.read();      // read the LSB from the sensor
      aux_crc            = Wire.read();

      signed_flow_value = (int16_t) sensor_flow_value;
      scaled_flow_value = ((float) signed_flow_value) / SCALE_FACTOR_FLOW;

      signed_temp_value = (int16_t) sensor_temp_value;
      scaled_temp_value = ((float) signed_temp_value) / SCALE_FACTOR_TEMP;
    
      // write to MODBUS registers
      ModbusRTUServer.holdingRegisterWrite(0, (uint16_t) count);
      ModbusRTUServer.holdingRegisterWrite(1, (uint16_t) scaled_temp_value*1000);
      ModbusRTUServer.holdingRegisterWrite(2, (uint16_t) scaled_flow_value*1000);
      ModbusRTUServer.holdingRegisterWrite(3,(uint16_t) aux_value);
      ModbusRTUServer.holdingRegisterWrite(4, (uint16_t) error);
    }
    startMillis = currentMillis;
  }
}

int start_continous_measurement() {
  Wire.beginTransmission(ADDRESS);
  Wire.write(0x36);
  Wire.write(0x08);
  return Wire.endTransmission();
}

int stop_continuous_measurement() {
    // To stop the continuous measurement, first send 0x3FF9.
    Wire.beginTransmission(ADDRESS);
    Wire.write(0x3F);
    Wire.write(0xF9);
    return Wire.endTransmission();
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-25 07:43:03

日志显示,只接收到部分数据:Expected 15 bytes Received 11 bytes。这可能是由错误的字符间计时引起的,即字符之间的静默时间被错误地解释为消息的结束。通过指定client.strict = False,实现了Modbus规范的字符间定时.

还可以看到类似的故事:Pymodbus :响应中的错误字节计数和pymodbus 问题

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74555963

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档