예제 #1
0
    def diff_get_error_angle(self):
        '''
        Input:
            self.Vy
            self.Wz
            self.theta
        Return ( (ref_ang, error_theta) , (ref_ang, error_theta) )
                 ^ leader                  ^ follower
        '''
        # Get refenrence angle
        R = self.get_radius_of_rotation(self.Vx, self.Wz)
        ref_ang_L = atan2(TOW_CAR_LENGTH / 2.0, abs(R))
        if not is_same_sign(R, self.Vx):
            ref_ang_L *= -1

        # Follower reverse ref_ang
        ref_ang_F = normalize_angle(pi - ref_ang_L)

        # Get error theta
        error_theta_L = normalize_angle(ref_ang_L - self.theta_L)
        error_theta_F = normalize_angle(ref_ang_F - self.theta_F)

        # In-place rotation, Find the nearest 90 degree to ref.
        if  abs(R) < INPLACE_ROTATION_R and\
            abs(error_theta_L) > pi/2 and\
            abs(error_theta_F) > pi/2:
            # ref_ang_L and ref_ang_F must have same sign
            ref_ang_L *= -1
            ref_ang_F *= -1
            error_theta_L = normalize_angle(ref_ang_L - self.theta_L)
            error_theta_F = normalize_angle(ref_ang_F - self.theta_F)

        return ((ref_ang_L, error_theta_L), (ref_ang_F, error_theta_F))
    def car2_feedback_cb(self, data):
        '''
        '''
        quaternion = (
            data.pose.orientation.x,
            data.pose.orientation.y,
            data.pose.orientation.z,
            data.pose.orientation.w)
        euler = transformations.euler_from_quaternion(quaternion)

        yaw = atan2(data.pose.position.y, data.pose.position.x)
        if data.pose.position.x != L * cos(yaw) or data.pose.position.y != L * sin(yaw):
            data.pose.position.x = L * cos(yaw)
            data.pose.position.y = L * sin(yaw)
            self.x = L * cos(yaw)
            self.y = L * sin(yaw)
            self.theta = normalize_angle (euler[2])
            SERVER.setPose( data.marker_name, data.pose )
        else: 
            self.x     = data.pose.position.x
            self.y     = data.pose.position.y
            self.theta = normalize_angle (euler[2])
        
        # self.update_markers()
        SERVER.applyChanges()
예제 #3
0
    def publish_theta(self):
        # Get theta1 or theta2
        if ROLE == "leader":  # Theta1
            self.theta = normalize_angle(-self.shelf_finder_base.center[2])
        elif ROLE == "follower":  # Theta2
            self.theta = normalize_angle(-self.shelf_finder_base.center[2] +
                                         pi)
        self.pub_theta.publish(self.theta)

        # Send tf
        if ROLE == "leader":
            send_tf((TOW_CAR_LENGTH / 2.0, 0, self.theta), "carB/base_link",
                    "car1/base_link")
예제 #4
0
    def crab_get_error_angle(self):
        '''
        Input:
            self.Vx
            self.Vy
            self.theta
        Return ( (ref_ang, error_theta) , (ref_ang, error_theta) , T/F)
                 ^ leader                  ^ follower
        '''
        # Get refenrence angle
        ref_ang_L = atan2(self.Vy, self.Vx)
        ref_ang_F = normalize_angle(ref_ang_L + pi)

        # Get error angle
        error_theta_L = normalize_angle(ref_ang_L - self.theta_L)
        error_theta_F = normalize_angle(ref_ang_F - self.theta_F)

        # Go backward or forward?
        is_forward = True
        if  abs(error_theta_L) > pi/2 and\
            abs(error_theta_F) > pi/2 and\
            (not(self.Vx == 0 and self.Vy == 0)):
            is_forward = False
            ref_ang_L = normalize_angle(ref_ang_L + pi)
            ref_ang_F = normalize_angle(ref_ang_F + pi)
            error_theta_L = normalize_angle(ref_ang_L - self.theta_L)
            error_theta_F = normalize_angle(ref_ang_F - self.theta_F)

        return ((ref_ang_L, error_theta_L), (ref_ang_F, error_theta_F),
                is_forward)
 def cal_FK_passing_paramters(self, x,y,theta,v,w):
     '''
     output (x_p,y_p,theta_p,x_c,y_c)
     '''
     try: 
         r = v/w # divide by zero
     except ZeroDivisionError:
         # w = INF_SMALL
         r = float('inf')
     # --- rotation center ----# 
     x_c = x - r*sin(theta)
     y_c = y + r*cos(theta)
     # --- result -----# 
     x_p = x_c + r*sin(theta + w*DT)
     y_p = y_c - r*cos(theta + w*DT)
     theta_p = normalize_angle (theta + w*DT)
     return (x_p,y_p,theta_p,x_c,y_c,r)
    def cal_IK(self):
        '''
        calculate inverse kinematics
        This should be only called by car_1, car_2
        Input : 
            self.x
            self.y
            self.theta
            self.x_p
            self.y_p
        Output:
            self.theta_p
            self.v
            self.w
            self.r
        '''
        A = 2*(self.x_p - self.x)
        B = 2*(self.y_p - self.y)
        C = self.x_p**2 + self.y_p**2 - self.x**2 - self.y**2
        D = cos(self.theta)
        E = sin(self.theta)
        F = cos(self.theta) * self.x + sin(self.theta) * self.y

        LHS = np.array([[A,B],[D,E]])
        RHS = np.array([C,F])
        try: 
            (self.x_c, self.y_c) = np.linalg.solve(LHS,RHS)
        except np.linalg.linalg.LinAlgError:
            print ("NO SOLUTION!!!!!!!!!!!!!!!!!")
        
        self.r = sqrt( (self.x - self.x_c)**2 + (self.y - self.y_c)**2 )
        
        self.theta_p = normalize_angle(atan2(self.x_c - self.x_p , self.y_p - self.y_c))
        #---- theta_p has a constraint that direction must be the same as the votex -----# 
        v_s = np.cross( [ self.x - self.x_c , self.y - self.y_c ,0 ]   , [ cos(self.theta) , sin(self.theta),0] )
        v_e = np.cross( [ self.x_p - self.x_c , self.y_p - self.y_c,0] , [ cos(self.theta_p) , sin(self.theta_p),0] )
        if v_s[2] * v_e [2] < 0: # different sign 
            self.theta_p = normalize_angle(self.theta_p + pi) # Switch the direction
        
        # Judge center of rotation is at RHS or LHS
        # if self.name == "start":
        dtheta = self.theta_p - self.theta
        if v_s[2] > 0 :
            self.dir_center = "LHS"
            # LHS
            if dtheta > 0.0:
                # print ("Forward")
                self.v = 1.0
            else:
                # print("backward")
                self.v = -1.0
        else:
            self.dir_center = "RHS"
            # RHS
            if dtheta < 0.0:
                # print ("Forward")
                self.v = 1.0
            else:
                # print("backward")
                self.v = -1.0
        
        #---- Go forward of Go backward ? ----#
        self.w = (self.theta_p - self.theta) / DT
        dtheta = self.theta_p - self.theta
        if   dtheta > pi :
            self.w = (self.theta_p - self.theta - 2*pi) / DT
        elif dtheta < -pi :
            self.w = (self.theta_p - self.theta + 2*pi) / DT
        
        if self.w != 0:
            self.v = abs(self.w * self.r) * sign(self.v)
        else:
            self.v = (self.x_p - self.x) / DT
예제 #7
0
    def run_once(self):
        # Check simple goal is already reached
        if self.simple_goal == None:
            return False
        
        # Update tf # TODO use odom_fuse result
        t_big_car   = get_tf(self.tfBuffer, MAP_FRAME, BIG_CAR_FRAME)
        if t_big_car != None:
            self.big_car_xyt = t_big_car
        if self.big_car_xyt == None: #tf is invalid
            time.sleep(1)
            return False
        
        # Get Local goal
        self.prune_global_path()
        local_goal = self.get_local_goal()
        if local_goal == None:
            rospy.logdebug("[rap_planner] Can't get local goal from global path.")
            return False

        # transform local goal to /base_link frame
        p_dif = (local_goal[0] - self.big_car_xyt[0],
                 local_goal[1] - self.big_car_xyt[1])
        t = self.big_car_xyt[2]
        x_goal = cos(t)*p_dif[0] + sin(t)*p_dif[1]
        y_goal =-sin(t)*p_dif[0] + cos(t)*p_dif[1]

        self.rho = sqrt((self.simple_goal[0] - self.big_car_xyt[0])**2 + \
                        (self.simple_goal[1] - self.big_car_xyt[1])**2)

        # Check xy_goal reached
        if  (not self.latch_xy) and self.rho < GOAL_TOLERANCE_XY:
            rospy.loginfo("[rap_planner] Goal xy Reached")
            if IGNORE_HEADING:
                self.reset_plan()
                return True
            else:
                self.latch_xy = True
        
        # Check goal_heading reached
        if self.latch_xy:
            if abs(normalize_angle(self.simple_goal[2] - self.big_car_xyt[2])) <\
                (GOAL_TOLERANCE_T/2.0):
                self.reset_plan()
                rospy.loginfo("[rap_planner] Goal Heading Reached")
                return True
        
        # Get alpha 
        alpha = atan2(y_goal, x_goal)
        
        # Get beta
        '''
        #  This is Benson's legacy, but it's not very helpful
        if (not IGNORE_HEADING) and local_goal[2] != None:
            beta = normalize_angle(local_goal[2] - alpha - self.big_car_xyt[2])
            if abs(alpha) > pi/2:# Go backward
                beta = normalize_angle(beta - pi)
        else:
            beta = 0
        '''
        pursu_angle = alpha
        self.alpha = alpha
        # self.beta = beta
        # self.angle = pursu_angle

        self.viz_marker.update_marker("local_goal", (x_goal, y_goal) )
        # p = (cos(alpha)*LOOK_AHEAD_DIST, sin(alpha)*LOOK_AHEAD_DIST)
        # self.viz_marker.update_marker("goal_head", ((0,0), p))

        ##################
        ###  Get Flags ###
        ##################
        # Check where is the goal
        is_aside_goal = False
        if abs(abs(alpha) - pi/2) < (ASIDE_GOAL_ANG/2.0):
            is_aside_goal = True
        # Check is need to consider heading
        d_head = normalize_angle(self.simple_goal[2] - self.big_car_xyt[2])
        need_consider_heading = False
        if (not IGNORE_HEADING) and local_goal[2] != None:
            
            need_consider_heading = True
        # Check need to switch to rota
        is_need_rota = False # current rota only when heading adjment
        if  self.latch_xy: #or\
            #(USE_CRAB_FOR_HEADING and\
            #need_consider_heading and\
            #abs(d_head) > (GOAL_TOLERANCE_T/2.0)): # TODO # ROTA, cause occlication
            # need to adjust heading
            is_need_rota = True
        
        ############################
        ### Finite State Machine ###
        ############################
        # Flags: 
        # States: crab, diff, rota, tran
        if self.mode == "crab":
            if self.latch_xy and (not IGNORE_HEADING):
                self.set_tran_mode("rota")
            else:
                if need_consider_heading:
                    if is_need_rota: 
                        if USE_CRAB_FOR_HEADING:
                            self.set_tran_mode("rota")
                        else:
                            self.set_tran_mode("diff")
                    else:
                        pass # Stay crab
                else:
                    if is_aside_goal:
                        pass # Stay crab
                    else:
                        # Transit to diff mode
                        self.set_tran_mode("diff")
        
        elif self.mode == "diff":
            if self.latch_xy and (not IGNORE_HEADING):
                self.set_tran_mode("rota")
            else:
                if is_aside_goal:
                    self.set_tran_mode("crab")
                else:
                    pass
                '''
                if need_consider_heading:
                    if USE_CRAB_FOR_HEADING:
                        # Current diff can't heading adj
                        # self.set_tran_mode("rota")
                        pass
                    else:
                        pass # Stay here
                else:
                    if is_aside_goal:
                        self.set_tran_mode("crab")
                    else:
                        pass
                '''
        elif self.mode == "rota":
            if need_consider_heading:
                if is_need_rota:
                    pass# Stay rota
                else: # Finish rota
                    if USE_CRAB_FOR_HEADING:
                        self.set_tran_mode("crab") # Go to goal
                    else:
                        self.set_tran_mode("diff") # Go to goal
            else:
                self.set_tran_mode("crab") # Leave heading adj
        
        elif self.mode == "tran":
            if (not RAP_CTL.is_transit):
               rospy.loginfo("[rap_planner] transit finish, switch to " + self.next_mode)
               self.mode_latch_counter = MODE_SWITCH_LATCH
               self.mode = self.next_mode

        else:
            rospy.logerr("[rap_planner] Invalid mode " + str(self.mode))

        ####################
        ### Execute mode ###
        ####################
        if self.mode == "crab" or (self.mode == "tran" and self.next_mode == "crab"):
            self.vx_out = cos(alpha) * CRAB_KP_VEL
            self.vy_out = sin(alpha) * CRAB_KP_VEL
            self.wz_out = 0.0
        elif self.mode == "rota" or (self.mode == "tran" and self.next_mode == "rota"):
            self.vx_out = 0.0
            self.vy_out = 0.0
            self.wz_out =sign(d_head) * ROTA_KP_VEL
        elif self.mode == "diff" or (self.mode == "tran" and self.next_mode == "diff"):
            # Get R
            if self.rho < LOOK_AHEAD_DIST:
                R = sqrt((tan(pi/2 - (pursu_angle))*self.rho/2)**2 +
                        (self.rho/2.0)**2 )
            else:
                R = sqrt((tan(pi/2 - (pursu_angle))*LOOK_AHEAD_DIST/2)**2 +
                        (LOOK_AHEAD_DIST/2.0)**2 )
            if pursu_angle < 0: # alpha = [0,-pi]
                R = -R
            self.vx_out = sqrt(x_goal**2 + y_goal**2) * DIFF_KP_VEL
            self.vy_out = 0.0
            # TODO test this , to avoid near-goal weird things
            if self.rho < LOOK_AHEAD_DIST:
                self.wz_out = (self.vx_out / R) * (self.rho/LOOK_AHEAD_DIST)
            else:
                self.wz_out = (self.vx_out / R)
            
            if abs(pursu_angle) > pi/2: # Go backward
                self.vx_out *= -1.0
        else:
            rospy.logerr("[rap_planner] Invalid mode " + str(self.mode))

        # Debug marker text
        if self.mode == "tran":
            text = str(self.previous_mode) + "->" + self.next_mode
        else:
            text = self.mode
        self.viz_marker.update_marker("mode_text", (0,-0.5), text)

        # Latch counts
        if self.mode_latch_counter > 0:
            self.mode_latch_counter -= 1

        return True