Exemple #1
0
class PickupPalletServer:
    def __init__(self):
        self.wheel_cmd_publisher = rospy.Publisher(WHEEL_CMD_TOPIC,
                                                   Twist,
                                                   queue_size=1)
        self.lift_cmd_publisher = rospy.Publisher(LIFT_CONTROL_TOPIC,
                                                  Float64,
                                                  queue_size=1)
        self.tf_listener = tf.TransformListener()

        rospy.wait_for_service('gazebo/get_model_state')
        rospy.wait_for_service('gazebo/get_link_state')
        self.modelStateService = rospy.ServiceProxy('gazebo/get_model_state',
                                                    GetModelState)
        self.linkStateService = rospy.ServiceProxy('gazebo/get_link_state',
                                                   GetLinkState)

        self.server = actionlib.SimpleActionServer(ACTION_SERVER_NAME,
                                                   PickupPalletAction,
                                                   self.execute, False)
        self.server.start()
        print('Server started')

    def execute(self, goal):
        rate = rospy.Rate(PUBLISH_RATE)
        self.targetPallet = goal.palletName.data
        self.done = False
        self.state = CONTROL_STATE_ALIGN
        self.start_time = rospy.get_time()
        self.lookupTransfrom()
        self.findTarget()

        while not rospy.is_shutdown() and not self.done:
            if self.server.is_preempt_requested():
                rospy.loginfo('Pickup Canceled')
                self.server.set_preempted()
                break

            self.lookupTransfrom()

            if self.state == CONTROL_STATE_ALIGN:
                self.control_alignment()
            elif self.state == CONTROL_STATE_LIFT:
                self.control_lift()
            elif self.state == CONTROL_STATE_DONE:
                self.server.set_succeeded()
                break

            rate.sleep()

    def findTarget(self):
        v_heading = np.array(
            [math.cos(self.robot_theta),
             math.sin(self.robot_theta)])
        v = np.array(
            [math.cos(self.pallet_theta),
             math.sin(self.pallet_theta)])
        if (np.dot(v, v_heading) > 0):
            self.target_position = self.pallet_position - (v * ALIGN_DISTANCE)
            self.target_theta = self.pallet_theta
            self.target_line = Line(self.target_position,
                                    self.target_position - v)
        else:
            self.target_position = self.pallet_position + (v * ALIGN_DISTANCE)
            self.target_theta = (self.pallet_theta + math.pi)
            self.target_line = Line(self.target_position,
                                    self.target_position + v)

    def lookupTransfrom(self):
        try:
            (trans,
             rot) = self.tf_listener.lookupTransform(MAP_FRAME, ROBOT_FRAME,
                                                     rospy.Time(0))
            euler = tf.transformations.euler_from_quaternion(
                [rot[0], rot[1], rot[2], rot[3]])
            self.robot_position = np.array([trans[0], trans[1]])
            self.robot_theta = euler[2]

            modelState = self.modelStateService(model_name=self.targetPallet)
            modelPos = modelState.pose.position
            self.pallet_position = np.array([modelPos.x, modelPos.y])
            q = modelState.pose.orientation
            euler = tf.transformations.euler_from_quaternion(
                [q.x, q.y, q.z, q.w])
            self.pallet_theta = euler[2]
        except Exception as e:
            rospy.logwarn('Failed to lookup transform')
            print(e)
            return 0

    def control_alignment(self):
        v_pallet = self.pallet_position - self.robot_position
        v_target = self.target_position - self.robot_position
        v_heading = np.array(
            [math.cos(self.robot_theta),
             math.sin(self.robot_theta)])
        distance = np.linalg.norm(v_pallet)

        if distance < ALIGN_DISTANCE:
            #self.server.set_succeeded()
            rospy.loginfo('Aligned')
            self.state = CONTROL_STATE_LIFT
            return

        theta_target = math.atan2(v_target[1], v_target[0])

        lineDot = np.dot(self.target_line.normal(), v_pallet)
        lineDistance = self.target_line.distance(self.robot_position)
        lineErr = np.sign(lineDot) * lineDistance

        alignErr = self.target_theta - self.robot_theta
        if (alignErr > math.pi):
            alignErr -= 2 * math.pi
        elif (alignErr < -math.pi):
            alignErr += 2 * math.pi

        headingErr = theta_target - self.robot_theta
        if (headingErr > math.pi):
            headingErr -= 2 * math.pi
        elif (headingErr < -math.pi):
            headingErr += 2 * math.pi

        if lineDistance > 0.5:
            steering = (alignErr * 0.2) + (headingErr * 1.5) + (lineErr * 1.0)
        elif distance > 2.4:
            steering = (alignErr * 2.0) + (headingErr * 4.0) + (lineErr * 0.5)
        else:
            steering = (alignErr * 3.0) + (headingErr * 0.0) + (lineErr * 1.0)

        target_turn = max(min(steering, MAX_TURN), -MAX_TURN)

        rospy.loginfo(
            'HErr: %.2f, AErr: %.2f, PDist: %.2f, Steering: %.2f, Dist: %.2f',
            headingErr, alignErr, lineErr, steering, distance)

        target_speed = 0.2
        angular = (target_speed / LENGTH) * math.tan(target_turn)

        cmd = Twist()
        cmd.linear = Vector3(target_speed, 0, 0)
        cmd.angular = Vector3(0, 0, angular)
        self.wheel_cmd_publisher.publish(cmd)

    def control_lift(self):

        lift_link = self.linkStateService(link_name=LIFT_LINK_NAME)
        height = lift_link.link_state.pose.position.z

        if height < 0.5:
            self.lift_cmd_publisher.publish(0.5)
        else:
            self.lift_cmd_publisher.publish(0)
            rospy.loginfo('Lift is up')
            self.state = CONTROL_STATE_DONE
Exemple #2
0
class FollowPathServer:
    def __init__(self):
        self.wheel_cmd_publisher = rospy.Publisher(WHEEL_CONTROL_TOPIC,
                                                   Twist,
                                                   queue_size=1)
        self.tf_listener = tf.TransformListener()

        self.pub_marker = rospy.Publisher('/path/marker',
                                          Marker,
                                          queue_size=10)

        self.server = actionlib.SimpleActionServer(ACTION_SERVER_NAME,
                                                   FollowPathAction,
                                                   self.execute, False)
        self.server.start()
        print('Server started')

    def execute(self, goal):
        self.done = False
        self.path = goal.poses
        self.pathIndex = 0
        self.updatePose()
        self.nextPathIndex()
        self.publishPathMarker(self.path, 99)

        rate = rospy.Rate(PUBLISH_RATE)
        while not rospy.is_shutdown() and not self.done:
            if self.server.is_preempt_requested():
                rospy.loginfo('Path Canceled')
                self.server.set_preempted()
                break

            self.updatePose()

            pos = np.array([self.pose[0], self.pose[1]])
            v1 = self.pathLine.p2 - pos

            pathDot = np.dot(self.pathLine.normal(), v1)
            endDot = np.dot(v1, self.pathLine.direction())

            endDistance = self.endLine.distance(pos)
            pathDistance = self.pathLine.distance(pos)
            pathErr = (-np.sign(pathDot)) * self.direction * pathDistance

            if (pathDistance > MAX_PATH_ERROR):
                self.server.set_aborted()
                rospy.loginfo('Too far off path')
                break

            if (endDot < 0):
                ## Aim for the next point on the path
                self.nextPathIndex()
                continue

            delta = self.getHeadingError()
            steering = delta * 3.0 + pathErr * 2.5
            target_turn = max(min(steering, MAX_TURN), -MAX_TURN)

            target_speed = 0.5 * self.direction
            angular = (target_speed / LENGTH) * math.tan(target_turn)

            cmd = Twist()
            cmd.linear = Vector3(target_speed, 0, 0)
            cmd.angular = Vector3(0, 0, angular)
            self.wheel_cmd_publisher.publish(cmd)

            rate.sleep()

        self.clearPathMarker(99)

    def updatePose(self):
        try:
            (trans,
             rot) = self.tf_listener.lookupTransform('/map', '/base_link',
                                                     rospy.Time(0))
            euler = tf.transformations.euler_from_quaternion(
                [rot[0], rot[1], rot[2], rot[3]])

            self.pose = [trans[0], trans[1], euler[2]]
        except:
            rospy.logwarn('Failed to lookup transform')

    def nextPathIndex(self):
        self.pathIndex += 1
        if (self.pathIndex >= len(self.path)):
            ## End of the path
            position = Point(self.pose[0], self.pose[1], 0)
            q = tf.transformations.quaternion_from_euler(0, 0, self.pose[2])
            orientation = Quaternion(q[0], q[1], q[2], q[3])
            finalPose = Pose(position, orientation)

            self.server.set_succeeded(FollowPathResult(finalPose))
            cmd = Twist(Vector3(0, 0, 0), Vector3(0, 0, 0))  ## Stop
            self.wheel_cmd_publisher.publish(cmd)
            self.done = True
            rospy.loginfo('Success')
            return

        targetPose = self.path[self.pathIndex]
        prevPose = self.path[self.pathIndex - 1]
        p1 = np.array([prevPose.position.x, prevPose.position.y])
        p2 = np.array([targetPose.position.x, targetPose.position.y])
        self.pathLine = Line(p1, p2)
        self.endLine = Line(p2, p2 + self.pathLine.normal())

        if (self.pathLine.length() < EPSILON):
            self.nextPathIndex()
            return

        headingErr = self.getHeadingError()
        if (abs(headingErr) > math.pi / 2):
            self.direction = -1
        else:
            self.direction = 1

    def getHeadingError(self):
        targetHeading = self.pathLine.heading()

        currentHeading = self.pose[2]
        delta = targetHeading - currentHeading
        if (delta > math.pi):
            delta -= 2 * math.pi
        elif (delta < -math.pi):
            delta += 2 * math.pi

        return delta

    def publishPathMarker(self, path, id):
        m = Marker()
        m.header.frame_id = "map"
        m.type = Marker.LINE_STRIP
        m.action = Marker.ADD

        m.points = []
        for pose in path:
            p = Point(pose.position.x, pose.position.y, 0.1)
            m.points.append(p)

        m.scale = Vector3(0.1, 0.1, 0.1)
        m.color = ColorRGBA(0, 1, 0, 1)
        m.id = id
        self.pub_marker.publish(m)

    def clearPathMarker(self, id):
        m = Marker()
        m.action = Marker.DELETE
        m.id = id
        self.pub_marker.publish(m)