modification guide - dingdongdengdong/astra_ws GitHub Wiki
ArUco ๋ง์ปค ์ขํ ๋ฐ ๋ฌผ๋ฆฌ์ ํ๋ผ๋ฏธํฐ ์์ ๊ฐ์ด๋
1. ArUco ๋ง์ปค ์ขํ ์์
1.1 ํ์ฌ ๋ง์ปค ์ขํ ๋ถ์
ํ์ผ ์์น: non_ros_src/astra_teleop/src/astra_teleop/process.py
ํ์ฌ ๋ง์ปค ์ขํ (SCARA ๋ก๋ดํ ๊ธฐ์ค):
obj_points_map = { # right part
# top_left, top_right, bottom_right, bottom_left
0: [ (-15.00, -15.00, 48.28), (-15.00, 15.00, 48.28), ( 15.00, 15.00, 48.28), ( 15.00, -15.00, 48.28) ],
1: [ ( 23.54, -15.00, 44.75), ( 23.54, 15.00, 44.75), ( 44.75, 15.00, 23.54), ( 44.75, -15.00, 23.54) ],
2: [ (-15.00, -23.54, 44.75), ( 15.00, -23.54, 44.75), ( 15.00, -44.75, 23.54), (-15.00, -44.75, 23.54) ],
# ... ๋ ๋ง์ ๋ง์ปค๋ค
}
1.2 ์๋ก์ด ๋ก๋ดํ์ฉ ๋ง์ปค ์ขํ ์ธก์ ๋ฐฉ๋ฒ
1.2.1 ์ธก์ ๋๊ตฌ ์ค๋น
# ์ธก์ ์ฉ ์คํฌ๋ฆฝํธ ์์
import numpy as np
import cv2
from astra_teleop.process import get_solve
def measure_marker_positions():
"""
์๋ก์ด ๋ก๋ดํ์์ ArUco ๋ง์ปค๋ค์ 3D ์ขํ๋ฅผ ์ธก์ ํ๋ ํจ์
"""
# 1. ์นด๋ฉ๋ผ ์บ๋ฆฌ๋ธ๋ ์ด์
(์ด๋ฏธ ์๋ฃ๋์ด ์๋ค๊ณ ๊ฐ์ )
camera_matrix = np.array([fx, 0, cx], [0, fy, cy], [0, 0, 1](/dingdongdengdong/astra_ws/wiki/fx,-0,-cx],-[0,-fy,-cy],-[0,-0,-1))
distortion_coefficients = np.array([k1, k2, p1, p2, k3])
# 2. ๊ฐ ๋ง์ปค์ ์ค์ 3D ์์น ์ธก์
marker_positions = {}
for marker_id in range(36): # 0-35๋ฒ ๋ง์ปค
# ์ค์ ๋ก๋ดํ์์ ๋ง์ปค ์์น๋ฅผ ์ธก์
# ์: ๋ ์ด์ ์ธก์ ๊ธฐ, 3D ์ค์บ๋, ๋๋ ์๋ ์ธก์
x, y, z = measure_marker_3d_position(marker_id)
# ๋ง์ปค์ 4๊ฐ ์ฝ๋ ์ขํ ๊ณ์ฐ (30mm x 30mm ๋ง์ปค ๊ธฐ์ค)
marker_size = 30.0 # mm
half_size = marker_size / 2
corners_3d = [
(x - half_size, y - half_size, z), # top_left
(x + half_size, y - half_size, z), # top_right
(x + half_size, y + half_size, z), # bottom_right
(x - half_size, y + half_size, z), # bottom_left
]
marker_positions[marker_id] = corners_3d
return marker_positions
1.2.2 ์ค์ ์ธก์ ์์
๊ธฐ์กด SCARA ๋ก๋ดํ ๋ง์ปค ๋ฐฐ์น:
๋ง์ปค 0: (-15.00, -15.00, 48.28) mm # ์ค๋ฅธ์ชฝ ํ ์๋จ
๋ง์ปค 1: ( 23.54, -15.00, 44.75) mm # ์ค๋ฅธ์ชฝ ํ ์ธก๋ฉด
๋ง์ปค 2: (-15.00, -23.54, 44.75) mm # ์ค๋ฅธ์ชฝ ํ ํ๋ฉด
...
๋ง์ปค 18: (-15.00, -15.00, 48.28) mm # ์ผ์ชฝ ํ ์๋จ (๊ธฐ์กด๊ณผ ๋์ผ)
์๋ก์ด ์์ 6์ถ ๋ก๋ดํ ๋ง์ปค ๋ฐฐ์น (์์):
๋ง์ปค 0: (-25.00, -20.00, 60.00) mm # ๋ ํฐ ๋ก๋ดํ, ๋ ๋์ ๊ฐ๊ฒฉ
๋ง์ปค 1: ( 35.00, -20.00, 55.00) mm # ํ ๊ธธ์ด๊ฐ ๊ธธ์ด์ ธ์ ๋ ๋ฉ๋ฆฌ
๋ง์ปค 2: (-25.00, -35.00, 55.00) mm # ์์
๊ณต๊ฐ์ด ๋์ด์ง
...
๋ง์ปค 18: (-25.00, -20.00, 60.00) mm # ์ผ์ชฝ ํ๋ ๋์ผํ ํจํด
1.3 ์์ ๋ ๋ง์ปค ์ขํ ์ ์ฉ
1.3.1 process.py ์์ ์์
# non_ros_src/astra_teleop/src/astra_teleop/process.py
def get_solve(scale=1):
# ์๋ก์ด ๋ก๋ดํ์ฉ ๋ง์ปค ์ขํ
obj_points_map = { # right part (์๋ก์ด ์์ 6์ถ ๋ก๋ดํ)
# top_left, top_right, bottom_right, bottom_left
0: [ (-25.00, -20.00, 60.00), (-25.00, 20.00, 60.00), ( 25.00, 20.00, 60.00), ( 25.00, -20.00, 60.00) ],
1: [ ( 35.00, -20.00, 55.00), ( 35.00, 20.00, 55.00), ( 55.00, 20.00, 35.00), ( 55.00, -20.00, 35.00) ],
2: [ (-25.00, -35.00, 55.00), ( 25.00, -35.00, 55.00), ( 25.00, -55.00, 35.00), (-25.00, -55.00, 35.00) ],
3: [ (-35.00, 20.00, 55.00), (-35.00, -20.00, 55.00), (-55.00, -20.00, 35.00), (-55.00, 20.00, 35.00) ],
4: [ ( 25.00, 35.00, 55.00), (-25.00, 35.00, 55.00), (-25.00, 55.00, 35.00), ( 25.00, 55.00, 35.00) ],
5: [ ( 60.00, -20.00, 20.00), ( 60.00, 20.00, 20.00), ( 60.00, 20.00, -20.00), ( 60.00, -20.00, -20.00) ],
6: [ ( 35.00, -55.00, 20.00), ( 55.00, -35.00, 20.00), ( 55.00, -35.00, -20.00), ( 35.00, -55.00, -20.00) ],
7: [ (-25.00, -60.00, 20.00), ( 25.00, -60.00, 20.00), ( 25.00, -60.00, -20.00), (-25.00, -60.00, -20.00) ],
8: [ (-55.00, -35.00, 20.00), (-35.00, -55.00, 20.00), (-35.00, -55.00, -20.00), (-55.00, -35.00, -20.00) ],
9: [ (-60.00, 20.00, 20.00), (-60.00, -20.00, 20.00), (-60.00, -20.00, -20.00), (-60.00, 20.00, -20.00) ],
10: [ (-35.00, 55.00, 20.00), (-55.00, 35.00, 20.00), (-55.00, 35.00, -20.00), (-35.00, 55.00, -20.00) ],
11: [ ( 25.00, 60.00, 20.00), (-25.00, 60.00, 20.00), (-25.00, 60.00, -20.00), ( 25.00, 60.00, -20.00) ],
12: [ ( 55.00, 35.00, 20.00), ( 35.00, 55.00, 20.00), ( 35.00, 55.00, -20.00), ( 55.00, 35.00, -20.00) ],
13: [ ( 55.00, -20.00, -35.00), ( 55.00, 20.00, -35.00), ( 35.00, 20.00, -55.00), ( 35.00, -20.00, -55.00) ],
14: [ (-25.00, -55.00, -35.00), ( 25.00, -55.00, -35.00), ( 25.00, -35.00, -55.00), (-25.00, -35.00, -55.00) ],
15: [ (-55.00, 20.00, -35.00), (-55.00, -20.00, -35.00), (-35.00, -20.00, -55.00), (-35.00, 20.00, -55.00) ],
16: [ ( 25.00, 55.00, -35.00), (-25.00, 55.00, -35.00), (-25.00, 35.00, -55.00), ( 25.00, 35.00, -55.00) ],
}
# ์ผ์ชฝ ํ ๋ง์ปค๋ค (18-35๋ฒ) - ๊ธฐ์กด๊ณผ ๋์ผํ ํจํด์ผ๋ก ๋ณต์ฌ
for i in range(18 - 1): # left part
obj_points_map[i + 18] = obj_points_map[i]
# ๋๋จธ์ง solve ํจ์๋ ๋์ผ...
1.3.2 ์ค์ผ์ผ ํฉํฐ ์กฐ์
# teleoprator.py์์ ์ค์ผ์ผ ํฉํฐ ์กฐ์
class Teleopoperator:
def __init__(self):
# ... ๊ธฐ์กด ์ฝ๋ ...
# ์๋ก์ด ๋ก๋ดํ์ ๋ง๋ ์ค์ผ์ผ ํฉํฐ ์กฐ์
# ๊ธฐ์กด: scale=1.0
# ์๋ก์ด ๋ก๋ดํ์ด ๋ ํฌ๋ค๋ฉด: scale=1.2
# ์๋ก์ด ๋ก๋ดํ์ด ๋ ์๋ค๋ฉด: scale=0.8
self.solve = get_solve(scale=1.2) # ์์: 20% ๋ ํฐ ๋ก๋ดํ
2. ๋ฌผ๋ฆฌ์ ํ๋ผ๋ฏธํฐ ์กฐ์
2.1 ๊ทธ๋ฆฌํผ ๊ด๋ จ ํ๋ผ๋ฏธํฐ
2.1.1 ๊ทธ๋ฆฌํผ ์ต๋ ๊ฐ๋ฐฉ ๊ฑฐ๋ฆฌ
ํ์ผ ์์น: non_ros_src/astra_teleop_web/src/astra_teleop_web/teleoprator.py
ํ์ฌ ์ค์ :
GRIPPER_MAX = 0.055 # 55mm (๊ธฐ์กด SCARA ๋ก๋ดํ)
์๋ก์ด ๋ก๋ดํ์ฉ ์์ ์์:
# ์๋ก์ด ๋ก๋ดํ์ ๊ทธ๋ฆฌํผ ํฌ๊ธฐ์ ๋ง๊ฒ ์กฐ์
GRIPPER_MAX = 0.080 # 80mm (๋ ํฐ ๊ทธ๋ฆฌํผ)
# ๋๋
GRIPPER_MAX = 0.040 # 40mm (๋ ์์ ๊ทธ๋ฆฌํผ)
2.1.2 ๊ทธ๋ฆฌํผ ์ ์ด ๋ก์ง ํ์ธ
def pedal_cb(self, pedal_real_values):
# ... ๊ธฐ์กด ์ฝ๋ ...
if self.teleop_mode == "arm":
# ... ๊ธฐ์กด ์ฝ๋ ...
gripper_pos = {}
for side in ["left", "right"]:
# GRIPPER_MAX๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์๋์ผ๋ก ๋ฐ์๋จ
gripper_pos[side] = (1 - values[f"{side}-gripper"]) * GRIPPER_MAX
2.2 ๋ฆฌํํธ ๊ด๋ จ ํ๋ผ๋ฏธํฐ
2.2.1 ์ด๊ธฐ ๋ฆฌํํธ ๋์ด
ํ์ฌ ์ค์ :
INITIAL_LIFT_DISTANCE = 0.8 # 800mm (๊ธฐ์กด SCARA ๋ก๋ดํ)
์๋ก์ด ๋ก๋ดํ์ฉ ์์ ์์:
# ์๋ก์ด ๋ก๋ดํ์ ์์
๋์ด์ ๋ง๊ฒ ์กฐ์
INITIAL_LIFT_DISTANCE = 1.0 # 1000mm (๋ ํฐ ๋ก๋ดํ)
# ๋๋
INITIAL_LIFT_DISTANCE = 0.6 # 600mm (๋ ์์ ๋ก๋ดํ)
2.2.2 ๋ฆฌํํธ ๋ฒ์ ๋ฐ ์๋
ํ์ฌ ์ค์ (pedal_cb ํจ์ ๋ด๋ถ):
LIFT_VEL_MAX = 0.5 # ๋ฆฌํํธ ์๋
LIFT_DISTANCE_MIN = 0 # ์ต์ ๋์ด
LIFT_DISTANCE_MAX = 1.2 # ์ต๋ ๋์ด
์๋ก์ด ๋ก๋ดํ์ฉ ์์ ์์:
def pedal_cb(self, pedal_real_values):
# ... ๊ธฐ์กด ์ฝ๋ ...
if self.teleop_mode == "arm":
# ์๋ก์ด ๋ก๋ดํ์ ๋ง๋ ๋ฆฌํํธ ํ๋ผ๋ฏธํฐ
LIFT_VEL_MAX = 0.3 # ๋ ์์ ํ ์๋
LIFT_DISTANCE_MIN = 0.2 # ์ต์ ๋์ด ์ฆ๊ฐ
LIFT_DISTANCE_MAX = 1.5 # ์ต๋ ๋์ด ์ฆ๊ฐ
# ... ๋๋จธ์ง ๋ก์ง์ ๋์ผ
2.3 ํค๋ ํธํธ ๊ณ์ฐ ํจ์
2.3.1 ํ์ฌ ์ค์
def get_head_tilt(self, lift_distance):
point0_lift = 0
point0_tilt = 1.36
point1_lift = 0.8
point1_tilt = 1.06
return point0_tilt + (point1_tilt - point0_tilt) * (lift_distance - point0_lift) / (point1_lift - point0_lift)
2.3.2 ์๋ก์ด ๋ก๋ดํ์ฉ ์์
def get_head_tilt(self, lift_distance):
# ์๋ก์ด ๋ก๋ดํ์ ์์
๊ณต๊ฐ์ ๋ง๊ฒ ์กฐ์
point0_lift = 0.2 # ์ต์ ๋์ด ์ฆ๊ฐ
point0_tilt = 1.36 # ์ต์ ๋์ด์์์ ํธํธ ๊ฐ๋
point1_lift = 1.0 # ์ต๋ ๋์ด ์ฆ๊ฐ (INITIAL_LIFT_DISTANCE์ ๋ง์ถค)
point1_tilt = 1.06 # ์ต๋ ๋์ด์์์ ํธํธ ๊ฐ๋
return point0_tilt + (point1_tilt - point0_tilt) * (lift_distance - point0_lift) / (point1_lift - point0_lift)
3. ์ค์ ์์ ์์ ์์
3.1 1๋จ๊ณ: ๋ง์ปค ์ขํ ์ธก์
# 1. ์๋ก์ด ๋ก๋ดํ์์ ๋ง์ปค ๋ฐฐ์น
# 2. 3D ์ขํ ์ธก์ (๋ ์ด์ ์ธก์ ๊ธฐ, 3D ์ค์บ๋ ๋ฑ)
# 3. ์ธก์ ๊ฒฐ๊ณผ๋ฅผ Excel์ด๋ CSV๋ก ์ ๋ฆฌ
3.2 2๋จ๊ณ: ์ฝ๋ ์์
# 1. process.py์ obj_points_map ์
๋ฐ์ดํธ
# 2. teleoprator.py์ ๋ฌผ๋ฆฌ์ ํ๋ผ๋ฏธํฐ ์กฐ์
# 3. ์ค์ผ์ผ ํฉํฐ ์กฐ์
3.3 3๋จ๊ณ: ํ ์คํธ
# ๋ง์ปค ๊ฐ์ง ํ
์คํธ
from astra_teleop.process import get_solve
solve = get_solve(scale=1.2) # ์๋ก์ด ์ค์ผ์ผ
# ์ค์ ์นด๋ฉ๋ผ๋ก ๋ง์ปค ๊ฐ์ง ํ
์คํธ
3.4 4๋จ๊ณ: ํตํฉ ํ ์คํธ
# ์ ์ฒด ํ
๋ ์คํผ๋ ์ด์
์์คํ
ํ
์คํธ
# - ๋ง์ปค ๊ธฐ๋ฐ ์ ์ถ์ ์ ํ๋ ํ์ธ
# - ๊ทธ๋ฆฌํผ ์ ์ด ๋ฒ์ ํ์ธ
# - ๋ฆฌํํธ ๋์ ๋ฒ์ ํ์ธ
4. ์ฃผ์์ฌํญ
4.1 ์ขํ๊ณ ์ผ๊ด์ฑ
- ๋ชจ๋ ๋ง์ปค ์ขํ๊ฐ ๋์ผํ ๊ธฐ์ค์ ์ ์ฌ์ฉํ๋์ง ํ์ธ
- ์ผ์ชฝ/์ค๋ฅธ์ชฝ ํ์ ๋์นญ์ฑ ์ ์ง
4.2 ๋จ์ ํต์ผ
- ๋ชจ๋ ์ขํ๋ mm ๋จ์
- ๋ชจ๋ ๊ฑฐ๋ฆฌ๋ m ๋จ์
- ๋ชจ๋ ๊ฐ๋๋ ๋ผ๋์ ๋จ์
4.3 ์์ ์ฑ ํ์ธ
- ์๋ก์ด ํ๋ผ๋ฏธํฐ๊ฐ ์์ ํ ๋ฒ์ ๋ด์ ์๋์ง ํ์ธ
- ๊ทธ๋ฆฌํผ ๊ฐ๋ฐฉ ๊ฑฐ๋ฆฌ๊ฐ ๋ฌผ๋ฆฌ์ ํ๊ณ๋ฅผ ์ด๊ณผํ์ง ์๋์ง ํ์ธ
- ๋ฆฌํํธ ๋ฒ์๊ฐ ๋ก๋ดํ์ ๊ธฐ๊ตฌํ์ ํ๊ณ๋ฅผ ์ด๊ณผํ์ง ์๋์ง ํ์ธ
5. ์์: ์ ์ฒด ์์ ๋ ํ์ผ
5.1 ์์ ๋ process.py ์์
# non_ros_src/astra_teleop/src/astra_teleop/process.py
def get_solve(scale=1):
# ์๋ก์ด ์์ 6์ถ ๋ก๋ดํ์ฉ ๋ง์ปค ์ขํ
obj_points_map = {
# ์ค๋ฅธ์ชฝ ํ ๋ง์ปค๋ค (0-17๋ฒ)
0: [ (-25.00, -20.00, 60.00), (-25.00, 20.00, 60.00), ( 25.00, 20.00, 60.00), ( 25.00, -20.00, 60.00) ],
1: [ ( 35.00, -20.00, 55.00), ( 35.00, 20.00, 55.00), ( 55.00, 20.00, 35.00), ( 55.00, -20.00, 35.00) ],
# ... ๋๋จธ์ง ๋ง์ปค๋ค
# ์ผ์ชฝ ํ ๋ง์ปค๋ค (18-35๋ฒ) - ์ค๋ฅธ์ชฝ๊ณผ ๋์ผํ ํจํด
18: [ (-25.00, -20.00, 60.00), (-25.00, 20.00, 60.00), ( 25.00, 20.00, 60.00), ( 25.00, -20.00, 60.00) ],
19: [ ( 35.00, -20.00, 55.00), ( 35.00, 20.00, 55.00), ( 55.00, 20.00, 35.00), ( 55.00, -20.00, 35.00) ],
# ... ๋๋จธ์ง ๋ง์ปค๋ค
}
# ๋๋จธ์ง solve ํจ์๋ ๋์ผ...
5.2 ์์ ๋ teleoprator.py ์์
# non_ros_src/astra_teleop_web/src/astra_teleop_web/teleoprator.py
# ์๋ก์ด ๋ก๋ดํ์ ๋ง๋ ๋ฌผ๋ฆฌ์ ํ๋ผ๋ฏธํฐ
GRIPPER_MAX = 0.080 # 80mm (๋ ํฐ ๊ทธ๋ฆฌํผ)
INITIAL_LIFT_DISTANCE = 1.0 # 1000mm (๋ ๋์ ์์
๊ณต๊ฐ)
FAR_SEEING_HEAD_TILT = 0.26 # ๋์ผ
class Teleopoperator:
def __init__(self):
# ... ๊ธฐ์กด ์ฝ๋ ...
# ์๋ก์ด ๋ก๋ดํ์ ๋ง๋ ์ค์ผ์ผ ํฉํฐ
self.solve = get_solve(scale=1.2) # 20% ๋ ํฐ ๋ก๋ดํ
# ... ๋๋จธ์ง ์ฝ๋๋ ๋์ผ
Robot-Arm-Modification
๊ฐ์ (Overview)
๋ก๋ดํ์ ํฌ๊ธฐ์ ํํ๊ฐ ๋ณ๊ฒฝ๋ ๋, ํ
๋ ์คํผ๋ ์ด์
์์คํ
์์ ์์ ํด์ผ ํ๋ ๋ถ๋ถ๋ค์ ๋ถ์ํ ๋ฌธ์์
๋๋ค. ์ด ๋ฌธ์๋ astra_teleop_web ํจํค์ง์ ๊ตฌ์กฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์์ฑ๋์์ต๋๋ค.
์๊ฒฉ์กฐ์ข ์์คํ : 6์ถ SCARA โ ์์ 6์ถ ๋ก๋ดํ ์ ํ
ํต์ฌ ๊ฒฐ๋ก : ์์ ํ์ ์์
์๊ฒฉ์กฐ์ข ์์คํ ์ ๊ด์ ์์ 6์ถ SCARA์์ ์์ 6์ถ ๋ก๋ดํ๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์ ๊ธฐ์กด ํ ๋ ์คํผ๋ ์ด์ ์ฝ๋๋ฅผ ์์ ํ ํ์๊ฐ ์์ต๋๋ค.
์ด์ ๋ถ์
1. ์ถ์ํ๋ ์ธํฐํ์ด์ค ์ฌ์ฉ
ํ์ฌ teleoprator.py๋ ๋ก๋ดํ์ ๊ตฌ์ฒด์ ์ธ ๊ธฐ๊ตฌํ์ ์์กดํ์ง ์์ต๋๋ค:
# teleoprator.py์ ํต์ฌ ์ฝ๋ฐฑ๋ค
self.on_pub_goal = None # ๋ชฉํ ์์น ์ ์ก (์ถ์ํ๋จ)
self.on_pub_gripper = None # ๊ทธ๋ฆฌํผ ์ ์ด (์ถ์ํ๋จ)
self.on_get_current_eef_pose = None # ํ์ฌ ์์น ์กฐํ (์ถ์ํ๋จ)
self.on_get_initial_eef_pose = None # ์ด๊ธฐ ์์น ์กฐํ (์ถ์ํ๋จ)
2. ์ขํ๊ณ ๋ณํ์ ์ถ์ํ
# hand_cb์์ ๋ก๋ด ๋ช
๋ น ์์ฑ
Tsgoal = self.Tscam[side] @ self.Tcamgoal_last[side]
self.on_pub_goal(side, Tsgoal) # 4x4 ๋ณํ ํ๋ ฌ๋ก ์ถ์ํ๋จ
3. ๊ธฐ๊ตฌํ ๋ ๋ฆฝ์ ์ค๊ณ
- ์ ๋ ฅ: ArUco ๋ง์ปค โ 3D ์์น (์นด๋ฉ๋ผ ์ขํ๊ณ)
- ์ฒ๋ฆฌ: ์ขํ๊ณ ๋ณํ (์นด๋ฉ๋ผ โ ๋ก๋ด)
- ์ถ๋ ฅ: 4x4 ๋ณํ ํ๋ ฌ (์ถ์ํ๋ ๋ก๋ด ๋ช ๋ น)
์ค์ ์์ ์ด ํ์ํ ๋ถ๋ถ
1. ํ์ ๋ ๋ฒจ ์ ์ด๊ธฐ๋ง ์์
# astra_controller ํจํค์ง์์๋ง ์์ ํ์
# - arm_controller.py: 6์ถ ์์ ๋์ ๋ง๋ ์ ์ด ๋ก์ง
# - URDF ํ์ผ: ์๋ก์ด ๊ธฐ๊ตฌํ ์ ์
# - MoveIt ์ค์ : ์๋ก์ด ๊ธฐ๊ตฌํ ๋ฐ์
2. ์ฝ๋ฐฑ ํจ์๋ค์ ๊ตฌํ์ฒด๋ง ๋ณ๊ฒฝ
# teleoprator.py๋ ์์ ๋ถํ์
# ๋์ ์ด ์ฝ๋ฐฑ๋ค์ ๊ตฌํํ๋ ํ์ ์์คํ
๋ง ์์ :
def on_pub_goal_implementation(side, Tsgoal):
# 6์ถ SCARA์ฉ ๊ตฌํ โ 6์ถ ์์ ๋์ฉ ๊ตฌํ์ผ๋ก ๋ณ๊ฒฝ
# ํ์ง๋ง teleoprator.py๋ ์ด ๊ตฌํ์ฒด๋ฅผ ๋ชฐ๋ผ๋ ๋จ
def on_get_current_eef_pose_implementation(side):
# 6์ถ SCARA์ฉ ๊ตฌํ โ 6์ถ ์์ ๋์ฉ ๊ตฌํ์ผ๋ก ๋ณ๊ฒฝ
# ํ์ง๋ง teleoprator.py๋ ์ด ๊ตฌํ์ฒด๋ฅผ ๋ชฐ๋ผ๋ ๋จ
ํ์ธํด์ผ ํ ๋ถ๋ถ
1. ArUco ๋ง์ปค ๋ฐฐ์น
# astra_teleop/process.py์ obj_points_map
# ๋ก๋ดํ ํฌ๊ธฐ๊ฐ ๋ณ๊ฒฝ๋๋ฉด ๋ง์ปค ์ขํ๋ง ์์
obj_points_map = {
0: [(-15.00, -15.00, 48.28), ...], # ๊ธฐ์กด ์ขํ
# โ ์๋ก์ด ๋ก๋ดํ ํฌ๊ธฐ์ ๋ง๋ ์ขํ๋ก ๋ณ๊ฒฝ
}
2. ๋ฌผ๋ฆฌ์ ํ๋ผ๋ฏธํฐ (์ ํ์ )
# teleoprator.py์ ์์๋ค (ํ์์๋ง ์กฐ์ )
GRIPPER_MAX = 0.055 # ๊ทธ๋ฆฌํผ ํฌ๊ธฐ๊ฐ ๋ค๋ฅด๋ฉด ์กฐ์
INITIAL_LIFT_DISTANCE = 0.8 # ์์
๋์ด๊ฐ ๋ค๋ฅด๋ฉด ์กฐ์
LIFT_DISTANCE_MIN = 0 # ๋ฆฌํํธ ๋ฒ์๊ฐ ๋ค๋ฅด๋ฉด ์กฐ์
LIFT_DISTANCE_MAX = 1.2 # ๋ฆฌํํธ ๋ฒ์๊ฐ ๋ค๋ฅด๋ฉด ์กฐ์
๊ฒฐ๋ก
์๊ฒฉ์กฐ์ข ์์คํ ์์ฒด๋ ์์ ํ ํ์๊ฐ ์์ต๋๋ค.
- โ
์ ์ง๋๋ ๋ถ๋ถ:
teleoprator.py,webserver.py, ArUco ์ฒ๋ฆฌ ๋ก์ง - ๐ง ์์ ํ์ํ ๋ถ๋ถ:
astra_controllerํจํค์ง์ ํ์ ์ ์ด๊ธฐ๋ค - ๐ ์กฐ์ ๊ฐ๋ฅํ ๋ถ๋ถ: ArUco ๋ง์ปค ์ขํ, ๋ฌผ๋ฆฌ์ ํ๋ผ๋ฏธํฐ (์ ํ์ )
๊ถ์ฅ ์์ ์์
- ์๋ก์ด ๋ก๋ดํ์ ArUco ๋ง์ปค ์ขํ ์ธก์ ๋ฐ ์ ๋ฐ์ดํธ
astra_controllerํจํค์ง์ ํ์ ์ ์ด๊ธฐ ์์ - URDF ๋ฐ MoveIt ์ค์ ์ ๋ฐ์ดํธ
- ํ์์ ๋ฌผ๋ฆฌ์ ํ๋ผ๋ฏธํฐ ์กฐ์ (๊ทธ๋ฆฌํผ ํฌ๊ธฐ, ์์ ๋์ด ๋ฑ)
์ด๋ ๊ฒ ํ๋ฉด ๊ธฐ์กด ์๊ฒฉ์กฐ์ข ์์คํ ์ ๊ทธ๋๋ก ์ฌ์ฉํ๋ฉด์ ์๋ก์ด 6์ถ ์์ ๋ ๋ก๋ดํ์ ์ ์ดํ ์ ์์ต๋๋ค.
SCARA โ ํ๋๋ก๋ด ์ ํ ํน๋ณ ๊ณ ๋ ค์ฌํญ
1. ๊ธฐ๊ตฌํ์ ์ฐจ์ด์
1.1 SCARA vs ํ๋๋ก๋ด์ ์ฃผ์ ์ฐจ์ด
- SCARA: ํ๋ฉด ์ด๋, ๊ณ ์ ๋ Z์ถ, ๋น ๋ฅธ ์๋, ์ ๋ฐํ ๋ฐ๋ณต ์์
- ํ๋๋ก๋ด: 6์ถ ์์ ๋, ์ ์ฐํ ์์ ๊ณต๊ฐ, ์์ ๊ธฐ๋ฅ, ์ฌ๋๊ณผ์ ํ์
1.2 ๊ธฐ๊ตฌํ์ ์์ ํ์์ฌํญ
ํ์ฌ SCARA ๊ธฐ๋ฐ ์ค์ :
# teleoprator.py์ reset_arm() ํจ์
goal_pose = {
"left": self.on_get_initial_eef_pose("left", [self.lift_distance, joint_bent, -joint_bent, 0, 0, 0]),
"right": self.on_get_initial_eef_pose("right", [self.lift_distance, -joint_bent, joint_bent, 0, 0, 0]),
}
ํ๋๋ก๋ด์ฉ ์์ :
# ํ๋๋ก๋ด์ 6์ถ ์์ ๋์ ๋ง๋ ์ด๊ธฐ ์์ธ ์ค์
def get_collaborative_robot_initial_pose(self, side):
if side == "left":
return [self.lift_distance, -math.pi/6, -math.pi/3, 0, math.pi/2, 0] # ํ๋๋ก๋ด ํน์ฑ์ ๋ง๋ ์์ธ
else: # right
return [self.lift_distance, math.pi/6, math.pi/3, 0, -math.pi/2, 0]
2. ์์ ์ฑ ๊ด๋ จ ์์
2.1 ์๋ ์ ํ ๋ฐ ์์ ํ๋ผ๋ฏธํฐ
ํ์ฌ SCARA ์ค์ :
LIFT_VEL_MAX = 0.5 # SCARA์ฉ ๋น ๋ฅธ ์๋
LINEAR_VEL_MAX = 1 # ๋ฒ ์ด์ค ์ด๋ ์๋
ANGULAR_VEL_MAX = 1 # ํ์ ์๋
ํ๋๋ก๋ด์ฉ ์์ :
# ํ๋๋ก๋ด์ ์์ ์๋ ์ ํ
COLLABORATIVE_LIFT_VEL_MAX = 0.2 # ๋ ๋ฎ์ ์๋๋ก ์์ ์ฑ ํ๋ณด
COLLABORATIVE_LINEAR_VEL_MAX = 0.5
COLLABORATIVE_ANGULAR_VEL_MAX = 0.5
# ์ถ๊ฐ ์์ ํ๋ผ๋ฏธํฐ
MAX_FORCE_THRESHOLD = 50.0 # N, ํ ์ ํ
MAX_TORQUE_THRESHOLD = 10.0 # Nm, ํ ํฌ ์ ํ
EMERGENCY_STOP_DISTANCE = 0.3 # m, ๊ธด๊ธ ์ ์ง ๊ฑฐ๋ฆฌ
2.2 ์ถฉ๋ ๊ฐ์ง ๋ฐ ํํผ
class CollaborativeRobotSafety:
def __init__(self):
self.force_sensor_active = True
self.proximity_sensor_active = True
self.emergency_stop_active = False
def check_safety_limits(self, current_pose, target_pose):
# ํ/ํ ํฌ ์ ํ ํ์ธ
if self.detect_excessive_force():
return False, "Force limit exceeded"
# ๊ทผ์ ๊ฐ์ง ํ์ธ
if self.detect_obstacle_proximity():
return False, "Obstacle detected"
return True, "Safe to move"
def emergency_stop(self):
self.emergency_stop_active = True
# ๋ชจ๋ ๋ชจํฐ ์ ์ง
self.stop_all_motors()
3. ์ ์ด ๋ชจ๋ ์์
3.1 ํ๋๋ก๋ด ์ ์ฉ ์ ์ด ๋ชจ๋
# teleoprator.py์ ์ถ๊ฐํ ํ๋๋ก๋ด ๋ชจ๋
COLLABORATIVE_MODES = {
"position_control": "์ ๋ฐ ์์น ์ ์ด",
"force_control": "ํ ์ ์ด ๋ชจ๋",
"impedance_control": "์ํผ๋์ค ์ ์ด",
"gravity_compensation": "์ค๋ ฅ ๋ณด์ ๋ชจ๋",
"manual_guidance": "์๋ ๊ฐ์ด๋์ค"
}
def update_collaborative_mode(self, mode):
if mode == "force_control":
self.enable_force_control()
self.set_force_limits(MAX_FORCE_THRESHOLD)
elif mode == "impedance_control":
self.enable_impedance_control()
self.set_impedance_parameters()
# ... ๊ธฐํ ๋ชจ๋๋ค
3.2 ํ๋ฌ ์ ์ด ์์
ํ๋๋ก๋ด์ฉ ํ๋ฌ ๋งคํ:
def pedal_cb_collaborative(self, pedal_real_values):
if self.teleop_mode == "arm":
# ํ๋๋ก๋ด ํนํ ์ ์ด
values = self.process_pedal_input(pedal_real_values)
# ํ ์ ์ด ๋ชจ๋
if self.collaborative_mode == "force_control":
force_x = values["force_x"] * MAX_FORCE_THRESHOLD
force_y = values["force_y"] * MAX_FORCE_THRESHOLD
force_z = values["force_z"] * MAX_FORCE_THRESHOLD
self.on_pub_force_command(force_x, force_y, force_z)
# ์ํผ๋์ค ์ ์ด ๋ชจ๋
elif self.collaborative_mode == "impedance_control":
stiffness = values["stiffness"] * MAX_STIFFNESS
damping = values["damping"] * MAX_DAMPING
self.on_pub_impedance_command(stiffness, damping)
4. ์ผ์ ๋ฐ ํผ๋๋ฐฑ ์์คํ
4.1 ํ๋๋ก๋ด ์ผ์ ํตํฉ
class CollaborativeRobotSensors:
def __init__(self):
self.force_sensor = None
self.torque_sensor = None
self.proximity_sensor = None
self.safety_light_curtain = None
def get_force_feedback(self):
# 6์ถ ํ/ํ ํฌ ์ผ์ ๋ฐ์ดํฐ
return {
"fx": self.force_sensor.get_force_x(),
"fy": self.force_sensor.get_force_y(),
"fz": self.force_sensor.get_force_z(),
"tx": self.torque_sensor.get_torque_x(),
"ty": self.torque_sensor.get_torque_y(),
"tz": self.torque_sensor.get_torque_z()
}
def get_proximity_data(self):
# ๊ทผ์ ์ผ์ ๋ฐ์ดํฐ
return {
"distance": self.proximity_sensor.get_distance(),
"direction": self.proximity_sensor.get_direction(),
"safety_zone": self.safety_light_curtain.get_status()
}
4.2 ์์ ํผ๋๋ฐฑ ์์คํ
def safety_feedback_cb(self, sensor_data):
# ์ค์๊ฐ ์์ ์ํ ๋ชจ๋ํฐ๋ง
force_data = sensor_data.get("force")
proximity_data = sensor_data.get("proximity")
# ์ํ ์ํฉ ๊ฐ์ง
if self.detect_dangerous_condition(force_data, proximity_data):
self.trigger_emergency_stop()
self.webserver.control_datachannel_log("EMERGENCY STOP: Safety limit exceeded")
# ์ฌ์ฉ์์๊ฒ ์์ ์ํ ์ ๋ฌ
safety_status = self.calculate_safety_status(force_data, proximity_data)
self.webserver.control_datachannel_log(f"Safety Status: {safety_status}")
5. ArUco ๋ง์ปค ์์คํ ์์
5.1 ํ๋๋ก๋ด์ฉ ๋ง์ปค ๋ฐฐ์น
ํ๋๋ก๋ด์ ์ ์ฐํ ์์ ๊ณต๊ฐ์ ๊ณ ๋ คํ ๋ง์ปค ๋ฐฐ์น:
# astra_teleop/process.py ์์
def get_collaborative_robot_marker_positions(self):
# ํ๋๋ก๋ด์ ๋ ๋์ ์์
๊ณต๊ฐ์ ๋ง๋ ๋ง์ปค ๋ฐฐ์น
obj_points_map_collaborative = {
# ๋ ๋์ ๋ฒ์์ ๋ง์ปค ๋ฐฐ์น
0: [(-20.00, -20.00, 60.00), (-20.00, 20.00, 60.00), (20.00, 20.00, 60.00), (20.00, -20.00, 60.00)],
# ... ํ๋๋ก๋ด ์์
๊ณต๊ฐ์ ๋ง๋ ๋ง์ปค๋ค
}
return obj_points_map_collaborative
5.2 ๋์ ๋ง์ปค ์ถ์
def adaptive_marker_tracking(self, camera_matrix, distortion_coefficients, corners, ids):
# ํ๋๋ก๋ด์ ๋์ ์์ง์์ ๋์ํ๋ ์ ์ํ ๋ง์ปค ์ถ์
if self.collaborative_mode == "manual_guidance":
# ์๋ ๊ฐ์ด๋์ค ๋ชจ๋์์๋ ๋ง์ปค ์ถ์ ์ ๋ณด์กฐ์ ์ผ๋ก ์ฌ์ฉ
return self.get_manual_guidance_pose()
else:
# ์ผ๋ฐ์ ์ธ ๋ง์ปค ๊ธฐ๋ฐ ์ถ์
return self.solve(camera_matrix, distortion_coefficients, corners, ids)
6. ์น ์ธํฐํ์ด์ค ์์
6.1 ํ๋๋ก๋ด ์ ์ฉ UI ์์
// static/index.html์ ์ถ๊ฐํ ํ๋๋ก๋ด UI
const collaborativeRobotUI = {
safetyStatus: document.getElementById('safety-status'),
forceDisplay: document.getElementById('force-display'),
modeSelector: document.getElementById('collaborative-mode'),
emergencyStop: document.getElementById('emergency-stop-btn'),
updateSafetyStatus(status) {
this.safetyStatus.textContent = status;
this.safetyStatus.className = `safety-${status.toLowerCase()}`;
},
updateForceDisplay(forceData) {
this.forceDisplay.innerHTML = `
Fx: ${forceData.fx.toFixed(2)}N
Fy: ${forceData.fy.toFixed(2)}N
Fz: ${forceData.fz.toFixed(2)}N
`;
},
enableEmergencyStop() {
this.emergencyStop.addEventListener('click', () => {
this.sendControlCommand('emergency_stop');
});
}
};
6.2 ์ค์๊ฐ ์์ ๋ชจ๋ํฐ๋ง
// ์ค์๊ฐ ์์ ์ํ ์
๋ฐ์ดํธ
function updateSafetyMonitoring() {
setInterval(() => {
fetch('/api/safety-status')
.then(response => response.json())
.then(data => {
collaborativeRobotUI.updateSafetyStatus(data.status);
collaborativeRobotUI.updateForceDisplay(data.force);
if (data.status === 'DANGER') {
collaborativeRobotUI.emergencyStop.style.backgroundColor = 'red';
}
});
}, 100); // 10Hz ์
๋ฐ์ดํธ
}
7. ํ๋์จ์ด ์ธํฐํ์ด์ค ์์
7.1 ํ๋๋ก๋ด ์ ์ด๊ธฐ ํต์
# astra_controller/astra_controller/collaborative_robot_controller.py
class CollaborativeRobotController:
def __init__(self, robot_ip, robot_port):
self.robot_ip = robot_ip
self.robot_port = robot_port
self.safety_monitor = CollaborativeRobotSafety()
self.sensors = CollaborativeRobotSensors()
def send_position_command(self, joint_positions):
# ํ๋๋ก๋ด ์ ์ด๊ธฐ๋ก ์์น ๋ช
๋ น ์ ์ก
command = {
"type": "position_control",
"joints": joint_positions,
"velocity": self.calculate_safe_velocity(),
"acceleration": self.calculate_safe_acceleration()
}
return self.send_command(command)
def send_force_command(self, force_vector):
# ํ ์ ์ด ๋ช
๋ น ์ ์ก
command = {
"type": "force_control",
"force": force_vector,
"max_force": MAX_FORCE_THRESHOLD
}
return self.send_command(command)
def emergency_stop(self):
# ๊ธด๊ธ ์ ์ง ๋ช
๋ น
command = {
"type": "emergency_stop",
"timestamp": time.time()
}
return self.send_command(command)
8. ์์ ์ฐ์ ์์ (ํ๋๋ก๋ด ์ ํ)
8.1 ๋์ ์ฐ์ ์์ (์์ ๊ด๋ จ)
- ์์ ์์คํ ํตํฉ: ํ/ํ ํฌ ์ผ์, ๊ทผ์ ์ผ์, ๊ธด๊ธ ์ ์ง
- ์๋ ์ ํ ์กฐ์ : ํ๋๋ก๋ด ์์ ์๋๋ก ๋ณ๊ฒฝ
- ๊ธฐ๊ตฌํ ์์ : 6์ถ ์์ ๋์ ๋ง๋ ์ ์ด ๋ก์ง
- URDF ์ ๋ฐ์ดํธ: ํ๋๋ก๋ด ๋ชจ๋ธ๋ก ๋ณ๊ฒฝ
8.2 ์ค๊ฐ ์ฐ์ ์์ (๊ธฐ๋ฅ ๊ด๋ จ)
- ์ ์ด ๋ชจ๋ ์ถ๊ฐ: ํ ์ ์ด, ์ํผ๋์ค ์ ์ด, ์๋ ๊ฐ์ด๋์ค
- ์ผ์ ํผ๋๋ฐฑ: ์ค์๊ฐ ํ/ํ ํฌ ๋ชจ๋ํฐ๋ง
- UI ๊ฐ์ : ์์ ์ํ ํ์, ๊ธด๊ธ ์ ์ง ๋ฒํผ
- ArUco ๋ง์ปค: ํ๋๋ก๋ด ์์ ๊ณต๊ฐ์ ๋ง๋ ๋ฐฐ์น
8.3 ๋ฎ์ ์ฐ์ ์์ (์ต์ ํ)
- ์ฑ๋ฅ ์ต์ ํ: ์ค์๊ฐ ์ ์ด ๋ฃจํ ์ต์ ํ
- ์ฌ์ฉ์ ๊ฒฝํ: ์ง๊ด์ ์ธ ํ๋๋ก๋ด ์ธํฐํ์ด์ค
- ๋ก๊น ์์คํ : ์์ ์ด๋ฒคํธ ๋ก๊น
์์คํ ๊ตฌ์กฐ ๋ถ์
1. ํต์ฌ ์ปดํฌ๋ํธ
1.1 Teleopoperator (teleoprator.py)
- ์ญํ : ์น ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ๋ฐ์ ์ ๋ ฅ์ ๋ก๋ด ๋ช ๋ น์ผ๋ก ๋ณํ
- ์ฃผ์ ๊ธฐ๋ฅ:
- ArUco ๋ง์ปค ๊ธฐ๋ฐ ์ ์์น ์ถ์
- ํ๋ฌ ์ ๋ ฅ ์ฒ๋ฆฌ (๊ทธ๋ฆฌํผ, ๋ฆฌํํธ, ๋ฒ ์ด์ค ์ ์ด)
- ์ ์ด ๋ชจ๋ ๊ด๋ฆฌ (arm, base, none)
1.2 WebServer (webserver.py)
- ์ญํ : ์น ํด๋ผ์ด์ธํธ์์ WebRTC ํต์ ๊ด๋ฆฌ
- ์ฃผ์ ๊ธฐ๋ฅ:
- ๋น๋์ค ์คํธ๋ฆผ ์ ๊ณต (head, wrist_left, wrist_right)
- ๋ฐ์ดํฐ ์ฑ๋ ๊ด๋ฆฌ (hand, pedal, control)
1.3 ArUco ๋ง์ปค ์ฒ๋ฆฌ (astra_teleop/process.py)
- ์ญํ : ์นด๋ฉ๋ผ์์ ArUco ๋ง์ปค๋ฅผ ๊ฐ์งํ๊ณ 3D ์์น ๊ณ์ฐ
- ์ฃผ์ ๊ธฐ๋ฅ:
get_solve()ํจ์๋ก ๋ง์ปค ์ขํ๋ฅผ ๋ก๋ด ์ขํ๊ณ๋ก ๋ณํ
์์ ์ด ํ์ํ ๋ถ๋ถ๋ค
1. ArUco ๋ง์ปค ์ขํ๊ณ (๊ฐ์ฅ ์ค์)
1.1 astra_teleop/process.py์ obj_points_map
ํ์ฌ ์ํ:
obj_points_map = { # right part
# top_left, top_right, bottom_right, bottom_left
0: [ (-15.00, -15.00, 48.28), (-15.00, 15.00, 48.28), ( 15.00, 15.00, 48.28), ( 15.00, -15.00, 48.28) ],
# ... ๋ ๋ง์ ๋ง์ปค ์ขํ๋ค
}
์์ ํ์ ์ฌํญ:
- ๋ง์ปค ์์น: ๋ก๋ดํ ํฌ๊ธฐ๊ฐ ๋ณ๊ฒฝ๋๋ฉด ArUco ๋ง์ปค๋ค์ ์ค์ 3D ์ขํ๊ฐ ๋ณ๊ฒฝ๋จ
- ์ค์ผ์ผ ํฉํฐ:
get_solve(scale=1.0)์ ์ค์ผ์ผ ๊ฐ ์กฐ์ ํ์ - ์ขํ๊ณ ๊ธฐ์ค์ : ๋ก๋ดํ์ ์๋ก์ด ๊ธฐํํ์ ์ค์ฌ์ ์ ๋ง์ถฐ ์ขํ๊ณ ์ฌ์ ์
์์ ๋ฐฉ๋ฒ:
- ์๋ก์ด ๋ก๋ดํ์์ ArUco ๋ง์ปค๋ค์ ์ค์ 3D ์์น ์ธก์
obj_points_map์ ๋ชจ๋ ์ขํ๊ฐ ์ ๋ฐ์ดํธ- ํ์์
scaleํ๋ผ๋ฏธํฐ ์กฐ์
2. ๋ก๋ดํ ๋ฌผ๋ฆฌ์ ํ๋ผ๋ฏธํฐ
2.1 teleoprator.py์ ์์๊ฐ๋ค
ํ์ฌ ์ํ:
GRIPPER_MAX = 0.055 # ๊ทธ๋ฆฌํผ ์ต๋ ๊ฐ๋ฐฉ ๊ฑฐ๋ฆฌ (๋ฏธํฐ)
INITIAL_LIFT_DISTANCE = 0.8 # ์ด๊ธฐ ๋ฆฌํํธ ๋์ด (๋ฏธํฐ)
FAR_SEEING_HEAD_TILT = 0.26 # ์๊ฑฐ๋ฆฌ ์์ผ ํค๋ ํธํธ (๋ผ๋์)
์์ ํ์ ์ฌํญ:
- GRIPPER_MAX: ์๋ก์ด ๊ทธ๋ฆฌํผ์ ์ต๋ ๊ฐ๋ฐฉ ๊ฑฐ๋ฆฌ
- INITIAL_LIFT_DISTANCE: ์๋ก์ด ๋ก๋ดํ์ ์ ์ ํ ์์ ๋์ด
- LIFT_DISTANCE_MIN/MAX: ๋ฆฌํํธ ๋ฒ์ ์กฐ์
- LIFT_VEL_MAX: ๋ฆฌํํธ ์๋ ์กฐ์
2.2 ํค๋ ํธํธ ๊ณ์ฐ ํจ์
ํ์ฌ ์ํ:
def get_head_tilt(self, lift_distance):
point0_lift = 0
point0_tilt = 1.36
point1_lift = 0.8
point1_tilt = 1.06
return point0_tilt + (point1_tilt - point0_tilt) * (lift_distance - point0_lift) / (point1_lift - point0_lift)
์์ ํ์ ์ฌํญ:
- ์๋ก์ด ๋ก๋ดํ์ ์์ ๊ณต๊ฐ์ ๋ง์ถฐ ํค๋ ํธํธ ๊ฐ๋ ์กฐ์
- ์นด๋ฉ๋ผ ์์ผ๊ฐ๊ณผ ๋ก๋ดํ ์์ ์์ญ์ ์ต์ ํ
3. ๋ฆฌ์ ํฌ์ฆ ์ค์
3.1 reset_arm() ํจ์์ ์ด๊ธฐ ์์ธ
ํ์ฌ ์ํ:
goal_pose = {
"left": self.on_get_initial_eef_pose("left", [self.lift_distance, joint_bent, -joint_bent, 0, 0, 0]),
"right": self.on_get_initial_eef_pose("right", [self.lift_distance, -joint_bent, joint_bent, 0, 0, 0]),
}
์์ ํ์ ์ฌํญ:
- ์๋ก์ด ๋ก๋ดํ์ ๊ธฐํํ์ ๋ง๋ ์ด๊ธฐ ์์ธ ์ค์
joint_bent๊ฐ ์กฐ์ (ํ์ฌ ฯ/4)- ์ข์ฐ ํ์ ๋์นญ์ฑ ์ ์ง
4. ์น ์ธํฐํ์ด์ค ๊ด๋ จ
4.1 ๋น๋์ค ์คํธ๋ฆผ ์ค์
ํ์ฌ ์ํ (webserver.py):
image_height = 360
image_width = 640
frames_per_second = 30
์์ ํ์ ์ฌํญ:
- ์นด๋ฉ๋ผ ํด์๋๊ฐ ๋ก๋ดํ ํฌ๊ธฐ์ ์ ํฉํ์ง ํ์ธ
- ํ์์ ํด์๋ ์กฐ์
4.2 ArUco ๋ง์ปค ๊ฐ์ง ์ค์
ํ์ฌ ์ํ:
min_aruco_thres=4 # ์ต์ ๊ฐ์ง ๋ง์ปค ์
์์ ํ์ ์ฌํญ:
- ์๋ก์ด ๋ง์ปค ๋ฐฐ์น์ ๋ฐ๋ฅธ ์ต์ ๋ง์ปค ์ ์กฐ์
- ๋ง์ปค ํฌ๊ธฐ์ ์นด๋ฉ๋ผ ํด์๋์ ๊ด๊ณ ๊ฒํ
5. ํ๋์จ์ด ์ ์ด ๊ด๋ จ
5.1 astra_controller ํจํค์ง
์์ ํ์ ์ฌํญ:
- ๊ทธ๋ฆฌํผ ๊ธฐ์ด ๋น์จ:
GRIPPER_GEAR_R = 0.027 / 2 - ๋ฆฌํํธ ๋ ์ผ ํ๋ผ๋ฏธํฐ:
RAIL_MM_PER_REV = 75,RAIL_MAX_LENGTH_MM = 1190 - ์คํ
ํผ ๋ชจํฐ ์ค์ :
STEPPER_PULSE_PER_REV = 800
5.2 URDF ๋ฐ MoveIt ์ค์
์์ ํ์ ์ฌํญ:
astra_descriptionํจํค์ง์ URDF ํ์ผ๋คastra_moveit_configํจํค์ง์ MoveIt ์ค์ - ๋ก๋ดํ์ ์๋ก์ด ๊ธฐํํ์ ํ๋ผ๋ฏธํฐ ๋ฐ์
์์ ์ฐ์ ์์
1. ๋์ ์ฐ์ ์์ (ํ์)
- ArUco ๋ง์ปค ์ขํ๊ณ ์ฌ์ ์ (
astra_teleop/process.py) - ๊ทธ๋ฆฌํผ ์ต๋ ๊ฐ๋ฐฉ ๊ฑฐ๋ฆฌ (
GRIPPER_MAX) - ์ด๊ธฐ ๋ฆฌํํธ ๋์ด (
INITIAL_LIFT_DISTANCE) - URDF ํ์ผ ์ ๋ฐ์ดํธ
2. ์ค๊ฐ ์ฐ์ ์์ (๊ถ์ฅ)
- ํค๋ ํธํธ ๊ณ์ฐ ํจ์ ์กฐ์
- ๋ฆฌํํธ ๋ฒ์ ๋ฐ ์๋ ์กฐ์
- ์ด๊ธฐ ์์ธ ์ค์ ์ต์ ํ
- ํ๋์จ์ด ์ ์ด ํ๋ผ๋ฏธํฐ ์ ๋ฐ์ดํธ
3. ๋ฎ์ ์ฐ์ ์์ (์ ํ)
- ๋น๋์ค ํด์๋ ์กฐ์
- ArUco ๊ฐ์ง ํ๋ผ๋ฏธํฐ ์ต์ ํ
- UI ๊ฐ์ (ํ์์)
ํ ์คํธ ๋ฐฉ๋ฒ
1. ArUco ๋ง์ปค ์์คํ ํ ์คํธ
# astra_teleop/process.py์ get_solve ํจ์ ํ
์คํธ
from astra_teleop.process import get_solve
solve = get_solve(scale=1.0)
# ์ค์ ์นด๋ฉ๋ผ๋ก ๋ง์ปค ๊ฐ์ง ํ
์คํธ
2. ํ ๋ ์คํผ๋ ์ด์ ์์คํ ํ ์คํธ
# teleoprator.py์ ํต์ฌ ๊ธฐ๋ฅ๋ค ํ
์คํธ
# - hand_cb: ๋ง์ปค ๊ธฐ๋ฐ ์ ์ถ์
# - pedal_cb: ๊ทธ๋ฆฌํผ ๋ฐ ๋ฆฌํํธ ์ ์ด
# - control_cb: ๋ชจ๋ ์ ํ
3. ํตํฉ ํ ์คํธ
- ์น ์ธํฐํ์ด์ค๋ฅผ ํตํ ์ ์ฒด ์์คํ ํ ์คํธ
- ์ค์ ๋ก๋ดํ๊ณผ์ ์ฐ๋ ํ ์คํธ
์ฃผ์์ฌํญ
- ์ขํ๊ณ ์ผ๊ด์ฑ: ๋ชจ๋ ์ขํ๊ณ๊ฐ ๋์ผํ ๊ธฐ์ค์ ์ ์ฌ์ฉํ๋์ง ํ์ธ
- ๋จ์ ํต์ผ: ๋ฏธํฐ, ๋ผ๋์ ๋ฑ ๋จ์์ ์ผ๊ด์ฑ ์ ์ง
- ์์ ์ฑ: ์๋ก์ด ํ๋ผ๋ฏธํฐ๊ฐ ์์ ํ ๋ฒ์ ๋ด์ ์๋์ง ํ์ธ
- ๋ฐฑ์ : ์์ ์ ๊ธฐ์กด ์ค์ ์ ๋ฐฑ์ ํ์
๊ฒฐ๋ก
๋ก๋ดํ์ ํฌ๊ธฐ์ ํํ ๋ณ๊ฒฝ ์, ๊ฐ์ฅ ์ค์ํ ๊ฒ์ ArUco ๋ง์ปค ์ขํ๊ณ์ ์ฌ์ ์์ ๋๋ค. ์ด๋ ํ ๋ ์คํผ๋ ์ด์ ์์คํ ์ ํต์ฌ์ธ ์ ์์น ์ถ์ ์ ์ ํ๋์ ์ง์ ์ ์ธ ์ํฅ์ ๋ฏธ์นฉ๋๋ค. ๊ทธ ๋ค์์ผ๋ก๋ ๋ก๋ดํ์ ๋ฌผ๋ฆฌ์ ํ๋ผ๋ฏธํฐ๋ค(๊ทธ๋ฆฌํผ, ๋ฆฌํํธ ๋ฑ)์ ์๋ก์ด ๊ธฐํํ์ ๋ง๊ฒ ์กฐ์ ํด์ผ ํฉ๋๋ค.
SCARA์์ ํ๋๋ก๋ด์ผ๋ก์ ์ ํ ์์๋ ์ถ๊ฐ์ ์ผ๋ก ์์ ์์คํ ํตํฉ, ์๋ ์ ํ ์กฐ์ , ๊ทธ๋ฆฌ๊ณ ํ๋๋ก๋ด ํนํ ์ ์ด ๋ชจ๋๋ค์ ๊ตฌํ์ด ํ์์ ์ ๋๋ค.
์๊ฒฉ์กฐ์ข ์์คํ ๊ด์ ์์๋ 6์ถ SCARA์์ ์์ 6์ถ ๋ก๋ดํ๋ก์ ์ ํ์ด ์ถ์ํ๋ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ํ ๋ ์คํผ๋ ์ด์ ์ฝ๋ ์์ฒด๋ ์์ ํ ํ์๊ฐ ์์ต๋๋ค.
์ด๋ฌํ ์์ ์ ํตํด ์๋ก์ด ๋ก๋ดํ์์๋ ์ ํํ๊ณ ์์ ํ ํ ๋ ์คํผ๋ ์ด์ ์ด ๊ฐ๋ฅํด์ง๋๋ค.