griip-sdk-dev 0.4.0.dev24238__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. griip_sdk_dev-0.4.0.dev24238/.coverage +0 -0
  2. griip_sdk_dev-0.4.0.dev24238/PKG-INFO +513 -0
  3. griip_sdk_dev-0.4.0.dev24238/README.md +481 -0
  4. griip_sdk_dev-0.4.0.dev24238/coverage.xml +23585 -0
  5. griip_sdk_dev-0.4.0.dev24238/docs/griip-sdk-consumer-improvements.md +476 -0
  6. griip_sdk_dev-0.4.0.dev24238/project.json +72 -0
  7. griip_sdk_dev-0.4.0.dev24238/pyproject.toml +72 -0
  8. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/__init__.py +77 -0
  9. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/__init__.py +0 -0
  10. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/app.py +638 -0
  11. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/apriltag_pose.py +101 -0
  12. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/camera_factory.py +105 -0
  13. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/cartesian_pose.py +220 -0
  14. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/config_store.py +131 -0
  15. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/hand_eye_calib/README.md +109 -0
  16. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/hand_eye_calib/__init__.py +40 -0
  17. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/hand_eye_calib/config/routine.yaml +7 -0
  18. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/hand_eye_calib/core.py +692 -0
  19. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/hand_eye_calib/main.py +596 -0
  20. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/hand_eye_calib/planning.py +122 -0
  21. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/hand_eye_calib/routines.py +223 -0
  22. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/hand_eye_calib/run_hand_eye_calibration.py +131 -0
  23. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/hand_eye_calib/transforms.py +57 -0
  24. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/mqtt_publisher.py +98 -0
  25. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/mqtt_topics.py +15 -0
  26. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/routines.py +36 -0
  27. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/scanning/__init__.py +11 -0
  28. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/scanning/environment_scanning.py +381 -0
  29. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/scanning/run_environment_scanning.py +142 -0
  30. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/tests/__init__.py +0 -0
  31. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/tests/conftest.py +33 -0
  32. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/tests/test_calibration_app.py +822 -0
  33. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/tests/test_camera_factory.py +126 -0
  34. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/tests/test_environment_scanning.py +547 -0
  35. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/tests/test_hand_eye_calibration_service.py +524 -0
  36. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/tests/test_hand_eye_helpers.py +211 -0
  37. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/tests/test_transforms.py +126 -0
  38. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/types.py +21 -0
  39. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/calibration/units.py +104 -0
  40. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/__init__.py +22 -0
  41. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/builders.py +631 -0
  42. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/config.py +505 -0
  43. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/end_effector_collision_model.py +160 -0
  44. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/initialize.py +282 -0
  45. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/loader.py +102 -0
  46. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/mock_builders.py +114 -0
  47. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/parts.py +63 -0
  48. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/recipes.py +872 -0
  49. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/tests/__init__.py +0 -0
  50. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/tests/conftest.py +7 -0
  51. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/tests/test_builders.py +13 -0
  52. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/tests/test_end_effector_collision_model.py +118 -0
  53. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/tests/test_initialize.py +458 -0
  54. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/tests/test_loader.py +70 -0
  55. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/tests/test_mock_cell_smoke.py +54 -0
  56. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/tests/test_parts.py +55 -0
  57. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/tests/test_recipes.py +156 -0
  58. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/cell/tests/test_recording_config.py +113 -0
  59. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/errors.py +16 -0
  60. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/grpc_adapters/__init__.py +0 -0
  61. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/grpc_adapters/servicer_as_stub.py +166 -0
  62. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/__init__.py +0 -0
  63. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/bin_shaker.py +86 -0
  64. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/camera.py +300 -0
  65. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/fanuc_robot_client.py +266 -0
  66. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/ft_sensor.py +352 -0
  67. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/gripper.py +339 -0
  68. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/grpc_vision_backend.py +123 -0
  69. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/io_client.py +194 -0
  70. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/mmai_vision_backend.py +265 -0
  71. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/mocks/__init__.py +0 -0
  72. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/mocks/camera_mock.py +62 -0
  73. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/mocks/gripper_client_mock.py +135 -0
  74. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/mocks/io_client_mock.py +28 -0
  75. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/mocks/robot_client_mock.py +584 -0
  76. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/onrobot_3fg15_gripper.py +103 -0
  77. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/robot_client.py +1692 -0
  78. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/robotiq_2f140_gripper.py +327 -0
  79. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/sim_gripper.py +365 -0
  80. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/sim_hand_eye.py +138 -0
  81. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/sim_robot_client.py +189 -0
  82. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/suction_gripper.py +112 -0
  83. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/__init__.py +0 -0
  84. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/conftest.py +8 -0
  85. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_call_with_timeout.py +56 -0
  86. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_command_state_fanout.py +131 -0
  87. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_gripper_command_listeners.py +90 -0
  88. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_grpc_vision_backend.py +220 -0
  89. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_mmai_vision_backend.py +312 -0
  90. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_reset_to_normal.py +101 -0
  91. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_robot_client_base.py +48 -0
  92. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_robot_client_lifecycle.py +323 -0
  93. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_robot_feedback_fanout.py +154 -0
  94. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_robotiq_2f140_gripper.py +86 -0
  95. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_robotiq_gripper_bus_lock.py +78 -0
  96. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_sim_gripper.py +230 -0
  97. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_sim_hand_eye.py +226 -0
  98. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_sim_robot_client.py +196 -0
  99. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_suction_gripper.py +82 -0
  100. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_tower_light.py +179 -0
  101. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_vision_codec.py +73 -0
  102. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tests/test_vrmcs_tcp_guard.py +81 -0
  103. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/torquing_client.py +23 -0
  104. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/tower_light.py +84 -0
  105. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/ur_robot_client.py +88 -0
  106. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/hardware/vision_codec.py +77 -0
  107. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/log_utils.py +42 -0
  108. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/__init__.py +0 -0
  109. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/sphere_generation_tool/README.md +187 -0
  110. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/sphere_generation_tool/__init__.py +8 -0
  111. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/sphere_generation_tool/__main__.py +242 -0
  112. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/sphere_generation_tool/_actors.py +278 -0
  113. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/sphere_generation_tool/_geometry.py +55 -0
  114. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/sphere_generation_tool/editor.py +1142 -0
  115. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/sphere_generation_tool/object_io.py +53 -0
  116. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/sphere_generation_tool/urdf_io.py +315 -0
  117. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/tests/__init__.py +0 -0
  118. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/tests/conftest.py +123 -0
  119. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/tests/test_editor_math.py +80 -0
  120. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/tests/test_editor_smoke.py +471 -0
  121. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/tests/test_mesh_loading.py +66 -0
  122. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/tests/test_object_io.py +72 -0
  123. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/modeling/tests/test_urdf_io.py +367 -0
  124. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/__init__.py +129 -0
  125. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/bin_cuboid_extraction.py +77 -0
  126. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/bin_picking_manager.py +580 -0
  127. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/bin_state.py +85 -0
  128. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/callbacks.py +60 -0
  129. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/cycle_pause_gate.py +92 -0
  130. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/errors.py +27 -0
  131. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/execution/__init__.py +18 -0
  132. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/execution/grasp_executor.py +105 -0
  133. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/execution/parallel_jaw_executor.py +132 -0
  134. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/execution/suction_executor.py +53 -0
  135. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/execution/tests/__init__.py +0 -0
  136. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/execution/tests/test_parallel_jaw_executor.py +164 -0
  137. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/execution/three_finger_executor.py +144 -0
  138. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/grasp_provider.py +258 -0
  139. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/grasp_queue.py +107 -0
  140. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/part_setup.py +52 -0
  141. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/perception_inputs.py +187 -0
  142. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/pick_and_place_manager.py +1514 -0
  143. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/pick_generator.py +230 -0
  144. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/placement_planner.py +365 -0
  145. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/planning.py +59 -0
  146. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/proto_conversions.py +113 -0
  147. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/roi_scheduler.py +150 -0
  148. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/scoop_executor.py +122 -0
  149. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/__init__.py +0 -0
  150. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/conftest.py +156 -0
  151. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/test_bin_picking_manager.py +485 -0
  152. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/test_bin_state.py +160 -0
  153. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/test_cycle_pause_gate.py +130 -0
  154. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/test_grasp_provider.py +307 -0
  155. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/test_part_setup.py +69 -0
  156. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/test_perception_inputs.py +122 -0
  157. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/test_phase_collision_spheres.py +57 -0
  158. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/test_pick_and_place_manager.py +760 -0
  159. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/test_pick_generator.py +130 -0
  160. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/test_placement_planner.py +333 -0
  161. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/test_planning.py +64 -0
  162. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/test_proto_conversions.py +96 -0
  163. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/tests/test_scoop_executor.py +106 -0
  164. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/trajectory_store.py +170 -0
  165. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/orchestration/types.py +466 -0
  166. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/prototyping/__init__.py +0 -0
  167. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/prototyping/config/__init__.py +20 -0
  168. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/prototyping/config/registry.py +22 -0
  169. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/prototyping/in_process_api.py +59 -0
  170. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/prototyping/read_tcp.py +67 -0
  171. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/prototyping/run_environment_scanning.py +99 -0
  172. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/prototyping/run_hand_eye_calibration.py +104 -0
  173. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/prototyping/run_linear_shuttle.py +556 -0
  174. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/__init__.py +71 -0
  175. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/foxglove_events.py +553 -0
  176. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/foxglove_joint_states.py +115 -0
  177. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/gripper_state_logger.py +203 -0
  178. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/gripper_state_mcap_recording.py +69 -0
  179. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/h264_video_logger.py +128 -0
  180. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/h264_video_mcap_recording.py +217 -0
  181. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/kpi_logger.py +186 -0
  182. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/kpi_mcap_recording.py +143 -0
  183. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/kpi_timer.py +148 -0
  184. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/mcap_recording.py +209 -0
  185. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/memory_utils.py +19 -0
  186. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/robot_state_logger.py +133 -0
  187. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/rotating_mcap_writer.py +326 -0
  188. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/tests/test_foxglove_event_publisher.py +324 -0
  189. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/tests/test_foxglove_joint_states.py +26 -0
  190. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/tests/test_kpi_timer.py +346 -0
  191. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/tests/test_mcap_foxglove_event_publisher.py +355 -0
  192. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/tests/test_mcap_gripper_state_logger.py +334 -0
  193. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/tests/test_mcap_h264_video_logger.py +118 -0
  194. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/tests/test_mcap_kpi_logger.py +72 -0
  195. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/tests/test_mcap_robot_state_logger.py +253 -0
  196. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/recording/tests/test_session.py +87 -0
  197. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/tests/__init__.py +0 -0
  198. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/tests/test_log_utils.py +81 -0
  199. griip_sdk_dev-0.4.0.dev24238/src/griip_sdk/tests/test_servicer_as_stub.py +69 -0
Binary file
@@ -0,0 +1,513 @@
1
+ Metadata-Version: 2.5
2
+ Name: griip-sdk-dev
3
+ Version: 0.4.0.dev24238
4
+ Summary: Dev build of griip-sdk from commit 920520032 (PR #6192). Not a release.
5
+ Author: VentionCo
6
+ License: Proprietary
7
+ Requires-Python: <3.11,>=3.10
8
+ Requires-Dist: defusedxml<0.8.0,>=0.7.1
9
+ Requires-Dist: fastapi[standard]>=0.121.1
10
+ Requires-Dist: foxglove-schemas-protobuf
11
+ Requires-Dist: griip-core>=0.4.0
12
+ Requires-Dist: grpcio>=1.78.0
13
+ Requires-Dist: httpx[http2]<0.29.0,>=0.28.1
14
+ Requires-Dist: mcap-protobuf-support<1.0,>=0.4.0
15
+ Requires-Dist: mcap<2.0,>=1.3.0
16
+ Requires-Dist: numpy>=1.24
17
+ Requires-Dist: omegaconf<3.0.0,>=2.3.0
18
+ Requires-Dist: opencv-python-headless<5.0.0,>=4.9.0
19
+ Requires-Dist: paho-mqtt<2.0,>=1.5
20
+ Requires-Dist: protobuf>=4.0
21
+ Requires-Dist: pydantic==2.11.1
22
+ Requires-Dist: pymodbus==3.11
23
+ Requires-Dist: pyserial<4.0,>=3.5
24
+ Requires-Dist: pyyaml<7.0,>=6.0
25
+ Requires-Dist: scipy<2.0,>=1.11.0
26
+ Requires-Dist: spatialmath-python<2.0.0,>=1.1.15
27
+ Requires-Dist: toppra<=0.6.3,>=0.6.0
28
+ Requires-Dist: trimesh<5.0,>=4.11
29
+ Requires-Dist: urchin<0.0.31,>=0.0.30
30
+ Requires-Dist: vention-grpc-py-sdk==0.0.67.dev34389318765
31
+ Description-Content-Type: text/markdown
32
+
33
+ # griip-sdk
34
+
35
+ Hardware control and orchestration for bin picking, by [Vention](https://vention.io).
36
+
37
+ The SDK owns the robot, gripper, perception, and planning. You own the loop:
38
+ when to pick, where the part goes, and what to do on failure.
39
+
40
+ ## Install
41
+
42
+ ```bash
43
+ pip install griip-sdk
44
+ ```
45
+
46
+ Python 3.10. Needs a running `mmai-griip-api`. From outside the Vention
47
+ monorepo, use gRPC mode.
48
+
49
+ Wheels publish to public PyPI from `master` via the monorepo `nx release`
50
+ pipeline. Pull-request CI only dry-runs. Cells that still keep private extras
51
+ under `/opt/vention/wheels/` can add `--find-links /opt/vention/wheels/`.
52
+
53
+ ### Testing a pull request
54
+
55
+ Every pull request that touches the SDK publishes a dev build to its own PyPI
56
+ project, so you can try a branch before it merges:
57
+
58
+ ```bash
59
+ pip uninstall -y griip-sdk # both own the `griip_sdk` import package
60
+ pip install griip-sdk-dev==<version>
61
+ ```
62
+
63
+ The version is on the pull request's CI summary, as
64
+ `<next release>.dev<run number>`. `pip show griip-sdk-dev` names the commit it
65
+ was built from. Dev builds depend on *released* siblings, so a branch that also
66
+ changes `griip-core` is only half-covered by one. Never install one on a
67
+ production cell.
68
+
69
+ ## Quickstart
70
+
71
+ ```python
72
+ from griip_sdk import build_pick_only_manager
73
+
74
+ DROP_JOINTS = [-1.5, -1.2, 1.0, -1.4, -1.5, 0.0] # your drop pose
75
+
76
+ with build_pick_only_manager("./pick.yaml", part_id="pcb") as manager:
77
+ pick = manager.pick(max_attempts=3)
78
+ if pick.succeeded:
79
+ manager.start_pick_generation() # perception runs while you move
80
+ manager.collision_free_move_to_joints(DROP_JOINTS, object_in_tcp=pick.obj_in_tcp)
81
+ manager.release()
82
+ ```
83
+
84
+ Two entry points, same setup under the hood:
85
+
86
+ - `build_pick_only_manager` for single-cycle pick-only work (above).
87
+ - `build_bin_picking_manager` for a continuous bin-pick + placement loop; you
88
+ pass a `handle_placement` callback and call `manager.run()`.
89
+
90
+ Both return a context manager that wires up hardware and tears it down on exit.
91
+
92
+ ## Handling failures
93
+
94
+ `manager.pick()` always returns a `PickResult`. On failure, `failure_reasons`
95
+ holds one reason per attempt in order. `failure_reasons[-1]` is the last
96
+ attempt; more than one distinct reason means the cell is failing for shifting
97
+ reasons.
98
+
99
+ | `PickFailureReason` | Meaning | Typical response |
100
+ |---|---|---|
101
+ | `NO_PARTS_DETECTED` | Perception saw no objects. | Request refill. |
102
+ | `NO_GRASPABLE_PARTS` | Parts visible but none reachable. | Shake / reorient. |
103
+ | `GRIP_CHECK_FAILED` | Scooped but nothing in hand. | Retry next loop. |
104
+ | `MOTION_FAILED` | Collision or scoop plan/exec failure. | Alert operator. |
105
+ | `PERCEPTION_FAILED` | Picking stream died mid-call (gRPC error). | Backoff + retry, or page ops. |
106
+ | `PLACEMENT_FAILED` | Pick OK, place leg failed (placement mode). | Cell-specific. |
107
+
108
+ `pick.attempts_made` and `pick.detail` are for logs and metrics, not control
109
+ flow. Hardware faults (robot or gripper driver) don't map to a reason: they
110
+ escape as exceptions, which is your "stop the cell" signal.
111
+
112
+ A loop that acts on each reason:
113
+
114
+ ```python
115
+ from griip_sdk import build_pick_only_manager, PickFailureReason
116
+
117
+ with build_pick_only_manager("./pick.yaml", part_id="pcb") as manager:
118
+ while True:
119
+ pick = manager.pick(max_attempts=3)
120
+
121
+ if pick.succeeded:
122
+ manager.start_pick_generation()
123
+ manager.collision_free_move_to_joints(DROP_JOINTS, object_in_tcp=pick.obj_in_tcp)
124
+ manager.release()
125
+ continue
126
+
127
+ if len(set(pick.failure_reasons)) > 1:
128
+ alert_operator(f"cell unstable: {pick.failure_reasons}")
129
+ break
130
+
131
+ match pick.failure_reasons[-1]:
132
+ case PickFailureReason.NO_PARTS_DETECTED:
133
+ request_refill()
134
+ case PickFailureReason.NO_GRASPABLE_PARTS:
135
+ shake_bin()
136
+ case PickFailureReason.GRIP_CHECK_FAILED:
137
+ pass # SDK already retried; try again next loop
138
+ case PickFailureReason.MOTION_FAILED | PickFailureReason.PERCEPTION_FAILED:
139
+ alert_operator(pick.detail)
140
+ break
141
+ ```
142
+
143
+ ## Manager methods
144
+
145
+ | Method | Effect |
146
+ |---|---|
147
+ | `pick(max_attempts=3)` | Pick only. Returns a `PickResult`; robot stays at the prep pose on success. |
148
+ | `pick_and_place_once(max_pick_attempts=3, target_pose=...)` | Pick, then place when `target_pose` is given. |
149
+ | `start_pick_generation()` | Move to the capture pose and run perception. The camera grab is synchronous; perception runs async. |
150
+ | `collision_free_move_to_joints(target, object_in_tcp=None, ...)` | Collision-aware joint move. Pass `object_in_tcp=pick.obj_in_tcp` while carrying a part. |
151
+ | `release()` | Open the gripper and clear `object_in_hand`. |
152
+ | `set_capture_joints(joints)` | Change where perception captures from, next capture on. |
153
+ | `set_part(part_id)` | Swap the active part mid-session. Re-sends Initialize over the existing channel; no hardware or planner re-init. |
154
+
155
+ ## `pick.yaml`
156
+
157
+ The cell YAML points the runner at the robot, gripper, camera, perception
158
+ backends, and the cell's collision geometry. It does not hold drop poses or
159
+ loop policy. That is your application code.
160
+
161
+ ## Bring your own gripper
162
+
163
+ Both builders take an optional `gripper=`. When set, the SDK uses your client
164
+ instead of building one from the YAML.
165
+
166
+ Use the SDK's Robotiq 2F-140 directly, so a bench consumer keeps its hardware
167
+ constants out of the cell YAML:
168
+
169
+ ```python
170
+ from griip_sdk import build_pick_only_manager
171
+ from griip_sdk.hardware.robotiq_2f140_gripper import Robotiq2F140Gripper
172
+
173
+ gripper = Robotiq2F140Gripper(serial_port="/tmp/ttyUR", baudrate=115200, modbus_slave_id=9, grip_force=20, release_width=800)
174
+
175
+ with build_pick_only_manager("./pick.yaml", part_id="pcb", gripper=gripper) as manager:
176
+ ...
177
+ ```
178
+
179
+ Or subclass `BaseGripper` for a gripper the SDK doesn't ship (a Modbus /
180
+ EtherNet-IP unit, or an in-memory fake for tests):
181
+
182
+ ```python
183
+ from griip_sdk import BaseGripper, GripperMoveResult, build_pick_only_manager
184
+
185
+ class MyEthernetIPGripper(BaseGripper):
186
+ def get_width(self) -> int: ...
187
+ def get_current_draw(self) -> int: ...
188
+ def is_in_safety_stop(self) -> bool: ...
189
+ def reset_safety(self) -> None: ...
190
+ def reconnect(self) -> None: ...
191
+ def stop(self) -> None: ...
192
+ def close_gripper(self, force_value=400, block=False, timeout=10.0) -> GripperMoveResult: ...
193
+ def open_gripper(self, force_value=400, block=False) -> GripperMoveResult: ...
194
+ def move_gripper(self, width_value, force_value=400, block=False, timeout=None) -> GripperMoveResult: ...
195
+
196
+ with build_pick_only_manager("./pick.yaml", part_id="pcb", gripper=MyEthernetIPGripper(...)) as manager:
197
+ ...
198
+ ```
199
+
200
+ Two things to know:
201
+
202
+ - The YAML `tool.gripper` block still drives manager state
203
+ (`closed_gripper_width`, `expected_grip_width_range`, `grip_check_width_margin`,
204
+ `min_grip_width_for_current_part`). Only the hardware-construction fields
205
+ (`serial_port`, `baudrate`, `modbus_slave_id`, `force`, `release_width`) are
206
+ ignored when you inject a gripper. The SDK logs this once at `INFO`.
207
+ - The SDK does no gripper-side teardown. If your gripper holds a connection
208
+ (TCP or serial), close it yourself.
209
+
210
+ ## Bring your own camera (vision ABC)
211
+
212
+ Both builders take an optional `vision_backend=`. The SDK camera path talks to
213
+ the `vention.vision.v1` Image/Source service ABCs, so the same `CameraManager`
214
+ drives the legacy Luxonis camera and the native gRPC cameras (vvis, Leopard)
215
+ behind one interface. When `vision_backend` is omitted (or in `mock` mode) the
216
+ SDK builds whichever backend the cell YAML `camera.backend` field selects.
217
+
218
+ The easiest route is config-only — pick the backend in the cell YAML:
219
+
220
+ ```yaml
221
+ camera:
222
+ backend: "grpc" # "mmai" (default, legacy Luxonis HTTP) or "grpc"
223
+ target: "127.0.0.1:41051" # vention.vision gRPC service
224
+ sensor: "full_frame_left" # primary source id reported by ListSources
225
+ right_source_id: "full_frame_right"
226
+ source_metadata: # only keys the service omits; service values always win
227
+ camera_vendor: "leopard"
228
+ mx_id: "LI-123456"
229
+ ```
230
+
231
+ or build it in code with the same dispatch:
232
+
233
+ ```python
234
+ from griip_sdk import build_bin_picking_manager
235
+ from griip_sdk.hardware.grpc_vision_backend import build_vision_backend
236
+
237
+ vision_backend = build_vision_backend("./cell.yaml") # Mmai or gRPC per camera.backend
238
+ with build_bin_picking_manager("./cell.yaml", part_id="pcb", handle_placement=..., vision_backend=vision_backend) as manager:
239
+ ...
240
+ ```
241
+
242
+ `GrpcVisionServiceBackend` composes the wheel's `create_image_service_backend`
243
+ / `create_source_service_backend` gRPC backends so one object satisfies both
244
+ ABC seams; `build_mmai_vision_backend` still builds the Luxonis adapter
245
+ explicitly. Intrinsics, resolution, and stereo baseline are resolved from the
246
+ backend's `list_sources`, so each camera reports its own calibration through
247
+ the same seam — native services own their calibration (no calibio upload), and
248
+ `source_metadata` must carry `baseline` / `camera_vendor` / `mx_id` (from the
249
+ service or the YAML overlay) or calibration resolution fails loudly.
250
+
251
+ > The camera layer imports the `vention.vision.v1` protos and `vision_service_abc`
252
+ > ABCs, so it needs `vention-firmware-grpc-client>=1.3.0`.
253
+
254
+ ## Swapping parts mid-session
255
+
256
+ ```python
257
+ with build_pick_only_manager("./pick.yaml", part_id="pcb_rev_a") as manager:
258
+ for _ in range(5):
259
+ manager.pick(max_attempts=3)
260
+
261
+ manager.set_part("pcb_rev_b") # ValueError if part_id isn't in pick.yaml
262
+
263
+ for _ in range(5):
264
+ manager.pick(max_attempts=3)
265
+ ```
266
+
267
+ Only works if both parts use the same gripper. If they don't, build a fresh
268
+ manager for each.
269
+
270
+ ## Manual lifecycle (without `with`)
271
+
272
+ The `with` form is crash-safe and recommended. For a long-running daemon that
273
+ needs a global-style handle, drive the lifecycle yourself:
274
+
275
+ ```python
276
+ _ctx = build_pick_only_manager("./pick.yaml", part_id="pcb")
277
+ manager = _ctx.__enter__()
278
+ try:
279
+ manager.pick(max_attempts=3)
280
+ # manager is usable anywhere in the process
281
+ finally:
282
+ _ctx.__exit__(None, None, None) # required: closes gRPC + hardware
283
+ ```
284
+
285
+ This is an escape hatch. Skip `__exit__` and you leak the gRPC channel and
286
+ hardware connections.
287
+
288
+ ## Grasp targets, your motion
289
+
290
+ For a cell where the application moves the robot itself. The SDK takes and
291
+ stores pictures, runs perception on a stored picture when asked, and keeps
292
+ one queue of ranked grasp poses. It never commands motion.
293
+
294
+ ```python
295
+ from griip_sdk import build_grasp_provider
296
+
297
+ with build_grasp_provider("pick.yaml", part_id="smallest_splice") as sdk:
298
+ # First round: one picture of each pallet, then start on the left.
299
+ move_robot_to(LEFT_CAPTURE_POSE) # your motion
300
+ sdk.capture("left") # take a picture now, store it as "left"
301
+ move_robot_to(RIGHT_CAPTURE_POSE)
302
+ sdk.capture("right") # take a picture now, store it as "right"
303
+ sdk.process("left") # start perception on the "left" picture, in the background
304
+
305
+ while True:
306
+ # Left pallet
307
+ target = sdk.next_target() # wait for the "left" run, pop its best pose; None = nothing graspable
308
+ sdk.process("right") # start perception on the "right" picture; it runs during the steps below
309
+ picked_left = target is not None
310
+ if picked_left:
311
+ pose = target.flange_pose_mm_deg # [x, y, z, rx, ry, rz], mm and degrees, as on the pendant
312
+ move_robot_to(approach(pose))
313
+ move_robot_to(pose)
314
+ close_gripper()
315
+ move_robot_to(approach(pose))
316
+ sdk.capture("left") # new picture of the left pallet for the next round, taken now
317
+ move_robot_to(PLACE_POSE)
318
+ open_gripper()
319
+
320
+ # Right pallet
321
+ target = sdk.next_target() # wait for the "right" run, pop its best pose
322
+ sdk.process("left") # start perception on the new "left" picture; runs while we pick right
323
+ picked_right = target is not None
324
+ if picked_right:
325
+ pose = target.flange_pose_mm_deg
326
+ move_robot_to(approach(pose))
327
+ move_robot_to(pose)
328
+ close_gripper()
329
+ move_robot_to(approach(pose))
330
+ sdk.capture("right") # new picture of the right pallet for the next round
331
+ move_robot_to(PLACE_POSE)
332
+ open_gripper()
333
+
334
+ if not picked_left and not picked_right:
335
+ break # both pallets came back empty
336
+ ```
337
+
338
+ Five verbs. `capture(tag)` stores a picture with the robot pose at that
339
+ moment, so park the robot first; the tag is any string you choose, one
340
+ stored picture per tag. `captures()` lists the stored pictures, `delete(tag)`
341
+ removes one. `process(tag)` runs perception on a stored picture in the
342
+ background, one image at a time. `next_target(timeout=None)` waits for
343
+ in-flight runs and pops the best pose; it returns `None` when the last
344
+ picture had nothing graspable, when the run failed (`captures()` carries the
345
+ state and the reason), or on timeout.
346
+
347
+ The results of a run replace the queue, so pop before starting the next run.
348
+ Re-capturing a tag replaces its picture, and a run still going for the old
349
+ picture is dropped.
350
+
351
+ Each `GraspTarget` answers what a motion-owning app needs to know:
352
+
353
+ - `capture_tag` says which picture, and therefore which pallet, it came from.
354
+ - Several come back per picture, ranked by `priority`, at most
355
+ `picking.max_detections × picking.max_grasps_per_object`.
356
+ - `flange_pose` and `tcp_pose` are the same target in the world / robot base
357
+ frame, the frame the robot reports (the camera pose is built from it and the
358
+ hand-eye calibration). `flange_pose = tcp_pose · X_tcp_flg⁻¹`, where
359
+ `X_tcp_flg` is the translation `tool.tcp_offset`, returned as `tcp_offset`.
360
+ - `flange_pose_mm_deg` and `tcp_pose_mm_deg` are the same poses as
361
+ `[x, y, z, rx, ry, rz]`: millimetres, and degrees of roll, pitch, yaw about
362
+ X, Y then Z, the convention the pendant shows. The `SE3` forms stay in metres
363
+ for code that composes transforms.
364
+
365
+ Same `pick.yaml` as a self-driving cell: part, grasps, `tool.tcp_offset`,
366
+ camera, hand-eye. No `home_bin*` poses are needed; the capture pose is
367
+ whatever the robot reports. The robot must be registered in VRMCS, where
368
+ reachability is checked. No gripper is built or actuated.
369
+
370
+ Only if the pictures show a container with walls: `capture(tag, bin_number=N)`
371
+ attaches the `bin_N_*` cuboids from `cuboids.json` to the request so grasps
372
+ through a wall or below the floor are rejected. `N` must be listed in
373
+ `runtime.bins.available`. It is not a taught pose. Open pallets need none of
374
+ this.
375
+
376
+ ## Calibration
377
+
378
+ The SDK exposes the two calibration primitives — hand-eye and
379
+ operator-driven environment scanning. The cell YAML is the source of
380
+ truth for the calibration starting pose
381
+ (`positions.calibration_joints`); commissioning authors it, the SDK
382
+ reads it, and the operator app never edits it at runtime.
383
+
384
+ The simplest hand-eye run — build the app, call the verb:
385
+
386
+ ```python
387
+ from griip_sdk import build_calibration_app
388
+
389
+ with build_calibration_app("cell.yaml") as cal:
390
+ x_cam_flg = cal.run_hand_eye_calibration()
391
+ ```
392
+
393
+ The SDK plans to `cell.positions.calibration_joints`, runs the bundled sphere
394
+ routine, returns the robot to that start pose, and persists the result. The
395
+ fuller form below adds progress reporting and the operator-driven scan session:
396
+
397
+ ```python
398
+ from pathlib import Path
399
+
400
+ from griip_sdk import build_calibration_app
401
+
402
+ with build_calibration_app(Path("cell.yaml")) as cal:
403
+ # Hand-eye: the SDK plans to cell.positions.calibration_joints, runs the
404
+ # bundled sphere routine, then returns the robot to the start pose.
405
+ # Override `routine=` only if your cell geometry truly needs a non-default recipe.
406
+ x_cam_flg = cal.run_hand_eye_calibration(
407
+ on_progress=lambda pct, status, msg: print(pct, status, msg),
408
+ is_cancelled=lambda: False,
409
+ )
410
+ cal.last_hand_eye_calibration_timestamp() # datetime | None
411
+
412
+ # Environment scanning: operator-driven session. start_environment_session
413
+ # switches the robot into freedrive; take_environment_image grabs one
414
+ # frame at the current pose; end_environment_session restores normal
415
+ # operation and persists the entry.
416
+ cal.start_environment_session()
417
+ for _ in range(num_frames_the_app_wants):
418
+ # operator manually repositions the robot between captures
419
+ cal.take_environment_image()
420
+ sequence_dir = cal.end_environment_session()
421
+ cal.last_environment_scan_timestamp() # datetime | None
422
+ ```
423
+
424
+ If `cell.positions.calibration_joints` is unset, `run_hand_eye_calibration`
425
+ raises `griip_sdk.ConfigError` with a message naming the missing field and
426
+ the config file. Surface this to the operator so commissioning can fix the
427
+ YAML.
428
+
429
+ Override the VAMP planner's world cuboids at build time when they live
430
+ outside the cell YAML:
431
+
432
+ ```python
433
+ with build_calibration_app(Path("cell.yaml"), cuboids_path=Path("custom.json")) as cal:
434
+ ...
435
+ ```
436
+
437
+ After a camera swap, before the new MxId has calibio intrinsics in the
438
+ store, opt into the live-defaults fallback so calibration verbs still
439
+ run:
440
+
441
+ ```python
442
+ with build_calibration_app(Path("cell.yaml"), strict_intrinsics=False) as cal:
443
+ cal.run_hand_eye_calibration(...) # uses camera defaults; logs warning
444
+ ```
445
+
446
+ ### Transport (direct vs gRPC)
447
+
448
+ `build_calibration_app` honors `griip_api.mode` in the cell YAML:
449
+
450
+ - `mode: direct` (default) — wires the in-process `PlanningApi` and
451
+ `PerceptionApi` from `mmai_griip_api`. Pulls the dev-only
452
+ `mmai_griip_api` package as a transitive runtime dep at the call site.
453
+ - `mode: grpc` — dials the gRPC server at `griip_api.url` (defaults to
454
+ `localhost:50051`) using the SDK's own generated stubs. No
455
+ `mmai_griip_api` dep needed; the published SDK wheel is enough.
456
+
457
+ The gRPC channel is closed for you on context-manager exit.
458
+
459
+ ### BYO stubs (advanced)
460
+
461
+ `CalibrationApp.__init__` is keyword-only and accepts the planning and
462
+ perception stubs as injected dependencies. When the cell-app needs a
463
+ non-standard transport (custom interceptors, an alternate server,
464
+ test fixtures), construct it directly and skip the factory:
465
+
466
+ ```python
467
+ import grpc
468
+ from griip_sdk import CalibrationApp
469
+ from griip_sdk.calibration.config_store import CalibrationConfigStore
470
+ from griip_core.generated import griip_pb2_grpc
471
+ from griip_sdk.hardware.mmai_vision_backend import MmaiVisionServiceBackend
472
+
473
+ channel = grpc.insecure_channel("custom-host:50051")
474
+
475
+ # vision_backend is the same vention.vision.v1 ABC used everywhere else in the
476
+ # SDK (CameraManager, teleop, ...); MmaiVisionServiceBackend adapts an already
477
+ # started MmaiVisionClient to it. See "Vision ABC" above for the interface.
478
+ vision_backend = MmaiVisionServiceBackend(camera_client, left_source_id="left", right_source_id="right")
479
+
480
+ cal = CalibrationApp(
481
+ cell=cell,
482
+ config_path=cell_yaml_path,
483
+ robot_client=robot_client,
484
+ vision_backend=vision_backend,
485
+ cam_name="luxonis",
486
+ camera_mxid="...",
487
+ sensor="left",
488
+ store=CalibrationConfigStore(),
489
+ calib_data_root="/data/vention/calib_data",
490
+ planning_stub=griip_pb2_grpc.PlanningServiceStub(channel),
491
+ perception_stub=griip_pb2_grpc.PerceptionServiceStub(channel),
492
+ )
493
+
494
+ # ...drive the verbs as normal, then close `channel` and unregister the
495
+ # robot when done (the BYO path skips the factory's cleanup).
496
+ ```
497
+
498
+ ### Verbs on `CalibrationApp`
499
+
500
+ | Verb | Effect |
501
+ |---|---|
502
+ | `cal.run_hand_eye_calibration(on_progress=None, is_cancelled=None, routine=None, ...)` | Plan to `cell.positions.calibration_joints`, run hand-eye, then return the robot to that start pose. `routine` defaults to `griip_sdk.calibration.routines.DEFAULT_ENCIRCLE_ROUTINE`. Persists `X_cam_flg__{cam}__{mxid}__{sensor}`. Returns the camera-to-flange `SE3`. Raises `ConfigError` when the YAML field is missing. |
503
+ | `cal.last_hand_eye_calibration_timestamp()` | `datetime` (UTC) of the latest hand-eye, or `None`. |
504
+ | `cal.start_environment_session(save_dir=None)` | Open an operator-driven scan session. Creates the sequence dir, persists post-crop intrinsics, switches robot to freedrive. Returns the sequence dir. |
505
+ | `cal.take_environment_image()` | Capture one frame in the active session (stereo, depth, pose). Robot stays in freedrive. Returns the frame index. |
506
+ | `cal.end_environment_session()` | Restore the robot to normal operation, persist `env_scan__{cam}__{mxid}` pointing at the sequence dir. Returns the sequence dir. |
507
+ | `cal.last_environment_scan_timestamp()` | `datetime` (UTC) of the latest completed scan session, or `None`. |
508
+
509
+ ## Release notes
510
+
511
+ The [PyPI release history](https://pypi.org/project/griip-sdk/#history) lists
512
+ every published version. Each page freezes the README and CHANGELOG as of that
513
+ release.