devagent-physical-engine 0.12.0__tar.gz → 0.12.2__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.
- {devagent_physical_engine-0.12.0/src/devagent_physical_engine.egg-info → devagent_physical_engine-0.12.2}/PKG-INFO +7 -3
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/README.md +6 -2
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/pyproject.toml +1 -1
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/__init__.py +1 -1
- devagent_physical_engine-0.12.2/src/devagent_physical_engine/ros2/gazebo_cli.py +77 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/gazebo_pose.py +6 -6
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/gazebo_world.py +2 -7
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/trajectory.py +40 -15
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2/src/devagent_physical_engine.egg-info}/PKG-INFO +7 -3
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine.egg-info/SOURCES.txt +2 -0
- devagent_physical_engine-0.12.2/tests/test_gazebo_cli_v0122.py +88 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_ros_trajectory_v09.py +60 -3
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/NOTICE +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/setup.cfg +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/agent/__init__.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/agent/compiler.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/agent/contracts.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/agent/coordinator.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/agent/critic.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/agent/evidence.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/agent/interpreter.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/agent/planner.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/agent/recovery.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/agent/routing.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/agent/runtime.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/agent/semantic.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/agent/structured.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ai_cli.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/cli.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/continuous_clearance.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/doctor.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/engineering_agent.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/engineering_request.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/execution.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/models.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/operating_envelope.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/optimization/__init__.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/optimization/benchmark.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/optimization/candidates.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/optimization/contracts.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/optimization/evaluator.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/optimization/evidence.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/optimization/experience.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/optimization/measured.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/optimization/optimizer.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/optimization/orchestrator.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/physical_campaign.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/physical_evidence.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/physical_motion.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/planning.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/preexecution_contract.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/provider_adapters/__init__.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/provider_adapters/anthropic.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/provider_adapters/common.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/provider_adapters/factory.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/provider_adapters/gemini.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/provider_adapters/openai.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/provider_qualification.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/providers.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/qualification.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/qualification_cli.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/qualification_harness.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/reference_workcell.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/robot_platform.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/robots.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/__init__.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/acceptance.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/commands.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/continuous_clearance_probe.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/doctor.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/fk_pose.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/fk_probe.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/frame_alignment.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/joint_state_recorder.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/measured_motion.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/moveit_joint_plan_probe.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/moveit_scene.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/moveit_task_planner.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/preexecution.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/qualification.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/qualification_v10.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/qualification_v11.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/qualification_v12.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/scene_probe.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/state_validity_probe.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/task_adapter.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/task_visualization.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/tf_probe.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/tool_scene.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/tool_scene_probe.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/ur5e.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/ur5e_adapter.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/ur5e_v10_adapter.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/workpiece_follow.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/workpiece_gazebo_follower.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/workpiece_scene.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/ros2/workpiece_scene_probe.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/setup_profile.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/sim_real_qualification.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/simulation.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/simulation_platform.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/tool_collision.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/trajectory_qualification.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/twin.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/twin_builder.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/twin_materialization.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/verification.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine/workpiece_lifecycle.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine.egg-info/dependency_links.txt +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine.egg-info/entry_points.txt +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine.egg-info/requires.txt +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/src/devagent_physical_engine.egg-info/top_level.txt +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_agent_core.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_agent_semantic_hardening.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_ai_cli.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_ai_cli_v07.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_continuous_clearance_v011.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_core.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_engineering_request_v07.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_interpreter_profiles_v08.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_live_provider_qualification.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_measured_motion_v10.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_natural_language_agent_v07.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_openai_strict_schema_v0113.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_optimization_v05.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_physical_campaign_v09.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_physical_evidence_v09.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_physical_motion_v09.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_planning_fallback_v012.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_preexecution_contract_v10.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_provider_and_qualification.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_qualification_cli_lifecycle_v06.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_qualification_harness_v06.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_readme_pypi.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_real_provider_adapters.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_reference_workcell_v012.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_robot_platform_v08.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_ros2_production_receipts_v011.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_ros2_simulation.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_setup_profile.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_sim_real_qualification_v011.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_simulation_platform_v08.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_tool_collision_v011.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_trajectory_qualification_v09.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_twin_materialization_v10.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_twin_v08.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_ur5e_adapter_scopes_v09.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_ur5e_v10_adapter_scopes.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_v052_stabilization.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_v08_catalog_mapping_regression.py +0 -0
- {devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_workpiece_lifecycle_v011.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devagent-physical-engine
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.2
|
|
4
4
|
Summary: Verification-first agentic engineering, simulation, and evidence runtime for robotics and industrial automation.
|
|
5
5
|
Author: Tom Ha
|
|
6
6
|
License: All Rights Reserved
|
|
@@ -189,6 +189,10 @@ measured motion/evidence report
|
|
|
189
189
|
|
|
190
190
|
On a successful run, Gazebo / MoveIt remains open by default so the engineer can inspect the final workcell. Add `--close-after` to close it after success.
|
|
191
191
|
|
|
192
|
+
v0.12.1 hardens the initial ROS joint-state snapshot by parsing `ros2 topic echo --once` output as a YAML document stream. This accepts the normal ROS 2 trailing `---` message separator instead of incorrectly classifying an otherwise valid `/joint_states` sample as `joint_state_snapshot_invalid`.
|
|
193
|
+
|
|
194
|
+
v0.12.2 additionally hardens Gazebo model-pose read-back across Harmonic CLI renderings. One shared parser now accepts both pipe-delimited and whitespace-delimited finite XYZ/RPY vectors and is used by initial world verification and dynamic workpiece pose read-back, so task simulation does not depend on a single human-readable `gz model --pose` delimiter style.
|
|
195
|
+
|
|
192
196
|
The packaged reference workcell is **not customer-site geometry**. Arbitrary plant layouts require an imported or user-declared physical Twin with trusted poses, collision geometry, tool/TCP information, and workpiece properties. DevAgent does not invent those site facts from a natural-language prompt.
|
|
193
197
|
|
|
194
198
|
The v0.12 implementation remains evidence-gated: source/CI success does not prove the ROS target campaign has passed on a particular workstation. Use the executable qualification below before treating the task-specific path as qualified on that target.
|
|
@@ -416,9 +420,9 @@ Detailed engineering documentation lives in the repository:
|
|
|
416
420
|
|
|
417
421
|
## Project status
|
|
418
422
|
|
|
419
|
-
**v0.12.
|
|
423
|
+
**v0.12.2 — Beta software / evidence-gated task-specific physical simulation.**
|
|
420
424
|
|
|
421
|
-
The software and release pipeline are production-oriented, but physical readiness is scope-specific and evidence-driven. The
|
|
425
|
+
The software and release pipeline are production-oriented, but physical readiness is scope-specific and evidence-driven. The UR5e task-specific reference-workcell path must pass the executable v0.12 ROS/Gazebo/MoveIt campaign on the target workstation before that scope is considered simulation-qualified there. Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
|
|
422
426
|
|
|
423
427
|
## Ownership
|
|
424
428
|
|
|
@@ -148,6 +148,10 @@ measured motion/evidence report
|
|
|
148
148
|
|
|
149
149
|
On a successful run, Gazebo / MoveIt remains open by default so the engineer can inspect the final workcell. Add `--close-after` to close it after success.
|
|
150
150
|
|
|
151
|
+
v0.12.1 hardens the initial ROS joint-state snapshot by parsing `ros2 topic echo --once` output as a YAML document stream. This accepts the normal ROS 2 trailing `---` message separator instead of incorrectly classifying an otherwise valid `/joint_states` sample as `joint_state_snapshot_invalid`.
|
|
152
|
+
|
|
153
|
+
v0.12.2 additionally hardens Gazebo model-pose read-back across Harmonic CLI renderings. One shared parser now accepts both pipe-delimited and whitespace-delimited finite XYZ/RPY vectors and is used by initial world verification and dynamic workpiece pose read-back, so task simulation does not depend on a single human-readable `gz model --pose` delimiter style.
|
|
154
|
+
|
|
151
155
|
The packaged reference workcell is **not customer-site geometry**. Arbitrary plant layouts require an imported or user-declared physical Twin with trusted poses, collision geometry, tool/TCP information, and workpiece properties. DevAgent does not invent those site facts from a natural-language prompt.
|
|
152
156
|
|
|
153
157
|
The v0.12 implementation remains evidence-gated: source/CI success does not prove the ROS target campaign has passed on a particular workstation. Use the executable qualification below before treating the task-specific path as qualified on that target.
|
|
@@ -375,9 +379,9 @@ Detailed engineering documentation lives in the repository:
|
|
|
375
379
|
|
|
376
380
|
## Project status
|
|
377
381
|
|
|
378
|
-
**v0.12.
|
|
382
|
+
**v0.12.2 — Beta software / evidence-gated task-specific physical simulation.**
|
|
379
383
|
|
|
380
|
-
The software and release pipeline are production-oriented, but physical readiness is scope-specific and evidence-driven. The
|
|
384
|
+
The software and release pipeline are production-oriented, but physical readiness is scope-specific and evidence-driven. The UR5e task-specific reference-workcell path must pass the executable v0.12 ROS/Gazebo/MoveIt campaign on the target workstation before that scope is considered simulation-qualified there. Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
|
|
381
385
|
|
|
382
386
|
## Ownership
|
|
383
387
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "devagent-physical-engine"
|
|
7
|
-
version = "0.12.
|
|
7
|
+
version = "0.12.2"
|
|
8
8
|
description = "Verification-first agentic engineering, simulation, and evidence runtime for robotics and industrial automation."
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from math import isfinite
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
from ..simulation_platform import SimulationPlatformError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
_ANSI_ESCAPE = re.compile(r"\x1b\[[0-?]*[ -/]*[@-~]")
|
|
10
|
+
_BRACKET = re.compile(r"\[([^\[\]\r\n]+)\]")
|
|
11
|
+
_POSE_HEADER = re.compile(r"(?im)^\s*[-*]?\s*Pose\s*\[\s*XYZ(?:\s*\(m\))?\s*\].*$")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _vector3(payload: str) -> tuple[float, float, float] | None:
|
|
15
|
+
"""Parse one Gazebo bracket vector across supported CLI renderings.
|
|
16
|
+
|
|
17
|
+
Gazebo Sim releases have rendered vectors both as ``[x | y | z]`` and
|
|
18
|
+
``[x y z]``. Some downstream packages also emit comma-separated values.
|
|
19
|
+
Accept those presentation differences while still requiring exactly three
|
|
20
|
+
finite numeric values.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
parts = payload.replace("|", " ").replace(",", " ").split()
|
|
24
|
+
if len(parts) != 3:
|
|
25
|
+
return None
|
|
26
|
+
try:
|
|
27
|
+
values = tuple(float(value) for value in parts)
|
|
28
|
+
except ValueError:
|
|
29
|
+
return None
|
|
30
|
+
if any(not isfinite(value) for value in values):
|
|
31
|
+
return None
|
|
32
|
+
return values[0], values[1], values[2]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def parse_gz_model_pose(
|
|
36
|
+
text: str,
|
|
37
|
+
) -> tuple[tuple[float, float, float], tuple[float, float, float]]:
|
|
38
|
+
"""Parse ``gz model -m NAME --pose`` output deterministically.
|
|
39
|
+
|
|
40
|
+
The human-readable Gazebo CLI is not stable in its vector delimiter style.
|
|
41
|
+
Anchor on the model Pose header and parse the first two valid 3-vectors
|
|
42
|
+
beneath it as XYZ metres and RPY radians. ANSI terminal escapes are ignored.
|
|
43
|
+
A legacy plain six-number pose line is accepted as a bounded compatibility
|
|
44
|
+
fallback.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
cleaned = _ANSI_ESCAPE.sub("", text)
|
|
48
|
+
header = _POSE_HEADER.search(cleaned)
|
|
49
|
+
section = cleaned[header.end() :] if header is not None else cleaned
|
|
50
|
+
|
|
51
|
+
vectors: list[tuple[float, float, float]] = []
|
|
52
|
+
for match in _BRACKET.finditer(section):
|
|
53
|
+
vector = _vector3(match.group(1))
|
|
54
|
+
if vector is None:
|
|
55
|
+
continue
|
|
56
|
+
vectors.append(vector)
|
|
57
|
+
if len(vectors) == 2:
|
|
58
|
+
return vectors[0], vectors[1]
|
|
59
|
+
|
|
60
|
+
# Compatibility with older Gazebo model tools that rendered
|
|
61
|
+
# ``x y z roll pitch yaw`` as one line instead of bracket vectors.
|
|
62
|
+
for line in section.splitlines():
|
|
63
|
+
parts = line.replace(",", " ").split()
|
|
64
|
+
if len(parts) != 6:
|
|
65
|
+
continue
|
|
66
|
+
try:
|
|
67
|
+
values = tuple(float(value) for value in parts)
|
|
68
|
+
except ValueError:
|
|
69
|
+
continue
|
|
70
|
+
if any(not isfinite(value) for value in values):
|
|
71
|
+
continue
|
|
72
|
+
return (
|
|
73
|
+
(values[0], values[1], values[2]),
|
|
74
|
+
(values[3], values[4], values[5]),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
raise SimulationPlatformError("gazebo_model_pose_output_invalid")
|
|
@@ -2,10 +2,10 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from dataclasses import asdict, dataclass
|
|
4
4
|
from math import isfinite
|
|
5
|
-
import re
|
|
6
5
|
|
|
7
6
|
from ..simulation_platform import SimulationPlatformError
|
|
8
7
|
from .commands import RosCommandRunner
|
|
8
|
+
from .gazebo_cli import parse_gz_model_pose
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@dataclass(frozen=True, slots=True)
|
|
@@ -21,11 +21,11 @@ class GazeboPoseUpdateReceipt:
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def _parse_position(text: str) -> tuple[float, float, float]:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
raise SimulationPlatformError("gazebo_pose_readback_invalid")
|
|
28
|
-
return
|
|
24
|
+
try:
|
|
25
|
+
position, _orientation = parse_gz_model_pose(text)
|
|
26
|
+
except SimulationPlatformError as exc:
|
|
27
|
+
raise SimulationPlatformError("gazebo_pose_readback_invalid") from exc
|
|
28
|
+
return position
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
class GazeboPoseBridge:
|
|
@@ -8,6 +8,7 @@ from typing import Any
|
|
|
8
8
|
from ..simulation_platform import SimulationPlatformError
|
|
9
9
|
from ..twin_materialization import CanonicalTwinMaterialization
|
|
10
10
|
from .commands import RosCommandRunner
|
|
11
|
+
from .gazebo_cli import parse_gz_model_pose
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
@dataclass(frozen=True, slots=True)
|
|
@@ -48,13 +49,7 @@ def _parse_model_names(text: str) -> set[str]:
|
|
|
48
49
|
|
|
49
50
|
|
|
50
51
|
def _parse_pose(text: str):
|
|
51
|
-
|
|
52
|
-
pattern = re.compile(r"\[\s*([-+0-9.eE]+)\s*\|\s*([-+0-9.eE]+)\s*\|\s*([-+0-9.eE]+)\s*\]")
|
|
53
|
-
for match in pattern.finditer(text):
|
|
54
|
-
triples.append(tuple(float(match.group(index)) for index in range(1, 4)))
|
|
55
|
-
if len(triples) < 2:
|
|
56
|
-
raise SimulationPlatformError("gazebo_model_pose_output_invalid")
|
|
57
|
-
return triples[0], triples[1]
|
|
52
|
+
return parse_gz_model_pose(text)
|
|
58
53
|
|
|
59
54
|
|
|
60
55
|
class GazeboWorldVerifier:
|
|
@@ -39,6 +39,43 @@ class JointStateSnapshot:
|
|
|
39
39
|
return tuple(values[name] for name in joint_names)
|
|
40
40
|
|
|
41
41
|
|
|
42
|
+
def _parse_joint_state_echo(stdout: str) -> JointStateSnapshot:
|
|
43
|
+
"""Parse ``ros2 topic echo --once`` output as a YAML document stream.
|
|
44
|
+
|
|
45
|
+
ROS 2 topic echo normally terminates a message with ``---``. PyYAML's
|
|
46
|
+
``safe_load`` rejects that otherwise-valid output because the separator starts a
|
|
47
|
+
second (empty) YAML document. Treat the CLI output as the stream it actually is,
|
|
48
|
+
ignore empty separator documents, and accept exactly one joint-state mapping.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
import yaml
|
|
53
|
+
|
|
54
|
+
documents = tuple(
|
|
55
|
+
document for document in yaml.safe_load_all(stdout) if document is not None
|
|
56
|
+
)
|
|
57
|
+
except Exception as exc:
|
|
58
|
+
raise RosTrajectoryError("joint_state_yaml_invalid") from exc
|
|
59
|
+
|
|
60
|
+
payloads = tuple(document for document in documents if isinstance(document, Mapping))
|
|
61
|
+
if len(payloads) != 1:
|
|
62
|
+
raise RosTrajectoryError("joint_state_document_count_invalid")
|
|
63
|
+
|
|
64
|
+
payload = payloads[0]
|
|
65
|
+
names_raw = payload.get("name")
|
|
66
|
+
positions_raw = payload.get("position")
|
|
67
|
+
if not isinstance(names_raw, list) or not isinstance(positions_raw, list):
|
|
68
|
+
raise RosTrajectoryError("joint_state_fields_invalid")
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
return JointStateSnapshot(
|
|
72
|
+
tuple(str(item) for item in names_raw),
|
|
73
|
+
tuple(float(item) for item in positions_raw),
|
|
74
|
+
)
|
|
75
|
+
except (TypeError, ValueError) as exc:
|
|
76
|
+
raise RosTrajectoryError("joint_state_values_invalid") from exc
|
|
77
|
+
|
|
78
|
+
|
|
42
79
|
def read_joint_state(
|
|
43
80
|
runner: RosCommandRunner,
|
|
44
81
|
*,
|
|
@@ -55,21 +92,9 @@ def read_joint_state(
|
|
|
55
92
|
+ (result.stderr.strip()[-300:] or "ros2_topic_echo_failed")
|
|
56
93
|
)
|
|
57
94
|
try:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if not isinstance(payload, Mapping):
|
|
62
|
-
raise TypeError("joint state payload is not a mapping")
|
|
63
|
-
names_raw = payload.get("name")
|
|
64
|
-
positions_raw = payload.get("position")
|
|
65
|
-
if not isinstance(names_raw, list) or not isinstance(positions_raw, list):
|
|
66
|
-
raise TypeError("name/position fields are not arrays")
|
|
67
|
-
return JointStateSnapshot(
|
|
68
|
-
tuple(str(item) for item in names_raw),
|
|
69
|
-
tuple(float(item) for item in positions_raw),
|
|
70
|
-
)
|
|
71
|
-
except Exception as exc:
|
|
72
|
-
raise RosTrajectoryError("joint_state_snapshot_invalid") from exc
|
|
95
|
+
return _parse_joint_state_echo(result.stdout)
|
|
96
|
+
except RosTrajectoryError as exc:
|
|
97
|
+
raise RosTrajectoryError(f"joint_state_snapshot_invalid:{exc}") from exc
|
|
73
98
|
|
|
74
99
|
|
|
75
100
|
def _duration_payload(seconds: float) -> dict[str, int]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devagent-physical-engine
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.2
|
|
4
4
|
Summary: Verification-first agentic engineering, simulation, and evidence runtime for robotics and industrial automation.
|
|
5
5
|
Author: Tom Ha
|
|
6
6
|
License: All Rights Reserved
|
|
@@ -189,6 +189,10 @@ measured motion/evidence report
|
|
|
189
189
|
|
|
190
190
|
On a successful run, Gazebo / MoveIt remains open by default so the engineer can inspect the final workcell. Add `--close-after` to close it after success.
|
|
191
191
|
|
|
192
|
+
v0.12.1 hardens the initial ROS joint-state snapshot by parsing `ros2 topic echo --once` output as a YAML document stream. This accepts the normal ROS 2 trailing `---` message separator instead of incorrectly classifying an otherwise valid `/joint_states` sample as `joint_state_snapshot_invalid`.
|
|
193
|
+
|
|
194
|
+
v0.12.2 additionally hardens Gazebo model-pose read-back across Harmonic CLI renderings. One shared parser now accepts both pipe-delimited and whitespace-delimited finite XYZ/RPY vectors and is used by initial world verification and dynamic workpiece pose read-back, so task simulation does not depend on a single human-readable `gz model --pose` delimiter style.
|
|
195
|
+
|
|
192
196
|
The packaged reference workcell is **not customer-site geometry**. Arbitrary plant layouts require an imported or user-declared physical Twin with trusted poses, collision geometry, tool/TCP information, and workpiece properties. DevAgent does not invent those site facts from a natural-language prompt.
|
|
193
197
|
|
|
194
198
|
The v0.12 implementation remains evidence-gated: source/CI success does not prove the ROS target campaign has passed on a particular workstation. Use the executable qualification below before treating the task-specific path as qualified on that target.
|
|
@@ -416,9 +420,9 @@ Detailed engineering documentation lives in the repository:
|
|
|
416
420
|
|
|
417
421
|
## Project status
|
|
418
422
|
|
|
419
|
-
**v0.12.
|
|
423
|
+
**v0.12.2 — Beta software / evidence-gated task-specific physical simulation.**
|
|
420
424
|
|
|
421
|
-
The software and release pipeline are production-oriented, but physical readiness is scope-specific and evidence-driven. The
|
|
425
|
+
The software and release pipeline are production-oriented, but physical readiness is scope-specific and evidence-driven. The UR5e task-specific reference-workcell path must pass the executable v0.12 ROS/Gazebo/MoveIt campaign on the target workstation before that scope is considered simulation-qualified there. Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
|
|
422
426
|
|
|
423
427
|
## Ownership
|
|
424
428
|
|
|
@@ -78,6 +78,7 @@ src/devagent_physical_engine/ros2/doctor.py
|
|
|
78
78
|
src/devagent_physical_engine/ros2/fk_pose.py
|
|
79
79
|
src/devagent_physical_engine/ros2/fk_probe.py
|
|
80
80
|
src/devagent_physical_engine/ros2/frame_alignment.py
|
|
81
|
+
src/devagent_physical_engine/ros2/gazebo_cli.py
|
|
81
82
|
src/devagent_physical_engine/ros2/gazebo_pose.py
|
|
82
83
|
src/devagent_physical_engine/ros2/gazebo_world.py
|
|
83
84
|
src/devagent_physical_engine/ros2/joint_state_recorder.py
|
|
@@ -112,6 +113,7 @@ tests/test_ai_cli_v07.py
|
|
|
112
113
|
tests/test_continuous_clearance_v011.py
|
|
113
114
|
tests/test_core.py
|
|
114
115
|
tests/test_engineering_request_v07.py
|
|
116
|
+
tests/test_gazebo_cli_v0122.py
|
|
115
117
|
tests/test_interpreter_profiles_v08.py
|
|
116
118
|
tests/test_live_provider_qualification.py
|
|
117
119
|
tests/test_measured_motion_v10.py
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import unittest
|
|
4
|
+
|
|
5
|
+
from devagent_physical_engine.ros2.gazebo_cli import parse_gz_model_pose
|
|
6
|
+
from devagent_physical_engine.ros2.gazebo_pose import _parse_position
|
|
7
|
+
from devagent_physical_engine.ros2.gazebo_world import _parse_pose
|
|
8
|
+
from devagent_physical_engine.simulation_platform import SimulationPlatformError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
PIPE_OUTPUT = """Requesting state for world [default]...
|
|
12
|
+
|
|
13
|
+
Model: [8]
|
|
14
|
+
|
|
15
|
+
- Name: BOX_101
|
|
16
|
+
|
|
17
|
+
- Pose [ XYZ (m) ] [ RPY (rad) ]:
|
|
18
|
+
|
|
19
|
+
[0.550000 | -0.350000 | 0.820000]
|
|
20
|
+
|
|
21
|
+
[0.000000 | 0.000000 | 1.570796]
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
HARMONIC_WHITESPACE_OUTPUT = """Requesting state for world [default]...
|
|
25
|
+
|
|
26
|
+
* Model [8]
|
|
27
|
+
* Name: BOX_101
|
|
28
|
+
* Pose [ XYZ (m) ] [ RPY (rad) ]:
|
|
29
|
+
[0.550000 -0.350000 0.820000]
|
|
30
|
+
[0.000000 -0.000000 1.570796]
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class GazeboCliPoseV0122Tests(unittest.TestCase):
|
|
35
|
+
def test_accepts_documented_pipe_delimited_pose(self):
|
|
36
|
+
position, orientation = parse_gz_model_pose(PIPE_OUTPUT)
|
|
37
|
+
self.assertEqual(position, (0.55, -0.35, 0.82))
|
|
38
|
+
self.assertEqual(orientation, (0.0, 0.0, 1.570796))
|
|
39
|
+
|
|
40
|
+
def test_accepts_harmonic_whitespace_delimited_pose(self):
|
|
41
|
+
position, orientation = parse_gz_model_pose(HARMONIC_WHITESPACE_OUTPUT)
|
|
42
|
+
self.assertEqual(position, (0.55, -0.35, 0.82))
|
|
43
|
+
self.assertEqual(orientation, (0.0, -0.0, 1.570796))
|
|
44
|
+
|
|
45
|
+
def test_world_verifier_parser_uses_harmonic_compatible_parser(self):
|
|
46
|
+
self.assertEqual(
|
|
47
|
+
_parse_pose(HARMONIC_WHITESPACE_OUTPUT),
|
|
48
|
+
((0.55, -0.35, 0.82), (0.0, -0.0, 1.570796)),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def test_dynamic_workpiece_readback_uses_same_parser(self):
|
|
52
|
+
self.assertEqual(
|
|
53
|
+
_parse_position(HARMONIC_WHITESPACE_OUTPUT),
|
|
54
|
+
(0.55, -0.35, 0.82),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def test_ansi_terminal_escape_does_not_break_pose(self):
|
|
58
|
+
payload = "\x1b[32m" + HARMONIC_WHITESPACE_OUTPUT + "\x1b[0m"
|
|
59
|
+
self.assertEqual(parse_gz_model_pose(payload)[0], (0.55, -0.35, 0.82))
|
|
60
|
+
|
|
61
|
+
def test_legacy_plain_six_number_pose_is_supported(self):
|
|
62
|
+
self.assertEqual(
|
|
63
|
+
parse_gz_model_pose("0.55 -0.35 0.82 0.0 0.0 1.570796\n"),
|
|
64
|
+
((0.55, -0.35, 0.82), (0.0, 0.0, 1.570796)),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
def test_incomplete_pose_fails_closed(self):
|
|
68
|
+
with self.assertRaisesRegex(
|
|
69
|
+
SimulationPlatformError,
|
|
70
|
+
"gazebo_model_pose_output_invalid",
|
|
71
|
+
):
|
|
72
|
+
parse_gz_model_pose(
|
|
73
|
+
"- Pose [ XYZ (m) ] [ RPY (rad) ]:\n[0.55 -0.35 0.82]\n"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def test_non_finite_pose_fails_closed(self):
|
|
77
|
+
with self.assertRaisesRegex(
|
|
78
|
+
SimulationPlatformError,
|
|
79
|
+
"gazebo_model_pose_output_invalid",
|
|
80
|
+
):
|
|
81
|
+
parse_gz_model_pose(
|
|
82
|
+
"- Pose [ XYZ (m) ] [ RPY (rad) ]:\n"
|
|
83
|
+
"[0.55 -0.35 nan]\n[0.0 0.0 0.0]\n"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
if __name__ == "__main__":
|
|
88
|
+
unittest.main()
|
{devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_ros_trajectory_v09.py
RENAMED
|
@@ -4,7 +4,11 @@ import unittest
|
|
|
4
4
|
|
|
5
5
|
from devagent_physical_engine.physical_motion import JointTrajectoryPoint, PhysicalMotionPlan
|
|
6
6
|
from devagent_physical_engine.ros2.commands import CommandResult
|
|
7
|
-
from devagent_physical_engine.ros2.trajectory import
|
|
7
|
+
from devagent_physical_engine.ros2.trajectory import (
|
|
8
|
+
RosTrajectoryError,
|
|
9
|
+
execute_joint_trajectory,
|
|
10
|
+
read_joint_state,
|
|
11
|
+
)
|
|
8
12
|
|
|
9
13
|
|
|
10
14
|
class FakeRunner:
|
|
@@ -29,11 +33,64 @@ def motion():
|
|
|
29
33
|
)
|
|
30
34
|
|
|
31
35
|
|
|
32
|
-
def result(stdout, *, code=0):
|
|
33
|
-
return CommandResult(("ros2",), code, stdout,
|
|
36
|
+
def result(stdout, *, code=0, stderr=""):
|
|
37
|
+
return CommandResult(("ros2",), code, stdout, stderr, 1.0)
|
|
34
38
|
|
|
35
39
|
|
|
36
40
|
class RosTrajectoryV09Tests(unittest.TestCase):
|
|
41
|
+
def test_joint_state_echo_accepts_ros2_trailing_document_separator(self):
|
|
42
|
+
stdout = """header:
|
|
43
|
+
stamp:
|
|
44
|
+
sec: 10
|
|
45
|
+
nanosec: 20
|
|
46
|
+
frame_id: ''
|
|
47
|
+
name:
|
|
48
|
+
- shoulder_pan_joint
|
|
49
|
+
- shoulder_lift_joint
|
|
50
|
+
position:
|
|
51
|
+
- 0.125
|
|
52
|
+
- -1.25
|
|
53
|
+
velocity: []
|
|
54
|
+
effort: []
|
|
55
|
+
---
|
|
56
|
+
"""
|
|
57
|
+
runner = FakeRunner(result(stdout))
|
|
58
|
+
|
|
59
|
+
snapshot = read_joint_state(runner)
|
|
60
|
+
|
|
61
|
+
self.assertEqual(
|
|
62
|
+
snapshot.names,
|
|
63
|
+
("shoulder_pan_joint", "shoulder_lift_joint"),
|
|
64
|
+
)
|
|
65
|
+
self.assertEqual(snapshot.positions_rad, (0.125, -1.25))
|
|
66
|
+
self.assertEqual(
|
|
67
|
+
runner.commands[0][0],
|
|
68
|
+
("ros2", "topic", "echo", "/joint_states", "--once"),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
def test_joint_state_echo_rejects_multiple_nonempty_documents(self):
|
|
72
|
+
stdout = """name: [j1]
|
|
73
|
+
position: [0.0]
|
|
74
|
+
---
|
|
75
|
+
name: [j1]
|
|
76
|
+
position: [0.1]
|
|
77
|
+
---
|
|
78
|
+
"""
|
|
79
|
+
runner = FakeRunner(result(stdout))
|
|
80
|
+
with self.assertRaisesRegex(
|
|
81
|
+
RosTrajectoryError,
|
|
82
|
+
"joint_state_snapshot_invalid:joint_state_document_count_invalid",
|
|
83
|
+
):
|
|
84
|
+
read_joint_state(runner)
|
|
85
|
+
|
|
86
|
+
def test_joint_state_echo_preserves_command_failure_detail(self):
|
|
87
|
+
runner = FakeRunner(result("", code=1, stderr="topic unavailable"))
|
|
88
|
+
with self.assertRaisesRegex(
|
|
89
|
+
RosTrajectoryError,
|
|
90
|
+
"joint_state_snapshot_failed:topic unavailable",
|
|
91
|
+
):
|
|
92
|
+
read_joint_state(runner)
|
|
93
|
+
|
|
37
94
|
def test_succeeded_action_is_accepted(self):
|
|
38
95
|
runner = FakeRunner(result("Goal accepted\nResult: error_code=0\nGoal finished with status: SUCCEEDED"))
|
|
39
96
|
completed = execute_joint_trajectory(runner, motion())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_agent_core.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_ai_cli_v07.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_optimization_v05.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_readme_pypi.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_robot_platform_v08.py
RENAMED
|
File without changes
|
|
File without changes
|
{devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_ros2_simulation.py
RENAMED
|
File without changes
|
{devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_setup_profile.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devagent_physical_engine-0.12.0 → devagent_physical_engine-0.12.2}/tests/test_v052_stabilization.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|