def publish(self):
        if not self._initialized:
            return
        now = rospy.Time.now()

        g_msg = AprilTagDetectionArray()
        g_msg.header.stamp = now
        g_msg.header.frame_id = 'base_link'

        gv_msg = PoseArray()
        gv_msg.header.stamp = now
        gv_msg.header.frame_id = 'base_link'

        # alignment ...
        q = tx.quaternion_from_euler(np.pi / 2, 0, -np.pi / 2)

        for i in range(self._num_markers):
            txn = self._xyz[i]
            rxn = tx.quaternion_from_euler(*(self._rpy[i]))
            rxn = tx.quaternion_multiply(rxn, q)

            msg = AprilTagDetection()
            msg.id = [i]
            msg.size = [self._tag_size]

            pwcs = msg.pose
            pwcs.header.frame_id = 'base_link'
            pwcs.header.stamp = now
            fill_pose_msg(pwcs.pose.pose, txn, rxn)

            g_msg.detections.append(msg)
            gv_msg.poses.append(pwcs.pose.pose)
            self._tfb.sendTransform(txn,
                                    rxn,
                                    now,
                                    child='gt_tag_{}'.format(i),
                                    parent='base_link')

        self._gpub.publish(g_msg)
        self._gvpub.publish(gv_msg)
    def data_cb(self, joint_msg, detection_msgs):
        try:
            jorder = ['waist', 'shoulder', 'elbow', 'hand', 'wrist']
            j_idx = [joint_msg.name.index(j) for j in jorder]
            j = [joint_msg.position[i] for i in j_idx]
            j = np.concatenate((j, [0]))  # assume final joint is fixed
        except Exception as e:
            rospy.logerr_throttle(
                1.0, 'Joint Positions Failed : {} \n {}'.format(e, joint_msg))

        Xs = [np.eye(4) for _ in range(self._num_markers)]
        vis = [False for _ in range(self._num_markers)]

        if len(detection_msgs.detections) <= 0:
            return

        try:
            for pm in detection_msgs.detections:
                # pm.pose = pwcs
                # pm.pose.pose = pwc
                # pm.pose.pose.pose = p

                # TODO : technically requires tf.transformPose(...) for robustness.
                #pose = tf.transformPose(

                ps = PoseStamped(header=pm.pose.header, pose=pm.pose.pose.pose)
                # this transform should theoretically be painless + static
                # Optionally, store the transform beforehand and apply it
                ps = self._tfl.transformPose('stereo_optical_link', ps)

                q = ps.pose.orientation
                p = ps.pose.position
                m_id = pm.id[0]
                X = tx.compose_matrix(angles=tx.euler_from_quaternion(
                    [q.x, q.y, q.z, q.w]),
                                      translate=[p.x, p.y, p.z])
                i = self._m2i[m_id]  # transform tag id to index
                if i >= self._num_markers:
                    continue
                self._i2m[i] = m_id
                Xs[i] = X
                vis[i] = True
                self._seen[i] = True
        except Exception as e:
            rospy.logerr_throttle(1.0, 'TF Failed : {}'.format(e))

        Xs = np.float32(Xs)

        self._data.append((j, Xs, vis))

        self._step += 1
        rospy.loginfo_throttle(
            1.0, 'Current Step : {}; vis : {}'.format(self._step, vis))

        T = self._calib.eval_1(j, Xs, vis)  # == (1, M, 4, 4)

        now = rospy.Time.now()

        m_msg = AprilTagDetectionArray()
        m_msg.header.frame_id = 'base_link'
        m_msg.header.stamp = now

        pv_msg = PoseArray()
        pv_msg.header.stamp = now
        pv_msg.header.frame_id = 'base_link'

        for i in range(self._num_markers):
            if vis[i]:
                txn = tx.translation_from_matrix(T[i])
                rxn = tx.quaternion_from_matrix(T[i])

                msg = AprilTagDetection()
                msg.id = [self._i2m[i]]
                msg.size = [0.0]  # not really a thing

                pwcs = msg.pose
                pwcs.header.frame_id = 'base_link'
                pwcs.header.stamp = now
                fill_pose_msg(pwcs.pose.pose, txn, rxn)

                m_msg.detections.append(msg)
                pv_msg.poses.append(pwcs.pose.pose)
        self._pub.publish(m_msg)
        self._vpub.publish(pv_msg)
Example #3
0
    def data_cb(self, joint_msg, detection_msgs):
        # set info-mat param
        # reorder joint information
        try:
            jorder = ['waist', 'shoulder', 'elbow', 'hand', 'wrist']
            j_idx = [joint_msg.name.index(j) for j in jorder]
            j = [joint_msg.position[i] for i in j_idx]
            #j = np.random.normal(loc=j, scale=0.005)
            j = np.concatenate((j, [0]))  # assume final joint is fixed
        except Exception as e:
            rospy.logerr_throttle(
                1.0, 'Joint Positions Failed : {} \n {}'.format(e, joint_msg))

        if len(detection_msgs.detections) <= 0:
            # nothing detected, stop
            return

        # form pose ...
        p, q = fk(self._dh0, j)

        # testing ; add motion noise
        # p = np.random.normal(p, scale=0.01)
        # dq = qmath.rq(s=0.01)
        # q = qmath.qmul(dq, q)

        if not self._initialized:
            # save previous pose and don't proceed
            self._p = p
            self._q = q
            #self._slam.initialize(np.concatenate([p,q], axis=0))
            self._initialized = True
            return

        # form observations ...
        # nodes organized as:
        # [base_link, landmarks{0..m-1}, poses{0..p-1}]

        zs = []
        try:
            for pm in detection_msgs.detections:
                m_id = pm.id[0]
                ps = PoseStamped(header=pm.pose.header, pose=pm.pose.pose.pose)
                # TODO : compute+apply static transform?
                ps = self._tfl.transformPose('stereo_optical_link', ps)
                zp, zq = pmsg2pq(ps.pose)

                # testing; add observation noise
                # zp = np.random.normal(zp, scale=0.05)
                # dzq = qmath.rq(s=0.05)
                # zq = qmath.qmul(dzq, zq)

                dz = np.concatenate([zp, zq], axis=0)
                zi = self._m2i[m_id]
                if zi >= self._num_markers:
                    continue
                self._i2m[zi] = m_id
                zs.append([zi, dz, self._omega.copy()])
        except Exception as e:
            rospy.logerr_throttle(1.0, 'TF Failed : {}'.format(e))
            return

        ### semi-offline batch optimization
        ox = 1.0 * self._omega
        self._graph.append([p, q, zs])
        if len(self._graph) >= self._batch_size:
            n_poses = 1 + len(self._graph)  # add 1 for 0-node constraint
            nodes = []
            edges = []
            p_nodes = []
            z_nodes = [[] for _ in range(self._num_markers)]

            # add 0-node
            nodes.append(np.asarray([0, 0, 0, 0, 0, 0, 1]))

            for gi, g in enumerate(self._graph):
                xi = 1 + self._num_markers + gi  # current pose index

                # pose info
                gp, gq, gz = g
                gx = np.concatenate([gp, gq], axis=0)
                p_nodes.append(gx)

                edges.append([0, xi, gx, ox])
                # TODO : handle scenarios when a landmark didn't appear in 200 observations

                for zi, dz, zo in gz:
                    # edge from motion index to re-computed landmark index
                    edges.append([xi, 1 + zi, dz, zo])
                    zp_a, zq_a = qmath.x2pq(qmath.xadd_rel(gx, dz, T=False))
                    z_nodes[zi].append([zp_a, zq_a])

            # add landmark nodes
            if self._zinit:
                # use the previous initialization for landmarks
                for zp, zq in self._z_nodes:
                    zx = np.concatenate([zp, zq], axis=0)
                    nodes.append(zx)
            else:
                #initialize landmarks with average over 200 samples
                for zi, zn in enumerate(z_nodes):
                    zp, zq = zip(*zn)
                    zp = np.mean(zp, axis=0)
                    zq = qmath.qmean(zq)
                    zx = np.concatenate([zp, zq], axis=0)
                    nodes.append(zx)
                lms = nodes[1:1 + self._num_markers]
                lms = [qmath.x2pq(x) for x in lms]
                lms_re = [lms[self._m2i[i]] for i in range(self._num_markers)]
                self._pub_ze.publish(msgn(lms_re, rospy.Time.now()))
                self._zinit = True

            # add motion nodes
            for zx in p_nodes:
                nodes.append(zx)

            #print "PRE:"
            #print nodes[-self._num_markers:]
            nodes = self._slam.optimize(nodes,
                                        edges,
                                        max_iter=100,
                                        tol=1e-12,
                                        min_iter=100)
            #print "POST:"
            #print nodes[-self._num_markers:]

            lms = nodes[1:1 + self._num_markers]  # landmarks
            lms = [qmath.x2pq(x) for x in lms]
            self._z_nodes = lms
            lms_re = [lms[self._m2i[i]] for i in range(self._num_markers)]
            self._pub_ze.publish(msgn(lms_re, rospy.Time.now()))
            self._graph.clear()

            stamp = rospy.Time.now()
            g_msg = AprilTagDetectionArray()
            g_msg.header.stamp = stamp
            g_msg.header.frame_id = 'base_link'

            for i in range(self._num_markers):
                msg = AprilTagDetection()
                m_id = self._i2m[i]
                msg.id = [m_id]
                msg.size = [0.0]  # not really a thing
                msg.pose.pose.pose = pose(lms[i][0], lms[i][1])
                msg.pose.header.frame_id = 'base_link'
                msg.pose.header.stamp = stamp
                g_msg.detections.append(msg)
            self._gt_pub.publish(g_msg)
        return
        ### END: semi-offline batch optimization

        ### online slam with "reasonable" initialization?
        #if not self._zinit:
        #    # add entry ...
        #    gx = np.concatenate([p,q], axis=0)
        #    for z in zs:
        #        _, zi, dz, _ = z
        #        zi = zi - 2
        #        zp_a, zq_a = qmath.x2pq(qmath.xadd_rel(gx, dz, T=False))
        #        self._z_nodes[zi].append( (zp_a, zq_a) )

        #    # check entries ...
        #    ls = [len(e) for e in self._z_nodes]
        #    if np.all(np.greater_equal(ls, 100)):
        #        znodes = []
        #        for zi, zn in enumerate(self._z_nodes):
        #            zp, zq = zip(*zn)
        #            zp   = np.mean(zp, axis=0)
        #            zq   = qmath.qmean(zq)
        #            zx   = np.concatenate([zp,zq], axis=0)
        #            znodes.append(zx)
        #            self._slam._nodes[2+zi] = zx
        #            self._slam.initialize(gx)
        #            self._p = p
        #            self._q = q
        #        self._zinit = True
        #    return
        ### END : online slam with reasonable initialization

        #dp, dq = qmath.xrel(self._p, self._q, p, q)
        #dx     = np.concatenate([dp,dq], axis=0)
        dx = np.concatenate([p, q], axis=0)
        self._slam._nodes[0] = np.asarray([0, 0, 0, 0, 0, 0, 1],
                                          dtype=np.float32)

        # save p-q
        #self._p = p
        #self._q = q

        #        for zp, zq in self._z_nodes:
        #            zx = np.concatenate([zp,zq], axis=0)
        #            nodes.append(zx)

        # form dz ...
        mu = self._slam.step(x=dx, zs=zs)
        mu = np.reshape(mu, [-1, 7])
        ep, eq = qmath.x2pq(mu[1])
        gtp, gtq = fk(self._dh, j)

        #perr = np.subtract(ep,  gtp)
        #perr = np.linalg.norm(perr)
        #qerr = qmath.T(qmath.qmul(qmath.qinv(gtq), eq))
        #qerr = ((qerr + np.pi) % (2*np.pi)) - np.pi
        #qerr = np.linalg.norm(qerr)
        #epe, eqe = perr, qerr

        #perr = np.subtract(p,  gtp)
        #perr = np.linalg.norm(perr)
        #qerr = qmath.T(qmath.qmul(qmath.qinv(gtq), q))
        #qerr = ((qerr + np.pi) % (2*np.pi)) - np.pi
        #qerr = np.linalg.norm(qerr)
        #pe, qe = perr, qerr
        #print pe-epe, qe-eqe

        ez = [qmath.x2pq(e) for e in mu[2:]]

        stamp = rospy.Time.now()
        g_msg = AprilTagDetectionArray()
        g_msg.header.stamp = stamp
        g_msg.header.frame_id = 'base_link'

        for i in range(self._num_markers):
            msg = AprilTagDetection()
            m_id = self._i2m[i]
            msg.id = [m_id]
            msg.size = [0.0]  # not really a thing
            msg.pose.pose.pose = pose(ez[i][0], ez[i][1])
            msg.pose.header.frame_id = 'base_link'
            msg.pose.header.stamp = stamp
            g_msg.detections.append(msg)
        self._gt_pub.publish(g_msg)

        #ez     = [unparametrize(e) for e in mu[1:]]

        self._p, self._q = ep.copy(), eq.copy()
        #self._p, self._q = p, q

        t = joint_msg.header.stamp
        self._pub_ee.publish(msg1(ep, eq, t))
        self._pub_ze.publish(msgn(ez, t))
Example #4
0
    def publish(self):
        now = rospy.Time.now()



        if self._smooth:
            # smooth change over time ...
            if self._j_0 is None:
                self._j_0 = np.random.uniform(low=-np.pi, high=np.pi, size=5)
                self._j_1 = np.random.uniform(low=-np.pi, high=np.pi, size=5)
                jpos = np.copy(self._j_0)
            else:
                self._m_i += 1
                jpos = alerp(self._j_0, self._j_1, float(self._m_i) / self._m_n)
                if self._m_i >= self._m_n:
                    self._j_0 = np.copy(self._j_1)
                    self._j_1 = np.random.uniform(low=-np.pi, high=np.pi, size=5)
                    self._m_i = 0
        else:
            # completely random
            jpos = np.random.uniform(low=-np.pi, high=np.pi, size=5)

        if self._zero:
            jpos *= 0
        txn, rxn = fk(self._dh, np.concatenate( [jpos, [0]] ))

        ## base_link --> object
        M07 = [tx.compose_matrix(translate = xyz, angles=rpy) for (xyz, rpy) in zip(self._xyz, self._rpy)]

        ## base_link --> stereo_optical_link
        M06 = tx.compose_matrix(
                angles = tx.euler_from_quaternion(rxn),
                translate = txn) # T_0_6

        M06R = tx.quaternion_matrix(rxn)
        Rt =  M06R[:3,:3].T
        T  = -np.matmul(Rt, np.reshape(txn, [3,1]))
        M06i = np.zeros((4,4), dtype=np.float32)
        M06i[:3,:3] = Rt
        M06i[:3, 3] = T[:,0]
        M06i[ 3, 3] = 1.0

        m_msg = AprilTagDetectionArray()
        m_msg.header.stamp = now
        m_msg.header.frame_id = 'stereo_optical_link'

        pv_msg = PoseArray()
        pv_msg.header.stamp = now
        pv_msg.header.frame_id = 'stereo_optical_link'

        M67 = [np.matmul(M06i, M) for M in M07]

        for i in range(self._num_markers):
            if np.random.random() > self._p:
                continue
            M = M67[i]
            txn = tx.translation_from_matrix(M)
            rxn = tx.quaternion_from_matrix(M)
            if self._noise > 0.0:
                txn = np.random.normal(loc=txn, scale=self._noise)
                h = np.random.uniform(-self._noise, self._noise)
                ax = np.random.normal(size=3)
                ax /= np.linalg.norm(ax)
                d_rxn = tx.quaternion_about_axis(h, ax)
                rxn = tx.quaternion_multiply(d_rxn, rxn)
            
            msg = AprilTagDetection()
            msg.id = [i]
            msg.size = [0.0] # not really a thing

            pwcs = msg.pose
            pwcs.header.frame_id = 'stereo_optical_link'
            pwcs.header.stamp = now
            fill_pose_msg(pwcs.pose.pose, txn, rxn)

            m_msg.detections.append(msg)
            pv_msg.poses.append(pwcs.pose.pose)

        self._ppub.publish(m_msg)
        self._pvpub.publish(pv_msg)

        g_msg = AprilTagDetectionArray()
        g_msg.header.stamp = now
        g_msg.header.frame_id = 'base_link'

        gv_msg = PoseArray()
        gv_msg.header.stamp = now
        gv_msg.header.frame_id = 'base_link'

        for i in range(self._num_markers):
            M = M07[i]
            txn = tx.translation_from_matrix(M)
            rxn = tx.quaternion_from_matrix(M)

            msg = AprilTagDetection()
            msg.id = [i]
            msg.size = [0.0] # not really a thing

            pwcs = msg.pose
            pwcs.header.frame_id = 'base_link'
            pwcs.header.stamp = now
            fill_pose_msg(pwcs.pose.pose, txn, rxn)
            
            g_msg.detections.append(msg)
            gv_msg.poses.append(pwcs.pose.pose)

        if self._ground_truth:
            self._gpub.publish(g_msg)
            
        # visualizations are always published
        self._gvpub.publish(gv_msg)

        #gmsg = PoseStamped()
        #gmsg.header.frame_id = 'base_link'
        #txn = tx.translation_from_matrix(M07)
        #rxn = tx.quaternion_from_matrix(M07)
        #gmsg.header.stamp = now
        #fill_pose_msg(gmsg.pose, txn, rxn)
        #self._gpub.publish(gmsg)

        jmsg = JointState()
        jmsg.header.stamp = now
        jmsg.header.frame_id = 'map' #??

        jmsg.name = ['waist', 'shoulder', 'elbow', 'hand', 'wrist']
        jmsg.position = jpos
        jmsg.velocity = np.zeros_like(jpos)
        jmsg.effort = np.zeros_like(jpos)
        self._jpub.publish(jmsg)