88import rclpy
99from geometry_msgs .msg import Pose , PoseStamped
1010from pollen_msgs .srv import GetForwardKinematics , GetInverseKinematics
11+ from pollen_msgs .msg import IKRequest , ReachabilityState
1112from rclpy .lifecycle import LifecycleNode , State , TransitionCallbackReturn
1213from rclpy .qos import (HistoryPolicy , QoSDurabilityPolicy , QoSProfile ,
1314 ReliabilityPolicy )
2122 limit_orbita3d_joints ,
2223 limit_orbita3d_joints_wrist ,
2324 limit_theta_to_interval ,
24- tend_to_prefered_theta ,
2525 get_best_theta_to_current_joints ,)
2626from scipy .spatial .transform import Rotation
2727from sensor_msgs .msg import JointState
@@ -56,7 +56,9 @@ def __init__(self):
5656
5757 self .chain , self .fk_solver , self .ik_solver = {}, {}, {}
5858 self .fk_srv , self .ik_srv = {}, {}
59+ self .reachability_pub = {}
5960 self .target_sub , self .averaged_target_sub = {}, {}
61+ self .ik_target_sub = {}
6062 self .averaged_pose = {}
6163 self .max_joint_vel = {}
6264
@@ -129,10 +131,18 @@ def __init__(self):
129131 qos_profile = 5 ,
130132 )
131133
134+ self .reachability_pub [arm ] = self .create_publisher (
135+ msg_type = ReachabilityState ,
136+ topic = f"/{ arm } _reachability_states" ,
137+ qos_profile = 10 ,
138+ )
139+
132140 if arm .startswith ("l" ):
133141 q0 = [0.0 , np .pi / 2 , 0.0 , - np .pi / 2 , 0.0 , 0.0 , 0.0 ]
134142 else :
135143 q0 = [0.0 , - np .pi / 2 , 0.0 , - np .pi / 2 , 0.0 , 0.0 , 0.0 ]
144+
145+ # Keeping both on _target_pose mechanisms for compatibility reasons
136146 self .target_sub [arm ] = self .create_subscription (
137147 msg_type = PoseStamped ,
138148 topic = f"/{ arm } /target_pose" ,
@@ -149,6 +159,18 @@ def __init__(self):
149159 )
150160 self .logger .info (f'Adding subscription on "{ self .target_sub [arm ].topic } "...' )
151161
162+ self .ik_target_sub [arm ] = self .create_subscription (
163+ msg_type = IKRequest ,
164+ topic = f"/{ arm } /ik_target_pose" ,
165+ qos_profile = high_freq_qos_profile ,
166+ callback = partial (
167+ self .on_ik_target_pose ,
168+ name = arm ,
169+ forward_publisher = forward_position_pub ,
170+ ),
171+ )
172+ self .logger .info (f'Adding subscription on "{ self .ik_target_sub [arm ].topic } "...' )
173+
152174 self .averaged_target_sub [arm ] = self .create_subscription (
153175 msg_type = PoseStamped ,
154176 topic = f"/{ arm } /averaged_target_pose" ,
@@ -371,7 +393,7 @@ def inverse_kinematics_srv(
371393 M ,
372394 "discrete" ,
373395 current_joints = current_joints ,
374- interval_limit = [ - np . pi , np . pi ] ,
396+ constrained_mode = "unconstrained" ,
375397 current_pose = current_pose
376398 )
377399 # # self.logger.info(M)
@@ -394,8 +416,65 @@ def inverse_kinematics_srv(
394416
395417 return response
396418
419+ def on_ik_target_pose (self , msg : IKRequest , name , forward_publisher ):
420+ M = ros_pose_to_matrix (msg .pose .pose )
421+ constrained_mode = msg .constrained_mode
422+ continuous_mode = msg .continuous_mode
423+ preferred_theta = msg .preferred_theta
424+ d_theta_max = msg .d_theta_max
425+ order_id = msg .order_id
426+
427+ if continuous_mode == "undefined" :
428+ continuous_mode = "continuous"
429+
430+ if constrained_mode == "undefined" :
431+ constrained_mode = "unconstrained"
432+
433+ # if constrained_mode == "low_elbow":
434+ # interval_limit = [-4 * np.pi / 5, 0]
435+ # self.logger.info(f"Preferred theta: {preferred_theta}")
436+ # self.logger.info(f"Continuous mode: {continuous_mode}")
437+ # self.logger.info(f"Constrained mode: {constrained_mode}")
438+ # self.logger.info(f"Order ID: {order_id}")
439+ # self.logger.info(f"Max d_theta: {d_theta_max}")
440+
441+ if "arm" in name :
442+ current_joints = self .get_current_position (self .chain [name ])
443+ error , current_pose = forward_kinematics (
444+ self .fk_solver [name ],
445+ current_joints ,
446+ self .chain [name ].getNrOfJoints (),
447+ )
448+
449+ sol , is_reachable , state = self .control_ik .symbolic_inverse_kinematics (
450+ name ,
451+ M ,
452+ continuous_mode ,
453+ current_joints = current_joints ,
454+ constrained_mode = constrained_mode ,
455+ current_pose = current_pose ,
456+ d_theta_max = d_theta_max ,
457+ preferred_theta = preferred_theta ,
458+ )
459+ else :
460+ self .logger .error ("IK target pose should be only for the arms" )
461+ raise ValueError ("IK target pose should be only for the arms" )
462+
463+ msg = Float64MultiArray ()
464+ msg .data = sol
465+ forward_publisher .publish (msg )
466+ reachability_msg = ReachabilityState ()
467+ reachability_msg .header .stamp = self .get_clock ().now ().to_msg ()
468+ reachability_msg .header .frame_id = "torso"
469+ reachability_msg .is_reachable = is_reachable
470+ reachability_msg .state = state
471+ reachability_msg .order_id = order_id
472+ self .reachability_pub [name ].publish (reachability_msg )
473+
474+
397475 def on_target_pose (self , msg : PoseStamped , name , q0 , forward_publisher ):
398476 M = ros_pose_to_matrix (msg .pose )
477+
399478 if "arm" in name :
400479 current_joints = self .get_current_position (self .chain [name ])
401480 error , current_pose = forward_kinematics (
@@ -408,7 +487,7 @@ def on_target_pose(self, msg: PoseStamped, name, q0, forward_publisher):
408487 M ,
409488 "continuous" ,
410489 current_joints = current_joints ,
411- interval_limit = [ - 4 * np . pi / 5 , 0 ],
490+ constrained_mode = "low_elbow" , # "unconstrained"
412491 current_pose = current_pose
413492 )
414493 else :
0 commit comments