Animate joints - modulabs/gazebo-tutorial GitHub Wiki

Overview

์ด๋ฒˆ ์žฅ์—์„œ๋Š” ROS topic์ธ trajectory_msgs::JointTrajectory message ๋ฅผ ์ด์šฉํ•˜์—ฌ dynamics ์—†์ด ์‹œ๋ฎฌ๋ ˆ์ด์…˜์œผ๋กœ ๋กœ๋ด‡์„ ์›€์ง์ผ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„ ๋ณธ๋‹ค.

์•„๋ž˜์™€ ๊ฐ™์ด ROS ํŒจํ‚ค์ง€๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

cd ~/catkin_ws/src
catkin_create_pkg joint_animation_tutorial rospy trajectory_msgs std_msgs
cd joint_animation_tutorial
mkdir scripts
cd scripts

Model Plugin Controller

joint trajectory model plugin์ด DRC robot์— ๋‚ด์žฅ๋˜์–ด ์žˆ๊ณ  ์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์ด JointTrajectory messages๋ฅผ ํฌํ•จํ•˜๋Š” ROS ํ† ํ”ฝ์„ ๋ฐ›๋Š”๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋กœ๋ด‡์˜ ์กฐ์ธํŠธ๋ฅผ trajectory์— ๋”ฐ๋ผ ์›€์ง์ด๊ฒŒ ๋œ๋‹ค. ์ด๊ฒƒ์€ ๋กœ๋ด‡ ๋ชจ๋ธ์˜ dynamics๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š๊ณ  ๋กœ๋ด‡์„ ์›€์ง์—ฌ ๋ณด๊ณ ์ž ํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค. ์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ๋˜ํ•œ ๋กœ๋ด‡์˜ ์กฐ์ธํŠธ trajectory๋ฅผ ๊ตฌ๋™ํ•˜๋Š” ๋™์•ˆ ๋ฌผ๋ฆฌ์ ์ธ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•˜์ง€ ์•Š๊ฒŒ ํ•œ๋‹ค.

Create a ROS Publisher

ํ˜„์žฌ์˜ ํด๋”์— joint trajectory messages joint_animation.py๋ฅผ ํผ๋ธ”๋ฆฌ์‹œ ํ•˜๋Š” ํŒŒ์ด์ฌ์˜ ROS ๋…ธ๋“œ๋ฅผ ๋‹ค์šด๋กœ๋“œ ํ•œ๋‹ค.

wget http://bitbucket.org/osrf/gazebo_tutorials/raw/default/drcsim_animate_joints/files/joint_animation.py
#!/usr/bin/env python

import roslib; roslib.load_manifest('joint_animation_tutorial')
import rospy, math, time

from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint

def jointTrajectoryCommand():
    # Initialize the node
    rospy.init_node('joint_control')

    print rospy.get_rostime().to_sec()
    while rospy.get_rostime().to_sec() == 0.0:
        time.sleep(0.1)
        print rospy.get_rostime().to_sec()

    pub = rospy.Publisher('/joint_trajectory', JointTrajectory, queue_size=10)
    jt = JointTrajectory()

    jt.header.stamp = rospy.Time.now()
    jt.header.frame_id = "atlas::pelvis"

    jt.joint_names.append("atlas::back_lbz" )
    jt.joint_names.append("atlas::back_mby" )
    jt.joint_names.append("atlas::back_ubx" )
    jt.joint_names.append("atlas::neck_ay"  )
    jt.joint_names.append("atlas::l_leg_uhz")
    jt.joint_names.append("atlas::l_leg_mhx")
    jt.joint_names.append("atlas::l_leg_lhy")
    jt.joint_names.append("atlas::l_leg_kny")
    jt.joint_names.append("atlas::l_leg_uay")
    jt.joint_names.append("atlas::l_leg_lax")
    jt.joint_names.append("atlas::r_leg_lax")
    jt.joint_names.append("atlas::r_leg_uay")
    jt.joint_names.append("atlas::r_leg_kny")
    jt.joint_names.append("atlas::r_leg_lhy")
    jt.joint_names.append("atlas::r_leg_mhx")
    jt.joint_names.append("atlas::r_leg_uhz")
    jt.joint_names.append("atlas::l_arm_elx")
    jt.joint_names.append("atlas::l_arm_ely")
    jt.joint_names.append("atlas::l_arm_mwx")
    jt.joint_names.append("atlas::l_arm_shx")
    jt.joint_names.append("atlas::l_arm_usy")
    jt.joint_names.append("atlas::l_arm_uwy")
    jt.joint_names.append("atlas::r_arm_elx")
    jt.joint_names.append("atlas::r_arm_ely")
    jt.joint_names.append("atlas::r_arm_mwx")
    jt.joint_names.append("atlas::r_arm_shx")
    jt.joint_names.append("atlas::r_arm_usy")
    jt.joint_names.append("atlas::r_arm_uwy")

    n = 1500
    dt = 0.01
    rps = 0.05
    for i in range (n):
        p = JointTrajectoryPoint()
        theta = rps*2.0*math.pi*i*dt
        x1 = -0.5*math.sin(2*theta)
        x2 =  0.5*math.sin(1*theta)

        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        jt.points.append(p)

        # set duration
        jt.points[i].time_from_start = rospy.Duration.from_sec(dt)
        rospy.loginfo("test: angles[%d][%f, %f]",n,x1,x2)

    pub.publish(jt)
    rospy.spin()

if __name__ == '__main__':
    try:
        jointTrajectoryCommand()
    except rospy.ROSInterruptException: pass

ํŒŒ์ผ์ด ์‹คํ–‰ ๋  ์ˆ˜ ์žˆ๋„๋ก ์•„๋ž˜์™€ ๊ฐ™์ด ํŒŒ์ผ ๊ถŒํ•œ์„ ๋ฐ”๊พผ๋‹ค.

chmod +x joint_animation.py

The Code explained

#!/usr/bin/env python

import roslib; roslib.load_manifest('joint_animation_tutorial')

์ด๊ฒƒ์€ roslib์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ์ด ํŒจํ‚ค์ง€์— ํฌํ•จ๋œ manifest.xml์„ ๋กœ๋“œํ•œ๋‹ค.

import rospy, math, time

from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint

๋” ๋งŽ์€ ๋ชจ๋“ˆ์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ  JointTrajectory, JointTrajectoryPoint์— ๋Œ€ํ•œ ๋ฉ”์‹œ์ง€ ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.

Import more modules, and import the message file for JointTrajectory and JointTrajectoryPoint.

def jointTrajectoryCommand():
    # Initialize the node
    rospy.init_node('joint_control')

    print rospy.get_rostime().to_sec()
    while rospy.get_rostime().to_sec() == 0.0:
        time.sleep(0.1)
        print rospy.get_rostime().to_sec()

    pub = rospy.Publisher('/joint_trajectory', JointTrajectory, queue_size=10)

์ด๊ฒƒ์€ ๋…ธ๋“œ๋ฅผ ์ดˆ๊ธฐํ™” ํ•˜๊ณ  joint_trajectory ํ† ํ”ฝ ํผ๋ธ”๋ฆฌ์…”๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

    jt = JointTrajectory()

    jt.header.stamp = rospy.Time.now()
    jt.header.frame_id = "atlas::pelvis"

JointTrajectory ๋ฉ”์‹œ์ง€์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ—ค๋”์— time stamp์™€ frame_id๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

    jt.joint_names.append("atlas::back_lbz" )
    jt.joint_names.append("atlas::back_mby" )
    jt.joint_names.append("atlas::back_ubx" )
    jt.joint_names.append("atlas::neck_ay"  )
    jt.joint_names.append("atlas::l_leg_uhz")
    jt.joint_names.append("atlas::l_leg_mhx")
    jt.joint_names.append("atlas::l_leg_lhy")
    jt.joint_names.append("atlas::l_leg_kny")
    jt.joint_names.append("atlas::l_leg_uay")
    jt.joint_names.append("atlas::l_leg_lax")
    jt.joint_names.append("atlas::r_leg_lax")
    jt.joint_names.append("atlas::r_leg_uay")
    jt.joint_names.append("atlas::r_leg_kny")
    jt.joint_names.append("atlas::r_leg_lhy")
    jt.joint_names.append("atlas::r_leg_mhx")
    jt.joint_names.append("atlas::r_leg_uhz")
    jt.joint_names.append("atlas::l_arm_elx")
    jt.joint_names.append("atlas::l_arm_ely")
    jt.joint_names.append("atlas::l_arm_mwx")
    jt.joint_names.append("atlas::l_arm_shx")
    jt.joint_names.append("atlas::l_arm_usy")
    jt.joint_names.append("atlas::l_arm_uwy")
    jt.joint_names.append("atlas::r_arm_elx")
    jt.joint_names.append("atlas::r_arm_ely")
    jt.joint_names.append("atlas::r_arm_mwx")
    jt.joint_names.append("atlas::r_arm_shx")
    jt.joint_names.append("atlas::r_arm_usy")
    jt.joint_names.append("atlas::r_arm_uwy")

์ปจํŠธ๋กค ๋  joint ์ด๋ฆ„์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

    n = 1500
    dt = 0.01
    rps = 0.05
    for i in range (n):
        p = JointTrajectoryPoint()
        theta = rps*2.0*math.pi*i*dt
        x1 = -0.5*math.sin(2*theta)
        x2 =  0.5*math.sin(1*theta)

n=1500์œผ๋กœ ์ˆ˜ํ–‰๋˜๋„๋ก ๋ฃจํ”„๋ฅผ ์…‹์—…ํ•˜๊ณ  ์ด ๋ฃจํ”„๋Š” x1, x2์˜ ์กฐ์ธํŠธ ๊ฐ๋„๋ฅผ ๊ณ„์‚ฐํ•œ๋‹ค. ์•„๋ž˜์— ์ถ”๊ฐ€๋œ ๊ฐ ์กฐ์ธํŠธ์˜ ์œ„์น˜๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค.

        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        jt.points.append(p)

JointTrajectoryPoint๊ฐ€ ๋”ฐ๋ผ๊ฐˆ ์œ„์น˜์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  JointTrajectoryPoint๋ฅผ JointTrajectory์— ์ถ”๊ฐ€ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ ํฌ์ธํŠธ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.

        # set duration
        jt.points[i].time_from_start = rospy.Duration.from_sec(dt)
        rospy.loginfo("test: angles[%d][%f, %f]",n,x1,x2)

์ƒ์„ฑ๋œ ํฌ์ธํŠธ๋ฅผ ๋กœ๊ทธ๋กœ ๋‚จ๊ธด๋‹ค.

    pub.publish(jt)
    rospy.spin()

์ด๊ฒƒ์€ ๋กœ๋ด‡์„ ์›€์ง์ผ ํ•˜๋‚˜์˜ JointTrajectory ๋ฉ”์‹œ์ง€๋ฅผ ํผ๋ธ”๋ฆฌ์‹œ ํ•  ๊ฒƒ์ด๋‹ค. ์ด ๋…ธ๋“œ๋Š” ๊ณ„์†ํ•ด์„œ ๋ฐ˜๋ณต ์ˆ˜ํ–‰๋œ๋‹ค.

if __name__ == '__main__':
    try:
        jointTrajectoryCommand()
    except rospy.ROSInterruptException: pass

rospy ๋…ธ๋“œ์˜ ๋ฉ”์ธ ํ•จ์ˆ˜์ด๊ณ  ๋งŒ์•ฝ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋‹ค์šด๋˜๋ฉด ์‹คํ–‰ ์ฝ”๋“œ๋กœ ๋ถ€ํ„ฐ ๋…ธ๋“œ๋ฅผ ๋ณดํ˜ธํ•œ๋‹ค.

Running the Simulation

  1. ํ„ฐ๋ฏธ๋„ ์ฐฝ์—์„œ DRC ๋กœ๋ด‡ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์„ ์‹œ์ž‘ํ•œ๋‹ค.

    VRC_CHEATS_ENABLED=1 roslaunch drcsim_gazebo atlas.launch
    
  2. ๋กœ๋ด‡์ด ๋„˜์–ด์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ ํ•˜๊ธฐ ์œ„ํ•ด(์–ด๋–ค ์ œ์–ด๊ธฐ๋“ค๋„ ์ž‘๋™๋˜์ง€ ์•Š๊ณ  ์žˆ๋‹ค) World->Physics->gravity->z์„ ํด๋ฆญํ•˜๊ณ  ๊ฐ’์„ 0.0์œผ๋กœ ์…‹ํŒ… ํ•ด์„œ ์ค‘๋ ฅ์„ ์—†์•ค๋‹ค. ํ˜น์€ ๋‹ค์Œ์˜ ๋ช…๋ น์–ด๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

    gz physics -g 0,0,0
    
  3. ๋กœ๋ด‡์ด ์ง€๋ฉด์—์„œ ํŠ€๊ธฐ๊ฑฐ๋‚˜ ํ•˜๋Š˜์— ๋– ์žˆ๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด(์ค‘๋ ฅ์ด ์—†๋‹ค) World->Models์„ ํด๋ฆญํ•˜๊ณ  ground_plane์„ ์˜ค๋ฅธ์ชฝ ํด๋ฆญํ•ด์„œ ์‚ญ์ œ๋ฅผ ํด๋ฆญํ•œ๋‹ค.

  4. ์ค‘๋ ฅ์„ ์—†์• ๊ณ  ground plane์„ ์‚ญ์ œํ•œ๋‹ค. Edit->Reset World์„ ํด๋ฆญํ•ด์„œ world๋ฅผ ๋ฆฌ์…‹ํ•œ๋‹ค. ๋กœ๋ด‡์€ ์ด์ œ ํŒ”์„ ํŽด๊ณ  ์›์ ์—์„œ ์„œ์žˆ๋Š” ์ดˆ๊ธฐ ์ž์„ธ๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค.

  5. ๋‹ค๋ฅธ ํ„ฐ๋ฏธ๋„ ์ฐฝ์„ ์—ด๊ณ  ์•„๋ž˜๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

    rosrun joint_animation_tutorial joint_animation.py
    

    DRC ๋กœ๋ด‡์€ ํผ๋ธ”๋ฆฌ์‹œ๋œ ROS JointTrajectory ๋ฉ”์‹œ์ง€์— ๋”ฐ๋ผ ์›€์ง์ผ ๊ฒƒ์ด๋‹ค.

Atlas v4, v5

์ด ์ƒ˜ํ”Œ์ฝ”๋“œ๋Š” Atlas v4์™€ v5์—์„œ๋Š” ์ž‘๋™๋˜์ง€ ์•Š๋Š”๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์ด ๋ชจ๋ธ๋“ค์€ ๋‹ค๋ฅธ ์กฐ์ธํŠธ์˜ ์ด๋ฆ„๊ณผ ๋” ๋งŽ์€ ์กฐ์ธํŠธ๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. Atlas v4, v5 ์กฐ์ธํŠธ๋“ค์„ ์›€์ง์ด๊ธฐ ์œ„ํ•ด์„œ๋Š” modified version๋ฅผ ๋‹ค์šด ๋ฐ›์•„์•ผ ํ•œ๋‹ค. ์ด ์ˆ˜์ •๋œ ์ฝ”๋“œ๋Š” ์—…๋ฐ์ดํŠธ ๋œ ์กฐ์ธํŠธ์˜ ์ด๋ฆ„์„ ํฌํ•จํ•œ๋‹ค.



    jt.joint_names.append("atlas::back_bkz" )
    jt.joint_names.append("atlas::back_bky" )
    jt.joint_names.append("atlas::back_bkx" )
    jt.joint_names.append("atlas::neck_ry"  )
    jt.joint_names.append("atlas::l_leg_hpz")
    jt.joint_names.append("atlas::l_leg_hpx")
    jt.joint_names.append("atlas::l_leg_hpy")
    jt.joint_names.append("atlas::l_leg_kny")
    jt.joint_names.append("atlas::l_leg_aky")
    jt.joint_names.append("atlas::l_leg_akx")
    jt.joint_names.append("atlas::r_leg_akx")
    jt.joint_names.append("atlas::r_leg_aky")
    jt.joint_names.append("atlas::r_leg_kny")
    jt.joint_names.append("atlas::r_leg_hpy")
    jt.joint_names.append("atlas::r_leg_hpx")
    jt.joint_names.append("atlas::r_leg_hpz")
    jt.joint_names.append("atlas::l_arm_elx")
    jt.joint_names.append("atlas::l_arm_ely")
    jt.joint_names.append("atlas::l_arm_shz")
    jt.joint_names.append("atlas::l_arm_shx")
    jt.joint_names.append("atlas::l_arm_wry")
    jt.joint_names.append("atlas::l_arm_wrx")
    jt.joint_names.append("atlas::l_arm_wry2")
    jt.joint_names.append("atlas::r_arm_elx")
    jt.joint_names.append("atlas::r_arm_ely")
    jt.joint_names.append("atlas::r_arm_shz")
    jt.joint_names.append("atlas::r_arm_shx")
    jt.joint_names.append("atlas::r_arm_wry")
    jt.joint_names.append("atlas::r_arm_wrx")
    jt.joint_names.append("atlas::r_arm_wry2")

ํ•ด๋‹น ์กฐ์ธํŠธ ๊ฐ๋„๋“ค์„ ์ƒ์„ฑํ•œ๋‹ค.

        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x2)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x1)
        p.positions.append(x1)
        jt.points.append(p)

Note: Atlas v4/v5์—์„œ joint trajectory control ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ€์ง€๊ธฐ ๋•Œ๋ฌธ์— PID ์ปจํŠธ๋กค์„ ๊บผ์•ผ ํ•œ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ Atlas๋Š” User ๋ชจ๋“œ๋กœ ์…‹ํŒ…์ด ๋œ๋‹ค.

  1. ์ƒˆ๋กœ์šด joint trajectory ํผ๋ธ”๋ฆฌ์…”๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด, ๋จผ์ € ํ–ˆ๋˜ ์œ ์‚ฌํ•œ ์ ˆใ…Š๋ผ๋ฅด ๋”ฐ๋ฅธ๋‹ค. Atlas v4๋ฅผ launchํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

    VRC_CHEATS_ENABLED=1 roslaunch drcsim_gazebo atlas.launch model_args:="_v4"
    

    Atlas v5๋ฅผ ์‹คํ–‰ํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด ์•„๋ž˜์˜ ๋ช…๋ น์–ด๋กœ ์‹คํ–‰ ๊ฐ€๋Šฅํ•˜๋‹ค.

    VRC_CHEATS_ENABLED=1 roslaunch drcsim_gazebo atlas.launch model_args:="_v5"
    
  2. World->Physics->gravity->z๋ฅผ ํด๋ฆญ ํ•˜์—ฌ 0.0์œผ๋กœ ๊ฐ’์„ ์„ค์ •ํ•˜๋ฉด ์ค‘๋ ฅ์„ ์—†์•จ ์ˆ˜ ์žˆ๋‹ค. ์•„๋‹ˆ๋ฉด ์•„๋ž˜์˜ ๋ช…๋ น์–ด๋กœ ์ˆ˜ํ–‰ ๊ฐ€๋Šฅํ•˜๋‹ค.

    gz physics -g 0,0,0
    
  3. ground๋ฅผ ์‚ญ์ œํ•œ๋‹ค. World->Models์„ ํด๋ฆญํ•˜๊ณ  ground_plane ์˜ค๋ฅธ์ชฝ ํด๋ฆญํ•˜์—ฌ ์‚ญ์ œ๋ฅผ ํด๋ฆญํ•œ๋‹ค.`

  4. Edit->Reset Model Poses๋ฅผ ํด๋ฆญํ•˜์—ฌ ๋ชจ๋ธ์˜ ์ž์„ธ๋ฅผ ์ดˆ๊ธฐํ™” ํ•œ๋‹ค.

  5. ๋งˆ์ง€๋ง‰์œผ๋กœ ๋‹ค๋ฅธ ํ„ฐ๋ฏธ๋„์ฐฝ์—์„œ joint_animation_v4v5.py๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

    rosrun joint_animation_tutorial joint_animation_v4v5.py