# hik_camera_panel

`hik_camera_ros2_driver`(cam1/cam2/cam3)의 노출·게인·ROI 파라미터를 슬라이더 또는 직접 숫자
입력으로 실시간 조절하는 패널. 카메라별 탭 안에 실시간 이미지 미리보기가 있고, ROI(측광 제외
상단 비율)를 조절하면 그 경계선이 이미지 위에 바로 그려진다.

## 실행

카메라 노드(`hik_camera_cam1`/`hik_camera_cam2`/`hik_camera_cam3`)가 먼저 떠 있어야 한다.

```bash
ros2 run hik_camera_panel panel_node
```

## 구성

- 탭 3개(cam1/cam2/cam3), 각 탭은 `/hik_camera_camN/get_parameters`·`/hik_camera_camN/set_parameters`
  서비스를 직접 호출해서 값을 읽고 쓴다.
- 그룹: 노출 / 게인 / 소프트웨어 AE·ROI / 동기화.
- 숫자 파라미터는 슬라이더+스핀박스를 같이 제공한다. 슬라이더를 드래그하는 동안은 로컬
  미리보기(ROI 오버레이)만 갱신되고, 손을 뗀 시점에 실제로 카메라에 값을 적용한다. 스핀박스는
  값을 직접 입력하고 포커스를 벗어나면(또는 Enter) 바로 적용된다.
- 노출/노출상한/노출하한은 범위가 15µs~100ms로 넓어서 슬라이더를 로그 스케일로 매핑했다
  (`param_spec.py`의 `log_scale=True`).
- ROI 미리보기: 카메라의 `/<camera_name>/image` 토픽을 구독해서 QImage로 바로 그린다
  (cv_bridge/OpenCV 의존성 없음 — 드라이버가 항상 `rgb8`로 발행하므로 `QImage.Format_RGB888`로
  직접 변환 가능).

## 알아둘 것

1. **`sync_role`/`sync_master_camera_ns`는 조회만 되고 편집은 막혀 있다.** 드라이버가 publisher/
   subscriber를 노드 시작 시 `initSync()`에서 한 번만 만들기 때문에, 런타임에 이 값을 바꿔도
   반영되지 않는다 (`hik_camera_node.cpp`의 `dynamicParametersCallback()`도 이 두 파라미터는
   처리하지 않음 — 시도하면 "Unknown parameter"로 거부됨). 마스터/슬레이브 역할을 바꾸려면
   yaml을 고치고 노드를 재시작해야 한다.
2. **나머지 파라미터는 이번에 `hik_camera_node.cpp`의 `dynamicParametersCallback()`을 확장해서
   전부 런타임에 반영되도록 만들었다** (`gain_auto_max_db`, `ae_roi_top_ratio`,
   `ae_target_percentile`, `ae_target_dn`, `ae_saturation_percentile`, `ae_saturation_dn`,
   `ae_step_gain`). 이 패널이 슬라이더로 값을 바꿨을 때 실제로 카메라에 반영되려면 드라이버
   쪽도 이 커밋 이후 버전이어야 한다.
3. **개발 PC(macOS)에는 ROS 2와 `python_qt_binding`이 없어서 실행 검증을 못 했다.** Python
   문법 검사(`python3 -m py_compile`)와 슬라이더↔값 변환 로직의 라운드트립 테스트만 순수
   Python으로 돌려봤고, 실제 rclpy 파라미터 서비스 호출·Qt 위젯 동작·이미지 렌더링은 로봇
   PC에서 `ros2 run hik_camera_panel panel_node`로 직접 확인해야 한다.
4. 카메라 노드/토픽 이름이 `camera_params_cam{1,2,3}.yaml` 및
   `hik_camera_triple_launch.py`와 다르면 `panel_node.py`의 `DEFAULT_CAMERAS` 목록을 맞춰
   수정할 것.
