libmodbus icon indicating copy to clipboard operation
libmodbus copied to clipboard

reading negative value from registers

Open roboticsai opened this issue 4 years ago • 5 comments

Here is the output of reading the registers of a motor driver:

0,0	0,0
9,6543	517,65015
19,6533	1751,63776
29,6523	3701,61819
39,6513	6369,59146
50,6503	9750,55761
60,6493	13839,51667
70,6483	18640,46860
80,6473	24156,41340

Code is:

std::cout<<controller.lm_vel<<","<<controller.rm_vel<<"\t"<<controller.lm_pos<<","<<controller.rm_pos<<std::endl;
...
void Controller::read_vel(int nb) {
    rc = modbus_read_registers(ctx, LM_READ_VEL_REG, nb, tab_rp_registers); // Actual velocity left
    lm_vel = tab_rp_registers[0] * 0.1;
    rc = modbus_read_registers(ctx, RM_READ_VEL_REG, 2, tab_rp_registers);
    rm_vel = tab_rp_registers[0] * 0.1;
}

Here as in the output, instead of -19 6543 is comming and so on. This is the motor driver i'm trying to control from the linux computer with modbus library.

roboticsai avatar Jun 11 '21 20:06 roboticsai

Guessing tab_rp_registers data type, you may want something like the following

rm_vel = ((short int)tab_rp_registers[0]) * 0.1;

devotip avatar Nov 28 '22 06:11 devotip

not only missing the type of tab_rp_registers (should be unsigned 16 bit word type of your compiler), also missing the idea behind the 2 in modbus_read_registers(ctx, RM_READ_VEL_REG, 2, tab_rp_registers), and then only taking 1 in rm_vel = tab_rp_registers[0] * 0.1 ... how about tab_rp_registers[1] here?

modem-man-gmx avatar Nov 29 '22 22:11 modem-man-gmx

If it is a 32 bit number, assuming endianness is ok, it may be rm_vel = (*((int32_t *)&tab_rp_registers[0])) * 0.1;

devotip avatar Nov 30 '22 06:11 devotip

Assume that the value of a certain PLC register is -12

USHORT *usNRegs = new USHORT[nRegNums]; memset(usNRegs, 0, nRegNums * sizeof(USHORT));

modbus_set_slave(g_MBMMaster, nSlaveId); modbus_read_registers(g_MBMMaster, nRegAddr, nRegNums, usNRegs);

int negativeValue = static_cast(usNRegs[0]) - 65536; output:-12

??

luocheng610 avatar Sep 14 '23 10:09 luocheng610

basically right, but some mini flaws and some Micro$oft C++ specific terms.

You already used C++98 stuff, how about preventing VC++ keywords and using bit more recent (year 2011) code, not creating a memory leak, btw ;-)

#include <cstdint>
#include <limits>
#include <vector>
#include <iostream>

... 

const int nRegAddr = 0x2000; // just for example, 1st address of the 11 registers
const size_t nRegNums = 11; // just f.i.

std::vector<uint16_t> vuiRegs(nRegNums); // creates a 11-element vector holding {0, 0, ..., 0}

modbus_set_slave(g_MBMMaster, nSlaveId);
modbus_read_registers(g_MBMMaster, nRegAddr, vuiRegs.size(), &vuiRegs[0]);

for(auto unsigVal : vuiRegs) {
  signed int negativeValue = static_cast<signed int>(unsigVal) - numeric_limits<uint16_t>::max();
  signed int16_t easyValue = static_cast<int16_t>(unsigVal);

  std::cout << "signed of " << unsigVal << "=" << negativeValue << ", but " << easyValue << " is also okay." << std::endl;
  }

;-)

modem-man-gmx avatar Sep 14 '23 12:09 modem-man-gmx