Matlab Model Robot Kinematics
MathWorksOfficialCreated by MathWorks
- Skill
- Tool integration
- Software development
- BSD-2-Clause
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured approach to creating and managing robot models using the MATLAB Robotics System Toolbox. It covers the entire lifecycle from model source selection (loadrobot, importrobot, or DH parameters) to configuration, gripper attachment, and kinematic validation. It emphasizes best practices such as setting DataFormat to row, ensuring correct end-effector frame alignment, and mandatory validation of IK/GIK solutions to prevent common errors in simulation and motion planning.
What it does
- Guides the selection of the optimal robot model source based on available data.
- Provides patterns for importing URDF files and handling collision geometry.
- Standardizes the process of attaching grippers and defining contact frames.
- Offers diagnostic procedures for verifying end-effector frame alignment.
- Details the configuration of generalized inverse kinematics constraints.
- Enforces mandatory validation steps for all kinematic solver outputs.
When to use it
- When you need to create or load a robot model in MATLAB for simulation or planning.
- When you are working with specific manipulators like UR5e, KUKA iiwa, or Panda.
- When you need to attach a gripper to a robot model for pick-and-place tasks.
- When you need to perform forward or inverse kinematics calculations.
- When you need to verify if a robot model is correctly configured for downstream tasks.
Advantages
- Reduces common errors by enforcing consistent data formats and frame conventions.
- Prevents silent failures in motion planning by mandating collision mesh verification.
- Provides clear decision trees for complex tasks like gripper selection and frame correction.
- Ensures robust kinematic solutions through mandatory exit flag and error checking.
Usage examples
- “How do I load a UR5e robot model in MATLAB for motion planning?”
- The agent will provide the command to load the robot using loadrobot with DataFormat set to row, ensuring it is ready for planning functions.
- “I need to attach a Robotiq gripper to my KUKA iiwa model.”
- The agent will guide you through the KUKA-specific frame correction (Ry 90-degree rotation) before attaching the gripper to ensure the approach axis is correct.
- “My IK solver is returning invalid joint configurations.”
- The agent will provide code to check the ExitFlag and position error, and suggest using the previous solution as an initial guess for sequential waypoints.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/matlab/matlab-model-robot-kinematics/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip matlab-model-robot-kinematics.zip -d .agents/skills
Documentation by MathWorks
Robot Modeling & Kinematics
Build manipulator models correctly and validate every kinematic solution.
When to Use
Any task that requires a robot model in MATLAB (even if the goal is downstream: animation, pick-and-place, trajectory, motion planning)
User mentions a specific manipulator by name (UR5e, KUKA iiwa14, Panda, Kinova Gen3, etc.)
Loading, building, or importing a robot model
Simulating, animating, or visualizing a manipulator
Tasks involving lifting, reaching, picking, placing, or grasping
Adding visual meshes or collision geometry
Attaching a gripper to a manipulator
Choosing between
inverseKinematicsvsgeneralizedInverseKinematicsValidating IK/GIK solutions (exit flags, position error, joint continuity)
When NOT to Use
Collision-free motion planning (RRT, CHOMP, path planning) — use a motion planning skill
Trajectory generation (
contopptraj,cubicpolytraj,trapveltraj) — use a trajectory skillClosed-loop parallel mechanisms (delta, Stewart) — see
references/parallel-robot-guidance.mdMobile robot navigation or wheeled platforms — not covered here
Dynamics simulation (
inverseDynamics,forwardDynamics) — separate domain
Workflow
Step 1: Determine Model Source
Choose the highest-fidelity source available:
| Priority | Source | When to Use | Why |
|---|---|---|---|
| 1 | loadrobot | Robot exists in the library | Includes collision meshes, inertias, visuals |
| 2 | importrobot | User has URDF/Xacro/SDF file | Preserves mesh references |
| 3 | Build from DH | Only DH parameters available | No collision meshes unless added manually |
Critical: A robot without collision meshes will cause downstream motion planning to silently report "collision-free" paths that actually collide. Always prefer sources that include meshes.
If the user says "build a robot" but names a known robot (UR5e, KUKA iiwa, Panda, etc.), suggest loadrobot first.
After importing from URDF, Simscape, or CAD: Check if collision meshes are present. Simscape Multibody models and many URDFs/CAD exports only provide visual geometry — no collision meshes. If collision meshes are missing, read references/import-mesh-handling.md for the decision tree on generating them from visuals.
Step 2: Load or Build the Model
Always set DataFormat="row" — this is required for planning and dynamics workflows.
Option A — loadrobot:
robot = loadrobot("universalUR5e", DataFormat="row");Option B — importrobot (URDF/Xacro/SDF):
robot = importrobot("myRobot.urdf", DataFormat="row");If the URDF has only visual geometry (no <collision> tags), add VHACD collision decomposition at import time:
opts = vhacdOptions("RigidBodyTree");
opts.SourceMesh = "VisualGeometry";
robot = importrobot("myRobot.urdf", DataFormat="row", ...
MeshPath="path/to/meshes", CollisionDecomposition=opts);Option C — Build from DH parameters:
robot = rigidBodyTree(DataFormat="row");
body = rigidBody("link1");
jnt = rigidBodyJoint("joint1", "revolute");
setFixedTransform(jnt, [a alpha d 0], "dh");
jnt.PositionLimits = [-pi, pi];
body.Joint = jnt;
addVisual(body, "Cylinder", [0.04, 0.3]);
addCollision(body, "Cylinder", [0.05, 0.3]);
addBody(robot, body, "base");Step 3: Ensure tool0 Exists with Z = Outward
Before attaching a gripper, the robot MUST have a tool0 body whose local Z-axis points along the arm's outward direction (away from the wrist). Most loadrobot models satisfy this already — but KUKA iiwa models do not.
Check references/ee-frame-alignment.md for the full compatibility table and diagnostic procedure.
If the robot already has tool0 with Z = outward (all UR, ABB, Techman, FANUC, Kinova, Yaskawa): proceed directly to gripper attachment.
If the robot lacks tool0 or EE Z is misaligned (KUKA iiwa 7/14): add a corrective tool0 frame:
% KUKA iiwa: iiwa_link_ee Z is perpendicular to arm — fix with Ry(90°)
tool0 = rigidBody("tool0");
tool0Joint = rigidBodyJoint("tool0_joint", "fixed");
R_correction = [0 0 1; 0 1 0; -1 0 0]; % Ry(90°)
setFixedTransform(tool0Joint, rotm2tform(R_correction));
tool0.Joint = tool0Joint;
addBody(robot, tool0, "iiwa_link_ee");For unknown robots (URDF imports): Run the diagnostic check from references/ee-frame-alignment.md to verify alignment before attaching anything.
Step 4: Configure the Model
Visuals vs collisions — both are needed, for different purposes:
| Function | Purpose | Used By |
|---|---|---|
addVisual(body, shape, dims) | Display appearance | show for visualization |
addCollision(body, shape, dims) | Planning geometry | checkCollision, motion planners |
To color a visual: addVisual(body, "Mesh", stlFile, tform, FaceColor=[1 0.8 0])
Robots from loadrobot already have both. When building from scratch, add both explicitly.
Attach a gripper (MANDATORY for manipulation tasks):
If the task involves object interaction (picking, placing, lifting, grasping, manipulating), a gripper is required — do not skip this step. Only omit for pure visualization or reachability studies with no object contact.
Before building ANY custom gripper, you MUST read references/gripper-models.md. Available models include both parallel-jaw (robotiq2F85, 85mm opening) AND vacuum grippers (robotiqEPick variants for large/flat objects). Do NOT assume robotiq2F85 is the only option.
Read
references/gripper-models.mdFollow the decision tree in that file (check compatibility → check object size → select grip strategy)
Only build custom if no provided model fits (incompatible manipulator AND object unsuitable for vacuum)
gripper = loadrobot("robotiq2F85", DataFormat="row");
addSubtree(robot, "tool0", gripper, ReplaceBase=false);Critical: Always use ReplaceBase=false. The default (true) merges the gripper's base link into the parent body, silently discarding the base visual mesh (the gripper housing/coupling). All provided grippers have a base visual that is lost without this flag.
After attaching a gripper, add a contact frame at the gripper's contact point (fixed joint, zero DOF added), then solve IK to that frame. This avoids confusing tip frame orientations and manual offset math. See references/gripper-models.md for per-gripper offsets and the full pattern.
contactFrame = rigidBody("contact_point");
contactJoint = rigidBodyJoint("contact_joint", "fixed");
setFixedTransform(contactJoint, trvec2tform([0, 0, gripperOffset]));
contactFrame.Joint = contactJoint;
addBody(robot, contactFrame, "tool0");Add a custom end-effector frame (when no gripper is attached or you need a specific offset):
ee = rigidBody("tool_tip");
eeJoint = rigidBodyJoint("tool_tip_joint", "fixed");
setFixedTransform(eeJoint, trvec2tform([0.1, 0, 0]));
ee.Joint = eeJoint;
addBody(robot, ee, "tool0");Step 5: Verify the Model with Kinematics
Use FK and IK to confirm the model is built correctly — correct link lengths, joint axes, limits, and end-effector frame placement.
Verify with FK: Move to a known configuration and check the end-effector reaches the expected position.
q = homeConfiguration(robot);
tform = getTransform(robot, q, "tool0");
fprintf("Home position: [%.3f, %.3f, %.3f] m\n", tform(1:3,4));Visually confirm the pose makes sense:
figure;
show(robot, q, Frames="off");
axis auto;
title("Home configuration");Verify with IK: Pick a target you know is reachable and confirm the solver converges.
Decision — IK vs GIK:
| Use | When |
|---|---|
inverseKinematics | Single target pose, no extra constraints |
generalizedInverseKinematics | Multiple constraints (position + aiming, joint bounds, orientation, etc.) |
See references/gik-constraints.md for all available GIK constraint types.
ik = inverseKinematics(RigidBodyTree=robot);
weights = [0.25 0.25 0.25 1 1 1];
targetPose = trvec2tform([0.4, 0.1, 0.3]) * eul2tform([0 pi 0], "ZYX");
[qSol, solnInfo] = ik("tool0", targetPose, weights, homeConfiguration(robot));Step 6: Validate Every IK/GIK Solution (MANDATORY)
Never skip this step. Agents consistently skip validation and deliver solutions that silently failed.
After inverseKinematics:
if solnInfo.ExitFlag <= 0
warning("IK did not converge. ExitFlag: %d, Status: %s", ...
solnInfo.ExitFlag, solnInfo.Status);
end
tformActual = getTransform(robot, qSol, "tool0");
posError = norm(tformActual(1:3,4)' - targetPose(1:3,4)');
if posError > 1e-3
warning("IK position error %.4f m exceeds threshold.", posError);
endAfter generalizedInverseKinematics:
if solInfo.ExitFlag <= 0
warning("GIK did not converge. ExitFlag: %d, Status: %s", ...
solInfo.ExitFlag, solInfo.Status);
end
for i = 1:numel(solInfo.ConstraintViolations)
cv = solInfo.ConstraintViolations(i);
if cv.Violation > 1e-3
warning("Constraint %d (%s) violated: %.4f", i, cv.Type, cv.Violation);
end
endFor sequential waypoints — check joint continuity:
for i = 2:size(qAll, 1)
maxJump = max(abs(qAll(i,:) - qAll(i-1,:)));
if maxJump > deg2rad(30)
warning("Joint jump of %.1f deg between waypoints %d and %d.", ...
rad2deg(maxJump), i-1, i);
end
endKey Functions
| Function | Purpose | Toolbox | Available From |
|---|---|---|---|
loadrobot | Load built-in robot with meshes | Robotics System Toolbox | R2019b |
importrobot | Import from URDF/Xacro/SDF/Simscape | Robotics System Toolbox | R2017a |
rigidBodyTree | Create empty robot model | Robotics System Toolbox | R2016b |
setFixedTransform | Set joint transform (DH or homogeneous) | Robotics System Toolbox | R2016b |
addVisual | Add visual geometry for display | Robotics System Toolbox | R2019a |
addCollision | Add collision geometry for planning | Robotics System Toolbox | R2019b |
addSubtree | Attach subtree (gripper) to body | Robotics System Toolbox | R2016b |
getTransform | Compute FK for a configuration | Robotics System Toolbox | R2016b |
inverseKinematics | Solve IK for single target pose | Robotics System Toolbox | R2016b |
generalizedInverseKinematics | Solve IK with multiple constraints | Robotics System Toolbox | R2017a |
show | Visualize robot configuration | Robotics System Toolbox | R2016b |
Patterns
Visualization
figure;
show(robot, q, Frames="off");
axis auto;
view(45, 30);
title("Robot at configuration q");For multiple configurations, use tiledlayout/nexttile:
figure;
tiledlayout(1, 3);
for i = 1:3
nexttile;
show(robot, qAll(i,:), Frames="off", PreservePlot=false);
axis auto;
title(sprintf("Waypoint %d", i));
endUsing Initial Guess to Improve IK Convergence
When solving IK for sequential waypoints, use the previous solution as the initial guess:
qPrev = homeConfiguration(robot);
for i = 1:numWaypoints
[qSol, solnInfo] = ik("tool0", targetPoses(:,:,i), weights, qPrev);
% ... validate ...
qPrev = qSol;
endConventions
Always set
DataFormat="row"on creation or importJoint limits in radians (use
deg2radwhen specifying in degrees)Use
Frames="off"andaxis autofor clean visualizationUse
tiledlayout/nexttileinstead ofsubplotName end-effector frames descriptively (e.g.,
"tool_tip","bucket_tip")Weights for
inverseKinematics:[orientation(3) position(3)]— set position weights higher for position-priority tasks
Common Mistakes
| Mistake | Why It's Wrong | Correct Approach |
|---|---|---|
Building from DH when loadrobot has the robot | No collision meshes → planning silently fails | Check loadrobot library first |
Using addCollision for visual appearance | Collision geometry is simplified, not rendered by show | Use addVisual for display, addCollision for planning |
| Skipping IK validation | Solution may not converge; ExitFlag <= 0 means failure | Always check ExitFlag and verify position error via FK |
Using DataFormat="column" or "struct" | Incompatible with planning/trajectory functions that expect row vectors | Always use DataFormat="row" |
| Skipping gripper for manipulation tasks | Object interaction (pick, lift, grasp) requires a gripper on the model | Always attach a gripper when the task involves object contact |
Solving IK to "tool0" or tip body without a contact frame | "tool0" is the flange (offset from contact point); tip body frames have confusing 90° rotations | Add a fixed "contact_point" frame at the gripper offset, solve IK to that |
| Building a custom gripper from scratch | Provided models have accurate geometry and are ready to attach | Check references/gripper-models.md for available grippers |
Using robotiq2F85 for objects > 85 mm | Jaw cannot open wide enough to grasp the object | Compare object dimensions to gripper max opening; use vacuum for large objects |
| Using IK when multiple constraints are needed | inverseKinematics only handles a single pose target | Use generalizedInverseKinematics with constraint objects |
| Not checking joint continuity for waypoint sequences | Large jumps between solutions cause unsafe trajectories | Compare consecutive solutions, flag jumps > 30 deg |
Using addSubtree without ReplaceBase=false | Gripper base visual mesh is silently discarded; housing disappears from visualization | Always pass ReplaceBase=false when attaching grippers |
| Attaching gripper to KUKA iiwa without frame correction | iiwa_link_ee Z is perpendicular to arm; gripper points sideways | Add tool0 with Ry(90°) correction before attaching — see references/ee-frame-alignment.md |
Assuming all loadrobot models have tool0 with Z = outward | Some robots (KUKA iiwa) lack tool0 or have misaligned EE frames | Check references/ee-frame-alignment.md table or run diagnostic before gripper attachment |
Using rigidBodyTree for closed-loop parallel robots | Cannot represent closed kinematic chains | See references/parallel-robot-guidance.md |
Copyright 2026 The MathWorks, Inc.
Files
- ATTRIBUTION.mdAdded by AutoGineer1.1 KiB
- LICENSELicence file added by AutoGineer1.4 KiB
- SKILL.md15.0 KiB
- manifest.yaml428 B
- references/ee-frame-alignment.md3.6 KiB
- references/gik-constraints.md2.9 KiB
- references/gripper-models.md6.7 KiB
- references/import-mesh-handling.md7.9 KiB
- references/parallel-robot-guidance.md1.5 KiB
references/gripper-models.md
Available Gripper Models
Models
| Model Name | Grip Type | DOF | Use Case |
|---|---|---|---|
robotiq2F85 | Two-finger mechanical (parallel jaw) | 6 (underactuated linkage) | General pick-and-place of rigid objects |
robotiqEPick4CupVacuumAssembly | Vacuum (4 suction cups) | 0 | Flat/smooth surfaces, heavier objects |
robotiqEPick2CupVacuumAssembly | Vacuum (2 suction cups) | 0 | Flat/smooth surfaces, smaller footprint |
robotiqEPickVacuumCup | Vacuum (single cup) | 0 | Single suction point, lightweight objects |
robotiqEPickVacuumCup200mm | Vacuum (single cup, 200mm extension) | 0 | Single suction with extended reach |
Compatibility
The robotiq2F85 gripper is only compatible with these manipulators:
Universal Robots UR3
Universal Robots UR3e
Universal Robots UR5
Universal Robots UR5e
Universal Robots UR10
Universal Robots UR10e
Universal Robots UR16e
KINOVA Gen3 (versions 1 and 2)
The robotiqEPick vacuum grippers can attach to any manipulator with a "tool0" body whose Z-axis points along the arm's outward direction. If the robot lacks tool0 or has a misaligned EE frame (e.g., KUKA iiwa), you must add a corrective tool0 frame first — see references/ee-frame-alignment.md.
Attachment Pattern
All grippers attach the same way — use addSubtree with ReplaceBase=false:
robot = loadrobot("universalUR5e", DataFormat="row");
gripper = loadrobot("robotiq2F85", DataFormat="row");
addSubtree(robot, "tool0", gripper, ReplaceBase=false);Critical: Always set ReplaceBase=false. The default (true) merges the gripper's base link into the parent body, silently discarding the gripper's base visual mesh (housing/coupling). Every provided gripper has a base visual that is lost without this flag — the fingers render but the housing disappears.
The gripper's base frame aligns to the specified body's frame. For most manipulators loaded via loadrobot, the end-effector body is named "tool0".
Choosing a Gripper
Step 1 — Check manipulator compatibility:
If the manipulator is not in the compatibility list above, the robotiq2F85 cannot be used. Proceed to vacuum grippers or build a custom gripper (Step 4).
Step 2 — Check object size against gripper opening:
| Gripper | Max Opening | Use Only When |
|---|---|---|
robotiq2F85 | 85 mm | Object's graspable dimension < 85 mm |
robotiqEPick variants | N/A (suction) | Object has a flat surface accessible from above |
The robotiq2F85 cannot grasp objects wider than 85 mm. If the object's smallest graspable dimension exceeds the jaw opening, the parallel-jaw gripper is physically unusable — select a vacuum gripper instead.
Step 3 — Select by grip strategy:
Small rigid objects with parallel faces (< 85 mm across the grasp axis) →
robotiq2F85Large rigid objects picked from above (boxes, cartons, panels, any object > 85 mm) →
robotiqEPickvariants (vacuum)Flat, smooth surfaces (sheets, sealed packages) →
robotiqEPickvariantsHeavy or large footprint →
robotiqEPick4CupVacuumAssembly(4 cups, higher payload)Smaller footprint or lighter objects →
robotiqEPick2CupVacuumAssembly
Step 4 — Build a custom gripper (last resort):
If none of the available grippers work (incompatible manipulator, object not suitable for vacuum, object exceeds jaw opening), build a custom gripper using rigidBody with appropriate visual and collision geometry. Use addVisual and addCollision to define the gripper shape, then attach via addSubtree or addBody.
IK Target Frame and Approach Axis
After attaching a gripper, you must know which body to solve IK to and how to orient the target so the gripper approaches correctly.
| Gripper | Contact Frame Offset (from tool0 along +Z) | Convention |
|---|---|---|
robotiq2F85 | 130 mm | Fingers close perpendicular to approach axis |
robotiqEPick4CupVacuumAssembly | 190 mm | Cups face in tool0 +Z direction |
robotiqEPick2CupVacuumAssembly | 190 mm | Cups face in tool0 +Z direction |
robotiqEPickVacuumCup | 129.5 mm | Cup faces in tool0 +Z direction |
robotiqEPickVacuumCup200mm | 319.5 mm | Cup faces in tool0 +Z direction |
Key insight: For ALL grippers, the physical contact direction follows tool0 +Z. The built-in tip body frames have internal rotations that are confusing to reason about — do not solve IK to them directly.
Recommended pattern: Add a contact frame, then solve IK to it.
This adds zero DOF (fixed joint) and gives a frame at the actual contact point with Z = approach direction:
contactFrame = rigidBody("contact_point");
contactJoint = rigidBodyJoint("contact_joint", "fixed");
setFixedTransform(contactJoint, trvec2tform([0, 0, gripperOffset]));
contactFrame.Joint = contactJoint;
addBody(robot, contactFrame, "tool0");Where gripperOffset is from the table above (e.g., 0.190 for EPick 4-cup).
Solve IK to the contact frame — Z = approach direction, position = where you want contact:
contactPoint = [0.4, 0, 0.05];
targetRotm = [1 0 0; 0 -1 0; 0 0 -1];
targetPose = trvec2tform(contactPoint) * rotm2tform(targetRotm);
[qSol, solnInfo] = ik("contact_point", targetPose, weights, q0);No offset math needed — the frame is already at the contact surface.
Helper to build rotation matrix from approach direction:
function R = rotm_from_approach(approachZ)
%rotm_from_approach Build rotation matrix from approach direction.
arguments
approachZ (1,3) double
end
approachZ = approachZ / norm(approachZ);
if abs(dot(approachZ, [1 0 0])) < 0.9
tempX = cross([1 0 0], approachZ);
else
tempX = cross([0 1 0], approachZ);
end
xAxis = tempX / norm(tempX);
yAxis = cross(approachZ, xAxis);
R = [xAxis', yAxis', approachZ'];
endFor robotiq2F85: The grasp center is between the finger pads, 130mm along tool0 +Z. Best practice is to add a fixed frame at the midpoint:
graspFrame = rigidBody("grasp_center");
graspJoint = rigidBodyJoint("grasp_joint", "fixed");
setFixedTransform(graspJoint, trvec2tform([0, 0, 0.130]));
graspFrame.Joint = graspJoint;
addBody(robot, graspFrame, "tool0");Then solve IK to "grasp_center" instead of "tool0".
Before Building a Custom Gripper
Exhaust the provided models first. Only build custom when:
The manipulator is not in the
robotiq2F85compatibility list, ANDThe object is not suitable for vacuum gripping (no flat surface, porous, irregular)
Discovery showed agents building grippers from scratch when provided models were available and ready to attach in one line.
Copyright 2026 The MathWorks, Inc.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- MathWorks
- Publisher
- MathWorks (Official)
- Source
- matlab/matlab-agentic-toolkit · skills-catalog/robotics-and-autonomous-systems/matlab-model-robot-kinematics · commit 2a7f215
- Licence
- BSD 2-Clause License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by MathWorks.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download matlab-model-robot-kinematics.zip