Bye Bye Moore

PoCソルジャーな零細事業主が作業メモを残すブログ

ikpyでURDFをもとにシンプルにIKをとく その2:空間角度の指定もやる

つづき

Roll 180°、それ以外0°として指定したいものの、このままオイラー角では使えません。
オイラー角を回転行列へ変換します。

実際のところ

import numpy as np
from ikpy.chain import Chain
import os

# URDFからチェーンを作成
chain = Chain.from_urdf_file(
    os.path.abspath("./minimalURDF.urdf.xml"),
    base_elements=["arm_base_link"],  
    active_links_mask=[False] + [True] * 7  
)

# 目標位置の設定
target_position = np.array([0.4, 0.21, -0.38])
print("\n目標位置 [m]:")
print(f"X: {target_position[0]:.3f}")
print(f"Y: {target_position[1]:.3f}") 
print(f"Z: {target_position[2]:.3f}")

# Roll 180°の回転行列を作成
# Roll(X): 180°, Pitch(Y): 0°, Yaw(Z): 0°
roll = np.radians(180)
pitch = np.radians(0)
yaw = np.radians(0)

# 回転行列の計算
Rx = np.array([
    [1, 0, 0],
    [0, np.cos(roll), -np.sin(roll)],
    [0, np.sin(roll), np.cos(roll)]
])

Ry = np.array([
    [np.cos(pitch), 0, np.sin(pitch)],
    [0, 1, 0],
    [-np.sin(pitch), 0, np.cos(pitch)]
])

Rz = np.array([
    [np.cos(yaw), -np.sin(yaw), 0],
    [np.sin(yaw), np.cos(yaw), 0],
    [0, 0, 1]
])

# 合成回転行列の計算 (順番: Z → Y → X)
target_orientation = Rx @ Ry @ Rz

print("\n目標姿勢(回転行列):")
print(target_orientation)

# 初期角度の設定
initial_position = [0] * len(chain.links)
initial_position[1] = 0.0  # joint1: (-0.785 to 0.785)
initial_position[2] = 0.0  # joint2: (-2.094 to 2.094)
initial_position[3] = 0.0  # joint3: (-3.001 to 3.001)
initial_position[4] = 0.0  # joint4: (-3.001 to 3.001)
initial_position[5] = 0.0  # joint5: (-3.001 to 3.001)
initial_position[6] = 0.0  # joint6: (-3.001 to 3.001)
initial_position[7] = 0.0  # joint7: (-6.197 to 6.197)

try:
    # IKを解く(姿勢制御を含む)
    joint_angles = chain.inverse_kinematics(
        target_position,
        target_orientation=target_orientation,
        orientation_mode="all",  # 全ての回転軸の姿勢を考慮
        initial_position=initial_position,
        max_iter=1000
    )
    
    # 結果の表示
    print("\n計算された関節角度(ラジアン => 度):")
    degrees = np.degrees(joint_angles)
    for i, (rad, deg) in enumerate(zip(joint_angles, degrees)):
        rad_str = f"{rad:+.8f}" if rad != 0 else " 0.00000000"
        deg_str = f"{deg:+.2f}" if deg != 0 else " 0.00"
        print(f"Joint {i}: {rad_str} => {deg_str}°")

    # 順運動学で最終的な位置と姿勢を確認
    final_frame = chain.forward_kinematics(joint_angles)
    print("\n最終的なエンドエフェクタの位置:")
    print(f"X: {final_frame[0, 3]:.3f}")
    print(f"Y: {final_frame[1, 3]:.3f}")
    print(f"Z: {final_frame[2, 3]:.3f}")
    
    print("\n最終的な姿勢行列:")
    print(final_frame[:3, :3])

except Exception as e:
    print(f"エラーが発生しました: {e}")
    
    # 現在の位置を確認
    current_position = chain.forward_kinematics(initial_position)
    print("\n初期位置での手先位置:")
    print(current_position[:3, 3])

結果

空間系を指定しない(前回のもの)

計算された関節角度(ラジアン => 度):
Joint 0:  0.00000000 =>  0.00°
Joint 1: +0.16759269 => +9.60°
Joint 2: -0.34032077 => -19.50°
Joint 3: +0.28041829 => +16.07°
Joint 4: -0.81002203 => -46.41°
Joint 5:  0.00000000 =>  0.00°
Joint 6:  0.00000000 =>  0.00°
Joint 7:  0.00000000 =>  0.00°

空間系を指定する(今回)

計算された関節角度(ラジアン => 度):
Joint 0:  0.00000000 =>  0.00°
Joint 1: -0.75274636 => -43.13°
Joint 2: -0.49511530 => -28.37°
Joint 3: +1.01860571 => +58.36°
Joint 4: +1.17755105 => +67.47°
Joint 5: +0.51352504 => +29.42°
Joint 6: +2.17411863 => +124.57°
Joint 7: +2.02237533 => +115.87°