Modbus Spindle Control
-
@gloomyandy said in Modbus Spindle Control:
So I think there might still be a case for having modbus specific read/write operations but I'd be tempted to try and make them more generic ones that simply read/write a bunch of bytes and apply the timing and crc to them, but leave the formatting and decoding of those bytes up to the user in the form of a script?
Looking at the Modbus gcodes again this evening (
M260.1
andM261.1
) and it occurs to me that if the user has the ability to send arbitrary data then there's no distinction between these 2 commands.It seems like this lower-level "raw" behaviour could be achieved with a single gcode that takes raw bytes and expects a particular number of bytes in response, something like this:
; Purely hypothetical request that expects 3 data bytes returned from the 3 byte data request. ; var.modbusRaw would be a vector of bytes M261.3 B3 D{10,12,14} V"modbusRaw"
The underlying implementation would send the station address and deal with CRC, but everything to do with the data would be up to the user.
-
@NineMile the Modbus protocol specifies what response is expected to each command. RRF checks those responses. We could ads a generic command but as the response to such a command would be undefined, we would not be able to check it.
Appending the CRC would only be appropriate if the non-Modbus device used the same CRC rules as Modbus.
-
@dc42 I had a quick look at the linuxCNC HAL code for the VFD that the user over on discord was using. That looks like it uses the same crc16 and seed as modbus but has a different payload. I get the impression from a quick scan of the linuxCNC stuff that this is fairly common, devices which claim to be "modbus" use the modbus signal timing. framing and crc but do not use the modbus register/coil model and associated commands. But I'm certainly no expert on this.
-
@gloomyandy said in Modbus Spindle Control:
@dc42 I had a quick look at the linuxCNC HAL code for the VFD that the user over on discord was using. That looks like it uses the same crc16 and seed as modbus but has a different payload. I get the impression from a quick scan of the linuxCNC stuff that this is fairly common, devices which claim to be "modbus" use the modbus signal timing. framing and crc but do not use the modbus register/coil model and associated commands. But I'm certainly no expert on this.
This is my understanding as well. Theres at least a couple quite common Chinese VFD's which advertise Modbus support but don't follow the modbus-rtu data format - the Huanyang one encountered on Discord seems to be the most common though.
For my own understanding of the RRF codebase, I spent a bit of time looking at how custom spindle control might be implemented using
DoFileMacro
.It seems like adjusting spindle state and rpm would probably need to move to some type of reconciliation based system - where direct calls to
spindle->SetRpm()
andspindle->SetState()
would store values that would then be applied later while spinning aGCodeBuffer
.Applying the settings could be simply setting pin output states for a standard spindle config, like what happens now, or calling
DoFileMacro
to execute a user-provided control system.However - there's areas in the code where spindle control actions appear to be taken from outside any particular
GCodeBuffer
(Tool::Activate()
for example, called from direct LCD requests). These would not map cleanly onto just switching into a spindle control state in the currentGCodeBuffer
where the request was made.My initial thought was to use the Daemon buffer for all spindle control, but a long-running daemon macro could impact spindle control, and vice-versa.
Does it make sense to run the spindle control actions in their own
GCodeBuffer
instance and synchronise it with the other buffers?For example - when
File
buffer callsM3
to start the spindle, we change the pending spindle settings, notify that the spindle needs to be reconciled and then don't allow theFile
channel to continue until theSpindle
buffer reports the settings have been applied?Any thoughts on this appreciated, or if I'm missing any prior art that might indicate a smarter way to do this?
I'm going to be at SMRRF in a couple weekends so I'd be happy to chat about this in person if you're going to be there (David / Andy)?
-
@NineMile I'm also planning to be at SMRRF, probably on the Sunday.
-
@NineMile I've added new command M290.4 in 3.6-dev to support nonstandard transactions that conform only partially to the Modbus specification. See https://docs.duet3d.com/en/User_manual/Reference/Gcodes#m2604-raw-modbus-transaction. It's unlikely that I will have time to do any more work in this area before the 3.6.0 release.
-
@NineMile I've merged and pushed David's changes to the stm32 repos. I don't currently have a modbus setup so have not been able to test either the old or new code.
-
-
@dc42 I have a suggestion for making things much simpler and not further complicating RRF GCODE.
We basically need M3, M4 and M5 commands to handle the spindle at the GCODE level, plus M950 to init the corresponding io.
As far as I understand, these commands, handle a spindle created with M950, which, in turn make the assumption we drive the spindle by pwm through a given pin. Nothing is related to modbus nor serial link in M950. This command is somewhat complex, because you handle many different peripherals (led strip,PWM, servo, temp, etc), everything that can be handled by DUET standard io at the hardware level.
As you said, there is little chance that you can support each and every modbus motor/controller on the market, and this should be the case, I think the program memory should be filled by unused code.
On the other hand, a GCODE command not implemented in RRF will call a macro of the same name ( e.g. M1000.g)
We could use a M3.1 M4.1 M5.1 to handle the modbus specific, but this would not be standard and would need some post processing.I suggest that RRF, for limited control codes (M3,M4,M5...), instead of handling what is defined by M950, just call corresponding macros when instructed by M950.
This way, M3,M4,M5 would be handled by the user, it's the user's responsibility to handle all the modbus specifics inside these macros.
Introduce a parameter M (0 or 1, default 0) in M950 that tells, for the corresponding spindle (R parameter), to call M3_R.g, M4_R.g, M5_R.g R being the spindle number. To avoid a race condition, M3,M4,M5 commands called from inside these macros should not be possible, either raise an error or just do nothing.
modbus complexity would then be handled by a macro.
you can extend this to other devices (fans, heater, leds,....) managed through serial, spi or I2C devices.
M3 P1 S1000 would call the macro M3_1.g with parameter S=1000 exactly like M98 P"M3_1.g" S1000.
M950 with the M1 and R1 would also call a macro M950_1.g that would init the serial link, maybe check the modbus status to make sure it will work.You could expand this to all codes related to M950 for handling special cases not handled by DUET ios.
I think it would solve the issues I have seen on the forum, included mine without introducing specific GCODES.
-
@audryhome that may be a neat solution. We will consider it. Thanks!
-
@audryhome I like this idea - however there's areas other than
M3
,M4
andM5
that can control the spindle currently. The ones I'm aware of are at leastM568
(set tool parameters, which can control spindle speed if the tool is currently active), as well asTool::Activate()
andTool::Standby()
which are called internally during tool changes,M109
and it looks like via an LCD screen as well.Not sure how well these areas fit into overriding the 'public facing' gcode commands
-
@NineMile Nothing prevent M568 to be treated like M3...4.. 5, since the spindle number should be used the same way.
-
@audryhome @NineMile does anyone actually use M568 to control the spindle?
However, there is still a need to turn the spindle off and on during pause/resume. So perhaps it would be better to define one or more standard macros to control spindles and have them invoked by M3/4/5/568.
-
@dc42 said in Modbus Spindle Control:
@audryhome @NineMile does anyone actually use M568 to control the spindle?
I do
I use it to vary the RPM set by
M3
orM4
fromdaemon.g
, to implement variable spindle speed. It adjusts the spindle RPM over a set period between a high and low point, to avoid potential resonance conditions between the tool and workpiece.I would say
M568
isn't an issue though - it could be overridden in the same manner asM3
,M4
orM5
.This isn't as clear cut with
Tool::Activate()
andTool::Standby()
as it appears that they can be called outside of aGCodeBuffer
context (see:MovementState::SelectTool
/GCodes::SelectPrimaryTool
)@dc42 said in Modbus Spindle Control:
However, there is still a need to turn the spindle off and on during pause/resume. So perhaps it would be better to define one or more standard macros to control spindles and have them invoked by M3/4/5/568.
Yes, agree. I think named macros for start / stop / rpm would work well. I'd prefer spindle details to be passed by parameter rather than part of the macro filename though.
-
@dc42 I don't plan to, I just need to calculate and adjust the rpm from a tick sensor on spindle start.
I use a biffy BLDC that transmit movement to an ER16 spindle through a set of GT2 pulleys.