Activating correct camera in the Light Sheet configuration

Dear Benedict,
We have built a light-sheet microscope and installed the ImSwitch software from the UC branch, selecting the light-sheet configuration.
But don’t know how to change the Mock camera to the Daheng one (drivers and image works on SQUID software on same Linux Ubuntu pc). It also loads a Hiki camera manager that does not seem to apply to us and we still have a few package errors.


Hey @MakerTobey, thanks for reaching out! Super cool, you’re building another light-sheet!
Did you follow the following tutorial:
ImSwitch Installation on Mac and Windows ?

If possible, I would need to have access to the full stacktrace (i.e. pervious outputs). Did you check if the camera works with the “normal” python scripts from Daheng?
Also, I would need the configuration file, just to see if there is maybe an error with the numbering of the camera.

Does the below code work?

# version:1.0.1905.9051
import gxipy as gx
from PIL import Image


def main():
    # print the demo information
    print("")
    print("-------------------------------------------------------------")
    print("Sample to show how to acquire mono image continuously and show acquired image.")
    print("-------------------------------------------------------------")
    print("")
    print("Initializing......")
    print("")

    # create a device manager
    device_manager = gx.DeviceManager()
    dev_num, dev_info_list = device_manager.update_device_list()
    if dev_num is 0:
        print("Number of enumerated devices is 0")
        return

    # open the first device
    cam = device_manager.open_device_by_index(1)

    # exit when the camera is a color camera
    if cam.PixelColorFilter.is_implemented() is True:
        print("This sample does not support color camera.")
        cam.close_device()
        return

    # set continuous acquisition
    cam.TriggerMode.set(gx.GxSwitchEntry.OFF)

    # set exposure
    cam.ExposureTime.set(10000)

    # set gain
    cam.Gain.set(10.0)

    # start data acquisition
    cam.stream_on()

    # acquire image: num is the image number
    num = 1
    for i in range(num):
        # get raw image
        raw_image = cam.data_stream[0].get_image()
        if raw_image is None:
            print("Getting image failed.")
            continue

        # create numpy array with data from raw image
        numpy_image = raw_image.get_numpy_array()
        if numpy_image is None:
            continue

        # show acquired image
        img = Image.fromarray(numpy_image, 'L')
        img.show()

        # print height, width, and frame ID of the acquisition image
        print("Frame ID: %d   Height: %d   Width: %d"
              % (raw_image.get_frame_id(), raw_image.get_height(), raw_image.get_width()))

    # stop data acquisition
    cam.stream_off()

    # close device
    cam.close_device()

if __name__ == "__main__":
    main()

The

Hello @benedictdied ! I’m working with @MakerTobey in the implementation of the new light-sheet. Thank you for your response.

We followed the documentation in the github repo. I would like to add that I made a mistake here and used the example_uc2_lightsheethik.json config file instead of the daheng based one. Even when correcting that, we still had problems. Additionaly, for some reason the ImSwitch software is always creating and using an ImSwitchConfig folder at the Home folder and not using the ImSwitchConfig that we downloaded in the Documents folder, as stated in your repo documentation.

I was able to make the camera work with the example_uc2_lightsheethik_gxipy.json config file. However, the daheng .json file gave me errors. I was able to use the camera in another software, so drivers shouldn’t be an issue. For the purpose of making this troubleshooting process cleaner I decided to make a clean install following the steps included in the URL you shared.

Since ImSwitch is using the ImSwitchConfig folder from Home. I pasted the .json config files I needed for testing there. After installation I run python -m imswitch. The software started with the example_virtual_microscope.json config file and the GUI is up and running but the following errors are present in the terminal:

  • [ImConMainView] Could not add widget imswitch_arkitekt to dock imswitch_arkitekt
  • [HistoScanManager] Could not load default config from /home/wenzel-lab/ImSwitchConfig/histoController: [Errno 2] No such file or directory: '/home/wenzel-lab/ImSwitchConfig/histoController/config.json'

While moving the mouse over the GUI it also gives me this error:

[ExceptionHandler] Traceback (most recent call last):
  File "/home/wenzel-lab/.local/lib/python3.9/site-packages/pyqtgraph/dockarea/Dock.py", line 345, in mouseMoveEvent
    self.mouseMoved = (lpos - self.pressPos).manhattanLength() > QtWidgets.QApplication.startDragDistance()
AttributeError: 'DockLabel' object has no attribute 'pressPos'

Ok, now I want to use my daheng camera. So, I change to the example_uc2_lightsheetdaheng.json config file. Unfortunately, the GUI throws me an error JSONDecodeError: Expecting property name enclosed in double quotes: line 8 column 1 (char 169). The terminal has the following output:

[main] Traceback (most recent call last):
  File "/home/wenzel-lab/Documents/wenzel_repositories/imswitch/imswitch/__main__.py", line 126, in main
    view, controller = modulePkg.getMainViewAndController(
  File "/home/wenzel-lab/Documents/wenzel_repositories/imswitch/imswitch/imcontrol/__init__.py", line 50, in getMainViewAndController
    setupInfo = configfiletools.loadSetupInfo(options, ViewSetupInfo)
  File "/home/wenzel-lab/Documents/wenzel_repositories/imswitch/imswitch/imcontrol/model/configfiletools.py", line 19, in loadSetupInfo
    return setupInfoType.from_json(setupFile.read(), infer_missing=True)
  File "/home/wenzel-lab/.local/lib/python3.9/site-packages/dataclasses_json/api.py", line 58, in from_json
    kvs = json.loads(s,
  File "/home/wenzel-lab/miniforge3/envs/imswitch/lib/python3.9/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "/home/wenzel-lab/miniforge3/envs/imswitch/lib/python3.9/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/home/wenzel-lab/miniforge3/envs/imswitch/lib/python3.9/json/decoder.py", line 353, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 8 column 1 (char 169)

In this step, the software breaks and I can’t change the config file with the interface. If I delete the imcontrol_setups folder from ImSwitchConfig in the Home folder it kind of resets and I’m able to add the necessary .json for testing. As I mentioned before, I discovered that the camera works with the example_uc2_lightsheethik_gxipy.json config file. So, this is fortunately fixed, but I still can’t move the stage. The output from the terminal is the following:

  • [ImConMainView] Could not add widget LightSheet to dock LightSheet
  • [ESP32Manager -> ESP32] [OpenDevice]: Wrong Firmware.
  • [LasersManager -> MultiManager] module 'imswitch.imcontrol.model.managers.lasers.ESP32LightSheetManager' has no attribute 'ESP32LightSheetManager'
  • [LasersManager -> MultiManager] module 'imswitch.imcontrol.model.managers.lasers.ESP32LightSheetManager' has no attribute 'ESP32LightSheetManager'
  • [ESP32StageManager -> LightsheetStage] argument of type 'int' is not iterable
  • [ESP32StageManager -> LightsheetStage] Could not register callback: 'Motor' object has no attribute 'register_callback'
  • [HistoScanManager] Could not load default config from /home/wenzel-lab/ImSwitchConfig/histoController: [Errno 2] No such file or directory: '/home/wenzel-lab/ImSwitchConfig/histoController/config.json'

It seems that it could be a firmware problem from the ESP32 device. I did try to install the drivers from this resource you gave, but it is giving me driver installation problems due to secure boot. I didn’t have much time so I left it there. Maybe flashing a new firmware into the ESP32 device could solve the issue?

Attached here is a screenshot of the GUI running with example_uc2_lightsheethik_gxipy.json. I also made an output.log file made with python -m imswitch > output.log 2>&1 and the .json files I used during this process but I can’t attach it here, where can I send it to you?

We would greatly appreciate any insights or guidance you can provide. Thank you for your time and patience.

Have a nice week,

J.

Hey @the_alquemist thanks a lot for your detailed report. There is a lot of errors you found. Thanks! :slight_smile:

Maybe to clear things up a bit I’d try to give a point-by-point explanation of the errors you’re writing about:

It’s important that we update the documentation (e.g. the first steps/landing docs…). Would you mind to file a pull request so that others better understand which will be the first thing they should do (or point me what would be a better place to explain it anyway)? Right now we have this forum ,the openuc2.github.io docs, the read-the-docs from Imswitch and the readme of the repo. We should have one unified version (at least for the openUC2 fork of ImSwitch).

Indeed, on Mac/Linux it’s in the ~ / home folder and not in documents. I hope I explained it here: GitHub - openUC2/ImSwitchConfig in more depth… also here, please let me know where I should add the information.

This is a new error. I have not found it’S cause (maybe napari/qt version related…). Chatgpt gives me this : ChatGPT Need to digg into it when i have some time. Is not really an issue. Deactivating the histoscan plugin should help getting rid of the error messages…

Can you tell me what’s the baudrate under the ESP32 tag?
ImSwitchConfig/imcontrol_setups/example_uc2_multicolour_daheng_lena.json at master · openUC2/ImSwitchConfig · GitHub (You can use this file, should work…)
In between I changed the baudrate from 50000 to 115200 due to stability reasons. You can check it on this website: openUC2 WebSERIAL Demonstration

Good luck! :slight_smile:

1 Like

Hello @benedictdied ! Thank you for the reply and additional comments. I will follow the same point-by-point scheme you used:

I’m happy to contribute in any way I can. I agree with you in that a unified version is the better approach for this. In my mind, the first thing to do is look up the git-hub repo from the project. When I visit the UC2 main repo there is a section that talks about the repos associated to it which are divided in 3: hardware, REST and ImSwitch. However, ImSwitch repo is associated to a fork born from beniroquai’s git ecosystem and not UC2’s official fork. This leads me to some confusion, so I’m already not sure where to make a pull request for a documentation update. Consolidating this would be a great start.

If the URL you provided is the updated installation protocol, the defined ImSwitch main repo should harbor this same set of instructions. Other documentation sources such as this forum, openuc2.github.io docs, read-the-docs and readme from the non-main or conflicting fork, should serve as additional information where time-stamps help make the difference between updated and obsolete information, when compared to the main repo.

It’s indeed explained there, sorry I missed that. I think that the focus of the main repo should be for Linux based systems and present macOS and Windows as optional installation methods. I followed Option C: Install from Github (UC2 version) but it wasn’t obvious to me that we weren’t talking about Linux based systems, leading to the confusion on working directories I mentioned before. That way it’s easier to follow the thread of information.

Unfortunately, no luck here. I tried to run ImSwitch with the new .json file and I get the following error:

ERROR [main] Traceback (most recent call last):
File “/home/wenzel-lab/Documents/wenzel_repositories/imswitch/imswitch/imcontrol/controller/ImConMainController.py”, line 56, in init
self.controllers[widgetKey] = self.__factory.createController(
File “/home/wenzel-lab/Documents/wenzel_repositories/imswitch/imswitch/imcommon/controller/basecontrollers.py”, line 46, in createController
controller = controllerClass(*self.__args, *args,
File “/home/wenzel-lab/Documents/wenzel_repositories/imswitch/imswitch/imcontrol/controller/controllers/DPCController.py”, line 96, in init
self.frameShape = self.detector.getLatestFrame().shape
AttributeError: ‘NoneType’ object has no attribute ‘shape’
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File “/home/wenzel-lab/Documents/wenzel_repositories/imswitch/imswitch/main.py”, line 126, in main
view, controller = modulePkg.getMainViewAndController(
File “/home/wenzel-lab/Documents/wenzel_repositories/imswitch/imswitch/imcontrol/init.py”, line 80, in getMainViewAndController
raise e
File “/home/wenzel-lab/Documents/wenzel_repositories/imswitch/imswitch/imcontrol/init.py”, line 75, in getMainViewAndController
controller = ImConMainController(options, setupInfo, view, moduleCommChannel)
File “/home/wenzel-lab/Documents/wenzel_repositories/imswitch/imswitch/imcontrol/controller/ImConMainController.py”, line 72, in init
raise ValueError(f’No controller found for widget {widgetKey}')
ValueError: No controller found for widget DPC

I also had problems with the openUC2 WebSERIAL Demonstration where no compatible devices were found. I tried changing the baudrate but nothing happened.

Regarding the documentation, as I mentioned earlier, I can make a pull request and I can attach the description with all the details regarding the information layout I have in mind.

I hope you find this information useful and we really appreciate your help.

Thank you for your time!

Hello @benedictdied ! So, in the end we followed the Docker method to solve the “it doesn’t run on my machine” issue. In our case, we have Ubuntu 24.04 LTS installed and we had to use Canonical’s app catalogue because Docker isn’t directly supported yet by the developer. Docker must be called as sudo, but it works great, here is what I did:

sudo docker run -it --rm -p 8001:8001 -p 2222:22 -e HEADLESS=1 -e HTTP_PORT=8001 -e UPDATE_GIT=1 -e CONFIG_PATH=/config  -v ~/Downloads:/config -e UPDATE_CONFIG=0 --privileged ghcr.io/openuc2/imswitch-noqt-x64:latest


At the end it gave us the following text:


INFO:     Uvicorn running on https://0.0.0.0:8001 (Press CTRL+C to quit)

We accessed the URL and gave it access. Since the default configuration of the container is to use the example_virtual_microscope.json config file, it worked right away when making use of the web interface from the following domain:


https://0.0.0.0:8001/imswitch/index.html

The file that stores which config .json is going to be used is the one named imcontrol_options.json under the /Downloads/ImSwitchConfig/config path. So, to test my Daheng Camera and stage controller, I switched the parameters to point the correct config file. In this case:

1.- From imcontrol_options.json

{
    "setupFileName": "example_uc2_lightsheet_gxipy.json",
    "recording": {
        "outputFolder": "./ImSwitch/ImSwitch/recordings",
        "includeDateInOutputFolder": true
    },
    "watcher": {
        "outputFolder": "/config/ImSwitchConfig/scripts"
    }
}

2.- Added the respective .json config file to the imcontrol_setups folder under the /Downloads/ImSwitchConfig/imcontrol_setups/ path.

After this, I rerun the previous steps to activate the docker container and as expected it used the new .json configuration file. The camera does work but the stage controller still doesn’t.

When trying to locate the device with the flashing tool in a chrome based web browser, the window that pops up says that it’s unable to locate the device.

I can confirm this from the terminal’s output too that details the following:

2024-08-22 21:30:03 DEBUG [ESP32Manager -> ESP32] No USB device connected! Using DUMMY!

When trying to use the stage controller from the web interface it throws the following error:

INFO:     172.17.0.1:59728 - "GET / HTTP/1.1" 422 Unprocessable Entity
INFO:     172.17.0.1:59728 - "GET /favicon.ico HTTP/1.1" 404 Not Found
INFO:     172.17.0.1:59728 - "GET /imswitch/index.html HTTP/1.1" 200 OK
INFO:     172.17.0.1:59728 - "GET /imswitch/static/js/main.fa009905.js HTTP/1.1" 200 OK
INFO:     172.17.0.1:59728 - "GET /path_to_your_logo.png HTTP/1.1" 404 Not Found
INFO:     172.17.0.1:59728 - "GET /path_to_your_logo.png HTTP/1.1" 404 Not Found
INFO:     172.17.0.1:36918 - "GET /PositionerController/movePositioner?axis=X&dist=1000&isAbsolute=false&isBlocking=false&speed=1000 HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/uvicorn/protocols/http/httptools_impl.py", line 401, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 70, in __call__
    return await self.app(scope, receive, send)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/fastapi/applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/applications.py", line 123, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/middleware/errors.py", line 186, in __call__
    raise exc
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/middleware/errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/middleware/cors.py", line 85, in __call__
    await self.app(scope, receive, send)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/middleware/httpsredirect.py", line 19, in __call__
    await self.app(scope, receive, send)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 65, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/routing.py", line 754, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/routing.py", line 774, in app
    await route.handle(scope, receive, send)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/routing.py", line 295, in handle
    await self.app(scope, receive, send)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/routing.py", line 77, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/starlette/routing.py", line 74, in app
    response = await f(request)
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/fastapi/routing.py", line 278, in app
    raw_response = await run_endpoint_function(
  File "/opt/conda/envs/imswitch/lib/python3.10/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
    return await dependant.call(**values)
  File "/tmp/ImSwitch/imswitch/imcontrol/controller/server/ImSwitchServer.py", line 194, in wrapper
    return func(*args, **kwargs)
  File "/tmp/ImSwitch/imswitch/imcontrol/controller/controllers/PositionerController.py", line 218, in movePositioner
    positionerName = self._master.positionersManager.getAllDeviceNames()[0]
IndexError: list index out of range

After some troubleshooting, the usb extensor that we used was broken, so we switched to another one and we were able to detect the usb connection from lsusb:

Bus 001 Device 007: ID 10c4:ea60 Silicon Labs CP210x UART Bridge

So I’m not sure why the flashing tool is not detecting it. I also tried switching to other versions just in case but nothing. lsmod shows these entries:

cp210x                 40960  0
usbserial              69632  1 cp210x

In the case of sudo dmesg | tail:

[27190.409721] docker0: port 1(veth6e8ad5b) entered disabled state
[27190.409726] veth6e8ad5b: entered allmulticast mode
[27190.409762] veth6e8ad5b: entered promiscuous mode
[27190.512888] eth0: renamed from veth7beafa3
[27190.522877] docker0: port 1(veth6e8ad5b) entered blocking state
[27190.522880] docker0: port 1(veth6e8ad5b) entered forwarding state
[27209.048170] usb 6-1: reset SuperSpeed USB device number 4 using xhci_hcd
[27233.721187] audit: type=1400 audit(1724362228.994:495): apparmor="DENIED" operation="open" class="file" profile="snap-update-ns.firefox" name="/proc/24735/maps" pid=24735 comm="5" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
[29029.235521] audit: type=1400 audit(1724364024.485:496): apparmor="DENIED" operation="open" class="file" profile="snap-update-ns.firmware-updater" name="/proc/25736/maps" pid=25736 comm="5" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
[29029.365111] audit: type=1400 audit(1724364024.615:497): apparmor="DENIED" operation="open" class="file" profile="snap.firmware-updater.firmware-notifier" name="/proc/sys/vm/max_map_count" pid=25705 comm="firmware-notifi" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0

And ls /dev/tty* shows a /dev/ttyUSB0 file.

Thank you for your help and time. Looking forward to your comments.

Thanks a lot @the_alquemist for the detailed reporting here! This is very helpful for future generations :slight_smile:
One more thing that pops up to my mind is the ownership of the serial devices in linux. In python you typically have to change the user permissions in order to access it via pyserial for example. Maybe it’S the same for chromium?
Can you test another OS like windows? if you see the esp already then it should work.

Here is the user-group issue for pyserial
https://forums.raspberrypi.com/viewtopic.php?t=199171

Hey @benedictdied ! No problem. Unfortunately, I wasn’t able to connect the stage yet. This is what I tried:

1.- Add user to dialout group (checked with groups)

sudo usermod -a -G dialout <user>

2.- Enable Experimental Web Platform features option under chrome://flags from Chrome web browser.

3.- Specific permissions for ttyUSB0


sudo chmod 666 /dev/ttyUSB0

4.- Windows does recognize a device but with the warning sign, meaning a problem with the drivers.

Looking forward to your comments!

Thanks again. I remember I had issues with Ubuntu a while ago. You replaced the user with yours I guess?

On Windows, you would need to install the driver:

Thanks again. I remember I had issues with Ubuntu a while ago. You replaced the user with yours I guess?

That’s correct.

On Windows, you would need to install the driver:

This is for the purpose of re-flashing it on Windows? We migrated to Linux and our setup is built around that OS so it’s not really an option to use Windows as a main thing.

Hey, sorry for my late reply. I just wanted to check if the board actually works on windows.
A colleague of mine tested Ubuntu yesterday with a new cable, all over sudden it worked. USB Micro cable seem to be tricky. Perhaps you find yet another cable and test it again? Sorry.