Skip to content

Commit 838bb49

Browse files
committed
feat: Added the Cartesian pose interface to pylibfranka
1 parent 56dab4b commit 838bb49

File tree

6 files changed

+152
-28
lines changed

6 files changed

+152
-28
lines changed

pylibfranka/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ This document provides comprehensive instructions for installing and using pylib
66
- [Prerequisites](#prerequisites)
77
- [Installation](#installation)
88
- [Installation from Source](#installation-from-source)
9-
- [Installation from Artifactory](#installation-from-artifactory)
109
- [Examples](#examples)
1110
- [Joint Position Example](#joint-position-example)
1211
- [Print Robot State Example](#print-robot-state-example)

pylibfranka/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from ._pylibfranka import (
44
ActiveControlBase,
5+
CartesianPose,
56
ControllerMode,
67
Errors,
78
Gripper,
@@ -18,6 +19,7 @@
1819
__all__ = [
1920
"ActiveControlBase",
2021
"ControllerMode",
22+
"CartesianPose",
2123
"Errors",
2224
"JointPositions",
2325
"JointVelocities",
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright (c) 2025 Franka Robotics GmbH
4+
# Use of this source code is governed by the Apache-2.0 license, see LICENSE
5+
6+
import argparse
7+
import time
8+
9+
import numpy as np
10+
11+
from pylibfranka import ControllerMode, CartesianPose, Robot
12+
13+
14+
def main():
15+
# Parse command line arguments
16+
parser = argparse.ArgumentParser()
17+
parser.add_argument("--ip", type=str, default="localhost", help="Robot IP address")
18+
args = parser.parse_args()
19+
20+
# Connect to robot
21+
robot = Robot(args.ip)
22+
23+
try:
24+
# Set collision behavior
25+
lower_torque_thresholds = [20.0, 20.0, 18.0, 18.0, 16.0, 14.0, 12.0]
26+
upper_torque_thresholds = [20.0, 20.0, 18.0, 18.0, 16.0, 14.0, 12.0]
27+
lower_force_thresholds = [20.0, 20.0, 20.0, 25.0, 25.0, 25.0]
28+
upper_force_thresholds = [20.0, 20.0, 20.0, 25.0, 25.0, 25.0]
29+
30+
robot.set_collision_behavior(
31+
lower_torque_thresholds,
32+
upper_torque_thresholds,
33+
lower_force_thresholds,
34+
upper_force_thresholds,
35+
)
36+
37+
# First move the robot to a suitable joint configuration
38+
print("WARNING: This example will move the robot!")
39+
print("Please make sure to have the user stop button at hand!")
40+
input("Press Enter to continue...")
41+
42+
# Start cartesian pose control with external control loop
43+
active_control = robot.start_cartesian_pose_control(ControllerMode.JointImpedance)
44+
45+
time_elapsed = 0.0
46+
motion_finished = False
47+
48+
robot_state, duration = active_control.readOnce()
49+
initial_cartesian_pose = robot_state.O_T_EE
50+
51+
# External control loop
52+
while not motion_finished:
53+
# Read robot state and duration
54+
robot_state, duration = active_control.readOnce()
55+
56+
kRadius = 0.3
57+
angle = np.pi / 4 * (1 - np.cos(np.pi / 5.0 * time_elapsed))
58+
delta_x = kRadius * np.sin(angle)
59+
delta_z = kRadius * (np.cos(angle) - 1)
60+
61+
# Update time
62+
time_elapsed += duration.to_sec()
63+
64+
65+
# Update joint positions
66+
new_cartesian_pose = initial_cartesian_pose.copy()
67+
new_cartesian_pose[12] += delta_x # x position
68+
new_cartesian_pose[14] += delta_z # z position
69+
70+
# Set joint positions
71+
cartesian_pose = CartesianPose(new_cartesian_pose)
72+
73+
# Set motion_finished flag to True on the last update
74+
if time_elapsed >= 5.0:
75+
cartesian_pose.motion_finished = True
76+
motion_finished = True
77+
print("Finished motion, shutting down example")
78+
79+
# Send command to robot
80+
active_control.writeOnce(cartesian_pose)
81+
82+
except Exception as e:
83+
print(f"Error occurred: {e}")
84+
if robot is not None:
85+
robot.stop()
86+
return -1
87+
88+
89+
if __name__ == "__main__":
90+
main()

pylibfranka/include/pylibfranka.h

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
*
88
* This header file provides C++ classes that wrap the Franka Robotics Robot Control Library
99
* for use in Python through pybind11. It offers:
10-
*
11-
* 1. PyRobot: A wrapper for the Franka robot control functionality, providing:
10+
* PyRobot: A wrapper for the Franka robot control functionality, providing:
1211
* - Active control methods (torque, joint position, joint velocity control)
1312
* - Configuration methods (collision behavior, impedance settings, etc.)
1413
* - State reading and control methods
@@ -44,11 +43,31 @@ class PyRobot {
4443
~PyRobot() = default;
4544

4645
// Active control methods
47-
std::unique_ptr<franka::ActiveControlBase> startTorqueControl();
48-
std::unique_ptr<franka::ActiveControlBase> startJointPositionControl(
49-
const franka::ControllerMode&);
50-
std::unique_ptr<franka::ActiveControlBase> startJointVelocityControl(
51-
const franka::ControllerMode&);
46+
/**
47+
* Starts torque control mode.
48+
*/
49+
auto startTorqueControl() -> std::unique_ptr<franka::ActiveControlBase>;
50+
51+
/**
52+
* Starts the joint position control mode.
53+
* @param control_type The type of controller to use (JointImpedance or CartesianImpedance).
54+
*/
55+
auto startJointPositionControl(franka::ControllerMode controller_mode)
56+
-> std::unique_ptr<franka::ActiveControlBase>;
57+
58+
/**
59+
* Starts the joint velocity control mode.
60+
* @param control_type The type of controller to use (JointImpedance or CartesianImpedance).
61+
*/
62+
auto startJointVelocityControl(franka::ControllerMode controller_mode)
63+
-> std::unique_ptr<franka::ActiveControlBase>;
64+
65+
/**
66+
* Starts the Cartesian pose control mode.
67+
* @param control_type The type of controller to use (JointImpedance or CartesianImpedance).
68+
*/
69+
auto startCartesianPoseControl(franka::ControllerMode controller_mode)
70+
-> std::unique_ptr<franka::ActiveControlBase>;
5271

5372
// Configuration methods
5473
void setCollisionBehavior(const std::array<double, 7>& lower_torque_thresholds,

pylibfranka/src/pylibfranka.cpp

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,26 @@
1616

1717
namespace py = pybind11;
1818

19+
namespace {
20+
21+
/**
22+
* Convert franka::ControllerMode to research_interface::robot::Move::ControllerMode
23+
* @param mode franka::ControllerMode the mode to convert
24+
* @return research_interface::robot::Move::ControllerMode
25+
*/
26+
auto convertControllerMode(franka::ControllerMode mode)
27+
-> research_interface::robot::Move::ControllerMode {
28+
switch (mode) {
29+
case franka::ControllerMode::kJointImpedance:
30+
return research_interface::robot::Move::ControllerMode::kJointImpedance;
31+
case franka::ControllerMode::kCartesianImpedance:
32+
return research_interface::robot::Move::ControllerMode::kCartesianImpedance;
33+
default:
34+
throw std::invalid_argument("Invalid franka::ControllerMode");
35+
}
36+
}
37+
} // namespace
38+
1939
namespace pylibfranka {
2040

2141
PyGripper::PyGripper(const std::string& franka_address)
@@ -51,30 +71,23 @@ franka::Gripper::ServerVersion PyGripper::serverVersion() {
5171
PyRobot::PyRobot(const std::string& franka_address, franka::RealtimeConfig realtime_config)
5272
: robot_(std::make_unique<franka::Robot>(franka_address, realtime_config)) {}
5373

54-
std::unique_ptr<franka::ActiveControlBase> PyRobot::startTorqueControl() {
74+
auto PyRobot::startTorqueControl() -> std::unique_ptr<franka::ActiveControlBase> {
5575
return robot_->startTorqueControl();
5676
}
5777

58-
std::unique_ptr<franka::ActiveControlBase> PyRobot::startJointPositionControl(
59-
const franka::ControllerMode& control_type) {
60-
research_interface::robot::Move::ControllerMode mode;
61-
if (control_type == franka::ControllerMode::kJointImpedance) {
62-
mode = research_interface::robot::Move::ControllerMode::kJointImpedance;
63-
} else {
64-
mode = research_interface::robot::Move::ControllerMode::kCartesianImpedance;
65-
}
66-
return robot_->startJointPositionControl(mode);
78+
auto PyRobot::startJointPositionControl(franka::ControllerMode controller_mode)
79+
-> std::unique_ptr<franka::ActiveControlBase> {
80+
return robot_->startJointPositionControl(convertControllerMode(controller_mode));
6781
}
6882

69-
std::unique_ptr<franka::ActiveControlBase> PyRobot::startJointVelocityControl(
70-
const franka::ControllerMode& control_type) {
71-
research_interface::robot::Move::ControllerMode mode;
72-
if (control_type == franka::ControllerMode::kJointImpedance) {
73-
mode = research_interface::robot::Move::ControllerMode::kJointImpedance;
74-
} else {
75-
mode = research_interface::robot::Move::ControllerMode::kCartesianImpedance;
76-
}
77-
return robot_->startJointVelocityControl(mode);
83+
auto PyRobot::startJointVelocityControl(franka::ControllerMode controller_mode)
84+
-> std::unique_ptr<franka::ActiveControlBase> {
85+
return robot_->startJointVelocityControl(convertControllerMode(controller_mode));
86+
}
87+
88+
auto PyRobot::startCartesianPoseControl(franka::ControllerMode controller_mode)
89+
-> std::unique_ptr<franka::ActiveControlBase> {
90+
return robot_->startCartesianPoseControl(convertControllerMode(controller_mode));
7891
}
7992

8093
void PyRobot::setCollisionBehavior(const std::array<double, 7>& lower_torque_thresholds,
@@ -430,6 +443,7 @@ PYBIND11_MODULE(_pylibfranka, m) {
430443
.def("start_torque_control", &PyRobot::startTorqueControl)
431444
.def("start_joint_position_control", &PyRobot::startJointPositionControl)
432445
.def("start_joint_velocity_control", &PyRobot::startJointVelocityControl)
446+
.def("start_cartesian_pose_control", &PyRobot::startCartesianPoseControl)
433447
.def("set_collision_behavior", &PyRobot::setCollisionBehavior)
434448
.def("set_joint_impedance", &PyRobot::setJointImpedance)
435449
.def("set_cartesian_impedance", &PyRobot::setCartesianImpedance)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ build-backend = "setuptools.build_meta"
1313

1414
[project]
1515
name = "pylibfranka"
16-
version = "0.1.0"
16+
version = "0.2.0"
1717
description = "Python bindings for libfranka with automatic dependency bundling"
1818
authors = [{name = "Franka Robotics GmbH", email = "[email protected]"}]
1919
license = {text = "Apache-2.0"}

0 commit comments

Comments
 (0)