Refresh can be an expensive operation (MM goes out to all devices and queries all states), so the idea of this happening 5 times a second does not sound so good. Since you get the OnPropertyChangedEvent now back from your device, why is there a need to query the state of all devices?
Idea for a "Smart Presets" option
I'm wondering where I should start looking to try and implement this. Also if you think this is a bad idea, please let me know.
The option I have in mind would find (and apply) the closest Preset when a property is changed.
With a group called "Filter cube" comprising "Excitation wavelength" and "Filter position", a test case for this would be: - User changes the filters using the buttons on the microscope - Excitation is ALSO changed accordingly.
or - User changes the excitation wavelength using the LED keypad - Filter cubes on the microscope are also changed accordingly
In my mind, this would happen because with the "Smart presets" option enabled, a change in "Filter position" and "Excitation wavelength" would be detected (as they must already be), but rather than making the preset blank because the combination of new "Filter position" + "Excitation wavelength" is NOT a defined preset, the closest preset matching the change in property would be selected instead.
There are probably edge cases I haven't thought of, but to me, this would make interactions with hardware inputs feel more "natural".
So really my question is, where in the code is a preset made blank when the combination of properties isn't recognised as an existing preset? Or is there another bit of code I should be looking instead?
EDIT I'm looking at extending setValueAt() in mmstudio/src/org/micromanager/ConfigGroupPad.java -- hopefully this is the right place to loop through the groupList_ items and work out the best config candidate that matches the changed item properties (if that makes sense).
EDIT2 I've added a new core property called SmartListener. The idea is twofold: - This core property can be globally set to true or false - Adding the core property to any config group makes the group "smart" (when SmartListener globally set to true).
I'll update my fork when (if) I get this last part to work...
- 点赞 评论 复制链接分享
Since you get the OnPropertyChangedEvent now back from your device, why is there a need to query the state of all devices?
Not there yet unfortunately. For now, I am only managing to return the right channel when the ChannelLabel property is queried.
I still need some kind of mechanism to read and update the current ChannelLabel value from the CoolLed controller. I see the PVCAM adapter uses a polling thread. Would that be the best way to check for hardware changes, and trigger the OnPropertyChangedEvent from the polling thread if ChannelLabel is changed?
So instead of trying to refresh every single MM property, I would only have one polling thread in the device adapter itself.
I'm not keen on polling for the reason you stated but I can't really think of a way round (the PrecisExcite is a serial device).点赞 评论 复制链接分享
Polling in the device adapter is much better than polling in the Java UI code. There are other cases where devices are polling through a serial port (for instance, the Arduino adapter can be set to poll the state of the input pins every second or so). It is not elegant, but sometimes it is the only way.点赞 评论 复制链接分享
I took inspiration from the Andor and Arduino adapters and implemented a polling thread for the PrecisExcite adapter in afaf89763bdfa6a9277cac2bdb852203bffccf29. But! I'm afraid I still have a deadlock issue to resolve. I'll check with a different light source tonight, as I'm not sure if it's the pe-2 that's causing the deadlock or my code (something something Occam's razor).
In any case, the OnPropertyChanged events generated in the polling thread are detected in MMStudio, which is absolutely fantastic! I can now go back to my original plan and implement the smart preset selection in ConfigGroupPad.java
Cheers, Egor点赞 评论 复制链接分享
in 2ae814cde3573cda3c24318c1ca5a785b082f53f I tried to add my "smart listening loop" to onPropertyChanged() in CoreEventCallback.java
This is an update on my progress so far.
Things I think will work: - a background update loop in the precisexcite adapter (or any adapter) that takes care of periodically probing the hardware and trigger OnPropertyChanged() events when needed. - a Core SmartListener property (which I think I need to make readonly) could be set to 0 or 1 to either disable or enable the smart listener. - user needs to add the Core-SmartListener property to any preset group to make it smart (which means that the group will switch presets to match the property changes of its devices). - a loop in onPropertyChanged() in CoreEventCallback.java checks each preset group in turn to check which preset to toggle to. I have two booleans for this: "isListening" (group contains the Core-SmartListener property and (later) Core-SmartListener is enabled) and "isConcerned" (the group contains the device as one of its members). New events / property changes are triggered if both these are true and the new device property actually differs from the one currently set in the matching preset.
Now for things that I couldn't get to work today. I really shouldn't try to set new device properties in the onPropertyChanged() method. Actually, trying to core.setConfig(group, cfgs.get(j));_ in there results in an infinite event loop. Unfortunately right now, I can't think of a way to make this work.
My current statements in the onPropertyChanged(): core_.waitForConfig(group, cfgs.get(j)); onPropertiesChanged();
briefly seem to change the GUI to the "guessed" changed presets, but then reverts the groupList to its previous unknown (blank) state. So maybe a better way to do this is to trigger a specific SmartListener event which can (in MMStudio.java or possibly in ConfigGroupPad.java) effect a preset change rather than simply setting the group to an unknown (blank) preset.
I think I have made some progress today, but am still very much stumped with where / how I should change the config presets in response to guesses made by the smart listening loop in CoreEventCallback.java
Cheers, Egor点赞 评论 复制链接分享
Sorry, just noted your response now. Does the infinite loop ensue by the call to core.setConfig() setting the same property again in your device adapter that issues the callback that calls core.setConfig() again? If so, I think that you could stop this cycle in the Device Adapter by only issuing the callback when the property actually changes rather than every time the property is set. Quite likely that there is something else going on though. It is always hard to avoid infinite cycles with the Swing UI.点赞 评论 复制链接分享
No worries Nico, I've only started working on this again. And thanks for chiming in.
Does the infinite loop ensue by the call to core.setConfig() setting the same property again in your device adapter that issues the callback that calls core.setConfig() again? If so, I think that you could stop this cycle in the Device Adapter by only issuing the callback when the property actually changes rather than every time the property is set.
It is definitely the same bit of the loop that's called over and over again recursively. I checked that by using the ignorePropertyChanges_ flag to ensure I would only call core.setConfig() once. And... yes, this seems to have broken the recursion! Even better, when I change the channels on the CoolLED keypad, I now see the changes propagated to the (demo) filterwheel as expected!
I'll need to check all this with real hardware of course but this is very encouraging (at least to me). See 4f20a1a for the relevant changes.
Next on my list: My Core-SmartListener is a Read-Only variable which I would like to enable/disable in the Micro-manager tools->options. I've added a checkbox in the dialog, but the variable being read-only, I can't just set its value it seems. I'll work it out I hope...
Edit: pushed 65e79db to make sure the update is truly bi-directional (CoolLED -> demo filterwheel, demo filterwheel -> CoolLED)点赞 评论 复制链接分享
- weixin_39778003 5月前
Pity I didn't join this conversation earlier, but you might want to take a look at the SnapOnMove plugin that I recently added to mm2 (it's a customer-sponsored project at Open Imaging). What that plugin does is monitor changes to XY and Z position (including changes originating in hardware) and snaps an image when there has been a change.
Although it's currently limited to monitoring stage positions and snapping images, the code is structured to support extensions, such as monitoring property values.
The SnapOnMove code is written so that it can be used with values whose changes are reported from the Core as well as those that are not and therefore require polling. The user needs to specify which method to use.
One possibility would be to extend SnapOnLive so that it can also monitor properties, and then add the ability to select between snapping an image or running a script. The trick will be, in the custom action, to avoid using
setConfigat all and to just set the properties other than the one whose change was noticed.
(SnapOnLive is still in the Beta submenu, because it doesn't play well with e.g. MDA. There needs to be a mechanism to stop SnapOnLive before starting an acquisition (and to allow one to re-enable it between time points), which will be added before it is considered completed.)点赞 评论 复制链接分享
- weixin_39778003 5月前
Closing this for now; please start a new issue if there are ideas to resurrect.点赞 评论 复制链接分享
I like the idea, but this may be hard to implement in a reliable way. For instance, what will the code do, when two configurations are equally plausible?
In the following I assume that you are working in the 2.0 branch. To implement it, you should start by subscribing to the OnPropertyChanged event. Then check which configuration you think matches and apply. Be aware that the OnPropertyChangedEvent may also be triggered when the user uses the configgrouppad to change configurations.点赞 评论 复制链接分享
I'm still working on this. It took much longer than expected just to get the coolled to change its ChannelLabel property when channels are changed via the keypad (I haven't submitted a PR for that latest fix yet as I have only tested this with my pE-300, but it's the PrecisExcite adapter in my MM2 branch).
Regarding OnPropertyChangedEvent if anyone wants to learn more, this thread contains some great information: https://sourceforge.net/p/micro-manager/mailman/message/33015801/
Kind regards, Egor点赞 评论 复制链接分享
Sorry about the wall of text!
In commit d52585a96f267302f943817f4ed4d6aec488788f I have modified the refresh button of the device property browser to autorefresh the properties every 200ms. I'm hoping to be able to trigger my smart presets from there (at least to trial the idea).点赞 评论 复制链接分享