Skip to content

Commit c7dcb1f

Browse files
Add nextage model (#616)
* Add nextage robot model and interface * Add nextage examples
1 parent 9474dd7 commit c7dcb1f

File tree

7 files changed

+199
-2
lines changed

7 files changed

+199
-2
lines changed

examples/batch_ik_demo.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from skrobot.coordinates import Coordinates
99
from skrobot.model.primitives import Axis
1010
from skrobot.models import Fetch
11+
from skrobot.models import Nextage
1112
from skrobot.models import Panda
1213
from skrobot.models import PR2
1314
from skrobot.models import R8_6
@@ -27,7 +28,7 @@ def parse_axis_constraint(axis_str):
2728
def main():
2829
parser = argparse.ArgumentParser(description='Advanced Batch IK Demo with axis constraints')
2930
parser.add_argument('--robot', type=str, default='pr2',
30-
choices=['fetch', 'pr2', 'panda', 'r8_6'],
31+
choices=['fetch', 'pr2', 'panda', 'r8_6', 'nextage'],
3132
help='Robot model to use. Default: fetch')
3233
parser.add_argument('--rotation-axis', '--rotation_axis', '-r',
3334
default='True',
@@ -84,6 +85,9 @@ def main():
8485
elif args.robot == 'r8_6':
8586
robot = R8_6()
8687
arm = robot.rarm
88+
elif args.robot == 'nextage':
89+
robot = Nextage()
90+
arm = robot.rarm
8791

8892
robot.reset_pose()
8993

@@ -102,6 +106,23 @@ def main():
102106
Coordinates(pos=(0.46, -0.24, 0.89)).rotate(np.deg2rad(8), 'z').rotate(np.deg2rad(3), 'x'),
103107
Coordinates(pos=(0.56, -0.24, 0.89)),
104108
]
109+
elif args.robot == 'nextage':
110+
target_poses = [
111+
Coordinates(pos=(0.3, -0.25, -0.1)).rotate(
112+
np.pi, 'y').rotate(np.deg2rad(-25), 'z'),
113+
Coordinates(pos=(0.3, -0.25, -0.15)).rotate(
114+
np.pi, 'y').rotate(np.deg2rad(-30), 'z'),
115+
Coordinates(pos=(0.4, -0.2, -0.1)).rotate(
116+
np.pi, 'y').rotate(np.deg2rad(15), 'y').rotate(
117+
np.deg2rad(-15), 'z'),
118+
Coordinates(pos=(0.28, -0.18, -0.08)).rotate(
119+
np.pi, 'y').rotate(np.deg2rad(90), 'x'),
120+
Coordinates(pos=(0.35, -0.2, -0.12)).rotate(
121+
np.pi, 'y').rotate(np.deg2rad(45), 'x'),
122+
Coordinates(pos=(0.35, -0.22, -0.08)).rotate(
123+
np.pi, 'y').rotate(np.deg2rad(-30), 'y').rotate(
124+
np.deg2rad(15), 'z'),
125+
]
105126
else:
106127
# Default target poses for Fetch/PR2/Panda
107128
target_poses = [

examples/robot_models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def main():
4040
robots = [
4141
skrobot.models.Kuka(),
4242
skrobot.models.Fetch(),
43+
skrobot.models.Nextage(),
4344
skrobot.models.PR2(),
4445
skrobot.models.Panda(),
4546
]

skrobot/data/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,20 @@ def kuka_urdfpath():
8383
return osp.join(data_dir, 'kuka_description', 'kuka.urdf')
8484

8585

86+
def nextage_urdfpath():
87+
path = osp.join(get_cache_dir(), 'nextage_description', 'urdf', 'NextageOpen.urdf')
88+
if osp.exists(path):
89+
return path
90+
_download(
91+
url='https://github.com/iory/scikit-robot-models/raw/refs/heads/master/nextage_description.tar.gz', # NOQA
92+
path=osp.join(get_cache_dir(), 'nextage_description.tar.gz'),
93+
md5='9805ac9cd97b67056dde31aa88762ec7',
94+
postprocess='extractall',
95+
quiet=True,
96+
)
97+
return path
98+
99+
86100
def panda_urdfpath():
87101
path = osp.join(get_cache_dir(),
88102
'franka_description', 'panda.urdf')

skrobot/interfaces/ros/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from skrobot._lazy_imports import LazyImportClass
22

33

4+
NextageROSRobotInterface = LazyImportClass(
5+
".nextage", "NextageROSRobotInterface", "skrobot.interfaces.ros")
46
PandaROSRobotInterface = LazyImportClass(
57
".panda", "PandaROSRobotInterface", "skrobot.interfaces.ros")
68
PR2ROSRobotInterface = LazyImportClass(
79
".pr2", "PR2ROSRobotInterface", "skrobot.interfaces.ros")
810

9-
__all__ = ["PandaROSRobotInterface", "PR2ROSRobotInterface"]
11+
__all__ = ["NextageROSRobotInterface", "PandaROSRobotInterface", "PR2ROSRobotInterface"]

skrobot/interfaces/ros/nextage.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import actionlib
2+
import control_msgs.msg
3+
4+
from .base import ROSRobotInterfaceBase
5+
6+
7+
class NextageROSRobotInterface(ROSRobotInterfaceBase):
8+
9+
def __init__(self, *args, **kwargs):
10+
super(NextageROSRobotInterface, self).__init__(*args, **kwargs)
11+
12+
self.rarm_move = actionlib.SimpleActionClient(
13+
'/rarm_controller/follow_joint_trajectory_action',
14+
control_msgs.msg.FollowJointTrajectoryAction
15+
)
16+
self.rarm_move.wait_for_server()
17+
18+
self.larm_move = actionlib.SimpleActionClient(
19+
'/larm_controller/follow_joint_trajectory_action',
20+
control_msgs.msg.FollowJointTrajectoryAction
21+
)
22+
self.larm_move.wait_for_server()
23+
24+
@property
25+
def rarm_controller(self):
26+
return dict(
27+
controller_type='rarm_controller',
28+
controller_action='/rarm_controller/follow_joint_trajectory_action',
29+
controller_state='/rarm_controller/state',
30+
action_type=control_msgs.msg.FollowJointTrajectoryAction,
31+
joint_names=[j.name for j in self.robot.rarm.joint_list],
32+
)
33+
34+
@property
35+
def larm_controller(self):
36+
return dict(
37+
controller_type='larm_controller',
38+
controller_action='/larm_controller/follow_joint_trajectory_action',
39+
controller_state='/larm_controller/state',
40+
action_type=control_msgs.msg.FollowJointTrajectoryAction,
41+
joint_names=[j.name for j in self.robot.larm.joint_list],
42+
)
43+
44+
def default_controller(self):
45+
return [self.rarm_controller, self.larm_controller]
46+
47+
def move_arm(self, trajectory, arm='rarm', wait=True):
48+
if arm == 'rarm':
49+
self.send_trajectory(self.rarm_move, trajectory, wait)
50+
elif arm == 'larm':
51+
self.send_trajectory(self.larm_move, trajectory, wait)
52+
53+
def send_trajectory(self, client, trajectory, wait=True):
54+
goal = control_msgs.msg.FollowJointTrajectoryGoal()
55+
goal.trajectory = trajectory
56+
if wait:
57+
client.send_goal_and_wait(goal)
58+
else:
59+
client.send_goal(goal)

skrobot/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from skrobot.models.fetch import Fetch
44
from skrobot.models.kuka import Kuka
5+
from skrobot.models.nextage import Nextage
56
from skrobot.models.panda import Panda
67
from skrobot.models.pr2 import PR2
78
from skrobot.models.r8_6 import R8_6

skrobot/models/nextage.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
from cached_property import cached_property
2+
import numpy as np
3+
4+
from ..coordinates import CascadedCoords
5+
from ..data import nextage_urdfpath
6+
from ..model import RobotModel
7+
from .urdf import RobotModelFromURDF
8+
9+
10+
class Nextage(RobotModelFromURDF):
11+
"""
12+
- Nextage Open Official Information.
13+
14+
https://nextage.kawadarobot.co.jp/open
15+
16+
- Nextage Open Robot Description
17+
18+
https://github.com/tork-a/rtmros_nextage/tree/indigo-devel/nextage_description/urdf
19+
"""
20+
21+
def __init__(self, *args, **kwargs):
22+
super(Nextage, self).__init__(*args, **kwargs)
23+
24+
# End effector coordinates
25+
self.rarm_end_coords = CascadedCoords(
26+
pos=[-0.185, 0.0, -0.01],
27+
parent=self.RARM_JOINT5_Link,
28+
name='rarm_end_coords')
29+
self.rarm_end_coords.rotate(-np.pi / 2.0, 'y')
30+
31+
self.larm_end_coords = CascadedCoords(
32+
pos=[-0.185, 0.0, -0.01],
33+
parent=self.LARM_JOINT5_Link,
34+
name='larm_end_coords')
35+
self.larm_end_coords.rotate(-np.pi / 2.0, 'y')
36+
37+
self.head_end_coords = CascadedCoords(
38+
pos=[0.06, 0, 0.025],
39+
parent=self.HEAD_JOINT1_Link,
40+
name='head_end_coords')
41+
self.head_end_coords.rotate(np.deg2rad(90), 'y')
42+
43+
self.reset_pose()
44+
45+
@cached_property
46+
def default_urdf_path(self):
47+
return nextage_urdfpath()
48+
49+
def reset_pose(self):
50+
angle_vector = [
51+
0.0,
52+
0.0,
53+
0.0,
54+
np.deg2rad(0.6),
55+
0.0,
56+
np.deg2rad(-100),
57+
np.deg2rad(-15.2),
58+
np.deg2rad(9.4),
59+
np.deg2rad(-3.2),
60+
np.deg2rad(-0.6),
61+
0.0,
62+
np.deg2rad(-100),
63+
np.deg2rad(15.2),
64+
np.deg2rad(9.4),
65+
np.deg2rad(3.2),
66+
]
67+
self.angle_vector(angle_vector)
68+
return self.angle_vector()
69+
70+
def reset_manip_pose(self):
71+
"""Reset robot to manipulation pose (same as reset_pose for Nextage)"""
72+
return self.reset_pose()
73+
74+
@cached_property
75+
def rarm(self):
76+
link_names = ["RARM_JOINT{}_Link".format(i) for i in range(6)]
77+
links = [getattr(self, n) for n in link_names]
78+
joints = [l.joint for l in links]
79+
model = RobotModel(link_list=links, joint_list=joints)
80+
model.end_coords = self.rarm_end_coords
81+
return model
82+
83+
@cached_property
84+
def larm(self):
85+
link_names = ["LARM_JOINT{}_Link".format(i) for i in range(6)]
86+
links = [getattr(self, n) for n in link_names]
87+
joints = [l.joint for l in links]
88+
model = RobotModel(link_list=links, joint_list=joints)
89+
model.end_coords = self.larm_end_coords
90+
return model
91+
92+
@cached_property
93+
def head(self):
94+
link_names = ["HEAD_JOINT{}_Link".format(i) for i in range(2)]
95+
links = [getattr(self, n) for n in link_names]
96+
joints = [l.joint for l in links]
97+
model = RobotModel(link_list=links, joint_list=joints)
98+
model.end_coords = self.head_end_coords
99+
return model

0 commit comments

Comments
 (0)