feat: add joint servo and cartesian controllers#1116
Conversation
Greptile OverviewGreptile SummaryAdds comprehensive streaming control capabilities to the control system with three new task types: Key changes:
Implementation quality:
Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User as User/Teleop
participant LCM as LCM Transport
participant Coord as ControlCoordinator
participant ServoTask as JointServoTask
participant VelTask as JointVelocityTask
participant IKTask as CartesianIKTask
participant Pinocchio as Pinocchio IK
participant TickLoop as TickLoop
participant Hardware as Hardware Adapter
Note over User,Hardware: Streaming Joint Position Control (Servo)
User->>LCM: Publish JointState (positions)
LCM->>Coord: joint_command callback
Coord->>ServoTask: set_target_by_name(positions, t_now)
ServoTask->>ServoTask: Update target & timestamp
Note over TickLoop,Hardware: Control Tick (100Hz)
TickLoop->>Hardware: read_joint_positions()
Hardware-->>TickLoop: current positions
TickLoop->>ServoTask: compute(state)
ServoTask->>ServoTask: Check timeout
ServoTask-->>TickLoop: JointCommandOutput (SERVO_POSITION)
TickLoop->>TickLoop: Arbitrate (priority-based)
TickLoop->>Hardware: write_joint_positions(commands)
Note over User,Hardware: Streaming Velocity Control
User->>LCM: Publish JointState (velocities)
LCM->>Coord: joint_command callback
Coord->>VelTask: set_velocities_by_name(velocities, t_now)
VelTask->>VelTask: Update velocities & timestamp
TickLoop->>VelTask: compute(state)
VelTask->>VelTask: Check timeout
alt Timeout
VelTask-->>TickLoop: Zero velocities (safety)
else Normal
VelTask-->>TickLoop: JointCommandOutput (VELOCITY)
end
TickLoop->>Hardware: write_joint_velocities(commands)
Note over User,Hardware: Cartesian IK Control
User->>LCM: Publish PoseStamped (cartesian pose)
LCM->>Coord: cartesian_command callback
Coord->>IKTask: set_target_pose(pose, t_now)
IKTask->>IKTask: Convert to SE3 & store
TickLoop->>IKTask: compute(state)
IKTask->>IKTask: Get current joints (warm-start)
IKTask->>Pinocchio: solve_ik(target_pose, q_current)
loop Max 100 iterations
Pinocchio->>Pinocchio: Forward kinematics
Pinocchio->>Pinocchio: Compute Jacobian
Pinocchio->>Pinocchio: Damped least-squares update
Pinocchio->>Pinocchio: Check convergence
end
Pinocchio-->>IKTask: q_solution, converged, error
IKTask->>IKTask: Safety check (clamp joint deltas)
IKTask-->>TickLoop: JointCommandOutput (SERVO_POSITION)
TickLoop->>Hardware: write_joint_positions(ik_solution)
Note over Coord: Unified RPC Interface
User->>Coord: task_invoke("task_name", "start", kwargs)
Coord->>ServoTask: start()
ServoTask-->>Coord: activated
|
7cf4229 to
0ae380d
Compare
…oint type classes
…c rpcs to 1 rpc to interact with all ControlTasks
…ys there but not caught before mypy wasn't strict enough to catch them until pinocchio's numpy type annotations tightened the checking.
…#1079) * added robot_description folders to data/ folder with lfs tracking * Base types: RobotModelConfig, Obstacle, Protocol specs for defining manipulation scenes * Mesh conversion utils for converting any urdf to drake compatible mesh files * DrakeWorld implementation that maintains all objects, robots in the scene and owns the scene graph * Monitor system keeps the world model (drake planning world) in synb with real world. manages obstacle lifecycle and more * FK and IK solver implementation with drake * RRT path planner using default drake planner * factory for building implementation of the different world, viz, planner etc specs * utils for ik solver and path planning * manipulation module manages the world monitor, planner, kinematics planner and interfaces with other modules * added blueprints and manipulation client for testing * added unit test, e2e tests and readme * general cleanup * added multi robot management and control to the manipulation module * refactored planning stack * Refactored manipulation planning stack: seperated planners from world implementation, split kinematics into JacobianIK and DrakeOptimizationIK * updated README * Address greptile comments: manipulation_blueprint - Added optional add_gripper: bool = True to make xarm6 ans xarm7 config consistent. world_obstacle_monitor - Added warning log when obstacle not found during cleanup manipulation_client - Removed unused numpy impor path_utils - Added explicit tolerances atol=1e-6, rtol=0 to np.allclose() for stricter joint-space duplicate detection jacobian_ik - Added division-by-zero protection for velocity limits using nonzero_mask to skip zero-valued limits drake_world.py - added more specific exception handling (avoids hiding bugs) mesh_utils - regex fixes * fix mypy import error with manipulation interface (file is deprecated) * protocol now only requires solve() method. * moved to using standard LCM data types and added type alias for readability * updated all coordinator references * fixed all bluepirnts order * updated paths to use Path object instead of str * mypy type fixes * all public api boundaries use standard message types, sim specific internal storage/helpers still use NDArrays in some places * removed unused import * removed manipulation history reference * added a Jacobian typealias * fixed mypy errors * updated manipulation dependencies in pyproject.toml
5ecf320 to
1da50f3
Compare
|
|
||
|
|
||
| # Jog speeds | ||
| LINEAR_SPEED = 0.05 # m/s |
There was a problem hiding this comment.
shouldnt these be at top and not buried down at bottom
There was a problem hiding this comment.
Yeah, can also make this user parameter or task parameter
| return max(min_val, min(max_val, value)) | ||
|
|
||
|
|
||
| def _get_piper_model_path() -> str: |
There was a problem hiding this comment.
Shouldnt be any arm specific stuff in generic methods. UNless this is just an example thing but seems like it may be used by other arms
There was a problem hiding this comment.
Shouldnt have piper in here
There was a problem hiding this comment.
You are right. This was implemented as an example with piper. I have asked @ruthwikdasyam to work on generic examples and extending support to more arms.
|
|
||
| return True, q_new | ||
|
|
||
| def on_preempted(self, by_task: str, joints: frozenset[str]) -> None: |
There was a problem hiding this comment.
Doesn't look like any of these on_preempted callbacks are used. Also not sure what they do its just for printing warning
There was a problem hiding this comment.
When there are multiple task controlling a hardware, and one task overrides another. then it logs a warning that this task was preempted, just so that it doesn't silently fail.
| mode=ControlMode.SERVO_POSITION, | ||
| ) | ||
|
|
||
| def on_preempted(self, by_task: str, joints: frozenset[str]) -> None: |
| mode=ControlMode.VELOCITY, | ||
| ) | ||
|
|
||
| def on_preempted(self, by_task: str, joints: frozenset[str]) -> None: |
JointServoTask for streaming joint position control (teleop, playback) and
JointVelocityTask for streaming joint velocity control (joystick) also,
Added CartesianIKTask with internal Pinocchio IK solver for cartesian control on any joint-space hardware
Add joint_command and cartesian_command input streams to ControlCoordinator for real-time streaming control via LCM
Add unified task_invoke RPC to interact with any ControlTask method
Add pygame-based cartesian jogger example for testing IK control
closes DIM-352