[docs]defplan_cartesian_motion(self,robot,frames_WCF,start_configuration=None,group=None,options=None):"""Calculates a cartesian motion path (linear in tool space). Parameters ---------- robot : :class:`compas_fab.robots.Robot` The robot instance for which the cartesian motion path is being calculated. frames_WCF : list of :class:`compas.geometry.Frame` The frames through which the path is defined. start_configuration : :class:`Configuration`, optional The robot's full configuration, i.e. values for all configurable joints of the entire robot, at the starting position. group : str, optional The planning group used for calculation. options : dict, optional Dictionary containing kwargs for arguments specific to the client being queried. Returns ------- :class:`compas_fab.robots.JointTrajectory` The calculated trajectory. Notes ----- This will only work with robots that have 6 revolute joints. """# what is the expected behaviour of that function?# - Return all possible paths or select only the one that is closest to the start_configuration?# - Do we use a stepsize to sample in between frames or use only the input frames?# convert the frame WCF to RCFbase_frame=robot.get_base_frame(group=group,full_configuration=start_configuration)frames_RCF=[base_frame.to_local_coordinates(frame_WCF)forframe_WCFinframes_WCF]options=optionsor{}options.update({"keep_order":True})configurations_along_path=[]forframeinframes_RCF:configurations=list(robot.iter_inverse_kinematics(frame,options=options))configurations_along_path.append(configurations)paths=[]forconfigurationsinzip(*configurations_along_path):ifall(configurations):paths.append(configurations)ifnotlen(paths):raiseCartesianMotionError("No complete trajectory found.")# now select the path that is closest to the start configuration.first_configurations=[path[0]forpathinpaths]diffs=[sum([abs(d)fordinstart_configuration.iter_differences(c)])forcinfirst_configurations]idx=argmin(diffs)path=paths[idx]path=self.smooth_configurations(path)trajectory=JointTrajectory()trajectory.fraction=len(path)/len(frames_RCF)trajectory.joint_names=path[0].joint_namestrajectory.points=[JointTrajectoryPoint(config.joint_values,config.joint_types)forconfiginpath]trajectory.start_configuration=robot.merge_group_with_full_configuration(path[0],start_configuration,group)returntrajectory
[docs]defsmooth_configurations(self,configurations):joint_values_corrected=[]prev=smallest_joint_angles(configurations[0].joint_values)joint_values_corrected.append(prev)foriinrange(1,len(configurations)):curr=configurations[i].joint_valuescorrected=[]forp,cinzip(prev,curr):c1=c/abs(c)*(abs(c)%(2*math.pi))c2=c1-2*math.pic3=c1+2*math.pivalues=[c1,c2,c3]diffs=[math.fabs(p-v)forvinvalues]idx=argmin(diffs)corrected.append(values[idx])prev=correctedjoint_values_corrected.append(corrected)# now that the values are continuous, try to bring them all "down"fori,jinenumerate(zip(*joint_values_corrected)):minj,maxj=min(j),max(j)v1=minj+maxjv2=minj-2*math.pi+maxj-2*math.piv3=minj+2*math.pi+maxj+2*math.pivalues=[math.fabs(v)forvin[v1,v2,v3]]idx=argmin(values)ifidx==1:forkinrange(len(joint_values_corrected)):joint_values_corrected[k][i]-=2*math.pielifidx==2:forkinrange(len(joint_values_corrected)):joint_values_corrected[k][i]+=2*math.piforiinrange(len(joint_values_corrected)):configurations[i].joint_values=joint_values_corrected[i]returnconfigurations