Closed WildPoYo closed 4 years ago
As I understand this package, its reference environment is ModularSensors on Mayfly.
There is a lot of basic setups that are needed, so if you aren't using that environment, then this package can be used as an educational outline for Modbus for your specific environment, and you may needs some tools to monitor what is on the line. I use Salae Logic Analyzer.
More recent discussion wrt to this pkg ModularSensors on Mayfly at
https://www.envirodiy.org/topic/rs485-without-auto-direction-control/
As I understand this package, its reference environment is ModularSensors on Mayfly. There is a lot of basic setups that are needed, so if you aren't using that environment, then this package can be used as an educational outline for Modbus for your specific environment, and you may needs some tools to monitor what is on the line. I use Salae Logic Analyzer. More recent discussion wrt to this pkg ModularSensors on Mayfly at https://www.envirodiy.org/topic/rs485-without-auto-direction-control/
in principle its simple modbus communication, library can be extended slightly maybe to be able to choose several other parameters to initiate modbus communication with any device.
Parity, Baudrate, Address are only crucial matters to access slave device and on arduino side to be able to choose Serial port(in case of mega) would be sufficient enough I guess.
@WildPoYo, yes, you are right that this library can be used alone. It requires no dependencies.
@neilh10, remember that the sensor test examples for these libraries only use SensorModbusMaster, without any reference to ModularSensors.
@WildPoYo, I'm not sure why your board is stuck. Do you have a proper RS-485 and voltage conversion (via hardware) in place? If not, check out https://github.com/EnviroDIY/SensorModbusMaster/tree/master/hardware
@aufdenkampe I am sure hardware is in tact, I've used the same hardware with another library other than library being too complicated it worked fine. By printing something in serial monitor i've come to conclusion it crashes the moment I try to read the
float rated = modbus.uint16FromRegister(0x04, 9604, bigEndian);
within the scanRegisters.ino file I saw this part where parity is defined for Serial1 this is for boards like Due no?
#else
Serial1.begin(38400, SERIAL_8O1); // port for communicating with sensor
modbus.begin(modbusAddress, &Serial1, DEREPin);
The parity setting is for whatever your modbus device uses. You said yours is 8E1. If you don't begin the serial port with that setting, you're not going to get any communication.
//baudrate
modbusSerial.begin(38400, SERIAL_8E1); // port for communicating with sensor
@SRGDamia1 thank you for the reply, short after my last comment I actually tried it and somehow I managed to communicate with the device. But there is some issue with the data I am sending. Response that I get from the device does not match the value I am setting.
modbus.int16ToRegister(8602, 56, littleEndian);
This line is supposed write to 8602 register value of 56 right?
Yes, it should. Are you sure your address is correct? Sometimes maps list addresses in hex, this needs to be in base 10. Are you sure your device supports writing to single registers using the 0x06 command? Not all do. Try forcing a 0x10 command for writing by setting the force multiple command: modbus.int16ToRegister(8602, 56, littleEndian, true);
Slowly but getting there. I tested the address with decimal or hex both were accepted by the slave device. Then I notice something weird, register that I am trying to write was presenting weird values on the slave device. Below is the parameter I am trying to access, and data type is int16, when i write 1 to register as value outcome is 8.5 at the device and when i write 2 its 17.1 and so on. I am not sure where is the issue here now. There is some conversion in some point it should be 1 to 1. And result is same with or without forcing multiple command.
modbus.int16ToRegister(8602, 1, littleEndian);
Update
issue was I was trying to write with littleEndian and when I replaced it with bigEndian and worked. After reading some article online about most significant and least significant bytes made it clear to me. But still can not read any value from Slave device
Big endian is the default for modbus, you can just omit the endianess argument all together if you need big endian (modbus.int16ToRegister(8602, 1);
)
How do you know what values are being set if you can't read it? What other software are you using? Can you see the raw hex of the request that software uses? Are you sure you're correctly specifying whether you're trying to get a input or holding register? Input registers are read-only, so given your clip shows that's a R/W (read/write) register, it must be a holding register and you need to read it with a 0x03 command, not the 0x04 you posted in your very first post.
Okay, I should've read more things related to Modbus before I started this project. Now it's clear, I've not tested your comment about using 0x04 or 0x03 but I am sure you are correct :) As you pointed, most of the values I am trying to reach are R/W meaning holding registers. So if I try to read them with 0x03 will be more successful. And to your question how I know values are set, device I use has a built in display which I can read the values that I am pushing to it. And I do not use any third party tool to track the flow of the data. Maybe would have been good if I used some from the beginning but too late :)
Purpose of this project is to use Arduino to control the speed of an old lathe spindle, its frustrating to change the gears all the time to adjust the speed. Using a VFD (Variable Frequency Drive) makes it more efficient. I could do all of this just using some buttons and a potentiometer without an or any controller arduino but this way I get to get feedback from device, like current, voltage, torque etc. which can give me a hint if I am pushing the machine too much or not.
I'll close the issue once I test it later today.
Thank you a lot!
Oh, wow, that's a totally different type of device than I've ever tried to control. I actually wrote this library because the first time I tried to control something with Modbus I found all of the existing Arduino libraries to be as confusing as writing the raw out commands in hex. Reading back through this thread and my ReadMe, I think it's obvious that I need to spruce up my documentation a bit to make it highlight some of the "most common" settings to try first (ie, that big endian is default and about input vs holding registers).
I also tried several other libraries and some worked but not efficient enough, some I couldn't understand basics but your library is really good 🥇
I think existing Read-Me file is quite efficient I should have read it properly rather than scrolling through it. What's really missing is the examples, maybe I can contribute to it by making some basic examples.
I created one fairly simple example: https://github.com/EnviroDIY/SensorModbusMaster/blob/master/examples/readWriteRegister/readWriteRegister.ino. Hopefully it will help the next person!
There is something odd with the reading, I checked the manual of the device and function 4 does not exist.
Tnx for the example, its far more sophisticated than something I would do :)
The 0x04 function is a standard modbus function, but not all devices actually support it. I grabbed the instructions I had sitting in my office for a DO sensor and it happens to use both input and holding registers. The specification is pretty broad and I think most manufacturers pick and choose what they feel like supporting.
Can I somehow specify the function to be used for reading? 23 would be the right function in this case I assume
Before switching to Ardunio I made a working concept using Raspberry Pi & Python with minimalmodbus library
according to this, its also using function 4 and I was able to read all the values necessary to me...
0x03 reads one or more input registers
0x04 reads one or more holding registers.
0x06 writes 1 (and only one) holding register
0x10 (16) writes 1 or more holding registers
I've never had a device that used function 23; this library doesn't support it. I do not know why you would use function 23. Wikipedia is not telling me.
Ah, found it. Apparently by using command 23 you can read some registers and write others in a single command. That would make it faster if you need a lot of back and forth and you need to shave off milliseconds of you communication time. This library doesn't support doing that right now.
But according to minimalmodbus library func 23 is not implemented. Now now I checked another library which is also working but I and somehow is too slow for me also does not have func 23. It uses 3 or 4 as your library..
You're the first person who has mentioned that function, so I'm not surprised other libraries don't support it either.
The speed difference between using function 6 several times to write and then 3 several times to read is the speed of sending bits along wire between one unit and another (the Arduino and the VFD in your case). If you can send the bits all at once without having to repeat the extra hello and introduction bits in between, it goes a little faster. From my perspective with one or two sensors and one Arduino, those fractions of milliseconds are pretty inconsequential. For someone running a manufacturing plant with complex systems all communicating over modbus, it becomes a lot more meaningful. (That's not uncommon in industry, but they're trying to use Arduinos as the main brains.)
I am a little surprised you say this library performs faster than others. I have not attempted to 'optimize' it in any particular way. My main goal was to make it easier to understand how to get data so users could get readings from a sensor using modbus without having to know all about how modbus itself works. I'm very glad it's working well for you, though.
With slow I meant like takes 10 to 20 secs to see the value at slave device. I am still puzzled why I can read it with raspberry pi but not arduino with both using same function
10-20s? That's orders of magnitude more than the actual conversation between the Arduino and the VFD takes no matter what library is doing the talking. I'd guess there's something more going on. We have an in-stream spectrometer device that we use with an Arduino. The spectrometer does a lot of fancy processing on board and then our Arduino just asks for finished results. If I query that device while it's doing the processing it will reply with a bunch of empty registers or registers full of random garbage. I have to wait until I'm sure it's done processing and then ask. In that case, though, the hold up is not the speed of the communication between the Arduino and the spectrometer but just how long it takes the spectrometer itself to do its thing and add data to the appropriate registers. I wonder if your VFD is doing something similar - it might accept the new values into registers right away when you write them but not actually apply them until it has thought about it for a while.
For the Arduino vs Pi.. I'd guess the difference is probably related to the accuracy of the baud rates and the communication. Some devices are very, very picky about accurate baud rate and parity. It's one of the reasons why devices might communicate with an Arduino ok using hardware serial but won't respond using software serial: the baud rate is not as accurate. That's kind-of a WAG though. You could possibly try (if your drive supports it) selecting a lower baud rate (like 9600) and no parity (8N1) to see if it goes better. The communication at 9600 baud is slower than at 38400, but the difference is in the ms and smaller range for setting or reading a few registers.
I started to dig in more after your last comment and finally solved the issue of delay with the other library I am using. It was so obvious... I was spamming the slave device so much it was failing to send me a response. There was a parameter (polling) to set the delay between handshake requests sent by the master to slave, by default in the library it was set to 1 which i assume is 1ms and I played with the value to find the best fitting delay and seems to work perfectly.
I've changed the TTL to RS485 adapter I was testing with, I am able to also use your library, which is even better because I really liked your implementation. And it works way more efficient than the library I intended to use. I spammed the slave with 50ms delay packages and all were received with no issue.
#include <SensorModbusMaster.h>
// Define the sensor's modbus address
int modbusAddress = 1; // The sensor's modbus address, or SlaveID
// Create the stream instance
HardwareSerial modbusSerial = Serial1;
modbusMaster modbus;
int potSetVal = 0;
unsigned long previousMillis = 0;
const long interval = 50;
void setup()
{
Serial.begin(9600);
//baudrate
Serial1.begin(38400, SERIAL_8E1); // port for communicating with sensor
modbus.begin(modbusAddress, &Serial1);
}
// ---------------------------------------------------------------------------
// Main loop function
// ---------------------------------------------------------------------------
void loop()
{
int16_t rated = modbus.int16FromRegister(0x03, 8603);
potSetVal = random(-1400, 1400);
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
Serial.print("pot set val ");
Serial.println(potSetVal);
delay(10);
modbus.int16ToRegister(8602, potSetVal);
delay(20);
Serial.print("actual speed ");
Serial.println(rated);
}
}
I'm glad it's working now!
I am trying to communicate with a VFD (Variable Frequency Drive) via Modbus, I've tried several libraries some did not work some were too slow for some reason and I wanted to give a try to your library but I get no response from Serial monitor, seems board is stuck once upload is complete.
VFD's(slave) address is 1, baudrate is 38400 and has even parity.(8E1)
below I am trying to read the value of 9604 or write to 8602 but nothing happens as mentioned above. I am using Arduino Mega.