Skip to content

Commit 99c03ec

Browse files
authored
Merge pull request #303 from RobotControlStack/juelg/fix-franka-controllers
fix(franka): controllers
2 parents c903475 + 5876a98 commit 99c03ec

8 files changed

Lines changed: 98 additions & 64 deletions

File tree

examples/teleop/franka.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"zed": "19928076",
4444
}
4545
MQ3_ADDR = "10.42.0.1"
46+
INCLUDE_DEPTH = False
4647

4748
# DIGIT_DICT = {
4849
# "digit_right_left": "D21182",
@@ -69,7 +70,7 @@
6970
mq3_addr=MQ3_ADDR,
7071
simulation=ROBOT_INSTANCE == RobotPlatform.SIMULATION,
7172
switched_left_right=False,
72-
display_cameras=True,
73+
display_cameras=False,
7374
)
7475
# config = GelloConfig(
7576
# arms={
@@ -82,10 +83,10 @@
8283

8384
def get_env():
8485
if ROBOT_INSTANCE == RobotPlatform.HARDWARE:
85-
from rcs_fr3.configs import DefaultFR3MultiHardwareEnv
86+
from rcs_fr3.configs import FrankaDuoEnv
8687
from rcs_fr3.creators import HardwareCameraCreatorConfig
8788

88-
env_creator = DefaultFR3MultiHardwareEnv()
89+
env_creator = FrankaDuoEnv()
8990
env_creator.left_ip = ROBOT2IP["left"]
9091
env_creator.right_ip = ROBOT2IP["right"]
9192
hw_cfg = env_creator.config()
@@ -135,15 +136,13 @@ def get_env():
135136
)
136137
hw_cfg.camera_cfgs = camera_cfgs or None
137138
hw_cfg.control_mode = config.operator_class.control_mode[0]
139+
hw_cfg.wrapper_cfg.include_depth = INCLUDE_DEPTH
138140
hw_cfg.max_relative_movement = (
139141
0.5 if config.operator_class.control_mode[0] == ControlMode.JOINTS else (0.5, np.deg2rad(90))
140142
)
141143
hw_cfg.relative_to = config.operator_class.control_mode[1]
142144
hw_cfg.robot_to_shared_base_frame = robot2world
143145
env_rel = env_creator.create_env(hw_cfg)
144-
# env_rel = StorageWrapper(
145-
# env_rel, DATASET_PATH, INSTRUCTION, batch_size=32, max_rows_per_group=100, max_rows_per_file=1000
146-
# )
147146
operator = GelloOperator(config) if isinstance(config, GelloConfig) else QuestOperator(config)
148147
else:
149148
# FR3
@@ -154,19 +153,21 @@ def get_env():
154153
async_control=True, realtime=True, frequency=RECORD_FPS, max_convergence_steps=500
155154
)
156155
sim_cfg_data.relative_to = RelativeTo.CONFIGURED_ORIGIN
156+
sim_cfg_data.wrapper_cfg.include_depth = INCLUDE_DEPTH
157157
if sim_cfg_data.root_frame_objects is None:
158158
sim_cfg_data.root_frame_objects = {}
159159
# cfg.root_frame_objects["green_cube"] = (rcs.OBJECT_PATHS["green_cube"], Pose(translation=[0.5, 0, 0.5], quaternion=[0, 0, 0, 1]))
160160
sim_cfg_data.task_cfg = PickTaskConfig(robot_name="right")
161161

162162
env_rel = scene.create_env(sim_cfg_data)
163-
env_rel = StorageWrapper(
164-
env_rel, DATASET_PATH, INSTRUCTION, batch_size=32, max_rows_per_group=100, max_rows_per_file=1000
165-
)
166163

167164
sim = env_rel.get_wrapper_attr("sim")
168165
MujocoPublisher(sim.model, sim.data, MQ3_ADDR, visible_geoms_groups=list(range(1, 3)))
169166
operator = GelloOperator(config, sim) if isinstance(config, GelloConfig) else QuestOperator(config, sim)
167+
168+
env_rel = StorageWrapper(
169+
env_rel, DATASET_PATH, INSTRUCTION, batch_size=32, max_rows_per_group=100, max_rows_per_file=1000
170+
)
170171
return env_rel, operator
171172

172173

extensions/rcs_fr3/src/hw/Franka.cpp

Lines changed: 61 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ FrankaConfig* Franka::get_config() {
7373

7474
FrankaState* Franka::get_state() {
7575
franka::RobotState current_robot_state;
76-
if (this->running_controller == Controller::none) {
76+
if (this->running_controller.load() == Controller::none) {
7777
current_robot_state = this->robot.readOnce();
7878
} else {
7979
std::lock_guard<std::mutex> lock(this->interpolator_mutex);
@@ -100,7 +100,7 @@ void Franka::set_default_robot_behavior() {
100100
common::Pose Franka::get_cartesian_position() {
101101
this->check_for_background_errors();
102102
common::Pose x;
103-
if (this->running_controller == Controller::none) {
103+
if (this->running_controller.load() == Controller::none) {
104104
this->curr_state = this->robot.readOnce();
105105
x = common::Pose(this->curr_state.O_T_EE);
106106
} else {
@@ -127,7 +127,7 @@ void Franka::set_joint_position(const common::VectorXd& q) {
127127
common::VectorXd Franka::get_joint_position() {
128128
this->check_for_background_errors();
129129
common::Vector7d joints;
130-
if (this->running_controller == Controller::none) {
130+
if (this->running_controller.load() == Controller::none) {
131131
this->curr_state = this->robot.readOnce();
132132
joints = common::Vector7d(this->curr_state.q.data());
133133
} else {
@@ -182,15 +182,15 @@ void Franka::controller_set_joint_position(const common::Vector7d& desired_q) {
182182
int policy_rate = 20;
183183
int traj_rate = 500;
184184

185-
if (this->running_controller == Controller::none) {
185+
if (this->running_controller.load() == Controller::none) {
186186
this->controller_time = 0.0;
187187
this->get_joint_position();
188188
this->joint_interpolator = common::LinearJointPositionTrajInterpolator();
189-
} else if (this->running_controller != Controller::jsc) {
189+
} else if (this->running_controller.load() != Controller::jsc) {
190190
// runtime error
191191
throw std::runtime_error(
192192
"Controller type must but joint space but is " +
193-
std::to_string(this->running_controller) +
193+
std::to_string(static_cast<int>(this->running_controller.load())) +
194194
". To change controller type stop the current controller first.");
195195
} else {
196196
this->interpolator_mutex.lock();
@@ -202,8 +202,8 @@ void Franka::controller_set_joint_position(const common::Vector7d& desired_q) {
202202
policy_rate, traj_rate, traj_interpolation_time_fraction);
203203

204204
// if not thread is running, then start
205-
if (this->running_controller == Controller::none) {
206-
this->running_controller = Controller::jsc;
205+
if (this->running_controller.load() == Controller::none) {
206+
this->running_controller.store(Controller::jsc);
207207
this->control_thread = std::thread(&Franka::joint_controller, this);
208208
} else {
209209
this->interpolator_mutex.unlock();
@@ -229,28 +229,35 @@ void Franka::osc_set_cartesian_position(
229229
int policy_rate = 20;
230230
int traj_rate = 500;
231231

232-
if (this->running_controller == Controller::none) {
232+
if (this->running_controller.load() == Controller::none) {
233233
this->controller_time = 0.0;
234+
{
235+
std::lock_guard<std::mutex> lock(this->interpolator_mutex);
236+
this->curr_state = this->robot.readOnce();
237+
}
234238
this->traj_interpolator = common::LinearPoseTrajInterpolator();
235-
} else if (this->running_controller != Controller::osc) {
239+
} else if (this->running_controller.load() != Controller::osc) {
236240
throw std::runtime_error(
237241
"Controller type must but osc but is " +
238-
std::to_string(this->running_controller) +
242+
std::to_string(static_cast<int>(this->running_controller.load())) +
239243
". To change controller type stop the current controller first.");
240244
} else {
241245
this->interpolator_mutex.lock();
242246
}
243247

244248
common::Pose curr_pose(this->curr_state.O_T_EE);
249+
if (!this->m_cfg.tcp_offset_configured_in_desk) {
250+
curr_pose = curr_pose * this->m_cfg.tcp_offset;
251+
}
245252
this->traj_interpolator.reset(
246253
this->controller_time, curr_pose.translation(), curr_pose.quaternion(),
247254
desired_pose_EE_in_base_frame.translation(),
248255
desired_pose_EE_in_base_frame.quaternion(), policy_rate, traj_rate,
249256
traj_interpolation_time_fraction);
250257

251258
// if not thread is running, then start
252-
if (this->running_controller == Controller::none) {
253-
this->running_controller = Controller::osc;
259+
if (this->running_controller.load() == Controller::none) {
260+
this->running_controller.store(Controller::osc);
254261
this->control_thread = std::thread(&Franka::osc, this);
255262
} else {
256263
this->interpolator_mutex.unlock();
@@ -259,10 +266,11 @@ void Franka::osc_set_cartesian_position(
259266

260267
// method to stop thread
261268
void Franka::stop_control_thread() {
262-
if (this->control_thread.has_value() &&
263-
this->running_controller != Controller::none) {
264-
this->running_controller = Controller::none;
265-
this->control_thread->join();
269+
if (this->control_thread.has_value()) {
270+
this->running_controller.store(Controller::none);
271+
if (this->control_thread->joinable()) {
272+
this->control_thread->join();
273+
}
266274
this->control_thread.reset();
267275
}
268276
}
@@ -291,7 +299,10 @@ void Franka::osc() {
291299
// translation: [150.0, 150.0, 150.0]
292300
// rotation: 250.0
293301

294-
Eigen::Matrix<double, 3, 3> Kp_p, Kp_r, Kd_p, Kd_r;
302+
Eigen::Matrix<double, 3, 3> Kp_p = Eigen::Matrix3d::Zero();
303+
Eigen::Matrix<double, 3, 3> Kp_r = Eigen::Matrix3d::Zero();
304+
Eigen::Matrix<double, 3, 3> Kd_p = Eigen::Matrix3d::Zero();
305+
Eigen::Matrix<double, 3, 3> Kd_r = Eigen::Matrix3d::Zero();
295306
Eigen::Matrix<double, 7, 1> static_q_task_;
296307
Eigen::Matrix<double, 7, 1> residual_mass_vec_;
297308
Eigen::Array<double, 7, 1> joint_max_;
@@ -323,7 +334,7 @@ void Franka::osc() {
323334
std::chrono::high_resolution_clock::now();
324335

325336
// torques handler
326-
if (this->running_controller == Controller::none) {
337+
if (this->running_controller.load() == Controller::none) {
327338
franka::Torques zero_torques{{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}};
328339
return franka::MotionFinished(zero_torques);
329340
}
@@ -335,7 +346,6 @@ void Franka::osc() {
335346
Eigen::Vector3d desired_pos_EE_in_base_frame;
336347
Eigen::Quaterniond desired_quat_EE_in_base_frame;
337348

338-
common::Pose pose(robot_state.O_T_EE);
339349
// form deoxys/config/charmander.yml
340350
int policy_rate = 20;
341351
int traj_rate = 500;
@@ -376,9 +386,15 @@ void Franka::osc() {
376386
jacobian_pos << jacobian.block(0, 0, 3, 7);
377387
jacobian_ori << jacobian.block(3, 0, 3, 7);
378388

379-
// End effector pose in base frame
380-
Eigen::Affine3d T_EE_in_base_frame(
381-
Eigen::Matrix4d::Map(robot_state.O_T_EE.data()));
389+
// Express OSC feedback in the same TCP frame exposed by the public
390+
// Cartesian API.
391+
common::Pose T_EE_in_base_frame_pose =
392+
this->m_cfg.tcp_offset_configured_in_desk
393+
? common::Pose(robot_state.O_T_EE)
394+
: common::Pose(robot_state.O_T_EE) * this->m_cfg.tcp_offset;
395+
Eigen::Affine3d T_EE_in_base_frame =
396+
T_EE_in_base_frame_pose.affine_matrix();
397+
382398
Eigen::Vector3d pos_EE_in_base_frame(T_EE_in_base_frame.translation());
383399
Eigen::Quaterniond quat_EE_in_base_frame(T_EE_in_base_frame.linear());
384400

@@ -487,7 +503,7 @@ void Franka::osc() {
487503
}
488504

489505
// Ensure we mark the controller as stopped so we can restart later
490-
this->running_controller = Controller::none;
506+
this->running_controller.store(Controller::none);
491507
}
492508

493509
void Franka::joint_controller() {
@@ -524,14 +540,13 @@ void Franka::joint_controller() {
524540
std::chrono::high_resolution_clock::now();
525541

526542
// torques handler
527-
if (this->running_controller == Controller::none) {
543+
if (this->running_controller.load() == Controller::none) {
528544
// TODO: test if this also works when the robot is moving
529545
franka::Torques zero_torques{{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}};
530546
return franka::MotionFinished(zero_torques);
531547
}
532548

533549
common::Vector7d desired_q;
534-
common::Pose pose(robot_state.O_T_EE);
535550

536551
this->interpolator_mutex.lock();
537552
this->curr_state = robot_state;
@@ -588,16 +603,18 @@ void Franka::joint_controller() {
588603
std::lock_guard<std::mutex> lock(this->exception_mutex);
589604
this->background_exception = std::current_exception();
590605
}
606+
607+
this->running_controller.store(Controller::none);
591608
}
592609

593610
void Franka::zero_torque_guiding() {
594611
this->check_for_background_errors();
595-
if (this->running_controller != Controller::none) {
612+
if (this->running_controller.load() != Controller::none) {
596613
throw std::runtime_error(
597614
"A controller is currently running. Please stop it first.");
598615
}
599616
this->controller_time = 0.0;
600-
this->running_controller = Controller::ztc;
617+
this->running_controller.store(Controller::ztc);
601618
this->control_thread = std::thread(&Franka::zero_torque_controller, this);
602619
}
603620

@@ -617,7 +634,7 @@ void Franka::zero_torque_controller() {
617634
this->curr_state = robot_state;
618635
this->controller_time += period.toSec();
619636
this->interpolator_mutex.unlock();
620-
if (this->running_controller == Controller::none) {
637+
if (this->running_controller.load() == Controller::none) {
621638
// stop
622639
return franka::MotionFinished(franka::Torques({0, 0, 0, 0, 0, 0, 0}));
623640
}
@@ -627,6 +644,8 @@ void Franka::zero_torque_controller() {
627644
std::lock_guard<std::mutex> lock(this->exception_mutex);
628645
this->background_exception = std::current_exception();
629646
}
647+
648+
this->running_controller.store(Controller::none);
630649
}
631650

632651
void Franka::move_home() {
@@ -714,8 +733,12 @@ std::optional<std::shared_ptr<common::Kinematics>> Franka::get_ik() {
714733

715734
void Franka::set_cartesian_position(const common::Pose& x) {
716735
// pose is assumed to be in the robots coordinate frame
736+
common::Pose target_pose = x;
737+
if (!this->m_cfg.tcp_offset_configured_in_desk) {
738+
target_pose = target_pose * this->m_cfg.tcp_offset.inverse();
739+
}
717740
if (this->m_cfg.async_control) {
718-
this->osc_set_cartesian_position(x);
741+
this->osc_set_cartesian_position(target_pose);
719742
return;
720743
}
721744
// TODO: this should handled with tcp offset config
@@ -733,10 +756,11 @@ void Franka::set_cartesian_position(const common::Pose& x) {
733756
// if gripper is attached the tcp offset will automatically be applied
734757
// by libfranka
735758
this->robot.setEE(nominal_end_effector_frame_value.affine_array());
736-
this->set_cartesian_position_internal(x, 1.0, std::nullopt, std::nullopt);
759+
this->set_cartesian_position_internal(target_pose, 1.0, std::nullopt,
760+
std::nullopt);
737761

738762
} else if (this->m_cfg.ik_solver == IKSolver::rcs_ik) {
739-
this->set_cartesian_position_ik(x);
763+
this->set_cartesian_position_ik(target_pose);
740764
}
741765
}
742766

@@ -786,14 +810,17 @@ void Franka::set_cartesian_position_internal(const common::Pose& pose,
786810

787811
this->robot.control(
788812
[&force_stop_condition, &initial_elbow, &elbow, &max_force, &time,
789-
&max_time, &initial_pose, &should_stop,
813+
&max_time, &initial_pose, &should_stop, this,
790814
&pose](const franka::RobotState& state,
791815
franka::Duration time_step) -> franka::CartesianPose {
792816
time += time_step.toSec();
793817
if (time == 0) {
794818
initial_elbow = state.elbow_c;
795819

796-
initial_pose = common::Pose(state.O_T_EE);
820+
initial_pose =
821+
this->m_cfg.tcp_offset_configured_in_desk
822+
? common::Pose(state.O_T_EE)
823+
: common::Pose(state.O_T_EE) * this->m_cfg.tcp_offset;
797824
}
798825
auto new_elbow = initial_elbow;
799826
const double progress = time / max_time;

extensions/rcs_fr3/src/hw/Franka.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <franka/robot.h>
55
#include <franka/robot_state.h>
66

7+
#include <atomic>
78
#include <cmath>
89
#include <memory>
910
#include <mutex>
@@ -43,10 +44,6 @@ struct FrankaConfig : common::RobotConfig {
4344
bool async_control = false;
4445
bool tcp_offset_configured_in_desk = true;
4546
bool ignore_realtime = false;
46-
std::optional<common::VectorXd> q_home =
47-
(common::VectorXd(7) << 0.0, -M_PI_4, 0.0, -3.0 * M_PI_4, 0.0, M_PI_2,
48-
M_PI_4)
49-
.finished();
5047
size_t dof = 7;
5148
Eigen::Matrix<double, 2, Eigen::Dynamic, Eigen::ColMajor> joint_limits =
5249
(Eigen::Matrix<double, 2, Eigen::Dynamic, Eigen::ColMajor>(2, 7) <<
@@ -89,7 +86,7 @@ class Franka : public common::Robot {
8986
common::LinearJointPositionTrajInterpolator joint_interpolator;
9087
franka::RobotState curr_state;
9188
std::mutex interpolator_mutex;
92-
Controller running_controller = Controller::none;
89+
std::atomic<Controller> running_controller{Controller::none};
9390
std::exception_ptr background_exception = nullptr;
9491
std::mutex exception_mutex;
9592
void osc();

extensions/rcs_fr3/src/rcs_fr3/__main__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ def home(
2323
ip: Annotated[str, typer.Argument(help="IP of the robot")],
2424
shut: Annotated[bool, typer.Option("-s", help="Should the robot be shut down")] = False,
2525
unlock: Annotated[bool, typer.Option("-u", help="unlocks the robot")] = False,
26+
fh: Annotated[bool, typer.Option("-h", help="franka hand open")] = False,
2627
):
2728
"""Moves the FR3 to home position"""
2829
user, pw = load_creds_franka_desk()
29-
rcs_fr3.desk.home(ip, user, pw, shut, unlock)
30+
rcs_fr3.desk.home(ip, user, pw, shut, unlock, fh)
3031

3132

3233
@fr3_app.command()

0 commit comments

Comments
 (0)