Exemple #1
0
    def get_command(self, cur, goal, dT):
        """
        cur: ChassisState
        goal: ChassisState
        dT: float
        """
        desired = ChassisState()

        t_err = cur.t - goal.t
        x_err = cur.x - goal.y
        y_err = cur.y - goal.y
        # From section 5.12, https://www.dis.uniroma1.it/~labrob/pub/papers/Ramsete01.pdf
        desired.vx = (goal.vx * math.cos(t_err) +
                      self.gain_fn(goal.vx, goal.vt, self.b, self.zeta) *
                      (x_err * math.cos(goal.t) + y_err * math.sin(goal.t)))
        desired.vt = (
            goal.vt + (self.b * goal.vx * math.sin(t_err) / t_err) *
            (y_err * math.cos(goal.t) - x_err * math.sin(goal.t)) +
            self.gain_fn(goal.vx, goal.vt, self.b, self.zeta) * t_err)

        return desired
    def __init__(self):
        """
        Initializes ROS and necessary services and publishers.
        """

        rospy.init_node("chassis_planning"
                        # disable_signals=True
                        # log_level=rospy.DEBUG
                        )
        rospy.on_shutdown(self.shutdown_hook)

        self.base_max_speed = rospy.get_param("~base_max_speed",
                                              0.36)  # m/s, absolute max: 0.36
        self.base_max_ang_v = rospy.get_param("~base_max_ang_v",
                                              0.7)  # rad/s, absolute max: 7.0
        self.kP = rospy.get_param("~kP", 3.0)
        self.kA = rospy.get_param("~kA", 8.0)
        self.kB = rospy.get_param("~kB", -1.5)

        self.twist_command = geometry_msgs.msg.Twist()
        self.cmd_vel_pub = rospy.Publisher("cmd_vel",
                                           geometry_msgs.msg.Twist,
                                           queue_size=100)

        self.result = ChassisResult()

        self.pos_tolerance = 0.01  # m
        self.angle_tolerance = 0.05  # rad
        self.base_speed = self.base_max_speed
        self.base_ang_v = self.base_max_ang_v

        self.min_ang_v = 0.1  # rad/s, cold start minimum: 0.75
        self.min_speed = 0.01  # m/s

        self.base_link_frame = "base_link"
        self.map_frame = "map"
        self.chassis_action_name = rospy.get_param("~chassis_action_name",
                                                   "chassis_actions")

        self.chassis_action_name = rospy.get_param("~chassis_action_name",
                                                   "chassis_actions")
        self.chassis_server = actionlib.SimpleActionServer(
            self.chassis_action_name,
            ChassisAction,
            self.chassis_callback,
            auto_start=False)
        self.chassis_server.start()
        rospy.loginfo("[%s] server started" % self.chassis_action_name)

        self.tf_buffer = tf2_ros.Buffer()
        self.tf_listener = tf2_ros.TransformListener(self.tf_buffer)
        self.state = ChassisState()

        self.controller = GoalController()
        self.controller.set_constants(self.kP, self.kA, self.kB)
        # self.controller.set_constants(3.5, 20.0, -1.0)
        self.controller.forward_movement_only = False

        self.chassis_ready_service_name = "chassis_ready_service"
        rospy.loginfo("Setting up service %s" %
                      self.chassis_ready_service_name)
        self.chassis_ready_srv = rospy.Service(self.chassis_ready_service_name,
                                               Trigger,
                                               self.chassis_ready_callback)
        rospy.loginfo("%s service is ready" % self.chassis_ready_service_name)

        rospy.loginfo("[%s] --- Dodobot chassis planning is up! ---" %
                      self.chassis_action_name)
    def goto_pose(self, params):
        default_val = None  # float("nan")
        goal_x = params.get("goal_x", default_val)
        goal_y = params.get("goal_y", default_val)
        goal_angle = params.get("goal_angle", default_val)

        self.base_speed = params.get("base_speed", self.base_speed)
        self.base_ang_v = params.get("base_ang_v", self.base_ang_v)
        self.pos_tolerance = params.get("pos_tolerance", self.pos_tolerance)
        self.angle_tolerance = params.get("angle_tolerance",
                                          self.angle_tolerance)
        drive_forwards = bool(params.get("drive_forwards"))

        goal_state = ChassisState(goal_x, goal_y, goal_angle)
        rospy.loginfo("Current pose: %s. Goal pose: %s" %
                      (self.state, goal_state))

        self.controller.max_linear_speed = self.base_speed
        self.controller.min_linear_speed = self.min_speed
        self.controller.max_angular_speed = self.base_ang_v
        self.controller.min_angular_speed = self.min_ang_v
        self.controller.linear_tolerance = self.pos_tolerance
        self.controller.angular_tolerance = self.angle_tolerance
        self.controller.reverse_direction = not drive_forwards

        rate = rospy.Rate(60.0)
        prev_time = rospy.Time.now()

        was_at_goal = False
        am_at_goal_timeout = rospy.Duration(0.25)
        am_at_goal_timer = rospy.Time.now()

        while True:
            rate.sleep()
            self.update_current_pose()
            rospy.loginfo("goal: %s, current: %s, error: %s" %
                          (goal_state, self.state, goal_state - self.state))

            is_at_goal = self.controller.at_goal(self.state, goal_state)
            if is_at_goal:
                break
            # if is_at_goal and abs(command_state.vx) < 0.001 and abs(command_state.vt) < 0.001:
            #     break
            # if is_at_goal:
            #     if is_at_goal != was_at_goal:
            #         am_at_goal_timer = rospy.Time.now()
            #         was_at_goal = is_at_goal
            #         self.send_stop()
            #     if rospy.Time.now() - am_at_goal_timer > am_at_goal_timeout:
            #         break
            # else:
            #     was_at_goal = is_at_goal

            current_time = rospy.Time.now()
            dt = (current_time - prev_time).to_sec()
            prev_time = current_time

            command_state = self.controller.get_command(
                self.state, goal_state, dt)
            self.send_cmd(command_state.vx, command_state.vt)

            if self.controller.is_stuck():
                rospy.logwarn("Robot got stuck during go to pose routine!")
                rospy.loginfo(
                    "goal: %s, current: %s, error: %s" %
                    (goal_state, self.state, goal_state - self.state))
                return False

            if self.check_cancelled():
                rospy.loginfo("Go to pose routine cancelled")
                return False

        rospy.loginfo("goto_pose command completed successfully!")
        rospy.loginfo("goal: %s, current: %s, error: %s" %
                      (goal_state, self.state, goal_state - self.state))
        return True
Exemple #4
0
    def get_velocity(self, cur, goal, dT):
        """
        cur: ChassisState
        goal: ChassisState
        dT: float
        """
        desired = ChassisState()

        goal_heading = math.atan2(goal.y - cur.y, goal.x - cur.x)
        if self.reverse_direction:
            goal_heading = self.normalize_pi(goal_heading + math.pi)
        a = -cur.t + goal_heading

        if goal.t is None:
            goal_t = goal_heading
        else:
            goal_t = goal.t

        # In Automomous Mobile Robots, they assume theta_G=0. So for
        # the error in heading, we have to adjust theta based on the
        # (possibly non-zero) goal theta.
        theta = self.normalize_pi(cur.t - goal_t)
        b = -theta - a

        # rospy.loginfo('cur=%f goal=%f a=%f b=%f', cur.theta, goal_heading,
        #               a, b)

        d = self.get_goal_distance(cur, goal)
        if self.forward_movement_only:
            direction = 1.0
            a = self.normalize_pi(a)
            b = self.normalize_pi(b)
        else:
            direction = math.copysign(1.0, math.cos(a))
            a = self.normalize_half_pi(a)
            b = self.normalize_half_pi(b)

        if self.reverse_direction:
            direction *= -1.0

        # rospy.loginfo('After normalization, a=%f b=%f', a, b)

        if abs(d) < self.linear_tolerance:
            desired.vx = 0.0
            desired.vt = self.kB * theta
        else:
            desired.vx = self.kP * d * direction
            desired.vt = self.kA * a + self.kB * b

        # TBD: Adjust velocities if linear or angular acceleration
        # too high.

        # Adjust velocities if X velocity is too high.
        if abs(desired.vx) > self.max_linear_speed:
            ratio = self.max_linear_speed / abs(desired.vx)
            desired.vx *= ratio
            desired.vt *= ratio

        # Adjust velocities if turning velocity too high.
        if abs(desired.vt) > self.max_angular_speed:
            ratio = self.max_angular_speed / abs(desired.vt)
            desired.vx *= ratio
            desired.vt *= ratio

        # Adjust velocities if too low, so robot does not stall.
        if abs(desired.vx) > 0 and abs(desired.vx) < self.min_linear_speed:
            ratio = self.min_linear_speed / abs(desired.vx)
            desired.vx *= ratio
            desired.vt *= ratio
        elif desired.vx == 0.0 and desired.vt != 0.0 and abs(
                desired.vt) < self.min_angular_speed:
            ratio = self.min_angular_speed / abs(desired.vt)
            desired.vx *= ratio
            desired.vt *= ratio

        return desired
Exemple #5
0
 def get_command(self, current_state, goal_state, dT):
     return ChassisState()