Task Trajectory Implementation#
Basic concepts have been covered in prior documents. This manual focuses on underlying implementation principles, standard field writing rules, and function linkage data flow, and disassembles the full trajectory generation logic based on the dual-arm fixture assembly task.
📃 Core Files#
action_bank.py: General underlying operator libraryResponsibilities: Encapsulate static functions for pose calculation, IK/FK solving, trajectory generation, gripper control, and rigid body binding. Decorators classify node and trajectory functions to expose callable capabilities for cross-task reuse.
Loading order: Load and register all functions upon environment startup, serving as the underlying dependency of the configuration file.
action_config.json: Task-specific workflow graphResponsibilities: Contains no computational logic. It invokes methods inside the bank via string function names, defines control domains, pose generation pipelines, motion trajectories, and multi-arm timing dependencies. Task adjustments only require edits to this file.
Loading order: Parsed during environment reset, which drives calls to bank functions to generate all key poses and action sequences.
Full Data Flow Pipeline#
Env initialization → Load JSON configuration → Call bank node functions to generate all poses/qpos and store them in the shared cache env.affordance_datas → Edges read key points from cache and call trajectory functions to generate time-series actions → Sync rules constrain execution order of multiple actuators → Actions are sent to the simulator for execution.
Core Dependency Relationship#
action_config.json acts as the orchestration and caller layer, while action_bank.py serves as the underlying computation implementation layer. The two files exchange data exclusively through the global cache env.affordance_datas, and neither can work independently.
🏦 Functions in action_bank.py#
All capabilities are implemented via static methods decorated with specific tags, which split functions into pose generation nodes and trajectory execution functions.
2.1 Core Decorator Principles#
@tag_nodeMarks functions that generate target poses or joint angles. These functions can only be invoked under thenodefield in JSON, and they write new poses/qpos intoaffordance_datasafter execution.@tag_edgeMarks functions that generate time-series trajectories or gripper commands. These functions can only be invoked under theedgefield in JSON and output continuous action arrays.@resolve_env_paramsAutomatically injects theenvinstance into function parameters, allowing direct read and write access to the shared cache without manual parameter passing.
2.2 Example: generate_left_arm_aim_qpos#
Underlying logic:
Read two 4x4 homogeneous transformation matrices:
guijiao2_poseandleft_arm_base_pose.Extract XY translational components and calculate the target horizontal rotation angle of the first joint via
np.arctan2.Deep copy the initial left arm qpos and overwrite its 0th joint value with the calculated horizontal angle.
Store the updated joint angles into the cache entry
left_arm_aim_qposfor subsequent nodes and trajectories to reference.
Corresponding JSON invocation syntax:
{
"left_arm_aim_qpos": {
"name": "generate_left_arm_aim_qpos",
"kwargs": {}
}
}
2.3 Gripper Execution#
Two separate execution branches are defined based on the flag return_action:
return_action=false: Only marks environment state without outputting action sequences.return_action=true: Outputs a 1-dimensional time-series gripper control sequence.When
expand=true,mul_linear_expandperforms linear interpolation to produce smooth opening/closing motion.When
expand=false, outputs a constant array filled with 0 or 1. Thedurationparameter controls the total number of simulation steps for the gripper movement.
2.4 Core Trajectory Planning#
plan_trajectoryAccepts multiple groups of key joint qpos values and generates smooth joint trajectories via the TOPPRA planner. If the distance between two consecutive key poses is extremely small, the function automatically falls back tostand_still.stand_stillGenerates stationary trajectories by filling all time steps with identical joint angles. If inconsistent key poses are passed, the function retains only the first qpos and prints a warning log.
2.5 attach_rigid_objects_now#
Creates parent-child binding between two rigid bodies and optionally locks object kinematics to KINEMATIC mode, ensuring synchronized movement of assembled components after connection.
🎯 Principles of action_config.json#
The configuration file contains five fixed top-level fields: scope, node, edge, sync, and misc.
3.1 scope#
Declare all independent actuators (6DoF left/right arms, 1DoF left/right grippers) and define action dimensions, initialization strategies, and data types.
Key field explanations:
type: Fixed valueDiGraph, all actuators adopt directed graph workflow logic.dim: Action dimension, set to[6]for robotic arms and[1]for grippers.init.methodcurrent_qpos: Initialize using real-time joint angles from the simulator.given_qpos: Initialize with fixed preset joint values.
dtype: Uniformly set tofloat32for all pose and joint calculations.
3.2 node#
All pose generation nodes use the unified generator generate_affordances_from_src, which relies on three core components: src_key, dst_key, and pass_processes.
src_key: Input cache identifier, referencing the original 4x4 pose matrix or joint angles stored inaffordance_datas.dst_key: Output cache identifier, storing transformed poses or IK-solved joint angles for later nodes and edges to reference.valid_funcs_name_kwargs_proc: A pipeline combining validation logic and transformation operators, split into validation functions and sequentialpass_processestransform operators.
🔧 Coordinate system definition
- extrinsic: Global world coordinate system, all translations and rotations are calculated relative to the world origin.
- intrinsic: Local object coordinate system, all transformations are calculated relative to the object’s current self-pose.
🎯 Core operator functions
- get_rotation_replaced_pose: Overwrite the object’s Z-axis rotation with a specified angle.
- get_rotated_pose: Rotate the object around a designated axis by a fixed angle in degrees.
- get_offset_pose: Translate the object along target axes with specified offset values, supporting both intrinsic and extrinsic coordinate modes.
- get_offset_qpos: Directly offset joint values in joint space without Cartesian space conversion.
- get_fk_xpos: Forward kinematics solver, mapping joint qpos to end-effector Cartesian pose.
🌰 Example#
Complete data flow: Raw object pose → sequential rotation and translation transformations → Cartesian grasp pose guijiao1_grasp_pose → IK inverse solving → grasp joint angles guijiao1_grasp_qpos.
Step 1: Generate grasp pose
"src_key": "guijiao1_pose",
"dst_key": "guijiao1_grasp_pose",
"pass_processes": [rotation replacement, 180-degree X-axis rotation, local X-axis offset...]
Step 2: IK solving to convert pose to qpos
"src_key": "guijiao1_grasp_pose",
"dst_key": "guijiao1_grasp_qpos",
"valid_funcs_name_kwargs_proc": [
{
"name": "get_ik_ret",
"kwargs": {
"ik_func": "env.robot.compute_ik",
"qpos_seed": "env.affordance_datas['guijiao1_pre1_qpos']",
"control_part": "right_arm"
},
"pass_processes": [{"name": "get_ik_qpos"}]
},
{"name": "is_qpos_flip", "kwargs": {...}}
]
get_ik_retandget_ik_qpos: Core inverse kinematics solvers.qpos_seedprovides initial joint guesses to improve solving success rate, andcontrol_partspecifies the target robotic arm for calculation.is_qpos_flip: Validates joint flip status to avoid singular joint configurations.
Two Categories of Nodes#
Pose generation nodes: Only apply coordinate transformations without IK solving, output 4x4 homogeneous pose matrices.
Qpos generation nodes: Accept pose inputs and output robotic arm joint angles via inverse kinematics solving.
3.3 edge#
Core Principle#
Directed edges connect two node entries (starting point src, target point sink). The name field binds tag-edge marked functions inside the action bank to generate continuous time-series trajectories.
Key field explanations:
src/sink: Cache names of the start and end key nodes.duration: Total simulation steps allocated for this motion segment; larger values result in slower movement.name: Bind trajectory functions inside the bank such asplan_trajectoryorexecute_open.keypose_names: Pass start and end node identifiers as key waypoints for trajectory planning.
Two typical edge types:
Robotic arm motion edges: Bind
plan_trajectoryto generate smooth interpolated joint trajectories across multiple waypoints.Gripper control edges: Bind
execute_openorexecute_closeto output 1-dimensional gripper opening/closing action sequences.
3.4 sync#
Core Principle#
Lock execution order via task dependencies to resolve timing conflicts, such as closing the gripper only after the arm reaches the grasp pose and lifting the object only after full gripper closure.
Key field: depend_tasks. The current edge will only start execution after all motion edges listed in this array complete fully.
Sample sequential logic:
"rclose0": {"depend_tasks": ["pre1_to_grasp"]},
"grasp_to_up": {"depend_tasks": ["rclose0"]}
Logical flow: The right gripper closes only after the right arm reaches the pre-grasp pose; the lifting motion starts only after gripper closure finishes.
3.5 misc#
Global debug switches. Disable all visualization options during dataset collection to reduce computational overhead:
vis_graph: Toggle rendering of the directed action graph.vis_gantt: Toggle generation of timeline Gantt charts.warpping: Trajectory smoothing switch, must remain enabled at all times.
🧠 Standard Step-by-Step Guide#
Reuse or extend
action_bank.pyto implement required node and edge underlying functions.Fill out the
scopesection to define dimension and initialization rules for all robotic arms and grippers.Layer the
nodesection: write raw object pose transformation nodes first, then IK solving nodes for pre-grasp, grasp, placement and home return qpos.Write all
edgeentries to connect sequential nodes and adjustdurationvalues to control movement speed.Configure
syncdependencies to constrain execution timing between grippers and dual arms.Turn off visualization switches in misc to complete the configuration.
🔧 Debug Reference#
Confusion between intrinsic and extrinsic coordinate systems: Incorrect reference frame for offsets and rotations leads to severe grasp position drift.
Improper selection of IK
qpos_seed: Failed inverse kinematics solving or singular joint configurations.Missing sync dependencies: Chaotic execution order of gripper actions and dual-arm movements.
Unreasonable
durationvalues: Excessively fast motion causes object penetration; overly slow motion reduces dataset sampling efficiency.
Summary#
action_bank.py: Underlying computation foundation, providing general functions for pose transformation, trajectory planning and simulator interaction, decoupled from specific assembly tasks.action_config.json: Task workflow orchestration layer. It only organizes function calls and timing rules, allowing rapid adaptation to new assembly tasks without modifying underlying code.Core full task generation pipeline: Coordinate transformation operators in nodes generate target Cartesian poses → IK solving nodes convert poses to joint qpos → Edges interpolate continuous motion trajectories → Sync rules enforce multi-actuator timing constraints, finally outputting complete dual-arm assembly action sequences.
For more details, please refer to 👉 [EmbodiChain tutorial Docs]https://dexforce.github.io/EmbodiChain/main/tutorial/index.html