Skip to content

Commit c05805e

Browse files
toshikikubocarandraug
authored andcommitted
Add support for Imagine Optic Mirao 52-e deformable mirror (issue #105)
* microscope/mirror/mirao52e.py (Mirao52e): new concrete class for the DeformableMirror. * microscope/mirror/mirao52e.py: add wrapper to the mirao52e.dll * doc/supported-devices.rst: document Mirao52e support. * NEWS: mention support from Mirao52e.
1 parent 16526fd commit c05805e

File tree

4 files changed

+147
-0
lines changed

4 files changed

+147
-0
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Version 0.3.0 (yyyy/mm/dd)
2121

2222
* Andor (EM)CCD cameras (requires Andor's atmcd C library)
2323
* Aurox Clarity (requires hidapi Python package)
24+
* Imagine Optic Mirao 52-e deformable mirror (requires mirao52e C library)
2425
* Linkam stage (requires LinkamSDK C library)
2526
* Ximea cameras (requires Ximea's xiAPI Python package)
2627

doc/supported-devices.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Deformable Mirrors
2121

2222
- Alpao (:class:`microscope.mirror.alpao`)
2323
- Boston Micromachines Corporation (:class:`microscope.mirror.bmc`)
24+
- Imagine Optic Mirao 52e (:class:`microscope.mirror.mirao52e`)
2425

2526
Filter Wheels
2627
-------------

microscope/_wrappers/mirao52e.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
## Copyright (C) 2019 David Miguel Susano Pinto <david.pinto@bioch.ox.ac.uk>
5+
##
6+
## Microscope is free software: you can redistribute it and/or modify
7+
## it under the terms of the GNU General Public License as published by
8+
## the Free Software Foundation, either version 3 of the License, or
9+
## (at your option) any later version.
10+
##
11+
## Microscope is distributed in the hope that it will be useful,
12+
## but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
## GNU General Public License for more details.
15+
##
16+
## You should have received a copy of the GNU General Public License
17+
## along with Microscope. If not, see <http://www.gnu.org/licenses/>.
18+
19+
"""Wrapper to the Imagine Optic Mirao 52-e API.
20+
"""
21+
22+
import ctypes
23+
24+
25+
# Vendor only supports Windows
26+
SDK = ctypes.WinDLL('mirao52e')
27+
28+
29+
TRUE = 1 # TRUE MroBoolean value
30+
FALSE = 0 # FALSE MroBoolean value
31+
32+
# Number of values of a mirao 52-e command (the number of actuators
33+
# is a define on the library header)
34+
NB_COMMAND_VALUES = 52
35+
36+
# Error code defines
37+
OK = 0
38+
39+
40+
Boolean = ctypes.c_char
41+
Command = ctypes.POINTER(ctypes.c_double)
42+
43+
44+
def prototype(name, argtypes, restype=Boolean):
45+
func = getattr(SDK, name)
46+
# All functions have 'int *' as the last argument for status.
47+
func.argtypes = argtypes + [ctypes.POINTER(ctypes.c_int)]
48+
func.restype = restype
49+
return func
50+
51+
52+
open = prototype('mro_open', [])
53+
close = prototype('mro_close', [])
54+
55+
applyCommand = prototype('mro_applyCommand', [Command, Boolean])

microscope/mirror/mirao52e.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
## Copyright (C) 2019 David Miguel Susano Pinto <david.pinto@bioch.ox.ac.uk>
5+
## Copyright (C) 2019 久保俊貴 <kubo@ap.eng.osaka-u.ac.jp>
6+
##
7+
## Microscope is free software: you can redistribute it and/or modify
8+
## it under the terms of the GNU General Public License as published by
9+
## the Free Software Foundation, either version 3 of the License, or
10+
## (at your option) any later version.
11+
##
12+
## Microscope is distributed in the hope that it will be useful,
13+
## but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
## GNU General Public License for more details.
16+
##
17+
## You should have received a copy of the GNU General Public License
18+
## along with Microscope. If not, see <http://www.gnu.org/licenses/>.
19+
20+
"""Imagine Optic Mirao 52-e deformable mirror.
21+
22+
The Mirao 52-e deformable mirror is not capable of receiving hardware
23+
triggers. It is only capable of sending hardware triggers. That
24+
sending of hardware triggers is not implemented on this module because
25+
it's pointless.
26+
27+
The Mirao 52-e deformable mirror has a limitation on valid patterns.
28+
From the vendor documentation (the command is the pattern to be
29+
applied):
30+
31+
[...] the sum of the absolute values defining the command must be
32+
lower than or equal to 24 and each value must be comprised between
33+
-1.0 and 1.0.
34+
35+
In microscope, a pattern must be specified in the [0 1] range.
36+
However, the limit of 24, after rescaling to [-1 1] range, still
37+
applies.
38+
39+
"""
40+
41+
import ctypes
42+
43+
import microscope.devices
44+
import microscope._wrappers.mirao52e as mro
45+
46+
47+
class Mirao52e(microscope.devices.DeformableMirror):
48+
def __init__(self, **kwargs):
49+
super().__init__(**kwargs)
50+
## Status is not the return code of the function calls.
51+
## Status is where we can find the error code in case a
52+
## function call returns false. This _status variable will be
53+
## an argument in all function calls.
54+
self._status = ctypes.pointer(ctypes.c_int(mro.OK))
55+
if not mro.open(self._status):
56+
self._raise_status(mro.open)
57+
58+
## super class needs this, but maybe it should be calling the
59+
## property directly?
60+
self._n_actuators = mro.NB_COMMAND_VALUES
61+
62+
@property
63+
def n_actuators(self):
64+
return mro.NB_COMMAND_VALUES
65+
66+
@staticmethod
67+
def _normalize_patterns(patterns):
68+
"""
69+
mirao52e SDK expects values in the [-1 1] range, so we normalize
70+
them from the [0 1] range we expect in our interface.
71+
"""
72+
patterns = (patterns * 2) -1
73+
return patterns
74+
75+
def apply_pattern(self, pattern):
76+
self._validate_patterns(pattern)
77+
pattern = self._normalize_patterns(pattern)
78+
command = pattern.ctypes.data_as(mro.Command)
79+
if not mro.applyCommand(command, mro.FALSE, self._status):
80+
self._raise_status(mro.applyCommand)
81+
82+
def _raise_status(self, func):
83+
error_code = self._status.contents.value
84+
raise RuntimeError('mro_%s() failed (error code %d)'
85+
% (func.__name__, error_code))
86+
87+
def __del__(self):
88+
if not mro.close(self._status):
89+
self._raise_status(mro.close)
90+
super().__del__()

0 commit comments

Comments
 (0)