Connecting Raspi 5 and ESP32 for ImSwitch

Hello! I am an undergraduate working with some OpenUC2 kits here at University of California, Irvine. I believe we were sent kits from the discovery line, as I was able to put together the LED fluorescence microscope. The main electronics we currently have are: an ESP32, a Raspberry Pi 5, a motorized z-stage, an LED array, a blue LED, and the Hikrobot MV-CS060-10UM-Pro camera. I was able to verify that the components work on their own through the WebSerialTest site, but I am having difficulties integrating the Pi 5 using ImSwitch. The tutorial I have followed for configuring the Pi and installing ImSwitch is here: Quickstart Guide: Using Raspberry Pi with ImSwitch and UC2-ESP | openUC2 Documentation
My primary concerns are whether the tutorial’s Raspberry Pi 4 instructions are fully compatible with our Pi 5, as running “launch_docker_container.sh” results in “AttributeError: ‘UC2ConfigManager’ object has no attribute ‘ESP32’” and issues with homing the objective. Additionally, when trying to reconnect to the UC2 board via the ImSwitch page, we encounter a similar “AttributeError” regarding the ESP32 object, and I’m unsure if the “example_virtual_microscope” config file is appropriate given our Hikrobot MV-CS060-10UM-Pro camera. We’d be very grateful for any insights or assistance you could offer on these integration and compatibility challenges. Please let us know if any further information or logs would be helpful. Thanks in advance for your support!
@benedictdied

Hey @afernandez! Thanks a lot for your first post :slight_smile:

I must admit that the current documentation is not quiet easy to understand and especially the configuration bit is something that I wish to simplify to some extend!

First of all: Great that ImSwitch has launched! Yay! By default, the example_virtual_microscope.json configuration file is active - this will only display show the simulated microscope (e.g. a camera stream that can be moved around with the buttons..).
You can change the active configuration file by adjusting the file
~/ImSwitchConfig/config/imcontrol_options.json

it may look like:

{
    "setupFileName": "/Users/bene/ImSwitchConfig/imcontrol_setups/example_virtual_microscope.json",
    "recording": {
        "outputFolder": "~/Downloads/recordings",
        "includeDateInOutputFolder": true
    },
    "watcher": {
        "outputFolder": "/Users/bene/ImSwitchConfig/scripts"
    }
}

where the setupFileName gives the right location to the file.
You can create a new one and save that somewhere and link to that file in the imcontrol_options.json file. For the HIK + ESP version it could look like this:

{
  "positioners": {
    "ESP32Stage": {
      "managerName": "ESP32StageManager",
      "managerProperties": {
        "rs232device": "ESP32",
        "isEnable": true,
        "enableauto": false,
        "stepsizeXDocu": "200*16 per revolution at 1.27 pitch",
        "stepsizeX": 0.396,
        "stepsizeY": 0.396,
        "stepsizeZ": 0.1563,
        "homeSpeedX": 10000,
        "homeSpeedY": 10000,
        "homeSpeedZ": 10000,
        "isDualaxis": false,
        "homeDirectionX": -1,
        "homeEndstoppolarityX": 0,
        "backlashXOld": 15,
        "backlashYOld": 40,
        "backlashX": 0,
        "backlashY": 0,
        "homeEndstoppolarityY": 0,
        "homeDirectionY": -1,
        "homeDirectionZ": 0,
        "homeXenabled": 1,
        "homeYenabled": 1,
        "homeZenabled": 0,
        "homeOnStartX":0,
        "homeOnStartY":0,
        "initialSpeed": {
          "X": 15000,
          "Y": 15000,
          "Z": 15000
        }
      },
      "axes": [
        "X",
        "Y",
        "Z"
      ],
      "forScanning": true,
      "forPositioning": true
    }
  },
  "rs232devices": {
    "ESP32": {
      "managerName": "ESP32Manager",
      "managerProperties": {
        "host_": "192.168.43.129",
        "serialport": "COM3",
        "baudrate":115200,
        "debug": true
      }
    }
  },
  "lasers": {
    "LEDRing": {
      "analogChannel": null,
      "digitalLine": null,
      "managerName": "ESP32LEDLaserManager",
      "managerProperties": {
        "rs232device": "ESP32",
        "channel_index": 1
      },
      "wavelength": 635,
      "valueRangeMin": 0,
      "valueRangeMax": 1023
    },
    "LED": {
      "analogChannel": null,
      "digitalLine": null,
      "managerName": "ESP32LEDLaserManager",
      "managerProperties": {
        "rs232device": "ESP32",
        "channel_index": 2
      },
      "wavelength": 1024,
      "valueRangeMin": 0,
      "valueRangeMax": 1023
    }
  },
  "detectors": {
    "WidefieldCamera": {
      "analogChannel": null,
      "digitalLine": null,
      "managerName": "AVManager",
      "managerProperties": {
        "isRGB": 0,
        "cameraListIndex": 0,
        "cameraEffPixelsize": 0.2257,
        "mocktype": "OffAxisHolo",
        "hikcam": {
          "exposure": 0,
          "gain": 0,
          "blacklevel": 100,
          "image_width": 1000,
          "image_height": 1000
        }
      },
      "forAcquisition": true,
      "forFocusLock": true
    }
  },
  "HistoScan": {
    "PreviewCamera1": "Observer"
  },
  "autofocus": {
    "camera": "WidefieldCamera",
    "positioner": "ESP32Stage",
    "updateFreq": 10,
    "frameCropx": 780,
    "frameCropy": 400,
    "frameCropw": 500,
    "frameCroph": 100
  },
  "mct": {
    "monitorIdx": 2,
    "width": 1080,
    "height": 1920,
    "wavelength": 0,
    "pixelSize": 0,
    "angleMount": 0,
    "patternsDirWin": "C:\\Users\\wanghaoran\\Documents\\ImSwitchConfig\\imcontrol_slm\\488\\",
    "patternsDir": "/users/bene/ImSwitchConfig/imcontrol_sim/488"
  },
  "dpc": {
    "wavelength": 0.53,
    "pixelsize": 0.2,
    "NA": 0.3,
    "NAi": 0.3,
    "n": 1.0,
    "rotations": [
      0,
      180,
      90,
      270
    ]
  },
  "webrtc": {},
  "PixelCalibration": {},
  "focusLock": {
    "camera": "WidefieldCamera",
    "positioner": "ESP32StageManager",
    "updateFreq": 4,
    "frameCropx": 0,
    "frameCropy": 0,
    "frameCropw": 0,
    "frameCroph": 0
  },
  "LEDMatrixs": {
    "ESP32 LEDMatrix": {
      "analogChannel": null,
      "digitalLine": null,
      "managerName": "ESP32LEDMatrixManager",
      "managerProperties": {
        "rs232device": "ESP32",
        "Nx": 4,
        "Ny": 4,
        "wavelength": 488,
        "valueRangeMin": 0,
        "valueRangeMax": 32768
      }
    }
  },
  "availableWidgets": [
    "Settings",
    "View",
    "Recording",
    "Image",
    "Laser",
    "Positioner",
    "Autofocus",
    "MCT",
    "UC2Config",
    "PixelCalibration",
    "HistoScan",
    "Joystick",
    "Flatfield",
    "Histogramm",
    "ROIScan"
  ],
  "nonAvailableWidgets": [
    "STORMRecon",
    "imswitch_arkitekt_next",
    "DPC",
    "Holo",
    "FFT",
    "Hypha",
    "FocusLock",
    "HistoScan",
    "FocusLock",
    "FOVLock"
  ]
}

See also Quickstart Guide: Using Raspberry Pi with ImSwitch and UC2-ESP | openUC2 Documentation under Edit ImSwitch configuration files

To check if the esp32 is connected, you can see relevant usb devices with this: lsusb

It should not matter wether it’s pi4 or pi5. I have changed the way it uses memory recently, so if you were to update the docker container, you can benefit from it:

Try running the following command to update and the restart to take effect (copy+paste + enter)
~/Desktop/update_docker_container.sh

I hope this helps. If you have a wish how to setup the configuration file in a more convenient way, please let me know. This is by far not idea! :wink:

Thank you for the config file! I was able to successfully launch the container, access the web page, move the motor, and control the blue LED after a few changes to the provided config! The only issue now is that the ImSwitch web page does not show the camera image. On the “LiveView” section of the page, the stream is stuck on “loading image.” Here is my current config file:

{
  "positioners": {
    "ESP32Stage": {
      "managerName": "ESP32StageManager",
      "managerProperties": {
        "rs232device": "ESP32",
        "isEnable": true,
        "enableauto": false,
        "stepsizeXDocu": "200*16 per revolution at 1.27 pitch",
        "stepsizeX": 0.396,
        "stepsizeY": 0.396,
        "stepsizeZ": 0.1563,
        "homeSpeedX": 10000,
        "homeSpeedY": 10000,
        "homeSpeedZ": 10000,
        "isDualaxis": false,
        "homeDirectionX": -1,
        "homeEndstoppolarityX": 0,
        "backlashXOld": 15,
        "backlashYOld": 40,
        "backlashX": 0,
        "backlashY": 0,
        "homeEndstoppolarityY": 0,
        "homeDirectionY": -1,
        "homeDirectionZ": 0,
        "homeXenabled": 1,
        "homeYenabled": 1,
        "homeZenabled": 0,
        "homeOnStartX":0,
        "homeOnStartY":0,
        "initialSpeed": {
          "X": 15000,
          "Y": 15000,
          "Z": 15000
        }
      },
      "axes": [
        "X",
        "Y",
        "Z"
      ],
      "forScanning": true,
      "forPositioning": true
    }
  },
  "rs232devices": {
    "ESP32": {
      "managerName": "ESP32Manager",
      "managerProperties": {
        "host_": "192.168.43.129",
        "serialport": "/dev/ttyUSB0",
        "baudrate":115200,
        "debug": true
      }
    }
  },
  "lasers": {
    "LEDRing": {
      "analogChannel": null,
      "digitalLine": null,
      "managerName": "ESP32LEDLaserManager",
      "managerProperties": {
        "rs232device": "ESP32",
        "channel_index": 1
      },
      "wavelength": 635,
      "valueRangeMin": 0,
      "valueRangeMax": 1023
    },
    "LED": {
      "analogChannel": null,
      "digitalLine": null,
      "managerName": "ESP32LEDLaserManager",
      "managerProperties": {
        "rs232device": "ESP32",
        "channel_index": 2
      },
      "wavelength": 1024,
      "valueRangeMin": 0,
      "valueRangeMax": 1023
    }
  },
  "detectors": {
    "WidefieldCamera": {
      "analogChannel": null,
      "digitalLine": null,
      "managerName": "HikCamManager", 
      "managerProperties": {
        "isRGB": 0,
        "cameraListIndex": 0,
        "cameraEffPixelsize": 0.2257,
        "mocktype": "OffAxisHolo",
        "hikcam": {
          "exposure": 0,
          "gain": 0,
          "blacklevel": 100,
          "image_width": 1000,
          "image_height": 1000
        }
      },
      "forAcquisition": true,
      "forFocusLock": true
    }
  },
  "HistoScan": {
    "PreviewCamera1": "Observer"
  },
  "autofocus": {
    "camera": "WidefieldCamera",
    "positioner": "ESP32Stage",
    "updateFreq": 10,
    "frameCropx": 780,
    "frameCropy": 400,
    "frameCropw": 500,
    "frameCroph": 100
  },
  "mct": {
    "monitorIdx": 2,
    "width": 1080,
    "height": 1920,
    "wavelength": 0,
    "pixelSize": 0,
    "angleMount": 0,
    "patternsDirWin": "C:\\Users\\wanghaoran\\Documents\\ImSwitchConfig\\imcontrol_slm\\488\\",
    "patternsDir": "/users/bene/ImSwitchConfig/imcontrol_sim/488"
  },
  "dpc": {
    "wavelength": 0.53,
    "pixelsize": 0.2,
    "NA": 0.3,
    "NAi": 0.3,
    "n": 1.0,
    "rotations": [
      0,
      180,
      90,
      270
    ]
  },
  "webrtc": {},
  "PixelCalibration": {},
  "focusLock": {
    "camera": "WidefieldCamera",
    "positioner": "ESP32StageManager",
    "updateFreq": 4,
    "frameCropx": 0,
    "frameCropy": 0,
    "frameCropw": 0,
    "frameCroph": 0
  },
  "LEDMatrixs": {
    "ESP32 LEDMatrix": {
      "analogChannel": null,
      "digitalLine": null,
      "managerName": "ESP32LEDMatrixManager",
      "managerProperties": {
        "rs232device": "ESP32",
        "Nx": 4,
        "Ny": 4,
        "wavelength": 488,
        "valueRangeMin": 0,
        "valueRangeMax": 32768
      }
    }
  },
  "availableWidgets": [
    "Settings",
    "View",
    "Recording",
    "Image",
    "Laser",
    "Positioner",
    "Autofocus",
    "MCT",
    "UC2Config",
    "PixelCalibration",
    "HistoScan",
    "Joystick",
    "Flatfield",
    "Histogramm",
    "ROIScan"
  ],
  "nonAvailableWidgets": [
    "STORMRecon",
    "imswitch_arkitekt_next",
    "DPC",
    "Holo",
    "FFT",
    "Hypha",
    "FocusLock",
    "HistoScan",
    "FocusLock",
    "FOVLock"
  ]
}

The changes I made were to the serialport under rs232devices, and to the managerName under detectors. During startup of the container, I also get these two warnings.

2025-07-25 21:49:41 WARNING [CameraHIK] Property image_width does not exist
2025-07-25 21:49:41 WARNING [CameraHIK] Property image_height does not exist

Do you have any other insights into the camera issues? Again, thank you for the help you have already provided, I really appreciate it!

Also, does UC2 have the documentation for the step-size to distance conversion for the z-stage motor? I have measured that 30000-33000 steps corresponds to a distance of 1 cm, or 3-3.3 steps corresponds to a distance of 1 micrometer.

Quick question: Do you use Firefox or Chrome? In case of Firefox you would need to go to https://IPADDRESS:8002 and accept the insecure connection. In case of Chrome we have to investigate - do you happen to see any container logs when you print this (taken from here:

docker ps # get the id of the docker container 

# View container logs (retreive container_id with docker ps)
sudo docker logs [container_id]

# Follow logs in real-time
sudo docker logs -f [container_id]

Regarding step-size: Good point. The value in the config is used of for an inch-based lead screw. So you can calculate: 1mm/3200 microsteps * 1E3 => 0,3125

I hope this helps :slight_smile:

Btw. I’m working on an installer: Release master · openUC2/ImSwitchInstaller · GitHub

maybe it would be fun to test this on your computer - which OS are you using?

I am on Windows 11! I would love to try it out. Btw, the live view works when using the Chrome browser. I tried your solution for Firefox but the page said “not found.” So I believe ImSwitch is now working fully as intended, with a liveview, control of motor, and control of blue LED. The last thing that remains to be connected to the ESP-Raspi loop is the LED array. Would you recommend using the USB to connect to the Pi or using the pin connector?