-
Notifications
You must be signed in to change notification settings - Fork 100
add Picohal plugin init and spindle define #715
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Is it for this plugin? |
Yes, this is correct. I am also working on some improvements to submit via a PR. Most notably I have added support for a laser spindle connected to the picoHAL based off of the existing implementation of RS485 VFD spindles. Hence the desire to add a picoHAL spindle definition. Feel free to advise if it is desirable to have this PR accepted by Expatria prior to adding the define, but I wasn’t sure of the proper order to proceed. In either case, hopefully it is possible to add the |
I would rather have generic names for plugin inits where possible and use id's for enabling a particular one. The spindle part should at least be guarded by SPINDLE_ENABLE and perhaps given a generic name, e.g SPINDLE_PWM3? The laser specific M-codes should be in another plugin? Possibly with a dependency on picoHAL for now? |
FWIW, I have also been working on a 32 bit I2C expander for an RP2350 based controller. I'm not sure we want to make the selection of I2C based IOEXPAND exclusive with RS485 based expansion. |
I agree that something more generic is preferred and also note the point from @andrewmarles that it could make sense to distinguish from onboard ioexpanders. What about something like
I have added a code guard within my fork of the picoHAL plugin, following the example of modbus connected VFDs. Is an additional code guard required for the
I think using How about
Currently my WIP fork for the picoHAL plugin includes both some generic features I plan to submit to the Expatria upstream but also some laser control specific features that I agree should be separated out in their own distinct plugin. For now I have used custom m-codes to control some additional IO but I am hoping to eventually use the ioports API. I’ve looked at the template code you provided here and it seems it should be relatively straightforward to add ports, but maybe not yet possible to make them available for claiming. I think I would need to claim them if I want to set their state with my custom m-codes - although perhaps there is some other way to do this for now? |
Onboard expanders should go in board specific code, possibly shared between boards? And enabled by IOEXPAND_ENABLE == 1 in combination with the board define if needed? Lately I have started to assign/claim more of the inputs and outputs from the ioport pools and ioexpanders should add to those. New properties for ports such as latency and local vs. external could be added to facilitate selection (by driver and plugin code alike).
Looking at the code I only see forwarding of spindle commands (via ModBus) so SPINDLE_GENERIC would be acceptable? Claiming of ioports is complicated if more than one implementation is behind - since the M62-M68 P and E numbers (IMO) should be consecutive and not having "holes"... Another detail that, IMO, should be addressed is conversion of controller state to sequential numbers. It would be better if this was standardized, and I want to do this by using ffs(): In v2 of the i2c_interface I do it like this:
I have added an enum to match the ffs() result in the latest core. |
Okay, if I understand correctly you are suggesting that
This works for me, although I’m not sure what you mean by only forwarding spindle commands, is there some additional functionality that I could be making use of and am not?
Yes, I can see how this is nontrivial. I will plan to use the existing ioports api functionality without worrying about claiming for now. And I will continue to think about how best to add my laser mcodes on top of this.
Okay, it looks to be straightforward for me to adopt a similar approach to handling states here. BTW, is this what you had referred to in my previous PR on the keypad plugin when you mentioned the need for “status code mapping and using NAN instead of 0xFFFFFFFF for indicating no A axis available”? I have already implemented the NAN support and was planning to submit a PR after I debug one more minor issue. |
I would like to have generic init names - give me some time to think about the best way forward.
No, since I cannot see any actual spindle code other than modbus messages then the receiving end actually implements the spindle. And that can be different spindle types depending on what is code running on the other end? There might even be some kind of discovery of capabilities added to the ModBus messaging. So IMO SPINDLE_GENERIC could be an approriate name.
Most, if not all, of your M-codes could be handled by M62-M68 eqivalents? Is there any official specification of what they do or are they custom codes you have selected? If the latter use of parameter words would reduce the number of M-codes quite a bit.
Yes. We should try to add stuff in a generic and consistent way as possible to avoid confusion and reduce maintenance cost. Hard, I know - but better to spend some time getting stuff right from the start... |
I am working on adding a new middle layer in the core to simplify adding claimable ioports, both from the driver and plugins. If you or anyone else is willing to test I can provide the changed files (it is only four), for the F4xx driver only for now. |
Wow! This looks great. I would absolutely be willing / interested in testing. |
Yes, I think you have a point here. Part of my logic for using the M-codes that I did is past experience working with Fanuc controls so I am familiar with thinking of the The three main reasons I was leaning towards custom m-codes were:
After thinking a bit more on this, it seems that perhaps the NGC
Agreed, and your experience and support with this is much appreciated. |
Here is a version that should work, I added a plugin for the MCP3221 ADC just for reference: |
Thanks! I had the chance to test the basic functionality today and it seems to work as expected. I will do some more testing (particularly with claiming), but so far so good. I have also been doing some unrelated testing on error handling for modbus comms issues (mostly trying to ensure that it fails gracefully should a disconnection occur) and I’m wondering if it would be best practice to use the task scheduler to periodically check for reconnection. I’m somewhat hesitant to do so, given this seems to be the potential source of some issues I’ve been troubleshooting with the keypad plugin, but would be curious to know your thoughts on this. |
IMO it is best to use the task scheduler, also for polling. Plugin code should not hook into grbl.on_execute_realtime unless sub millisecond execution is required. And driverReset() should flush the queue? If the task scheduler is the source of your issue it may be helpful to stress it a bit more? |
I have come up with a separate scheme for registering expander plugins to allow the driver to have the first go at claiming ports. Plugins that combines expander code and provides additional functionality should, IMO, register itself as two plugins with separate init functions. One for the expander bit and one for the rest. This to ensure correct sequencing. I also have added FYI when the driver/board binds to a port it copies the |
This looks like it will provide a very powerful framework for integrating with the picoHAL. The possibility of claiming external pins for “basic” functions like coolant, spindle, etc., is particularly interesting since it would mean that the picoHAL plugin will not need to hook into all the various core handlers (at least when it is primarily functioning as an ioexpander). I will start to work on refactoring the existing plugin to separate the io functionality as you suggest. Thanks for sharing! |
Yeah, I have not dug in detail just yet, hopefully this weekend, but looks perfect for the flexihal2350 which uses i2c for enables, coolant and spindle en/dir. |
FYI I have improved the new API and added wrappers/veneers for the old in the latest commit. |
I've got a draft working for picomodbus.c, which adds digital + analog inputs and also sets up the queue functions from the Expatria picohal plugin. I've also changed the polling to use the task scheduler, and implemented a basic keepalive (although I am planning to still make some updates so that the keepalive interval can be longer than the basic polling interval). I've left out all of the non-io functionality (spindle, reacting to state changes, etc.) from this file, and my plan would be to add these messages to the queue from a separate (picohal specific) plugin. Hopefully this aligns with your previous guidance. Based on the changes you have made with regards to ioexpansion, it seems like it could now make sense for this modbus ioexpansion functionality to be within Plugins_misc alongside the i2c expanders. I tried to follow your advice from earlier and keep it fairly generic. I've done all my testing with the picoHAL, but I see no reason it couldn't work with something like this, provided the addresses are adjusted at compile time. The naming is still very much WIP, I had initially dropped the HAL to avoid confusion on some of the variable names, but now am thinking that pico is also not the best, since there is no reason that it couldn't work with modbus devices that are not based on rp2040. In either case, curious to know if this is something you would support adding to the upstream, and if there are any particular changes you would want to see first? |
I've taken a closer look at the plugin I wonder why it buffers modbus messages and then send them in blocking mode. Why not just send them non-blocking and thus use the buffering provided by the modbus driver? Is it due to the driver not supporting retries for non-blocking messages? Since the messages are buffered the ports should be flagged as async as it is now. BTW I think this should be made configurable via the xbar_t config call so that the client code can select either blocking or non-blocking (async) mode. And perhaps blocking mode should be the default? Another complication is handling pin settings such as signal inversion. This is delegated to the port implementation and is handled by adding a config function like this. And to avoid confusion settings affecting ports should not be duplicated, e.g. inversion of coolant signals should not be available both via $15 (coolant setting) and $372 (aux ouput inversion) when a coolant output is claimed from aux ports. If the port driver supports the set_function call this will be handled by the core by removing the $372 setting flag for the claimed port. A set_function call is easy to add...
For now I would like it to be a 3rd part plugin both as an example and since it maps to the implementation of the receiving end on the PicoHAL board. A truly generic version would have to query the receiving end for capabilities and configure itself accordingly? And I do not have a PicoHAL board available for testing... |
This is more due to my own unfamiliarity with the modbus driver. My starting point was the picohal plugin which implemented its own queue, and I did not realize that this functionality was also available within the modbus driver itself. I will look into this as I would gladly remove the queueing functionality from this plugin to simplify things.
Not exactly (at least I don't think so). This choice was due to some dropped messages I observed on reset if I used non-blocking calls combined with the my custom
Okay, I will do this. I have also reconfigured the keepalive to always send as non-blocking which I think should be okay.
I will work on adding this also, I have been meaning to learn more about working with settings and this is a good excuse.
Okay this makes sense. In that case I will leave some of my picoHAL variable naming (at least for now) since I think this makes it a better "example" as it is more clear what would need to be changed to reuse it elsewhere. I guess I should also clarify that I am not affiliated with Expatria, and it is likely that at least some of the WIP changes to the plugin (e.g., switching to the new ioports API) will probably necessitate a new firmware on the receiving end. That said, I have no reason to believe a PR would not be well received, so hopefully a non-issue. In terms of generality, my plan was to provide compile-time options for the addresses. To interface with the waveshare device the only things that I think would need to change are the modbus device address, and the register addresses for DOUT and AOUT (and of course the number of "pins" for each type). Run-time settings would be another option but, I was thinking that the number of IO ports would likely need to be set at compile-time, and so maybe it makes sense to set everything together rather than splitting things up between run-time and compile-time . . . Perhaps there is a better way to handle this? |
The message queue was because back when I first did the picoHAL plug-in I had issues where the vfd rpm would be queried continuously making it impossible to get any other non blocking messages on the bus. With the queue I could have the get_rpm command check only run if at least 30% of the queue was free so that other messages could find space in the line to be sent. I am not sure if all of the other modbus updates since then have resolved that issue. |
It seems that this would require an additional async flag in gpio_out_config_t, or perhaps you had something else in mind? |
I have tested using the task scheduler to send the keepalive within my WIP picohal plugin code here. Unfortunately, it seems that it is triggering the same issues (getting caught in a loop) that I had previously observed. I have not been able to reproduce these issues when using the older expatria keypad plugin, so I still think it must somehow relate to the new keypad plugin code. Although, the loop it gets caught in seems to be the keepalive task, so maybe there is something wrong with how I am using the task scheduler in the picohal plugin? Any thoughts / suggestions are much appreciated. |
Wait with this, get a picoHAL specific version up and running first. Compile time options could be the best but then selected as a single option that sets the parameters so it would be possible to add it to the Web Builder without to much fuss. I would rather avoid adding too many $-settings for this.
There and in pin_mode_t as well.
Is the receiving end of the picoHAL code/firmware available somewhere so I can set up a test environment on a Pico board? It is hard to tell what might be the issue if I cannot replicate it myself. |
Okay.
Yes, the WIP firmware is here. |
Please download the ModBus spec from here. Also check section 6.21 - this could be used to discover which and the properties of the device connected, I do not know how widely this is implemented, if it is by the e.g. the Waveshare linked above it could be used to configure a generic plugin? FYI I do get a response to the keepalive message but no luck yet in outputting anything with M64.
Odd that keypad plugin is involved - if not adding that the issue goes away? You run it in I2C mode? |
Thank-you for sharing this reference. Unfortunately, I don't think that the python umodbus library has implemented the diagnostic function code. For this initial testing I am just writing to a spare register and using the exception callback to detect if the client is offline. Likely this could be improved, but for now I was just hoping to confirm the task scheduler was working as expected.
It seems the umodbus library may not implement this either. Perhaps there are alternatives to umodbus that should be considered for the picohal firmware. I will look into this a bit further.
Is it possible you are not using the keepalive_dev branch for the receiver firmware? I have been testing with a slightly stripped down version from the expatria firmware to keep things simple for now. I just checked and the register
Yes this strikes me as odd also, but the issue only appears if the keypad plugin is enabled. I have tested successfully with the RP2040 driver without the keypad and with the STM32F4XX driver with the expatria keypad plugin, and in both cases have not experienced this lock-up.
Yes. I am also planning to setup a minimal i2C controller implementation with a spare PICO to see if I can reproduce the issue on generic hardware. Also, while looking through the keypad plugin code, one thing that stuck out to me is that some of the task scheduler calls are within an interrupt context. Wondering if its possible this is creating some sort of race condition if the button is pressed at the wrong time? But it also looks like there are guards for most parts of the task execution with |
Yep, it does not. Should be easy to add though. Anyway, the keepalive message is, IMO, nasty in that it raises an alarm if it fails. If gcode is running that does not use the expander it might be terminated for no good reason. I would suggest that it should only be sent when in IDLE state. And if you insist it should sent during motion it should only output a warning?
I am not, but I modified the python code so it is working now.
Is the unlock command sent from the keypad? And can you post your FYI I have tweaked your picohal code a bit:
Instead of passing the whole message it is faster to pass just a pointer, which is what you use after all.
Here I added a check for reset pending and do not send the keepalive if it is. Perhaps I should add it to the modbus code instead? In
Perhaps I should return flags so that one could check explicitly for rtu or tcp...? I am going to deprecate
It should be safe since the task lists are manipulated with IRQ off, but who knows... |
I agree the current implementation is a bit aggressive, although this was intentional. If the picohal is used for outputting any critical signals (e.g., laser enable), I think it is important that it falls back to a safe state when there is a loss of communication. My reasoning for the alarm was that if a missed keepalive means the picohal drops to fail-safe state (not yet configured to do so, but in the works), then the controller should be notified with similar urgency to, for example, a loss of comms to the spindle. I see your point that this could be overkill for some uses of the io expansion though. . .
Good point, thanks!
Part of my reasoning for this was to test a modification of the modbus_RTU function so that
I have also been thinking to implement something that returns all outputs to the
This sounds like a good idea to me.
Okay. I will update to the new function once available.
|
Yes, I will do this (although I do not have an stm32f4xx board with me over the long weekend) so it will probably be in a few days. |
Update committed, I believe I have resolved the crash issue and also the task lock up. New check for modbus up:
|
Issue seems to be resolved with the latest commit, but just in case this is still helpful, here is the output from
|
2769ea2
to
c472a24
Compare
Ready for merge now? |
d9702c1
to
99293bb
Compare
Yes, I have now also added a check for |
99293bb
to
e2ad52c
Compare
Request to add plugin init and spindle definition for Expatria picoHAL - modbus RTU connected io-expander and general purpose auxiliary control board.