2121
2222# ------------------------------------------------------------------------ #
2323@block
24- class Forward_Kinematics (FunctionBlock ):
24+ class FKine (FunctionBlock ):
2525 """
26- :blockname:`FORWARD_KINEMATICS `
26+ :blockname:`FKINE `
2727
2828 .. table::
2929 :align: left
@@ -74,9 +74,9 @@ def output(self, t=None):
7474 return [self .robot .fkine (self .inputs [0 ], ** self .args )]
7575
7676@block
77- class Inverse_Kinematics (FunctionBlock ):
77+ class IKine (FunctionBlock ):
7878 """
79- :blockname:`INVERSE_KINEMATICS `
79+ :blockname:`IKINE `
8080
8181 .. table::
8282 :align: left
@@ -385,10 +385,59 @@ def output(self, t=None):
385385 return [T ]
386386
387387# ------------------------------------------------------------------------ #
388+
388389@block
389- class Foward_Dynamics ( TransferBlock ):
390+ class TR2T ( FunctionBlock ):
390391 """
391- :blockname:`FORWARD_DYNAMICS`
392+ :blockname:`TR2T`
393+
394+ .. table::
395+ :align: left
396+
397+ +------------+----------+---------+
398+ | inputs | outputs | states |
399+ +------------+----------+---------+
400+ | 1 | 3 | 0 |
401+ +------------+----------+---------+
402+ | SE3 | float | |
403+ +------------+----------+---------+
404+ """
405+
406+ def __init__ (self , * inputs , ** kwargs ):
407+ """
408+ :param T: the transform
409+ :type T: SE3
410+ :param ``*inputs``: Optional incoming connections
411+ :type ``*inputs``: Block or Plug
412+ :param ``**kwargs``: common Block options
413+ :return: a POINT2TR block
414+ :rtype: Point2Tr instance
415+
416+ The block has one input port:
417+
418+ 1. a 3D point as an ndarray(3)
419+
420+ and one output port:
421+
422+ 1. T as an SE3 with its position part replaced by the input
423+
424+ :seealso: :func:`spatialmath.base.delta2tr`
425+ """
426+ super ().__init__ (nin = 1 , nout = 3 , inputs = inputs , ** kwargs )
427+ self .type = 'tr2t'
428+
429+ self .inport_names (('T' ,))
430+ self .outport_names (('x' , 'y' , 'z' ))
431+
432+ def output (self , t = None ):
433+ t = self .inputs [0 ].t
434+ return list (t )
435+
436+ # ------------------------------------------------------------------------ #
437+ @block
438+ class FDyn (TransferBlock ):
439+ """
440+ :blockname:`FDYN`
392441
393442 .. table::
394443 :align: left
@@ -468,9 +517,9 @@ def deriv(self):
468517 return np .r_ [qd , qdd ]
469518
470519@block
471- class Inverse_Dynamics (FunctionBlock ):
520+ class IDyncs (FunctionBlock ):
472521 """
473- :blockname:`INVERSE_DYNAMICS `
522+ :blockname:`IDYN `
474523
475524 .. table::
476525 :align: left
@@ -571,6 +620,7 @@ def __init__(self, robot=None, *inputs, q0=None, backend=None, **kwargs):
571620 """
572621 super ().__init__ (nin = 1 , inputs = inputs , ** kwargs )
573622 self .type = 'armplot'
623+ self .inport_names (('q' ,))
574624
575625 if q0 is None :
576626 q0 = np .zeros ((robot .n ,))
@@ -592,7 +642,9 @@ def step(self):
592642 if self .bd .options .graphics :
593643
594644 self .robot .q = self .inputs [0 ]
595- self .env .step ()
645+
646+ if self .bd .options .animation :
647+ self .env .step ()
596648
597649 super ().step ()
598650
@@ -601,8 +653,6 @@ def done(self, block=False, **kwargs):
601653 plt .show (block = block )
602654
603655 super ().done ()
604-
605-
606656@block
607657class Traj (FunctionBlock ):
608658 """
@@ -709,6 +759,132 @@ def output(self, t=None):
709759 return [np .hstack (y ), np .hstack (yd ), np .hstack (ydd )]
710760
711761@block
762+ class JTraj (SourceBlock ):
763+ """
764+ :blockname:`JTRAJ`
765+
766+ .. table::
767+ :align: left
768+
769+ +------------+------------+---------+
770+ | inputs | outputs | states |
771+ +------------+------------+---------+
772+ | 0 | 3 | 0 |
773+ +------------+------------+---------+
774+ | | ndarray(n) | |
775+ +------------+------------+---------+
776+ """
777+
778+ def __init__ (self , q0 , qf , qd0 = None , qdf = None , T = None , * inputs , ** kwargs ):
779+ """
780+ Compute a joint-space trajectory
781+
782+ :param q0: initial joint coordinate
783+ :type q0: array_like(n)
784+ :param qf: final joint coordinate
785+ :type qf: array_like(n)
786+ :param tv: time vector or number of steps
787+ :type tv: array_like or int
788+ :param qd0: initial velocity, defaults to zero
789+ :type qd0: array_like(n), optional
790+ :param qd1: final velocity, defaults to zero
791+ :type qd1: array_like(n), optional
792+ :param ``*inputs``: Optional incoming connections
793+ :type ``*inputs``: Block or Plug
794+ :param ``**kwargs``: common Block options
795+ :return: TRAJ block
796+ :rtype: Traj instance
797+
798+ - ``tg = jtraj(q0, qf, N)`` is a joint space trajectory where the joint
799+ coordinates vary from ``q0`` (M) to ``qf`` (M). A quintic (5th order)
800+ polynomial is used with default zero boundary conditions for velocity and
801+ acceleration. Time is assumed to vary from 0 to 1 in ``N`` steps.
802+
803+ - ``tg = jtraj(q0, qf, t)`` as above but ``t`` is a uniformly-spaced time
804+ vector
805+
806+ The return value is an object that contains position, velocity and
807+ acceleration data.
808+
809+ Notes:
810+
811+ - The time vector, if given, scales the velocity and acceleration outputs
812+ assuming that the time vector starts at zero and increases
813+ linearly.
814+
815+ :seealso: :func:`ctraj`, :func:`qplot`, :func:`~SerialLink.jtraj`
816+ """
817+ super ().__init__ (nin = 0 , nout = 3 , ** kwargs )
818+ self .blockclass = 'jtraj'
819+ self .type = 'source'
820+ self .outport_names (('q' , 'qd' , 'qdd' ,))
821+ self .T = T
822+
823+ q0 = base .getvector (q0 )
824+ qf = base .getvector (qf )
825+
826+ if not len (q0 ) == len (qf ):
827+ raise ValueError ('q0 and q1 must be same size' )
828+
829+ if qd0 is None :
830+ qd0 = np .zeros (q0 .shape )
831+ else :
832+ qd0 = getvector (qd0 )
833+ if not len (qd0 ) == len (q0 ):
834+ raise ValueError ('qd0 has wrong size' )
835+ if qdf is None :
836+ qdf = np .zeros (q0 .shape )
837+ else :
838+ qd1 = getvector (qdf )
839+ if not len (qd1 ) == len (q0 ):
840+ raise ValueError ('qd1 has wrong size' )
841+
842+ self .q0 = q0
843+ self .qf = qf
844+ self .qd0 = qd0
845+ self .qdf = qf
846+
847+
848+ def start (self ):
849+
850+ if self .T is None :
851+ self .T = self .bd .state .T
852+ tscal = self .T
853+
854+ q0 = self .q0
855+ qf = self .qf
856+ qd0 = self .qd0
857+ qdf = self .qdf
858+
859+ # compute the polynomial coefficients
860+ A = 6 * (qf - q0 ) - 3 * (qdf + qd0 ) * tscal
861+ B = - 15 * (qf - q0 ) + (8 * qd0 + 7 * qdf ) * tscal
862+ C = 10 * (qf - q0 ) - (6 * qd0 + 4 * qdf ) * tscal
863+ E = qd0 * tscal
864+ F = q0
865+
866+ self .coeffs = np .array ([A , B , C , np .zeros (A .shape ), E , F ])
867+ self .dcoeffs = np .array (
868+ [np .zeros (A .shape ), 5 * A , 4 * B , 3 * C , np .zeros (A .shape ), E ])
869+ self .ddcoeffs = np .array ([
870+ np .zeros (A .shape ), np .zeros (A .shape ),
871+ 20 * A , 12 * B , 6 * C , np .zeros (A .shape )])
872+
873+ def output (self , t = None ):
874+
875+ tscal = self .T
876+ tt = np .array ([t ** 5 , t ** 4 , t ** 3 , t ** 2 , t , 1 ]).T
877+
878+ qt = tt @ self .coeffs
879+
880+ # compute velocity
881+ qdt = tt @ self .dcoeffs / tscal
882+
883+ # compute acceleration
884+ qddt = tt @ self .ddcoeffs / tscal ** 2
885+
886+ return [qt , qdt , qddt ]
887+ @block
712888class CirclePath (SourceBlock ):
713889 """
714890 :blockname:`CIRCLEPATH`
0 commit comments