Writing the Main Configuration File
1. Preparation
Please prepare the robot's URDF file.
Next, using OpenLoong as an example, we will introduce how to construct the configuration file.
Confirm URDF Availability
In the OpenLoong path, use the following Python 3 script to test:
import pybullet as p
import time
p.connect(p.GUI)
p.loadURDF("azureloong_description/urdf/AzureLoong_sr.urdf")
while 1:
time.sleep(0.1)
Correct operation should display the robot correctly in pybullet.

2. Determine the Robot's Home Pose
Adjust the Robot's Home Pose
In the OpenLoong path, use the following Python 3 script to test:
import pybullet as p
import time
p.connect(p.GUI)
robot_id = p.loadURDF("azureloong_description/urdf/AzureLoong_sr.urdf")
joint_index_debug_param_dt = {}
for i in range(0, p.getNumJoints(robot_id)):
joint_info = p.getJointInfo(robot_id, i)
print(joint_info)
if joint_info[2] != p.JOINT_FIXED:
joint_index_debug_param_dt[i] = p.addUserDebugParameter(
paramName=f" {i} {joint_info[1].decode('utf-8')}",
rangeMin=joint_info[8],
rangeMax=joint_info[9],
startValue=p.getJointState(robot_id, i)[0],
)
while 1:
for joint_index, param_id in joint_index_debug_param_dt.items():
p.resetJointState(robot_id, joint_index, p.readUserDebugParameter(param_id))
time.sleep(0.1)
After running the program, you should see the following visualization interface

By adjusting the sliders on the right, adjust the joint angles of the robot arm to the desired home pose. For example:
Adjust the right arm to approximately the following position: [0.20, -0.97, -2.00, 1.70, 0.63, 0.00, -0.43]
Adjust the left arm to approximately the following position:
[-0.20, -0.97, 2.00, 1.70, -0.63, 0.00, 0.43]

3. Add EE Definition
After adjusting the robot arm to the home pose, you need to add EE link and joint in the URDF for end-effector pose mapping.
When running the Adjust the Robot's Home Pose script, the terminal will print out the robot's joint information. Find the end link of the robot arm, usually the last joint, or with keywords like gripper, hand, palm.
For example, in OpenLoong, we choose:
(11, b'J_arm_r_palm', 4, -1, -1, 0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, b'Link_arm_r_palm', (0.0, 0.0, 0.0), (0.007859, 0.00817000000000001, 0.037736), (0.0, 0.0, 0.0, 1.0), 10)
(47, b'J_arm_l_palm', 4, -1, -1, 0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, b'Link_arm_l_palm', (0.0, 0.0, 0.0), (0.0077872, -0.30705, 0.027733), (0.0, 0.0, 0.0, 1.0), 46)
In the URDF, find the corresponding link, add EE link and joint, pay attention to the dependency order of the URDF tree:
<link name="io_teleop_ee_link_left"/>
<joint name="io_teleop_ee_joint_left" type="fixed">
<origin rpy="0 0 0" xyz="0 0 0"/>
<parent link="Link_arm_l_palm"/>
<child link="io_teleop_ee_link_left"/>
</joint>
<link name="io_teleop_ee_link_right"/>
<joint name="io_teleop_ee_joint_right" type="fixed">
<origin rpy="0 0 0" xyz="0 0 0"/>
<parent link="Link_arm_r_palm"/>
<child link="io_teleop_ee_link_right"/>
</joint>

After adding, run the Adjust the Robot's Home Pose script again,
Record the arm joint IDs (the first element printed in each line) and the EE link IDs from the terminal print information.
For OpenLoong, it should be:
joint_id_dt = {
"right_arm_joint_ids": [4, 5, 6, 7, 8, 9, 10],
"left_arm_joint_ids": [41, 42, 43, 44, 45, 46, 47],
}
ee_id_dt = {"right_ee_link_id": 12, "left_ee_link_id": 49}
In the OpenLoong path, run the following Python 3 script to visualize the EE coordinate system
import pybullet as p
import time
import numpy as np
def debug_draw_pose(pose, replace_line_ids=None, line_width=5, line_length=0.3):
axes = np.identity(3) * line_length
colors = np.identity(3)
line_ids = [] if replace_line_ids is None else replace_line_ids
for i in range(3):
if replace_line_ids is None:
line_id = p.addUserDebugLine(
lineFromXYZ=pose[0],
lineToXYZ=p.multiplyTransforms(pose[0], pose[1], axes[i], [0, 0, 0, 1])[
0
],
lineColorRGB=colors[i],
lineWidth=line_width,
lifeTime=0,
)
line_ids.append(line_id)
else:
p.addUserDebugLine(
lineFromXYZ=pose[0],
lineToXYZ=p.multiplyTransforms(pose[0], pose[1], axes[i], [0, 0, 0, 1])[
0
],
lineColorRGB=colors[i],
lineWidth=line_width,
lifeTime=0,
replaceItemUniqueId=replace_line_ids[i],
)
return line_ids
p.connect(p.GUI)
robot_id = p.loadURDF("azureloong_description/urdf/AzureLoong_sr.urdf")
joint_id_dt = {
"right_arm_joint_ids": [4, 5, 6, 7, 8, 9, 10],
"left_arm_joint_ids": [41, 42, 43, 44, 45, 46, 47],
}
ee_id_dt = {"right_ee_link_id": 12, "left_ee_link_id": 49}
# joint home is list concat of right and left arm home pos, it must be right arm first then left arm
joint_home = [0.20, -0.97, -2.00, 1.70, 0.63, 0.00, -0.43] +
[-0.20, -0.97, 2.00, 1.70, -0.63, 0.00, 0.43]
joint_ids = [id for ids in joint_id_dt.values() for id in ids]
ee_ids = [id for id in ee_id_dt.values()]
for i in range(p.getNumJoints(robot_id)):
if i in joint_ids:
p.resetJointState(robot_id, i, joint_home[joint_ids.index(i)])
if i in ee_ids:
debug_draw_pose(p.getLinkState(robot_id, i)[4:6], line_width=10)
while 1:
time.sleep(0.1)
Correct operation should display the following visualization interface

Next, by modifying the origin rpy and xyz fields of io_teleop_ee_joint_right and io_teleop_ee_joint_left in the URDF,
Adjust the position and pose of the EE link to meet:
- The position falls at the center of the palm (or gripper) (TCP)
- The Z-axis is vertically upward
- The Y-axis is parallel to the hand surface and facing forward (from the robot's perspective, facing the front of the robot base)
Small tip: For fixed-axis rotation in pybullet
For the AzureLoong robot, the adjusted result should be:
<link name="io_teleop_ee_link_left"/>
<joint name="io_teleop_ee_joint_left" type="fixed">
<origin rpy="3.14 -1.57 0" xyz="0 0 0"/>
<parent link="Link_arm_l_palm"/>
<child link="io_teleop_ee_link_left"/>
</joint>
<link name="io_teleop_ee_link_right"/>
<joint name="io_teleop_ee_joint_right" type="fixed">
<origin rpy="3.14 1.57 0" xyz="0 0 0"/>
<parent link="Link_arm_r_palm"/>
<child link="io_teleop_ee_link_right"/>
</joint>
