G1 팔 동작 초기 포지션 변경 방법에 대한 문의

예전에, wego 측에서 교육해주실때 알려주셨던 아래 방식으로 g1 팔 동작을 수행하기 위한 준비 상태를 만들었습니다.

  • 준비 상태 만들기 소스 코드 실행 절차
  1. 실제 g1 구동하는 스크립트 켜주셔야합니다. g1 먼저 0 포지션으로 만들어 놓고 사용.
    (/home/megagen/unitree_g1_lee/src/unitree_sdk2_python/scripts/g1_29dof_arm7_ys_waist.py) 실행

  2. moveit을 켜주셔야 합니다.
    cd unitree_g1_lee 작업공간에서 구동
    (ros2 launch unitree_g1_29dof_wasit_moveit demo.launch.py) 실행

  • 초기 세팅 zero 포지션 확인 방법 : planning → goal state current 설정 → joints 0 degree 확인
  1. 1번과 2번을 이어주는 브릿지 역할 스크립트 켜주셔야합니다 (!!!실제 G1과 rviz에 있는 G1의 암 포지션이 무조건 같아야합니다!!!) - 둘 다 제로포지션
    (/home/megagen/unitree_g1_lee/src/unitree_sdk2_python/scripts/joint_to_Float32_29dof_waist.py) 실행

그런데, 캡처와 같이 팔이 앞으로 들려진 상태인 zero position으로 시작하다 보니, 팔 동작을 하기에 앞에 사물이 있으면 부딪히는 현상들이 있습니다. 이런 초기 position을 변경하는 방법이 있을까요?

현재 활용하고 있는 moveit config 파일들을 전달드립니다. 추가적으로 필요하신 정보가 있으시면 말씀 부탁드립니다.

g1회전각도전달코드.zip (3.8 KB)

moveit_config_file.zip (6.6 KB)

네, 초기 자세(initial position)는 원하는 형태로 변경이 가능합니다.
이를 위해서는 최종적으로 유지하고자 하는 관절 자세를 self.stand_up_joint_pos에 설정하고,
초기 제로 포지션에서 해당 자세로 이동하는 과정에서 **충돌을 방지하기 위한 중간 목표 자세(intermediate targets)**를 함께 정의해야 합니다.

예를 들어, 초기 및 중간 목표 관절 각도는 아래와 같이 설정할 수 있습니다.

self.stand_up_joint_pos = np.zeros(29, dtype=float)
self.stand_up_joint_pos[15:22] = [0.26, 0.26, 0.0, 1.0472, 0.0, 0.0, 0.0]
self.stand_up_joint_pos[22:29] = [0., -kPi_2, 0., 0., 0., 0., 0.]

self.target_pos = [
    0.26, 0.26, 0.0, 1.0472, 0.0, 0.0, 0.0,
    0., -kPi_2, 0., kPi_2, 0., 0., 0.,
    0, 0, 0
]

self.target_pos1 = [
    0.26, 0.26, 0.0, 1.0472, 0.0, 0.0, 0.0,
    0., -kPi_2, 0., 0., 0., 0., 0.,
    0, 0, 0
]

이후, 로봇이 단계적으로 목표 자세로 이동하도록 LowCmdWrite 함수를 수정하여
다단계 전이 방식으로 관절 명령을 전달해야 합니다.

def LowCmdWrite(self):
    self.time_ += self.control_dt_

    if self.time_ < self.duration_:
        # [Stage 1]: 첫 번째 중간 목표 자세로 이동
        self.low_cmd.motor_cmd[G1JointIndex.kNotUsedJoint].q = 1  # arm_sdk 활성화
        for i, joint in enumerate(self.arm_joints):
            ratio = np.clip(self.time_ / self.duration_, 0.0, 1.0)
            self.low_cmd.motor_cmd[joint].tau = 0.0
            self.low_cmd.motor_cmd[joint].q = (
                ratio * self.target_pos[i]
                + (1.0 - ratio) * self.low_state.motor_state[joint].q
            )
            self.low_cmd.motor_cmd[joint].dq = 0.0
            self.low_cmd.motor_cmd[joint].kp = self.kp
            self.low_cmd.motor_cmd[joint].kd = self.kd

    elif self.time_ < self.duration_ * 2:
        # [Stage 2]: 두 번째 중간 목표 자세로 이동
        for i, joint in enumerate(self.arm_joints):
            ratio = np.clip(
                (self.time_ - self.duration_) / (self.duration_ * 0.5),
                0.0,
                1.0,
            )
            self.low_cmd.motor_cmd[joint].tau = 0.0
            self.low_cmd.motor_cmd[joint].q = (
                ratio * self.target_pos1[i]
                + (1.0 - ratio) * self.low_state.motor_state[joint].q
            )
            self.low_cmd.motor_cmd[joint].dq = 0.0
            self.low_cmd.motor_cmd[joint].kp = self.kp
            self.low_cmd.motor_cmd[joint].kd = self.kd

    else:
        # [Final Stage]: 최종 stand-up 자세 유지
        for i, joint in enumerate(self.arm_joints):
            self.low_cmd.motor_cmd[joint].tau = 0.0
            self.low_cmd.motor_cmd[joint].q = self.stand_up_joint_pos[joint]
            self.low_cmd.motor_cmd[joint].dq = 0.0
            self.low_cmd.motor_cmd[joint].kp = self.kp
            self.low_cmd.motor_cmd[joint].kd = self.kd

    self.low_cmd.crc = self.crc.Crc(self.low_cmd)
    self.arm_sdk_publisher.Write(self.low_cmd)

참고를 위해, 저희가 사용한 중간 관절 자세의 이미지를 첨부드립니다.
필요에 따라 다른 관절 자세를 적용하고자 하실 경우, MoveIt에서 해당 관절 값을 확인하신 후 설정하시면 됩니다.
target_pos:


target_pos1:

이와 같이 중간 단계를 포함한 점진적인 관절 이동 방식을 적용하면,
기본 제로 포지션에서 사용자가 정의한 초기 자세로 안전하게 전환할 수 있으며,
로봇 전방에 물체가 존재하는 환경에서도 충돌 위험을 효과적으로 줄일 수 있습니다.

Note: MoveIt에서 표시되는 G1 팔의 자세가 제로 포지션이 아닌, 실제로 적용하고자 하는 목표 자세와 일치하는지 반드시 확인해 주시기 바랍니다.

친절한 답변 감사합니다. 추가적인 문의사항이 있습니다.

문의 사항

  1. 제가 이해한 바로는 처음에는 팔이 앞으로 위치하는건 어쩔 수 없이 해당 코드가 실행되면, 수행되야하는 것은 변함이 없는 건가요? 초기 포지션을 Release arm 상태로 변경하고 싶습니다.

  2. def LowCmdWrite(self):
        self.time_ += self.control_dt_
    
        if self.time_ < self.duration_:
            # [Stage 1]: 첫 번째 중간 목표 자세로 이동
            self.low_cmd.motor_cmd[G1JointIndex.kNotUsedJoint].q = 1  # arm_sdk 활성화
            for i, joint in enumerate(self.arm_joints):
                ratio = np.clip(self.time_ / self.duration_, 0.0, 1.0)
                self.low_cmd.motor_cmd[joint].tau = 0.0
                self.low_cmd.motor_cmd[joint].q = (
                    ratio * self.target_pos[i]
                    + (1.0 - ratio) * self.low_state.motor_state[joint].q
                )
                self.low_cmd.motor_cmd[joint].dq = 0.0
                self.low_cmd.motor_cmd[joint].kp = self.kp
                self.low_cmd.motor_cmd[joint].kd = self.kd
    
  3. 그렇다면, rviz에서는 팔을 앞으로 뻗은 상태로 시작이 되던데, 그러면 제가 첨부한 moveit_config_file.zip (6.6 KB) 이 moveit config 파일들에 대한 urdf 파일에 설정된 초기 position에 대한 설정이나 이런 것들을 변경해야되는 것으로 추정되는데 맞을까요? 맞다면, 어떤 부분을 수정해야되는지 문의드립니다.

  4. 저는 아래 사진과 같이 Release arm 상태를 초기 자세로 만들고 싶습니다. zero position으로 이동을 안하고 release arm 상태에서 시작하게끔이요. 그러면 아래 코드에서 # [Stage 1]: 첫 번째 중간 목표 자세로 이동에 관절별 목표 회전 각도를 라디안으로 적용해서 넣으면 되는 것 같은데 맞을까요?

  • [“shoulder_pitch”, “shoulder_roll”, “shoulder_yaw”, “elbow”, “wrist_roll”, “wrist_pitch”, “wrist_yaw”]
  • 왼팔: [16.44, 13.10, -0.70, 55.69, 4.66, -0.20, 0.16]
  • 오른팔: [16.84, -12.57, 0.42, 56.18, -6.83, -0.55, -0.09]

self.stand_up_joint_pos = np.zeros(29, dtype=float)
self.stand_up_joint_pos[15:22] = [0.26, 0.26, 0.0, 1.0472, 0.0, 0.0, 0.0]
self.stand_up_joint_pos[22:29] = [0., -kPi_2, 0., 0., 0., 0., 0.]

# 여기에 release arm 좌표로 이동하는 target_pos를 설정
# 왼팔: [16.44, 13.10, -0.70, 55.69, 4.66, -0.20, 0.16]
# 오른팔: [16.84, -12.57, 0.42, 56.18, -6.83, -0.55, -0.09]
# 위 값을 radian으로 변환 후 아래에 joint index에 맞게 대입
self.target_pos = [
    0.26, 0.26, 0.0, 1.0472, 0.0, 0.0, 0.0,
    0., -kPi_2, 0., kPi_2, 0., 0., 0.,
    0, 0, 0
]

def LowCmdWrite(self):
    self.time_ += self.control_dt_

    if self.time_ < self.duration_:
        # 이 부분에 release arm 좌표로 이동하는 target_pos를 설정. 
        self.low_cmd.motor_cmd[G1JointIndex.kNotUsedJoint].q = 1  # arm_sdk 활성화
        for i, joint in enumerate(self.arm_joints):
            ratio = np.clip(self.time_ / self.duration_, 0.0, 1.0)
            self.low_cmd.motor_cmd[joint].tau = 0.0
            self.low_cmd.motor_cmd[joint].q = (
                ratio * self.target_pos[i]
                + (1.0 - ratio) * self.low_state.motor_state[joint].q
            )
            self.low_cmd.motor_cmd[joint].dq = 0.0
            self.low_cmd.motor_cmd[joint].kp = self.kp
            self.low_cmd.motor_cmd[joint].kd = self.kd

MoveIt 설정 파일의 initial_positions.yaml라디안 단위의 Release arm 자세로 업데이트하는 것만으로 MoveIt의 시작 상태를 변경할 수 있으며, URDF 파일을 수정할 필요는 없습니다.

또한, self.stand_up_joint_pos를 Release arm 자세로 설정하는 것만으로 충분하며, 본 사례에서는 복잡한 초기 전이 과정이 필요하지 않기 때문에 추가적인 중간 목표 관절(target_pos, target_pos1)을 정의할 필요가 없습니다.

그렇다면,

  1. g1_29dof_arm7_ys_waist.py 코드에서 self.stand_up_joint_pos를 Release arm 자세로 설정 (초기 관절 회전 각도가 Release arm 라디안 값으로 이동하도록)
  2. initial_positions.yaml 을 Release arm 라디안 값으로 변경

이렇게 진행하면 ros2 launch unitree_g1_29dof_wasit_moveit demo.launch.py 실행했을때, rviz에서도 Release arm을 초기 값으로 가져서 휴머노이드 g1의 팔 제어 준비 동작이 매칭되게 된다는 말씀이신거죠? 초기 자세가 일치하지 않으면 급격히 초기 자세로 이동 되는 오작동이 발생할까봐 이렇게 상세히 문의드립니다.

네, 맞습니다.
먼저 MoveIt 파일을 실행한 후 RViz2에서 초기 상태를 반드시 확인하시기 바랍니다. 초기 관절 상태가 예상한 자세와 일치하는 것이 확인되면, 그 이후에 실제 로봇을 연결하시는 것이 좋습니다.

실제 로봇에 명령을 보내기 전에 RViz와 실제 로봇 간의 설정된 관절 값이 서로 일치하는지 확인하고, 갑작스럽거나 의도하지 않은 움직임이 발생하지 않도록 충분한 안전 조치를 취한 상태에서 테스트를 진행하시기 바랍니다.

아래와 같이 초기 설정 변환 코드를 공유드립니다.

self.ema_angles = np.array([
            # 왼팔 7개
            math.radians(16.440354124679903),   # left_shoulder_pitch
            math.radians(13.097076417475272),    # left_shoulder_roll
            math.radians(-0.7024383721112378),   # left_shoulder_yaw
            math.radians(55.689698095794256),    # left_elbow
            math.radians(4.657516667202273),     # left_wrist_roll
            math.radians(-0.20478517295434204),  # left_wrist_pitch
            math.radians(0.15952149598445434),   # left_wrist_yaw
            # 오른팔 7개
            math.radians(16.838608794805005),    # right_shoulder_pitch
            math.radians(-12.567672723775814),   # right_shoulder_roll
            math.radians(0.42366027911447995),   # right_shoulder_yaw
            math.radians(56.177902942193846),    # right_elbow
            math.radians(-6.834869557141502),    # right_wrist_roll
            math.radians(-0.5462402700860972),   # right_wrist_pitch
            math.radians(-0.08833008074976102),  # right_wrist_yaw
            # 허리
            0.0  # waist_yaw
        ], dtype=float)

해당 부분을 적용하지 않으면, moveit에서 관절 각도를 전달할때 저 각도를 zero position으로 주다보니까 zero position으로 급격히 이동하는 문제가 발생했었습니다. 향후에 참고하시기 바랍니다!!!

"""
g1_29dof_arm7_ys_waist_release.py:
   - /hmr2/angles 받음
   - EMA 스무딩 적용
   - G1 관절 인덱스로 매핑
   - PD 제어로 모터 명령 생성
   - Unitree SDK로 로봇에 전송
   - Stage 1: Release Arm 포지션으로 초기 자세 설정

원본: g1_29dof_arm7_ys_waist.py
변경사항: Stage 1에서 zero posture 대신 Release Arm 포지션으로 이동
"""

import time
import sys
import math
import rclpy
from rclpy.node import Node
from std_msgs.msg import Float32MultiArray
sys.path.insert(0, '/home/megagen/unitree_g1_lee/src/unitree_sdk2_python')

from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize
from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize
from unitree_sdk2py.idl.default import unitree_hg_msg_dds__LowCmd_
from unitree_sdk2py.idl.default import unitree_hg_msg_dds__LowState_
from unitree_sdk2py.idl.unitree_hg.msg.dds_ import LowCmd_
from unitree_sdk2py.idl.unitree_hg.msg.dds_ import LowState_
from unitree_sdk2py.utils.crc import CRC
from unitree_sdk2py.utils.thread import RecurrentThread

import numpy as np


class G1JointIndex:
    # Left leg
    LeftHipPitch = 0
    LeftHipRoll = 1
    LeftHipYaw = 2
    LeftKnee = 3
    LeftAnklePitch = 4
    LeftAnkleB = 4
    LeftAnkleRoll = 5
    LeftAnkleA = 5

    # Right leg
    RightHipPitch = 6
    RightHipRoll = 7
    RightHipYaw = 8
    RightKnee = 9
    RightAnklePitch = 10
    RightAnkleB = 10
    RightAnkleRoll = 11
    RightAnkleA = 11

    WaistYaw = 12
    WaistRoll = 13        # NOTE: INVALID for g1 23dof/29dof with waist locked
    WaistA = 13           # NOTE: INVALID for g1 23dof/29dof with waist locked
    WaistPitch = 14       # NOTE: INVALID for g1 23dof/29dof with waist locked
    WaistB = 14           # NOTE: INVALID for g1 23dof/29dof with waist locked

    # Left arm
    LeftShoulderPitch = 15
    LeftShoulderRoll = 16
    LeftShoulderYaw = 17
    LeftElbow = 18
    LeftWristRoll = 19
    LeftWristPitch = 20   # NOTE: INVALID for g1 23dof
    LeftWristYaw = 21     # NOTE: INVALID for g1 23dof

    # Right arm
    RightShoulderPitch = 22
    RightShoulderRoll = 23
    RightShoulderYaw = 24
    RightElbow = 25
    RightWristRoll = 26
    RightWristPitch = 27  # NOTE: INVALID for g1 23dof
    RightWristYaw = 28    # NOTE: INVALID for g1 23dof

    kNotUsedJoint = 29 # NOTE: Weight

class Custom(Node):
    def __init__(self):
        super().__init__('unitree_g1_sdk_node')
        self.time_ = 0.0
        self.control_dt_ = 0.02
        self.duration_ = 3.0
        self.counter_ = 0
        self.weight = 0.
        self.weight_rate = 0.2
        self.kp = 180.
        self.kd = 6.0
        self.dq = 0.
        self.tau_ff = 0.
        self.mode_machine_ = 0
        self.low_cmd = unitree_hg_msg_dds__LowCmd_()
        self.low_state = None
        self.first_update_low_state = False
        self.crc = CRC()
        self.done = False
        self.stand_up_joint_pos = np.zeros(29, dtype=float)
        # Release Arm 포지션으로 초기값 설정 (Stage 2 진입 시 zero로 튀는 것 방지)
        # 왼팔
        self.stand_up_joint_pos[15] = math.radians(16.440354124679903)
        self.stand_up_joint_pos[16] = math.radians(13.097076417475272)
        self.stand_up_joint_pos[17] = math.radians(-0.7024383721112378)
        self.stand_up_joint_pos[18] = math.radians(55.689698095794256)
        self.stand_up_joint_pos[19] = math.radians(4.657516667202273)
        self.stand_up_joint_pos[20] = math.radians(-0.20478517295434204)
        self.stand_up_joint_pos[21] = math.radians(0.15952149598445434)
        # 오른팔
        self.stand_up_joint_pos[22] = math.radians(16.838608794805005)
        self.stand_up_joint_pos[23] = math.radians(-12.567672723775814)
        self.stand_up_joint_pos[24] = math.radians(0.42366027911447995)
        self.stand_up_joint_pos[25] = math.radians(56.177902942193846)
        self.stand_up_joint_pos[26] = math.radians(-6.834869557141502)
        self.stand_up_joint_pos[27] = math.radians(-0.5462402700860972)
        self.stand_up_joint_pos[28] = math.radians(-0.08833008074976102)
        # EMA parameters (Release Arm 포지션으로 초기값 설정하여 zero로 튀는 것 방지)
        self.ema_angles = np.array([
            # 왼팔 7개
            math.radians(16.440354124679903),   # left_shoulder_pitch
            math.radians(13.097076417475272),    # left_shoulder_roll
            math.radians(-0.7024383721112378),   # left_shoulder_yaw
            math.radians(55.689698095794256),    # left_elbow
            math.radians(4.657516667202273),     # left_wrist_roll
            math.radians(-0.20478517295434204),  # left_wrist_pitch
            math.radians(0.15952149598445434),   # left_wrist_yaw
            # 오른팔 7개
            math.radians(16.838608794805005),    # right_shoulder_pitch
            math.radians(-12.567672723775814),   # right_shoulder_roll
            math.radians(0.42366027911447995),   # right_shoulder_yaw
            math.radians(56.177902942193846),    # right_elbow
            math.radians(-6.834869557141502),    # right_wrist_roll
            math.radians(-0.5462402700860972),   # right_wrist_pitch
            math.radians(-0.08833008074976102),  # right_wrist_yaw
            # 허리
            0.0  # waist_yaw
        ], dtype=float)
        self.alpha = 0.15  # Smoothing factor for EMA

        self.arm_joints = [
          G1JointIndex.LeftShoulderPitch,  G1JointIndex.LeftShoulderRoll,
          G1JointIndex.LeftShoulderYaw,    G1JointIndex.LeftElbow,
          G1JointIndex.LeftWristRoll,      G1JointIndex.LeftWristPitch,
          G1JointIndex.LeftWristYaw,
          G1JointIndex.RightShoulderPitch, G1JointIndex.RightShoulderRoll,
          G1JointIndex.RightShoulderYaw,   G1JointIndex.RightElbow,
          G1JointIndex.RightWristRoll,     G1JointIndex.RightWristPitch,
          G1JointIndex.RightWristYaw,
          G1JointIndex.WaistYaw,
          G1JointIndex.WaistRoll,
          G1JointIndex.WaistPitch
        ]

        # Release Arm 초기 포지션 (arm_joints 순서와 동일)
        # 왼팔 7개 + 오른팔 7개 + 허리 3개
        self.initial_target_pos = [
            # 왼팔: [16.44, 13.10, -0.70, 55.69, 4.66, -0.20, 0.16] (degrees)
            math.radians(16.440354124679903),
            math.radians(13.097076417475272),
            math.radians(-0.7024383721112378),
            math.radians(55.689698095794256),
            math.radians(4.657516667202273),
            math.radians(-0.20478517295434204),
            math.radians(0.15952149598445434),
            # 오른팔: [16.84, -12.57, 0.42, 56.18, -6.83, -0.55, -0.09] (degrees)
            math.radians(16.838608794805005),
            math.radians(-12.567672723775814),
            math.radians(0.42366027911447995),
            math.radians(56.177902942193846),
            math.radians(-6.834869557141502),
            math.radians(-0.5462402700860972),
            math.radians(-0.08833008074976102),
            # 허리 3개: [0, 0, 0]
            0.0, 0.0, 0.0
        ]

        # Unitree SDK DDS 통신 (로봇 하드웨어와 직접 통신)
        # create publisher #
        self.arm_sdk_publisher = ChannelPublisher("rt/arm_sdk", LowCmd_)
        self.arm_sdk_publisher.Init()
        # Unitree SDK DDS 통신 (로봇 하드웨어와 직접 통신)
        # create subscriber #
        self.lowstate_subscriber = ChannelSubscriber("rt/lowstate", LowState_)
        self.lowstate_subscriber.Init(self.LowStateHandler, 10)
        self.create_subscription(
            Float32MultiArray,
            '/hmr2/angles',
            self.angles_callback,
            10
        )

    def Start(self):
        self.lowCmdWriteThreadPtr = RecurrentThread(
            interval=self.control_dt_, target=self.LowCmdWrite, name="control"
        )
        while self.first_update_low_state == False:
            time.sleep(1)

        if self.first_update_low_state == True:
            self.lowCmdWriteThreadPtr.Start()

    def angles_callback(self, data):
        angles = np.array(data.data, dtype=np.float32)

        # Update EMA values (급격한 변화 방지)
        self.ema_angles = self.alpha * angles + (1 - self.alpha) * self.ema_angles
        # moveit에서 들어오는 joint 값
        self.stand_up_joint_pos[22] = self.ema_angles[7]  # right_shoulder_pitch
        self.stand_up_joint_pos[23] = self.ema_angles[8]  # right_shoulder_roll
        self.stand_up_joint_pos[24] = self.ema_angles[9]  # right_shoulder_yaw
        self.stand_up_joint_pos[25] = self.ema_angles[10]  # right_elbow
        self.stand_up_joint_pos[26] = self.ema_angles[11]  # right_wrist_roll
        self.stand_up_joint_pos[27] = self.ema_angles[12]  # right_wrist_pitch
        self.stand_up_joint_pos[28] = self.ema_angles[13]  # right_wrist_yaw

        self.stand_up_joint_pos[15] = self.ema_angles[0]  # left_shoulder_pitch
        self.stand_up_joint_pos[16] = self.ema_angles[1]  # left_shoulder_roll
        self.stand_up_joint_pos[17] = self.ema_angles[2]  # left_shoulder_yaw
        self.stand_up_joint_pos[18] = self.ema_angles[3]  # left_elbow
        self.stand_up_joint_pos[19] = self.ema_angles[4]  # left_wrist_roll
        self.stand_up_joint_pos[20] = self.ema_angles[5]  # left_wrist_pitch
        self.stand_up_joint_pos[21] = self.ema_angles[6]  # left_wrist_yaw

        self.stand_up_joint_pos[12] = self.ema_angles[-1]  # wrist_yaw
        print(self.stand_up_joint_pos)

    def LowStateHandler(self, msg: LowState_):
        self.low_state = msg

        if self.first_update_low_state == False:
            self.first_update_low_state = True

    def LowCmdWrite(self):
        self.time_ += self.control_dt_

        if self.time_ < self.duration_ :
            # [Stage 1]: Release Arm 포지션으로 이동
            self.low_cmd.motor_cmd[G1JointIndex.kNotUsedJoint].q =  1 # 1:Enable arm_sdk, 0:Disable arm_sdk
            for i,joint in enumerate(self.arm_joints):
                ratio = np.clip(self.time_ / self.duration_, 0.0, 1.0)
                self.low_cmd.motor_cmd[joint].tau = 0.
                self.low_cmd.motor_cmd[joint].q = ratio * self.initial_target_pos[i] + (1.0 - ratio) * self.low_state.motor_state[joint].q
                self.low_cmd.motor_cmd[joint].dq = 0.
                self.low_cmd.motor_cmd[joint].kp = self.kp
                self.low_cmd.motor_cmd[joint].kd = self.kd
            self.get_logger().info("Arm and wrist motors smoothly transitioning to Release Arm position.")
        else:
            # angles_callback에서 moveit에서 목표 각도가 들어오면 self.stand_up_joint_pos[joint] 그 값으로 제어

            for i,joint in enumerate(self.arm_joints):
                self.low_cmd.motor_cmd[joint].tau = 0.
                self.low_cmd.motor_cmd[joint].q = self.stand_up_joint_pos[joint]
                self.low_cmd.motor_cmd[joint].dq = 0.
                self.low_cmd.motor_cmd[joint].kp = self.kp
                self.low_cmd.motor_cmd[joint].kd = self.kd


        self.low_cmd.crc = self.crc.Crc(self.low_cmd)
        self.arm_sdk_publisher.Write(self.low_cmd)

def main(args=None):

    print("WARNING: Please ensure there are no obstacles around the robot while running this example.")
    # input("Press Enter to continue...")

    rclpy.init(args=args)  # Initialize ROS2 node

    if len(sys.argv) > 1:
        ChannelFactoryInitialize(0, sys.argv[1])
    else:
        ChannelFactoryInitialize(0)

    custom_node = Custom()
    custom_node.Start()

    rclpy.spin(custom_node)  # Keep the node alive and allow callbacks to be executed

    custom_node.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

1개의 좋아요