Skip to content

Commit f8e4cbf

Browse files
committed
update with some customer's request
1 parent 5d3ed5c commit f8e4cbf

23 files changed

+724
-483
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,3 @@ i2rt.egg-info/
8989

9090
# Ignore temporary scripts or generated files
9191
scripts/temp_*/
92-

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ sh scripts/reset_all_can.sh
4444

4545
## Gripper type
4646

47-
Currently YAM supports three different grippers:
47+
Currently YAM supports three different grippers:
4848
![YAM supported Grippers](./assets/photos/yam_three_grippers.png)
4949

5050
| Gripper Name | Description |
5151
|---------------------|-------------|
52-
| `yam_compact_small` | Zero-linkage crank gripper, optimized for minimizing gripper width. |
53-
| `yam_lw_gripper` | Linear gripper with smaller DM3507 motor. Lightweight, but requires calibration or starting with the gripper in the closed configuration. |
54-
| `yam_teaching_handle` | Used for the leader arm setup. Includes a trigger to control the gripper and two customizable buttons that can be mapped to different functions. |
52+
| `crank_4310` | Zero-linkage crank gripper, optimized for minimizing gripper width. |
53+
| `linear_3507` | Linear gripper with smaller DM3507 motor. Lightweight, but requires calibration or starting with the gripper in the closed configuration. |
54+
| `yam_teaching_handle`| Used for the leader arm setup. Includes a trigger to control the gripper and two customizable buttons that can be mapped to different functions. |
5555

5656
The linear gripper requires an additional calibration step because its motor must rotate more than 2π radians to complete the full stroke.
5757

@@ -84,7 +84,7 @@ robot.command_joint_pos(target_pos)
8484
### Running the arm and visualizing it
8585
To launch the follower robot run.
8686
```bash
87-
python scripts/minimum_gello.py --mode follower
87+
python scripts/minimum_gello.py --gripper $YOUR_FOLLOWER_ARM_GRIPPER --mode follower
8888
```
8989

9090
To launch the robot mujoco visualizer run
@@ -177,6 +177,7 @@ python i2rt/flow_base/flow_base_controller.py
177177
### Getting started
178178
```python
179179
from i2rt.flow_base.flow_base_controller import Vehicle
180+
import time
180181

181182
# Get a robot instance
182183
vehicle = Vehicle()

devices/FlowBase.desktop

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[Desktop Entry]
2+
Type=Application
3+
Name=FlowBase
4+
Comment=Run my Python program
5+
Exec=lxterminal -e "bash -c '/usr/bin/python3 /home/i2rt/i2rt/i2rt/flow_base/flow_base_controller.py --channel can0 --game_pad shanwan; echo; echo \"Process finished. Press Enter to close...\"; read'"
6+
Icon=/home/i2rt/Documents/base_icon.png
7+
Terminal=true
8+
Categories=Utility;

devices/install_devices.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/bin/sh
2+
3+
USER_ID="$(id -u)"
4+
USER=$(logname)
5+
6+
if [ "$USER_ID" -ne 0 ]; then
7+
echo "Please run this as root."
8+
exit 1
9+
fi
10+
11+
INSTALL_DIR=$(dirname "$0")
12+
RULES_DIR="$INSTALL_DIR/rules/*.rules"
13+
14+
for udev_rule in $RULES_DIR; do
15+
rule=$(basename "$udev_rule")
16+
echo "Installing $rule"
17+
cp $udev_rule /etc/udev/rules.d/$rule
18+
done
19+
20+
echo "Adding $LOGNAME to group plugdev, video"
21+
adduser $USER plugdev
22+
adduser $USER video
23+
24+
echo "Reloading udev rules..."
25+
udevadm control --reload-rules
26+
udevadm trigger
27+
28+
echo "Finished, please re-insert devices."

devices/pi_setup.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
## Create image from SD card
2+
sudo dd if=/dev/sdb of=pi_system.img bs=4M status=progress
3+
sync
4+
5+
## Flash image into new SD card
6+
sudo wipefs -a /dev/sdc
7+
sudo dd if=pi_system.img of=/dev/sdc bs=4M status=progress
8+
sync
9+
10+
## Eject SD card
11+
eject /dev/sdc
12+
13+
## Reduce image size
14+
sudo ./pishrink.sh pi_system.img pi_system_shrunk.img

devices/rules/flow_base.rules

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Flow Base CAN
2+
# Auto load gs_usb driver
3+
ACTION=="add|change", SUBSYSTEM=="usb", ATTR{idVendor}=="1d50", ATTR{idProduct}=="606f", RUN+="/sbin/modprobe gs_usb"
4+
5+
# Bind device to gs_usb driver
6+
ACTION=="add|change", SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="606f", \
7+
RUN+="/bin/sh -c 'echo 1d50 606f > /sys/bus/usb/drivers/gs_usb/new_id'"
8+
9+
# Configure CAN interface when detected
10+
SUBSYSTEM=="net", ENV{INTERFACE}=="can0|FlowBaseCAN*", ATTRS{bInterfaceNumber}=="00", \
11+
RUN+="/sbin/ip link set $name type can bitrate 1000000", \
12+
RUN+="/sbin/ip link set $name up"

devices/setup_flow_desktop.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/sh
2+
3+
USER_ID="$(id -u)"
4+
USER=$(logname)
5+
6+
INSTALL_DIR=$(dirname "$0")
7+
cp $INSTALL_DIR/FlowBase.desktop ~/Desktop/
8+
9+
gio set ~/Desktop/FlowBase.desktop metadata::trusted true
10+
chmod +x ~/Desktop/FlowBase.desktop

devices/setup_led.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
cd ~/
2+
git clone https://github.com/goodtft/LCD-show.git
3+
chmod -R 755 LCD-show
4+
cd LCD-show/
5+
6+
sudo ./LCD24-show

doc/set_persist_id_socket_can.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ $ ip link show
5656
2: enp5s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
5757
link/ether d8:43:ae:b7:43:0b brd ff:ff:ff:ff:ff:ff
5858
5: tailscale0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1280 qdisc fq_codel state UNKNOWN mode DEFAULT group default qlen 500
59-
link/none
59+
link/none
6060
6: can_right: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
61-
link/can
61+
link/can
6262
7: can_left: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
63-
link/can
63+
link/can
6464
```
6565

6666
You should see that the CAN device is named `can_right`/`can_left`.

i2rt/flow_base/flow_base_controller.py

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -457,52 +457,64 @@ def joint_state_spec(self) -> Array:
457457
def num_dofs(self) -> int:
458458
return self.num_dofs
459459

460+
def running(self) -> bool:
461+
return self.caster_module_controller.motor_interface.running
462+
460463

461464
if __name__ == "__main__":
462465
import os
463-
464-
os.environ["SDL_VIDEODRIVER"] = "dummy" # Force headless mode
465466
import time
467+
import argparse
468+
from i2rt.utils.gamepad_utils import Gamepad
466469

467-
import pygame
470+
parser = argparse.ArgumentParser()
471+
parser.add_argument("--channel", type=str, default="can0")
468472

469-
vehicle = Vehicle(max_vel=(0.2, 0.2, 0.3), max_accel=(1, 1, 1))
470473
# Initialize pygame and joystick
471474
pygame.init()
472475
pygame.joystick.init()
476+
CALIBRATION_RETRY_DELAY = 1
477+
DEADZONE = 0.05
478+
args = parser.parse_args()
473479

474-
if pygame.joystick.get_count() == 0:
475-
print("No joystick/gamepad connected!")
476-
exit()
477-
else:
478-
print(f"Detected {pygame.joystick.get_count()} joystick(s).")
480+
max_vel = np.array([0.4, 0.4, 1.2])
481+
max_accel = np.array([0.5, 0.5, 1])
479482

480-
# Initialize the joystick
481-
joy = pygame.joystick.Joystick(0)
482-
joy.init()
483+
vehicle = Vehicle(max_vel=max_vel, max_accel=max_accel, channel=args.channel)
483484

484485
print(f"Joystick Name: {joy.get_name()}")
485486
print(f"Number of Axes: {joy.get_numaxes()}")
486487
print(f"Number of Buttons: {joy.get_numbuttons()}")
487488

489+
# Check all x, y, th are 0 at the beginning, if not ask user to check joystick
490+
while True:
491+
# Pump events to update joystick state
492+
pygame.event.pump()
493+
four_axis = [joy.get_axis(1), joy.get_axis(0), joy.get_axis(2), joy.get_axis(3)]
494+
if all(np.abs(axis) < DEADZONE for axis in four_axis):
495+
logging.info("Joystick is at rest, please check joystick")
496+
break
497+
else:
498+
logging.warning(f"four_axis: {four_axis}")
499+
logging.warning("Joystick's rest position is not at the center, please check joystick")
500+
time.sleep(CALIBRATION_RETRY_DELAY)
501+
488502
# Main loop to read joystick inputs
503+
gamepad = Gamepad()
489504

505+
count = 0
490506
try:
491507
while True:
492-
# for _ in range(100):
493-
pygame.event.pump()
494-
495-
# Read inputs
496-
start = joy.get_button(7) # Example button
497-
x = joy.get_axis(1) # Left stick Y-axis
498-
y = joy.get_axis(0) # Left stick X-axis
499-
th = joy.get_axis(2) # Right stick X-axis
500-
501-
user_cmd = np.array([-x, y, -th])
502-
# if < 0.05 force to zero
503-
user_cmd[np.abs(user_cmd) < 0.05] = 0
504-
print(f"user_cmd: {user_cmd}")
505-
vehicle.set_target_velocity(user_cmd, frame="local")
508+
user_cmd = gamepad.get_user_cmd()
509+
if not vehicle.running():
510+
print("Motor interface is not running, exiting...")
511+
print(f"Please check the E stop or the motor connection. ")
512+
break
513+
if count % 20 == 0:
514+
# print up 1 float point
515+
print(f"user_cmd: {user_cmd[0]:.1f}, {user_cmd[1]:.1f}, {user_cmd[2]:.1f}")
516+
count += 1
517+
vehicle.set_target_velocity(user_cmd*max_vel, frame="local")
506518

507519
time.sleep(0.02)
508520
except KeyboardInterrupt:

0 commit comments

Comments
 (0)