wavefrontshaping / ALP4lib

Python control module for Vialux DMDs based on ALP4.X API.
MIT License
58 stars 41 forks source link

Use DMD in Slave Mode #24

Closed gourdun closed 4 months ago

gourdun commented 5 months ago

Hi,

Thanks for creating this package! I am trying to use a Vialux DMD in slave mode such that an external trigger signal can be used to display the next image. I've seen some hints in the code about this, but I'm unsure about how to apply it. Also, do you know if there's a method to externally trigger the DMD to turn off? Would appreciate any help!

Best,

Felix & Gordon :D

cc: @roflmaostc

roflmaostc commented 4 months ago

Hi @wavefrontshaping,

I wanted to see if there is any news? Otherwise we probably use this librarry: https://gitlab.phys.ethz.ch/mohanj/holography/-/blob/096ce42d18efc5f4eda14a53013a4cffb3220830/dmd/communication.py

Best,

Felix

wavefrontshaping commented 4 months ago

Hi,

Have you check the ALP API documentation?

It seems that, according to Section 2.14 AlpProjControl of the API description, that one can change such parameters using the C function ALPProjControl, which you can call using DMD.ProjControl(...) in Python.

Never done it but according to the doc, you should simply use DMD.ProjControl(ALP_PROJ_MODE, ALP_SLAVE) to put it in slave mode.

from ALP4 import *
...
DMD.ProjControl(ALP_PROJ_MODE, ALP_SLAVE)

Of course, you should then configure the timings according to your needs.

roflmaostc commented 3 months ago

Just to write down for future readers. Triggers works, there are some sharp edges noted below.

from ALP4 import *
dmd = ALP4(version = '4.3', libDir=".")

# Initialize the device
dmd.Initialize()

imgSeq = ([
    np.asarray(Image.open("../01.png").convert('L')).ravel(),
    np.asarray(Image.open("../02.png").convert('L')).ravel(),
]

imgSeq = np.array(imgSeq)
print(imgSeq.shape)
dmd.SeqAlloc(nbImg = imgSeq.shape[0], bitDepth = 8)

# Send the image sequence as a 1D list/array/numpy array
dmd.SeqPut(imgData = imgSeq)

# set to 50Hz
# If you set fraction to 1, then the DMD misses sometimes the triggers because
# the DMD switches to the next image only if the pictureTime is over.
# so it shows an image for the pictureTime, blanks the DMD and waits for the trigger
# to show the next image.
fraction = 0.95
dmd.SetTiming(pictureTime = round(0.05*1_000_000 * fraction))
dmd.ProjControl(ALP_PROJ_MODE, ALP_SLAVE)

dmd.Run()
# best case start the triggers here otherwise you might skip some frames

@wavefrontshaping if welcomed, I can put a minimal example to the README with a PR

RealBrandonChen commented 3 months ago

Hi,

@roflmaostc I wonder why you are setting the pictureTime? This should be the framerate of the DMD but you're using the hardware trigger. fraction = 0.95 dmd.SetTiming(pictureTime = round(0.05*1_000_000 * fraction))

roflmaostc commented 3 months ago

We observed some issues if the pictureTime is longer than the real trigger intervals. In that case the DMD would ignore the triggers. So pictureTime has to be slightly lower than real interval. Maybe it's better to subtract 10 (in units of microsecond) instead of the fraction hack.