Micro-Epsilon:scanCONTROL:PythonWrapper
Micro-Epsilon scanCONTROL 3D Sensor SDK - Python Wrapper
pymegc는 Micro-Epsilon의 MEGC(Micro-Epsilon Genicam Control) C 라이브러리에 대한 Python 래퍼입니다. ctypes를 기반으로 하여 센서 장치의 검색, 연결, 파라미터 설정, 2D/3D 측정 데이터 획득을 Python 환경에서 수행할 수 있습니다.
지원 센서
- scanCONTROL
- ReflectControl
- SurfaceControl
지원 플랫폼
- Windows (DLL)
- Linux (SO)
- macOS (DYLIB)
설치 방법
- Python 설치 경로를 확인합니다 (예:
C:\Program Files\Python310) -
PythonWrapper/pymegc폴더를Lib\site-packages디렉토리에 복사합니다 - 예제 스크립트를
PythonWrapper/examples/에서 실행하여 정상 동작을 확인합니다
디렉토리 구조
PythonWrapper/
├── README.txt # 설치 안내
├── pymegc/ # 메인 라이브러리 패키지
│ ├── __init__.py # 패키지 초기화 (MEGC.py 재수출)
│ └── MEGC.py # ctypes 기반 C 라이브러리 바인딩 (자동 생성)
└── examples/ # 18개 예제 스크립트
├── FindDevices/ # 장치 검색
├── DeviceInfo/ # 장치 정보 조회
├── ParameterList/ # 파라미터 목록 출력
├── ReadOnlyAccess/ # 읽기 전용 접근
├── ScanControl2dMeasurement/ # 2D 측정 (콜백)
├── ScanControl3dMeasurement/ # 3D 측정 (콜백)
├── ScanControl2dMeasurementPoll/ # 2D 측정 (폴링)
├── ScanControl3dMeasurementPoll/ # 3D 측정 (폴링)
├── ReflectControl2dMeasurement/ # ReflectControl 2D (콜백)
├── ReflectControl3dMeasurement/ # ReflectControl 3D (콜백)
├── ReflectControl2dMeasurementPoll/ # ReflectControl 2D (폴링)
├── ReflectControl3dMeasurementPoll/ # ReflectControl 3D (폴링)
├── ScanControlCameraLive/ # 카메라 라이브 영상
├── ReflectControlCameraLive/ # ReflectControl 라이브 영상
├── SurfaceControl2dMeasurement/ # SurfaceControl 2D (콜백)
├── SurfaceControl3dMeasurement/ # SurfaceControl 3D (콜백)
├── SurfaceControl2dMeasurementPoll/ # SurfaceControl 2D (폴링)
└── SurfaceControl3dMeasurementPoll/ # SurfaceControl 3D (폴링)
기본 워크플로우
import ctypes as ct
import pymegc as megc
# 1. 시스템 초기화 및 장치 검색
sys_obj = megc.megc_system_t()
megc.SysInit(ct.byref(sys_obj))
megc.SysFindDevices(ct.byref(sys_obj))
# 2. 장치 정보 조회
device_count = megc.SysGetDeviceCount(ct.byref(sys_obj))
device = megc.SysGetDevice(ct.byref(sys_obj), 0)
# 3. MEGC 클라이언트 초기화 및 연결
megc_obj = megc.megc_t()
megc.Init(ct.byref(megc_obj))
megc.ConnectByDevice(ct.byref(megc_obj), device)
# 4. 파라미터 설정
params = megc.GetDeviceParams(ct.byref(megc_obj))
param = megc.ParamsGetParamByName(params, b"ExposureTime")
megc.ParamSetFloatValue(param, ct.c_double(100.0))
# 5. 컴포넌트 설정 및 획득 시작
# ... (측정 유형에 따라 다름)
# 6. 데이터 획득 (콜백 또는 폴링)
# ... (아래 상세 설명 참조)
# 7. 정리
megc.AcquisitionStop(ct.byref(megc_obj))
megc.Disconnect(ct.byref(megc_obj))
megc.Destroy(ct.byref(megc_obj))
megc.SysDestroy(ct.byref(sys_obj))
API 레퍼런스
시스템 함수 (System)
시스템 레벨에서 장치를 검색하고 관리하는 함수들입니다.
| 함수 | 매개변수 | 반환값 | 설명 |
| | megc_system_t 포인터 | 상태 코드 | 시스템 객체를 초기화합니다 |
| | megc_system_t 포인터 | 상태 코드 | 시스템 객체를 정리합니다 |
| | megc_system_t 포인터 | 상태 코드 | 네트워크상의 장치를 검색합니다 |
| | megc_system_t 포인터 | 정수 | 검색된 장치 수를 반환합니다 |
| | 시스템 포인터, 인덱스 | megc_device_t 포인터 | 인덱스로 장치를 가져옵니다 |
| | 시스템 포인터, IP 문자열 | megc_device_t 포인터 | IP 주소로 장치를 가져옵니다 |
| | 시스템 포인터, 시리얼 번호 | megc_device_t 포인터 | 시리얼 번호로 장치를 가져옵니다 |
| | 시스템 포인터, 패턴 문자열 | megc_device_t 포인터 | 패턴으로 장치를 가져옵니다 |
| | megc_system_t 포인터 | 정수 | 네트워크 인터페이스 수를 반환합니다 |
| | 시스템 포인터, 인덱스 | megc_interface_t 포인터 | 네트워크 인터페이스를 가져옵니다 |
연결 함수 (Connection)
MEGC 클라이언트 객체의 초기화, 연결, 해제를 담당합니다.
| 함수 | 매개변수 | 반환값 | 설명 |
| | megc_t 포인터 | 상태 코드 | MEGC 클라이언트 객체를 초기화합니다 |
| | megc_t 포인터 | 상태 코드 | 빈 MEGC 객체를 초기화합니다 |
| | 클라이언트 포인터, 장치 포인터 | 상태 코드 | 장치 핸들로 연결합니다 |
| | 클라이언트 포인터, IP 문자열 | 상태 코드 | IP 주소로 연결합니다 |
| | 클라이언트 포인터, 시리얼 번호 | 상태 코드 | 시리얼 번호로 연결합니다 |
| | 클라이언트 포인터, 패턴 | 상태 코드 | 패턴으로 연결합니다 |
| | megc_t 포인터 | 상태 코드 | 장치 연결을 해제합니다 |
| | megc_t 포인터 | 상태 코드 | MEGC 객체를 정리합니다 |
장치 정보 함수 (Device Info)
연결된 장치의 속성 정보를 조회합니다.
| 함수 | 설명 |
| | 모델명 조회 |
| | 제조사명 조회 |
| | 시리얼 번호 조회 |
| | IP 주소 조회 |
| | MAC 주소 조회 |
| | 서브넷 마스크 조회 |
| | 기본 게이트웨이 조회 |
| | 장치 ID 조회 |
| | GigE Vision 버전 조회 |
| | DHCP 활성화 여부 |
| | DHCP 사용 가능 여부 |
| | Link-Local Address 활성화 여부 |
| | 고정 IP 활성화 여부 |
| | IP 설정 변경 |
사용 예시:
# 장치 모델명 조회
buffer_size = ct.c_ulong(256)
buffer = ct.create_string_buffer(256)
megc.DeviceGetModelName(device, buffer, ct.byref(buffer_size))
print(f"모델명: {buffer.value.decode()}")
# 장치 시리얼 번호 조회
megc.DeviceGetSerialNumber(device, buffer, ct.byref(buffer_size))
print(f"시리얼: {buffer.value.decode()}")
# IP 주소 조회
megc.DeviceGetIPAddress(device, buffer, ct.byref(buffer_size))
print(f"IP: {buffer.value.decode()}")
파라미터 함수 (Parameter)
장치 파라미터를 조회하고 설정하는 함수들입니다.
파라미터 타입
| 상수 | 값 | 설명 |
| | 0 | 없음 |
| | 1 | 불리언 |
| | 2 | 명령 |
| | 3 | 열거형 |
| | 4 | 부동소수점 |
| | 5 | 정수 |
| | 6 | 부호 없는 정수 |
| | 7 | 문자열 |
| | 8 | 레지스터 |
파라미터 접근 함수
| 함수 | 설명 |
| | 파라미터 타입 조회 |
| | 파라미터 이름 조회 |
| | 표시 이름 조회 |
| | 설명 조회 |
| | 툴팁 조회 |
| | 단위 조회 |
| | 가시성 레벨 조회 |
| | 사용 가능 여부 |
| | 읽기 가능 여부 |
| | 쓰기 가능 여부 |
타입별 값 조회/설정
| 타입 | 읽기 함수 | 쓰기 함수 | 범위 조회 |
| Boolean | | | - |
| Integer | | | |
| UInteger | | | |
| Float | | | |
| String | | | |
| Enum | | | |
| Register | | | |
| Command | - | | - |
Enum 파라미터 전용 함수
| 함수 | 설명 |
| | 이름으로 열거형 값 설정 |
| | 열거형 값을 문자열로 조회 |
| | 열거형 항목 수 조회 |
| | 인덱스로 항목 이름 조회 |
| | 인덱스로 표시 이름 조회 |
| | 인덱스로 항목 값 조회 |
| | 항목 사용 가능 여부 |
사용 예시:
# 파라미터 컬렉션 가져오기
params = megc.GetDeviceParams(ct.byref(megc_obj))
param_count = megc.GetDeviceParamsCount(ct.byref(megc_obj))
# 이름으로 파라미터 가져오기
param = megc.ParamsGetParamByName(params, b"ExposureTime")
# Float 값 읽기
value = ct.c_double()
megc.ParamGetFloatValue(param, ct.byref(value))
print(f"노출 시간: {value.value}")
# Float 범위 조회
min_val = ct.c_double()
max_val = ct.c_double()
megc.ParamGetFloatMinMaxValues(param, ct.byref(min_val), ct.byref(max_val))
print(f"범위: {min_val.value} ~ {max_val.value}")
# Float 값 쓰기
megc.ParamSetFloatValue(param, ct.c_double(200.0))
# Integer 파라미터 예시
param_width = megc.ParamsGetParamByName(params, b"Width")
int_value = ct.c_longlong()
megc.ParamGetIntegerValue(param_width, ct.byref(int_value))
print(f"Width: {int_value.value}")
# Enum 파라미터 예시
param_trigger = megc.ParamsGetParamByName(params, b"TriggerMode")
megc.ParamSetEnumValueByName(param_trigger, b"On")
파라미터 컬렉션 함수 (Params)
| 함수 | 설명 |
| | 장치 파라미터 컬렉션 조회 |
| | 장치 파라미터 수 조회 |
| | 스트림 파라미터 컬렉션 조회 |
| | 스트림 파라미터 수 조회 |
| | 통신 파라미터 컬렉션 조회 |
| | 통신 파라미터 수 조회 |
| | 이름으로 파라미터 검색 |
| | 인덱스로 파라미터 조회 |
| | 이름으로 카테고리 검색 |
| | 인덱스로 카테고리 조회 |
| | 카테고리 수 조회 |
| | 카테고리 내 파라미터 조회 |
컴포넌트 함수 (Component)
이미지 소스(컴포넌트)를 관리합니다. 센서는 여러 종류의 이미지를 제공할 수 있으며, 필요한 컴포넌트만 활성화하여 사용합니다.
| 함수 | 설명 |
| | 인덱스로 컴포넌트 조회 |
| | 전체 컴포넌트 배열 조회 |
| | 컴포넌트 수 조회 |
| | 컴포넌트 활성화/비활성화 |
| | 활성화 여부 확인 |
| | 컴포넌트 셀렉터 조회 |
| | 컴포넌트 셀렉터 설정 |
| | 소스 셀렉터 조회 |
| | 소스 셀렉터 설정 |
| | 리전 셀렉터 조회 |
| | 리전 셀렉터 설정 |
획득 함수 (Acquisition)
데이터 획득을 시작하고 제어합니다.
| 함수 | 설명 |
| | 획득 시작 (간편 함수) |
| | 획득 정지 (간편 함수) |
| | 연속 획득 시작 |
| | 모드 지정 획득 (0=연속, 1=단일 프레임) |
| | 획득 정지 |
| | 획득 중단 |
| | 획득 활성 상태 확인 |
| | 획득 모드 설정 |
데이터 수신 방식
콜백 방식 (Callback)
비동기적으로 이미지를 수신합니다. 이미지가 도착하면 등록된 콜백 함수가 자동 호출됩니다.
| 함수 | 설명 |
| | 단일 이미지 콜백 등록 |
| | 이미지 벡터 콜백 등록 |
| | 이벤트 콜백 등록 |
| | 연결 해제 콜백 등록 |
콜백 함수 시그니처:
# 단일 이미지 콜백
@ct.CFUNCTYPE(None, ct.POINTER(megc.meg_image_t), ct.c_void_p)
def image_callback(image, user_data):
# 이미지 처리 로직
pass
# 이미지 벡터 콜백
@ct.CFUNCTYPE(None, ct.POINTER(megc.meg_image_vec_t), ct.c_void_p)
def image_vec_callback(image_vec, user_data):
# 복수 이미지 처리 로직
pass
폴링 방식 (Polling)
동기적으로 이미지가 도착할 때까지 대기합니다. 스크립트 기반의 순차 처리에 적합합니다.
# 이미지 벡터 초기화
image_vec = megc.meg_image_vec_t()
megc.ImageVecInitEmpty(ct.byref(image_vec))
# 타임아웃(밀리초)으로 이미지 대기
status = megc.PollImages(ct.byref(megc_obj), ct.byref(image_vec), 20000, None)
if megc.MEGC_STATUS_IS_OK(status):
# 이미지 처리
pass
# 정리
megc.ImageVecDestroy(ct.byref(image_vec))
트리거 함수 (Trigger)
| 함수 | 설명 |
| | 트리거 모드 설정 |
| | 트리거 소스 설정 |
| | 소프트웨어 트리거 전송 |
이미지 관리 함수 (Image)
| 함수 | 설명 |
| | 이미지 객체 초기화 |
| | 데이터로 이미지 초기화 |
| | 빈 이미지 초기화 |
| | 이미지 크기 변경 |
| | 이미지 메모리 해제 |
| | 이미지 벡터 초기화 |
| | 빈 이미지 벡터 초기화 |
| | 이미지 벡터 크기 변경 |
| | 이미지 벡터 메모리 해제 |
데이터 구조체
이미지 타입
| 구조체 | 픽셀 포맷 상수 | 설명 |
| | | 8비트 흑백 이미지 |
| | | 16비트 흑백 이미지 |
| | - | 32비트 부동소수점 흑백 이미지 |
| | | 8비트 RGB 이미지 |
| | | 16비트 RGB 이미지 |
| | | 8비트 RGBA 이미지 |
| | | 16비트 RGBA 이미지 |
| | | 3D 포인트 클라우드 (X, Y, Z 좌표) |
| | | 2D 프로파일 (진폭 + 거리) |
| | | 16비트 진폭/신뢰도 |
| | | 32비트 신뢰도 이미지 |
3D 포인트 클라우드 데이터 (meg_abc32f_t)
3D 측정에서 사용하는 핵심 데이터 구조체입니다.
# meg_abc32f_t 구조체 필드
# .a = X 좌표 (float32)
# .b = Y 좌표 (float32)
# .c = Z 좌표 (float32)
# 3D 이미지 데이터 접근 예시
data_ptr = ct.cast(image.contents.data, ct.POINTER(megc.meg_abc32f_t))
width = image.contents.width
height = image.contents.height
for row in range(height):
for col in range(width):
idx = row * width + col
x = data_ptr[idx].a
y = data_ptr[idx].b
z = data_ptr[idx].c
if not math.isnan(x): # 유효한 포인트만 처리
print(f"X={x:.3f}, Y={y:.3f}, Z={z:.3f}")
2D 프로파일 데이터 (meg_ac32f_t)
2D 측정에서 사용하는 핵심 데이터 구조체입니다.
# meg_ac32f_t 구조체 필드
# .a = X 좌표/진폭 (float32)
# .c = Z 좌표/거리 (float32)
# 2D 프로파일 데이터 접근 예시
data_ptr = ct.cast(image.contents.data, ct.POINTER(megc.meg_ac32f_t))
width = image.contents.width
for col in range(width):
x = data_ptr[col].a
z = data_ptr[col].c
if not math.isnan(x):
print(f"X={x:.3f}, Z={z:.3f}")
접근 모드
| 상수 | 값 | 설명 |
| | 0 | 알 수 없음 |
| | 1 | 개방 (연결 가능) |
| | 2 | 제어 모드 (다른 클라이언트가 제어 중) |
| | 3 | 읽기 전용 모드 |
| | 4 | 배타적 접근 (다른 클라이언트 차단) |
읽기 전용 접근 설정
다른 클라이언트가 제어 중인 장치의 데이터를 수동으로 수신합니다.
# 접근 타입 확인
access_type = megc.GetAccessTypeByIPAddress(b"192.168.1.100")
if access_type == megc.MEGC_ACCESS_TYPE_CONTROL:
print("다른 클라이언트가 제어 중 - 읽기 전용 모드로 연결")
# 읽기 전용 모드로 설정 (포트 1042: 멀티캐스트 수신)
megc.SetAccessReadOnly(ct.byref(megc_obj), 1042)
# 또는 제어 모드로 전환
megc.SetAccessControl(ct.byref(megc_obj))
# 읽기 전용 여부 확인
is_readonly = megc.IsAccessReadOnly(ct.byref(megc_obj))
에러 처리
상태 코드
모든 API 함수는 상태 코드를 반환합니다. 상태 코드는 다음 세 가지 범주로 나뉩니다:
| 범주 | 조건 | 헬퍼 함수 |
| 성공 || status == 0 | | |
| 경고 | status > 0 | |
| 오류 | status < 0 | |
주요 에러 코드
| 상수 | 값 | 설명 |
| | 0 | 성공 |
| | -1 | 일반 오류 |
| | -2 | 메모리 부족 |
| | -3 | 초기화되지 않음 |
| | -4 | 내부 오류 |
| | -6 | 범위 초과 |
| | -200 | 장치 열기 실패 |
| | -201 | 장치 연결 실패 |
| | -202 | 스트림 열기 실패 |
| | -204 | 장치를 찾을 수 없음 |
| | -205 | 파라미터 쓰기 불가 |
| | -206 | 파라미터 타입 불일치 |
| | -207 | 파라미터 쓰기 실패 |
| | -208 | 파라미터 읽기 불가 |
| | -209 | 유효하지 않은 파라미터 값 |
| | -213 | 획득이 이미 시작됨 |
| | -214 | 획득이 시작되지 않음 |
| | -225 | 타임아웃 |
| | -226 | 장치가 이미 열려 있음 |
| | -229 | 콜백과 폴링 동시 사용 불가 |
| | 200 | 파라미터 범위 경고 |
에러 메시지 조회:
status = megc.ConnectByIPAddress(ct.byref(megc_obj), b"192.168.1.100")
if megc.MEGC_STATUS_IS_ERR(status):
error_msg = megc.GetErrorMessage(status)
print(f"오류 ({status}): {error_msg}")
가시성 레벨
파라미터의 표시 수준을 제어합니다.
| 상수 | 값 | 설명 |
| | 0 | 초급 사용자에게 표시 |
| | 1 | 전문가에게 표시 |
| | 2 | 고급 전문가에게 표시 |
| | 3 | 숨김 |
| | 4 | 정의되지 않음 |
로깅
| 함수 | 설명 |
| | 로그 레벨 설정 |
| | 로깅 활성화/비활성화 |
| | 콘솔 출력 활성화/비활성화 |
| | 로깅 시작 |
| | 파일로 로깅 시작 |
| | 로깅 중지 |
| | 로그 콜백 설정 |
로그 레벨
| 상수 | 값 | 설명 |
| | 0x000 | 로그 끔 |
| | 0x001 | 정보 |
| | 0x002 | 경고 |
| | 0x004 | 오류 |
| | 0x008 | 심각 |
| | 0x010 | 치명적 |
유틸리티 함수
| 함수 | 설명 |
| | 라이브러리 버전 조회 |
| | 상세 버전 정보 조회 |
| | 오류 메시지 문자열 조회 |
| | 라이선스 유효성 확인 |
| | 라이선스 오류 조회 |
| | 지정 시간(ms) 대기 |
| | 픽셀 타입의 바이트 크기 조회 |
| | 버퍼 수 설정 |
| | 현재 버퍼 수 조회 |
| | 스레드 지연 시간 설정 |
파일 전송
| 함수 | 설명 |
| | 로컬 파일을 장치로 업로드 |
| | 장치 파일을 로컬로 다운로드 |
| | 장치 XML 설명을 파일로 저장 |
실전 예제
예제 1: 장치 검색 (FindDevices)
네트워크에 연결된 모든 센서를 검색하고 정보를 출력합니다.
import ctypes as ct
import pymegc as megc
# 시스템 초기화
megc_sys = megc.megc_system_t()
status = megc.SysInit(ct.byref(megc_sys))
if megc.MEGC_STATUS_IS_ERR(status):
print("시스템 초기화 실패")
exit(1)
# 장치 검색
megc.SysFindDevices(ct.byref(megc_sys))
device_count = megc.SysGetDeviceCount(ct.byref(megc_sys))
print(f"검색된 장치 수: {device_count}")
# 각 장치 정보 출력
buffer_size = ct.c_ulong(256)
buffer = ct.create_string_buffer(256)
for i in range(device_count):
device = megc.SysGetDevice(ct.byref(megc_sys), i)
buffer_size.value = 256
megc.DeviceGetModelName(device, buffer, ct.byref(buffer_size))
model = buffer.value.decode()
buffer_size.value = 256
megc.DeviceGetSerialNumber(device, buffer, ct.byref(buffer_size))
serial = buffer.value.decode()
buffer_size.value = 256
megc.DeviceGetIPAddress(device, buffer, ct.byref(buffer_size))
ip = buffer.value.decode()
print(f" [{i}] {model} (S/N: {serial}, IP: {ip})")
# 정리
megc.SysDestroy(ct.byref(megc_sys))
예제 2: 3D 포인트 클라우드 측정 (콜백 방식)
scanCONTROL 센서로 3D 포인트 클라우드 데이터를 획득합니다.
import ctypes as ct
import pymegc as megc
import math
import time
# --- 콜백 함수 정의 ---
received_count = 0
@ct.CFUNCTYPE(None, ct.POINTER(megc.meg_image_t), ct.c_void_p)
def on_image(image, user_data):
global received_count
received_count += 1
img = image.contents
if img.type == megc.MEG_PIX_ABC32F:
data = ct.cast(img.data, ct.POINTER(megc.meg_abc32f_t))
valid_points = 0
for i in range(img.width * img.height):
if not math.isnan(data[i].a):
valid_points += 1
print(f"프레임 #{received_count}: {img.width}x{img.height}, "
f"유효 포인트: {valid_points}")
# --- 메인 로직 ---
# 시스템 초기화 및 장치 검색
megc_sys = megc.megc_system_t()
megc.SysInit(ct.byref(megc_sys))
megc.SysFindDevices(ct.byref(megc_sys))
if megc.SysGetDeviceCount(ct.byref(megc_sys)) == 0:
print("장치를 찾을 수 없습니다")
megc.SysDestroy(ct.byref(megc_sys))
exit(1)
device = megc.SysGetDevice(ct.byref(megc_sys), 0)
# MEGC 클라이언트 연결
megc_obj = megc.megc_t()
megc.Init(ct.byref(megc_obj))
megc.ConnectByDevice(ct.byref(megc_obj), device)
# 파라미터 설정
params = megc.GetDeviceParams(ct.byref(megc_obj))
# 노출 시간 설정
param = megc.ParamsGetParamByName(params, b"ExposureTime")
if param:
megc.ParamSetFloatValue(param, ct.c_double(100.0))
# 트리거 모드 설정
param = megc.ParamsGetParamByName(params, b"TriggerMode")
if param:
megc.ParamSetEnumValueByName(param, b"On")
# 3D 컴포넌트 활성화 (MEG_PIX_ABC32F)
comp_count = megc.GetComponentCount(ct.byref(megc_obj))
for i in range(comp_count):
comp = megc.GetComponent(ct.byref(megc_obj), i)
if comp and comp.contents.type == megc.MEG_PIX_ABC32F:
megc.ComponentEnable(ct.byref(megc_obj), comp, 1)
break
# 콜백 등록 및 획득 시작
megc.SetImageCallback(ct.byref(megc_obj), on_image, None)
megc.AcquisitionStart(ct.byref(megc_obj))
# 소프트웨어 트리거로 데이터 요청
for i in range(5):
megc.TriggerSoftware(ct.byref(megc_obj))
time.sleep(1)
# 정리
megc.AcquisitionStop(ct.byref(megc_obj))
megc.Disconnect(ct.byref(megc_obj))
megc.Destroy(ct.byref(megc_obj))
megc.SysDestroy(ct.byref(megc_sys))
print(f"총 수신 프레임: {received_count}")
예제 3: 2D 프로파일 측정 (폴링 방식)
폴링 방식으로 2D 프로파일 데이터를 획득합니다.
import ctypes as ct
import pymegc as megc
import math
# 시스템 초기화 및 연결
megc_sys = megc.megc_system_t()
megc.SysInit(ct.byref(megc_sys))
megc.SysFindDevices(ct.byref(megc_sys))
device = megc.SysGetDevice(ct.byref(megc_sys), 0)
megc_obj = megc.megc_t()
megc.Init(ct.byref(megc_obj))
megc.ConnectByDevice(ct.byref(megc_obj), device)
# 파라미터 설정
params = megc.GetDeviceParams(ct.byref(megc_obj))
param = megc.ParamsGetParamByName(params, b"ExposureTime")
if param:
megc.ParamSetFloatValue(param, ct.c_double(100.0))
# 2D 컴포넌트 활성화 (MEG_PIX_AC32F)
comp_count = megc.GetComponentCount(ct.byref(megc_obj))
for i in range(comp_count):
comp = megc.GetComponent(ct.byref(megc_obj), i)
if comp and comp.contents.type == megc.MEG_PIX_AC32F:
megc.ComponentEnable(ct.byref(megc_obj), comp, 1)
break
# 이미지 벡터 초기화
image_vec = megc.meg_image_vec_t()
megc.ImageVecInitEmpty(ct.byref(image_vec))
# 획득 시작
megc.Start(ct.byref(megc_obj))
# 폴링으로 이미지 수신 (타임아웃: 20초)
for frame in range(5):
status = megc.PollImages(ct.byref(megc_obj), ct.byref(image_vec), 20000, None)
if megc.MEGC_STATUS_IS_OK(status):
# 이미지 벡터에서 데이터 추출
for j in range(image_vec.count):
img = image_vec.images[j]
if img.type == megc.MEG_PIX_AC32F:
data = ct.cast(img.data, ct.POINTER(megc.meg_ac32f_t))
print(f"프레임 #{frame}: 너비={img.width}")
# 처음 5개 포인트 출력
for k in range(min(5, img.width)):
x = data[k].a
z = data[k].c
if not math.isnan(x):
print(f" 포인트[{k}]: X={x:.3f}, Z={z:.3f}")
else:
print(f"폴링 실패: {status}")
# 정리
megc.Stop(ct.byref(megc_obj))
megc.ImageVecDestroy(ct.byref(image_vec))
megc.Disconnect(ct.byref(megc_obj))
megc.Destroy(ct.byref(megc_obj))
megc.SysDestroy(ct.byref(megc_sys))
예제 4: 파라미터 목록 조회
장치의 모든 파라미터를 타입별로 조회하고 현재 값을 출력합니다.
import ctypes as ct
import pymegc as megc
# 연결 (생략: 위 예제 참조)
# ...
params = megc.GetDeviceParams(ct.byref(megc_obj))
param_count = megc.GetDeviceParamsCount(ct.byref(megc_obj))
buffer_size = ct.c_ulong(256)
buffer = ct.create_string_buffer(256)
for i in range(param_count):
param = megc.ParamsGetParam(params, i)
param_type = megc.ParamGetType(param)
buffer_size.value = 256
megc.ParamGetName(param, buffer, ct.byref(buffer_size))
name = buffer.value.decode()
# 읽기 가능한 파라미터만 값 표시
if not megc.ParamIsReadable(param):
print(f" {name}: [읽기 불가]")
continue
if param_type == megc.MEG_PARAM_BOOLEAN:
val = ct.c_ubyte()
megc.ParamGetBooleanValue(param, ct.byref(val))
print(f" {name} (Boolean): {bool(val.value)}")
elif param_type == megc.MEG_PARAM_INTEGER:
val = ct.c_longlong()
megc.ParamGetIntegerValue(param, ct.byref(val))
min_v, max_v, inc = ct.c_longlong(), ct.c_longlong(), ct.c_longlong()
megc.ParamGetIntegerMinMaxIncValues(param, ct.byref(min_v), ct.byref(max_v), ct.byref(inc))
print(f" {name} (Integer): {val.value} [{min_v.value}..{max_v.value}, step={inc.value}]")
elif param_type == megc.MEG_PARAM_FLOAT:
val = ct.c_double()
megc.ParamGetFloatValue(param, ct.byref(val))
min_v, max_v = ct.c_double(), ct.c_double()
megc.ParamGetFloatMinMaxValues(param, ct.byref(min_v), ct.byref(max_v))
print(f" {name} (Float): {val.value} [{min_v.value}..{max_v.value}]")
elif param_type == megc.MEG_PARAM_ENUM:
val = ct.c_longlong()
megc.ParamGetEnumValue(param, ct.byref(val))
buffer_size.value = 256
megc.ParamGetEnumStringValue(param, buffer, ct.byref(buffer_size))
print(f" {name} (Enum): {buffer.value.decode()} ({val.value})")
elif param_type == megc.MEG_PARAM_STRING:
buffer_size.value = 256
megc.ParamGetStringValue(param, buffer, ct.byref(buffer_size))
print(f" {name} (String): {buffer.value.decode()}")
예제 5: 읽기 전용 접근 (ReadOnlyAccess)
다른 클라이언트가 제어 중인 장치의 데이터를 수동으로 모니터링합니다.
import ctypes as ct
import pymegc as megc
device_ip = b"192.168.1.100"
# 접근 타입 확인
access_type = megc.GetAccessTypeByIPAddress(device_ip)
print(f"접근 타입: {access_type}")
if access_type == megc.MEGC_ACCESS_TYPE_OPEN:
print("장치가 사용 가능합니다 - 제어 모드로 연결")
elif access_type == megc.MEGC_ACCESS_TYPE_CONTROL:
print("다른 클라이언트가 제어 중 - 읽기 전용으로 연결")
# 클라이언트 초기화 및 읽기 전용 설정
megc_obj = megc.megc_t()
megc.Init(ct.byref(megc_obj))
megc.SetAccessReadOnly(ct.byref(megc_obj), 1042) # 멀티캐스트 포트
megc.ConnectByIPAddress(ct.byref(megc_obj), device_ip)
# 콜백 등록 후 데이터 수신
megc.SetImageCallback(ct.byref(megc_obj), on_image, None)
megc.Start(ct.byref(megc_obj))
# ... 데이터 수신 대기 ...
# 정리
megc.Stop(ct.byref(megc_obj))
megc.Disconnect(ct.byref(megc_obj))
megc.Destroy(ct.byref(megc_obj))
주요 장치 파라미터
센서에서 자주 사용되는 파라미터 목록입니다.
| 파라미터명 | 타입 | 설명 |
| | Float | 센서 노출 시간 (마이크로초) |
| | Integer | 이미지 너비 (픽셀) |
| | Integer | 이미지 높이 (픽셀) |
| | Integer | 수평 비닝 계수 |
| | Enum | 관심 영역(ROI) 모드 |
| | Enum | 관심 영역 선택 |
| | Enum | 트리거 모드 (On/Off) |
| | Enum | 트리거 선택 |
| | Float | 스캔 라인 속도 (lines/sec) |
| | Float | 프레임 속도 (frames/sec) |
| | Enum | 3D 좌표 선택 |
| | Boolean | 무효 데이터 마커 활성화 |
| | Float | 무효 데이터 값 (기본: NaN) |
| | Integer | 프로파일 카운터 (청크 데이터) |
| | Enum | 인코더 출력 모드 |
| | Integer | 데이터 요청 타임아웃 (ms) |
센서별 차이점
| 기능 | scanCONTROL 3xxx | scanCONTROL 8xxx | ReflectControl | SurfaceControl |
| 획득 시작 | | | | |
| 트리거 | 획득 모드로 직접 트리거 | | 동일 | 동일 |
| 프레임 속도 | | | 장치별 상이 | 장치별 상이 |
| 리전 모드 | 설정 필요 | 기본값 사용 | 기본값 사용 | 기본값 사용 |
| 카메라 라이브 | MONO8/MONO10 | MONO8/MONO10 | MONO8/MONO10 | MONO8/MONO10 |
네트워크 인터페이스
| 함수 | 설명 |
| | 인터페이스 설명 조회 |
| | 인터페이스 IP 주소 조회 |
| | 인터페이스 MAC 주소 조회 |
| | 서브넷 마스크 조회 |
| | 기본 게이트웨이 조회 |
| | IP 주소 수 조회 |
| | 연결된 장치 수 조회 |
| | 인덱스로 장치 조회 |
| | IP 주소를 고정으로 설정 |
멀티캐스트 스트리밍
모범 사례
리소스 관리
- 반드시
Destroy()와SysDestroy()를 호출하여 리소스를 해제합니다 -
ImageVecDestroy()로 이미지 벡터를 해제합니다 - try/finally 블록을 사용하여 예외 발생 시에도 정리가 수행되도록 합니다
에러 처리
- 모든 API 호출 후
MEGC_STATUS_IS_ERR()로 상태를 확인합니다 -
GetErrorMessage()로 상세 오류 메시지를 조회합니다
성능 최적화
- 필요한 컴포넌트만 활성화합니다
- 적절한 버퍼 수를 설정합니다 (
SetBufferCount()) - 대량 데이터 처리 시 콜백 방식을 사용합니다
- 스크립트 기반 순차 처리에는 폴링 방식이 간단합니다
콜백 vs 폴링
| 방식 | 장점 | 단점 | 적합한 경우 |
| 콜백 | 비동기, 높은 처리량, 실시간 | 스레드 안전성 주의 필요 | 연속 모니터링, 고속 획득 |
| 폴링 | 간단한 코드, 순차 처리 | 타임아웃 대기, 낮은 처리량 | 스크립트, 단발 측정 |
| WARNING |
| 콜백과 폴링을 동시에 사용하면 |
문제 해결
| 증상 | 원인 | 해결 방법 |
| 장치를 찾을 수 없음 | 네트워크 설정 문제 | 방화벽 설정 확인, 센서와 같은 서브넷인지 확인 |
| 연결 실패 (-201) | 다른 클라이언트가 배타적 접근 중 | |
| 타임아웃 (-225) | 트리거가 전송되지 않음 | 트리거 모드/소스 설정 확인, |
| 데이터가 NaN | 측정 범위 밖의 포인트 | |
| 라이선스 오류 | DLL 라이선스 문제 | |
| 파라미터 쓰기 실패 (-207) | 획득 중 변경 불가 파라미터 | 획득을 정지한 후 파라미터 변경 |
README.txt
How to install PythonWrapper
- Identify your Python installation folder, e.g. C:\Program Files\Python310
- Go to folder Lib\site-packages, e.g. C:\Program Files\Python310\Lib\site-packages
- From PythonWrapper, copy the pymegc folder to site-packages
- Test your installation by running a sample in PythonWrapper/examples/*