The Kinova Gen3 is a lightweight arm built for research and light-industrial manipulation, sold in both 6-DoF and 7-DoF configurations sharing the same actuator family, payload range, and Kortex control stack. A separate, smaller Gen3 lite exists too, but it is a distinct product with a much lower payload — this page is about the Gen3 proper.
Teams collect data on the Gen3 for reasons that are mostly about access, not raw capability: the Kortex API is documented and stable, the arm ships with an integrated wrist camera so you get a hand-eye view without mounting your own, and the 7-DoF variant's extra joint gives you kinematic redundancy that some teleoperation and retargeting pipelines depend on. None of that makes the Gen3 unusual among research arms — it makes it a reasonable, well-documented default, the same role UFACTORY's xArm plays a price tier down, with a comparable open-SDK philosophy.
Control interfaces that matter for data collection
Everything you can do with a Gen3 goes through the Kortex API, Kinova's vendor SDK. It exposes clients in C++ and Python, communicates over Protocol Buffer messages, and covers the arm's base controller, actuators, interface module, and vision module through one set of services. Two servoing modes matter for how you'll actually drive the robot:
- High-level servoing is the default on bootup. You send Cartesian poses, joint targets, or twist commands, and the base handles inverse kinematics, trajectory shaping, and singularity handling internally. This is what almost all teleoperation and scripted-motion code uses.
- Low-level servoing bypasses the kinematic library entirely: the client streams small per-actuator position, velocity, or torque increments and the base routes them to the actuators at 1 kHz. This is what you want for custom impedance control, torque-based compliance, or any controller that needs actuator-level access.
A minimal high-level Cartesian command through the Python client looks like this:
from kortex_api.autogen.messages import Base_pb2
action = Base_pb2.Action()
action.name = "reach_pose"
cartesian_pose = action.reach_pose.target_pose
cartesian_pose.x, cartesian_pose.y, cartesian_pose.z = 0.4, 0.0, 0.35
cartesian_pose.theta_x, cartesian_pose.theta_y, cartesian_pose.theta_z = 90, 0, 90
base_client.ExecuteAction(action)For ROS 2 stacks, Kinova maintains ros2_kortex, a driver built on top of the Kortex API that implements the standard ros2_control hardware interface — position, velocity, and effort command interfaces per joint, plus a twist interface for operational-space control. It is actively maintained against current ROS 2 distributions, which matters if your recording and playback tooling is already ROS-native.
The arm's integrated Vision module sits in the wrist and combines a 2D RGB sensor (an Omnivision OV5640 color imager) with an Intel RealSense D410 depth sensor, giving synchronized color and depth without a separate camera mount. Kinova's own documentation identifies the two sensor models but does not publish a single authoritative operating resolution for the color stream, so treat the RGB feed's usable resolution as something to confirm against your firmware version rather than a fixed spec. Both streams are exposed through the same API and can be pulled alongside joint and pose data, which simplifies time alignment considerably compared to bolting on a third-party wrist camera.
Teleoperation options
Nothing about the Gen3 forces one teleoperation approach, but the practical options and their trade-offs are shaped by the arm's control interfaces:
- Leader–follower with a second arm or a haptic device. Because high-level servoing accepts smooth Cartesian targets, a leader device streaming pose commands maps directly onto
ExecuteActioncalls. This gives clean joint-space or task-space correspondence and is the most direct way to collect contact-rich demonstrations, at the cost of needing a second input device to drive. - VR controller or hand-tracking retargeting. The operator's tracked hand pose is retargeted to an end-effector target and sent as a Cartesian command. This is cheap to set up and portable across tasks, but retargeting accuracy depends on how well the mapping handles the arm's workspace limits — on the 7-DoF variant specifically, the redundant elbow means a single end-effector pose has a family of valid joint solutions, so the retargeting layer also has to resolve which elbow configuration to use, not just the wrist pose.
- Space mouse. A rate-control device mapped to Cartesian velocity through high-level servoing. Reasonable for coarse repositioning and inspection tasks, weak for fine insertion or contact work where position control is easier to reason about.
- Admittance / hand-guiding. The Gen3 supports Cartesian, joint, and null-space admittance modes, where the arm moves in response to a wrench or torque applied by hand rather than a streamed command. This is closer to kinesthetic teaching than teleoperation — useful for quick single demonstrations or calibration, but it puts the operator in physical contact with the arm, which does not scale the way remote input devices do.
Across all of these, the Gen3's own base loop still runs the low-level kinematics, so latency budgets are dominated by your teleoperation transport and input-device processing rather than the arm's own control loop.
What a clean dataset looks like on this platform
A Gen3 episode worth training on records, at minimum: joint positions, velocities, and (if you're using torque control or an F/T sensor) joint torques from the base feedback stream; end-effector pose derived from forward kinematics or read directly from Kortex; gripper position and, if available, force; the wrist Vision module's RGB and depth frames; and at least one external RGB camera covering the workspace the wrist camera cannot see. Joint and pose feedback are naturally available at the base's control rate, but most demonstration pipelines downsample to something more tractable for storage and later playback — pick a rate and hold it constant across an episode rather than logging whatever each subsystem happens to produce.
Sync is the part that actually breaks datasets. The Vision module's RGB and depth sensors run their own capture clocks, the base's actuator feedback runs on the 1 kHz control loop, and an external camera is a third, independent source — none of these arrive pre-aligned. Timestamp every stream at capture time against one clock rather than reconstructing alignment afterward from arrival order; see multi-camera calibration for the general pattern of aligning intrinsics, extrinsics, and timing across camera pairs before you rely on any downstream geometry.
The 6-DoF vs 7-DoF split matters for anything downstream that consumes joint angles rather than end-effector pose. A policy or retargeting pipeline trained on 7-DoF Gen3 joint trajectories will not transfer cleanly to a 6-DoF Gen3, or to a different arm's joint space, because the redundant joint has no counterpart to map to. If you expect to mix data across Gen3 variants or other platforms, standardize on end-effector pose and gripper state as the primary action representation and treat raw joint angles as supplementary.
Common pitfalls
Recording only end-effector pose and discarding joint states. Pose-only logging looks sufficient until you need to debug a failed grasp or retarget the trajectory to a different arm — at that point you need the joint configuration the arm actually used, especially on the 7-DoF variant where pose alone underdetermines the joints.
Treating the wrist camera as a complete observation. It moves with the gripper, which is exactly why it's good for contact events and exactly why it's bad as the only camera — the field of view is constantly changing and anything outside the current reach is invisible. Pair it with a fixed external view every time.
Assuming ROS 1 tooling carries over. ros_kortex (ROS 1) and ros2_kortex are separate packages with separate maintenance tracks; scripts, launch files, and topic names written for one do not run unmodified on the other.
Underestimating low-level control's language constraint. Teams sometimes prototype a torque controller in Python against the low-level interface, see it work at low speed on the bench, and only discover the missed-cycle behavior once timing gets tight in a real collection session — by which point the recorded data has irregular control intervals baked into it.