Skip to content

Commit 7f03912

Browse files
authored
Improve velocity scaling (#11)
* Add LeRobot integration * fix scaling * increase accuracy * version * add joint dict to forward kinematics
1 parent 94265ff commit 7f03912

File tree

5 files changed

+68
-21
lines changed

5 files changed

+68
-21
lines changed

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ The web application leverages the WebXR API, which combines your phone’s senso
2020
The package is available on [PyPI](https://pypi.org/project/teleop/). You can install it using pip:
2121

2222
```bash
23-
pip3 install teleop
23+
pip install teleop
2424
```
2525

2626
## Usage
@@ -32,7 +32,7 @@ We provide some ready-to-use robot arm interfaces, but you can also create your
3232
A simple interface that prints the teleop responses. You can use it as a reference to build your own interface.
3333

3434
```bash
35-
python3 -m teleop.basic
35+
python -m teleop.basic
3636
```
3737

3838
### xArm
@@ -41,7 +41,7 @@ Interface to teleoperate the [uFactory Lite 6](https://www.ufactory.cc/lite-6-co
4141
Minor changes are probably necessary to support other xArm robots.
4242

4343
```bash
44-
python3 -m teleop.xarm
44+
python -m teleop.xarm
4545
```
4646

4747
Note that the interface is very simple, it doesn't implement any kind of filtering.
@@ -53,7 +53,7 @@ Smart phones are typically 30fps while VR joysticks 90fps which is much more pre
5353
The ROS 2 interface is designed primarily for use with the [cartesian_controllers](https://github.com/fzi-forschungszentrum-informatik/cartesian_controllers) package, but it can also be adapted for [MoveIt Servo](https://moveit.picknik.ai/main/doc/examples/realtime_servo/realtime_servo_tutorial.html) or other packages.
5454

5555
```bash
56-
python3 -m teleop.ros2
56+
python -m teleop.ros2
5757
```
5858

5959
**Published topics:**
@@ -66,7 +66,7 @@ python3 -m teleop.ros2
6666
You can override the default topic names using standard ROS 2 arguments:
6767

6868
```bash
69-
python3 -m teleop.ros2 --ros-args -r target_frame:=/some_other_topic_name
69+
python -m teleop.ros2 --ros-args -r target_frame:=/some_other_topic_name
7070
```
7171

7272
### ROS 2 Interface with IK
@@ -76,15 +76,15 @@ No servoing support, no problem.
7676

7777
Panda arm usage example:
7878
```bash
79-
python3 -m teleop.ros2_ik \
79+
python -m teleop.ros2_ik \
8080
--joint-names panda_joint1 panda_joint2 panda_joint3 panda_joint4 panda_joint5 panda_joint6 panda_joint7 \
8181
--ee-link panda_hand \
8282
--ros-args -r /joint_trajectory:=/panda_arm_controller/joint_trajectory
8383
```
8484

8585
xArm usage example:
8686
```bash
87-
python3 -m teleop.ros2_ik \
87+
python -m teleop.ros2_ik \
8888
--joint-names joint1 joint2 joint3 joint4 joint5 joint6 \
8989
--ee-link link6 \
9090
--ros-args -r /joint_trajectory:=/joint_trajectory_controller/joint_trajectory
@@ -191,8 +191,8 @@ If you’d like to contribute, install the package in editable mode:
191191
# Install the package in editable mode
192192
git clone https://github.com/SpesRobotics/teleop.git
193193
cd teleop
194-
pip3 install -e .
194+
pip install -e .
195195

196196
# Run the tests
197-
python3 -m pytest
197+
python -m pytest
198198
```

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
setup(
1818
name="teleop",
19-
version="0.1.1",
19+
version="0.1.2",
2020
packages=["teleop", "teleop.basic", "teleop.ros2", "teleop.utils", "teleop.ros2_ik", "teleop.xarm"],
2121
long_description=long_description,
2222
long_description_content_type="text/markdown",

teleop/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,16 @@ def __update(self, message):
260260
relative_orientation = received_pose[:3, :3] @ np.linalg.inv(
261261
self.__relative_pose_init[:3, :3]
262262
)
263+
264+
if scale > 1.0:
265+
relative_position *= scale
266+
263267
self.__pose = np.eye(4)
264268
self.__pose[:3, 3] = self.__absolute_pose_init[:3, 3] + relative_position
265269
self.__pose[:3, :3] = relative_orientation @ self.__absolute_pose_init[:3, :3]
266270

267271
# Apply scale
268-
if scale != 1.0:
272+
if scale < 1.0:
269273
self.__pose = interpolate_transforms(
270274
self.__absolute_pose_init, self.__pose, scale
271275
)

teleop/teleop-ui.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,21 @@ class TeleopUI extends HTMLElement {
186186
.info-box {
187187
flex: 1;
188188
}
189+
190+
.auxilary-section {
191+
display: flex;
192+
flex-direction: row;
193+
justify-content: center;
194+
gap: 20px;
195+
}
196+
197+
.scale-section {
198+
width: 300px;
199+
}
200+
201+
.reserved-section {
202+
width: 200px;
203+
}
189204
}
190205
</style>
191206
@@ -207,16 +222,18 @@ class TeleopUI extends HTMLElement {
207222
</div>
208223
</div>
209224
225+
<div class="auxilary-section">
210226
<div class="scale-section">
211227
<input type="range" class="scale-slider" id="scaleSlider"
212-
min="0" max="3" step="1" value="3">
228+
min="0" max="5" step="1" value="3">
213229
<div class="scale-value" id="scaleValue">scale 1.0</div>
214230
</div>
215231
216232
<div class="reserved-section">
217233
<div class="reserved-button" id="reservedButtonA">A</div>
218234
<div class="reserved-button" id="reservedButtonB">B</div>
219235
</div>
236+
</div>
220237
221238
<div class="controls">
222239
<button class="control-button gripper-button" id="gripperButton">
@@ -246,7 +263,7 @@ class TeleopUI extends HTMLElement {
246263

247264
// Scale slider
248265
scaleSlider.addEventListener('input', (event) => {
249-
const sliderValues = [0.1, 0.25, 0.5, 1.0];
266+
const sliderValues = [0.1, 0.25, 0.5, 1.0, 2.0, 4.0];
250267
this.sliderValue = sliderValues[event.target.value];
251268
this.shadowRoot.getElementById('scaleValue').textContent = `scale scale ${this.sliderValue.toFixed(2)}`;
252269

teleop/utils/jacobi_robot.py

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ def __init__(
5555
# Load robot model
5656
self.model = pin.buildModelFromUrdf(urdf_path)
5757
self.data = self.model.createData()
58+
self.data_tmp = self.model.createData()
5859

5960
# Get end-effector frame ID
6061
try:
@@ -87,10 +88,6 @@ def __init__(
8788
self.kp_pos = 1.0 # Position gain (reduced from 5.0)
8889
self.kp_ori = 0.5 # Orientation gain (reduced from 3.0)
8990
self.kd = 0.05 # Damping gain
90-
91-
# IK solver parameters
92-
self.eps = 1e-4
93-
self.max_iter = 100
9491
self.damping = 1e-4 # Increased damping for stability
9592

9693
# IK regularization parameters
@@ -118,12 +115,27 @@ def __update_kinematics(self):
118115
pin.framesForwardKinematics(self.model, self.data, self.q)
119116
pin.computeJointJacobians(self.model, self.data, self.q)
120117

121-
def get_ee_pose(self) -> np.ndarray:
118+
def get_ee_pose(self, joint_positions_dict: dict = None) -> np.ndarray:
122119
"""Get current end-effector pose as 4x4 transformation matrix."""
120+
if joint_positions_dict is not None:
121+
return self._get_ee_pose_given_positions(joint_positions_dict)
123122
self.__update_kinematics()
124123
se3_pose = self.data.oMf[self.ee_frame_id]
125124
return se3_to_matrix(se3_pose)
126125

126+
def _get_ee_pose_given_positions(self, joint_positions_dict: dict) -> np.ndarray:
127+
joint_positions = np.zeros(self.model.nq)
128+
for joint_name, position in joint_positions_dict.items():
129+
joint_index = self.__get_joint_index(joint_name)
130+
if joint_index < 0 or joint_index >= self.model.nq:
131+
raise ValueError(f"Joint '{joint_name}' not found in model.")
132+
joint_positions[joint_index] = position
133+
134+
pin.forwardKinematics(self.model, self.data_tmp, joint_positions)
135+
pin.framesForwardKinematics(self.model, self.data_tmp, joint_positions)
136+
se3_pose = self.data_tmp.oMf[self.ee_frame_id]
137+
return se3_to_matrix(se3_pose)
138+
127139
def __get_ee_velocity(self) -> np.ndarray:
128140
"""Get current end-effector velocity."""
129141
self.__update_kinematics()
@@ -175,8 +187,8 @@ def servo_to_pose(
175187
self,
176188
target_pose: np.ndarray,
177189
dt: float = 0.01,
178-
linear_tol: float = 0.005,
179-
angular_tol: float = 0.01,
190+
linear_tol: float = 0.0005,
191+
angular_tol: float = 0.005,
180192
) -> bool:
181193
"""
182194
Compute joint velocities for servoing to target pose with velocity/acceleration limits.
@@ -214,7 +226,7 @@ def servo_to_pose(
214226
linear_vel_norm = np.linalg.norm(desired_linear_vel)
215227
if linear_vel_norm > 0 and linear_vel_norm < self.min_linear_vel:
216228
desired_linear_vel = desired_linear_vel * (
217-
self.min_angular_vel / linear_vel_norm
229+
self.min_linear_vel / linear_vel_norm
218230
)
219231

220232
if angular_error_norm > angular_tol:
@@ -572,6 +584,20 @@ def set_regularization_params(
572584
urdf_path, ee_link="link6", max_linear_vel=0.05, max_angular_vel=0.2
573585
) # Reduced limits
574586

587+
print(
588+
"EEF pose",
589+
robot.get_ee_pose(
590+
{
591+
"joint1": 0.0,
592+
"joint2": 0.0,
593+
"joint3": 0.0,
594+
"joint4": 0.0,
595+
"joint5": 0.0,
596+
"joint6": 0.0,
597+
}
598+
),
599+
)
600+
575601
# Start visualization
576602
robot.start_visualization()
577603

0 commit comments

Comments
 (0)