Пример #1
0
    def test_updateState_NegOffsetNegSpin(self):
        '''
        Test the robot following a path starting from an angle with
        a positive offset
        '''
        pathSeg = PathSegmentMsg()
        pathSeg.seg_type = pathSeg.SPIN_IN_PLACE
        pathSeg.seg_number = 1
        pathSeg.seg_length = math.pi

        pathSeg.ref_point.x = 0.0
        pathSeg.ref_point.y = 0.0
        pathSeg.ref_point.z = 0.0

        init_quat = quaternion_from_euler(0, 0, 0.0)
        pathSeg.init_tan_angle.w = init_quat[3]
        pathSeg.init_tan_angle.x = init_quat[0]
        pathSeg.init_tan_angle.y = init_quat[1]
        pathSeg.init_tan_angle.z = init_quat[2]

        pathSeg.curvature = 1.0

        ref_point = PointMsg()
        ref_point.x = 1.0
        ref_point.y = 1.0
        pathSeg.ref_point = ref_point

        maxSpeed = TwistMsg()
        maxSpeed.linear.x = 1.0
        maxSpeed.angular.z = 1.0
        pathSeg.max_speeds = maxSpeed

        minSpeed = TwistMsg()
        pathSeg.min_speeds = minSpeed

        pathSeg.accel_limit = 1.0
        pathSeg.decel_limit = -1.0

        state = State(pathSeg)

        vel_cmd = TwistMsg()
        vel_cmd.linear.x = 0.0
        vel_cmd.angular.z = 0.5

        point = PointMsg()

        psi = 0.0
        maxIter = 1000
        count = 1
        # extrapolate next point
        while (state.segDistDone < 1.0 and maxIter > count):
            # create where the robot should have moved
            psi = 2.0 * state.pathSeg.seg_length * count / maxIter + math.pi / 4.0
            state.updateState(vel_cmd, point, psi)
            count += 1

        self.assertTrue(count < maxIter)
        self.assertTrue(state.segDistDone >= 1.0)
Пример #2
0
    def test_updateState_PosOffsetPosArc(self):
        '''
        Test the robot following a path starting from the same angle
        but with a positive offset and larger radius
        '''
        pathSeg = PathSegmentMsg()
        pathSeg.seg_type = pathSeg.ARC
        pathSeg.seg_number = 1
        pathSeg.seg_length = math.pi / 2.0

        pathSeg.ref_point.x = 0.0
        pathSeg.ref_point.y = 0.0

        init_quat = quaternion_from_euler(0, 0, math.pi + math.pi / 2)
        pathSeg.init_tan_angle.w = init_quat[3]
        pathSeg.init_tan_angle.x = init_quat[0]
        pathSeg.init_tan_angle.y = init_quat[1]
        pathSeg.init_tan_angle.z = init_quat[2]

        pathSeg.curvature = 1.0

        maxSpeed = TwistMsg()
        maxSpeed.linear.x = 1.0
        maxSpeed.angular.z = 1.0
        pathSeg.max_speeds = maxSpeed

        minSpeed = TwistMsg()
        pathSeg.min_speeds = minSpeed

        pathSeg.accel_limit = 1.0
        pathSeg.decel_limit = -1.0

        state = State(pathSeg)

        vel_cmd = TwistMsg()
        vel_cmd.linear.x = 0.5
        vel_cmd.angular.z = 0.0

        point = PointMsg()

        maxIter = 1000
        count = 1

        rhoDes = pathSeg.curvature - .3
        angle = State.getYaw(pathSeg.init_tan_angle)
        r = 1 / abs(rhoDes)
        startAngle = angle - math.pi / 2.0

        # extrapolate next point
        while (state.segDistDone < 1.0 and maxIter > count):
            # create where the robot should have moved
            dAng = pathSeg.seg_length * (count / (maxIter / 2.0)) * rhoDes
            arcAng = startAngle + dAng
            point.x = pathSeg.ref_point.x + r * math.cos(arcAng)
            point.y = pathSeg.ref_point.y + r * math.sin(arcAng)
            state.updateState(vel_cmd, point, 0.0)
            count += 1

        self.assertTrue(count < maxIter)
        self.assertTrue(state.segDistDone >= 1.0)
Пример #3
0
def getStartAndEndPoints():
    if(currSeg.seg_type == PathSegmentMsg.LINE):
        p_s = PointMsg()
        p_f = PointMsg()

        p_s.x = currSeg.ref_point.x
        p_s.y = currSeg.ref_point.y

        p_f.x = currSeg.ref_point.x + currSeg.seg_length*cos(getYaw(currSeg.init_tan_angle))
        p_f.y = currSeg.ref_point.y + currSeg.seg_length*sin(getYaw(currSeg.init_tan_angle))
        return (p_s,p_f)
    elif(currSeg.seg_type == PathSegmentMsg.ARC):
        return (0.0,0.0) # TODO
    elif(currSeg.seg_type == PathSegmentMsg.SPIN_IN_PLACE):
        return (currSeg.ref_point,currSeg.ref_point) # spins should never move in x,y plane
    else:
        return (0.0,0.0) # not sure if this is the best default answer
Пример #4
0
    def test_updateState_NegOffsetLine(self):
        '''
        Test the robot following a path starting with a negative
        offset and crossing over the path
        '''
        pathSeg = PathSegmentMsg()
        pathSeg.seg_type = pathSeg.LINE
        pathSeg.seg_number = 1
        pathSeg.seg_length = math.sqrt(2) * 2

        pathSeg.ref_point.x = 0.0
        pathSeg.ref_point.y = 0.0
        pathSeg.ref_point.z = 0.0

        init_quat = quaternion_from_euler(0, 0, math.pi / 4.0)
        pathSeg.init_tan_angle.w = init_quat[3]
        pathSeg.init_tan_angle.x = init_quat[0]
        pathSeg.init_tan_angle.y = init_quat[1]
        pathSeg.init_tan_angle.z = init_quat[2]

        pathSeg.curvature = 0.0

        maxSpeed = TwistMsg()
        maxSpeed.linear.x = 1.0
        maxSpeed.angular.z = 1.0
        pathSeg.max_speeds = maxSpeed

        minSpeed = TwistMsg()
        pathSeg.min_speeds = minSpeed

        pathSeg.accel_limit = 1.0
        pathSeg.decel_limit = -1.0

        state = State(pathSeg)

        vel_cmd = TwistMsg()
        vel_cmd.linear.x = 0.5
        vel_cmd.angular.z = 0.0

        point = PointMsg()

        actSegLength = 2.0 * math.sqrt(2) + 1.0

        maxIter = 1000
        count = 1
        # extrapolate next point
        while (state.segDistDone < 1.0 and maxIter > count):
            # create where the robot should have moved
            point.x = actSegLength * (count / (maxIter / 2.0)) * math.cos(
                3 * math.pi / 4.0) + 1.0
            point.y = actSegLength * (count / (maxIter / 2.0)) * math.sin(
                3 * math.pi / 4.0)
            state.updateState(vel_cmd, point, 0.0)
            count += 1

        self.assertTrue(count < maxIter)
        self.assertTrue(state.segDistDone >= 1.0)
Пример #5
0
def main():
    global corner1, corner2, numCells
    global brush
    global position
    global pointList

    rospy.init_node('brushfire_alpha_main')

    corner1 = (-6.25, 8.2)
    corner2 = (15.75, 28.2)
    numCells = 100

    brush = BrushFire(corner1, corner2, numCells, size=15)
    naptime = rospy.Rate(RATE)

    print "corner1: "
    print corner1
    print ""
    print "corner2: "
    print corner2
    print ""
    print "numCels: "
    print numCells
    print ""

    rospy.Subscriber('goal_point', GoalMsg, goalCallback)
    rospy.Subscriber('/costmap_alpha/costmap/obstacles', GridCellsMsg,
                     obstaclesCallback)
    rospy.Subscriber('map_pos', PoseStampedMsg, poseCallback)

    pathPointPub = rospy.Publisher('point_list', PointListMsg)

    pointList = PointListMsg()

    t = Timer(2.0, resetPath)
    t.start()
    while not rospy.is_shutdown():
        if (position is None or brush is None or brush.goal is None):
            naptime.sleep()
            continue

        brush.extractLocal(position.x, position.y)
        brush.brushfire()
        brush.computePath()
        pointList.points = []
        for point in brush.pathList:
            pathPoint = PointMsg()
            pathPoint.x = point[0]
            pathPoint.y = point[1]
            pointList.points.append(pathPoint)

        pathPointPub.publish(pointList)
        pointList.new = False

        naptime.sleep()
Пример #6
0
 def test_newSegment_None(self):
     point = PointMsg()  # initial point
     testState = State(point=point)
     testState.newPathSegment(
     )  # putting in a new segment shouldn't overwrite the point by default
     self.assertEqual(testState.pathSeg, None,
                      str(testState.pathSeg) + " is not None")
     self.assertEqual(testState.pathPoint, None,
                      str(testState.pathPoint) + " is not None")
     self.assertEqual(testState.point, point,
                      str(testState.pathPoint) + " is not " + str(point))
     self.assertEqual(testState.segDistDone, 0.0,
                      str(testState.segDistDone) + " is not 0.0")
     self.assertEqual(testState.dt, 1 / 20.0,
                      str(testState.dt) + " is not " + str(1 / 20.0))
Пример #7
0
 def test_newSegment_PathSeg(self):
     point = PointMsg()  # initial point
     pathSeg = PathSegmentMsg()
     testState = State(point=point)
     testState.newPathSegment(pathSeg)
     self.assertEqual(testState.pathSeg, pathSeg,
                      str(testState.pathSeg) + " is not " + str(pathSeg))
     self.assertEqual(
         testState.pathPoint, pathSeg.ref_point,
         str(testState.pathPoint) + " is not " + str(pathSeg.ref_point))
     self.assertEqual(testState.point, point,
                      str(testState.point) + " is not " + str(point))
     self.assertEqual(testState.segDistDone, 0.0,
                      str(testState.segDistDone) + " is not 0.0")
     self.assertEqual(testState.dt, 1 / 20.0,
                      str(testState.dt) + " is not " + str(1 / 20.0))
Пример #8
0
 def test_init_PathSegAndPoint(self):
     pathSeg = PathSegmentMsg()
     point = PointMsg()
     testState = State(pathSeg, point)
     self.assertEqual(
         testState.pathSeg, pathSeg,
         str(testState.pathSeg) + " is not equal to " + str(pathSeg))
     self.assertEqual(
         testState.pathPoint, pathSeg.ref_point,
         str(testState.pathPoint) + " is not equal to " +
         str(pathSeg.ref_point))
     self.assertEqual(
         testState.point, point,
         str(testState.point) + " is not equal to " + str(point))
     self.assertEqual(testState.segDistDone, 0.0,
                      str(testState.segDistDone) + " is not 0.0")
     self.assertEqual(testState.dt, 1 / 20.0,
                      str(testState.dt) + " is not " + str(1 / 20.0))
Пример #9
0
def main(fullList):
	global pose
	global pathList

	rospy.init_node('pathplanner_alpha_dummyNode')
	rospy.Subscriber('map_pos', PoseStampedMsg, poseCallback)
	dummyPointPub = rospy.Publisher('point_list', PointListMsg)


	pathList.new = True

	naptime = rospy.Rate(RATE)

	#point = PointMsg()
	#point.x = pose.pose.position.x
	#point.y = pose.pose.position.y
	#appendToList(point)

	with open(fullList, 'rb') as csvFile:
		dialect = csv.Sniffer().sniff(csvFile.read(1024)) # auto detect delimiters
		csvFile.seek(0)
		reader = csv.reader(csvFile, dialect) # open up a csv reader object with the csv file

		for i,row in enumerate(reader):

			point1 = PointMsg()
			try:
				point1.x = float(row[0])
			except ValueError:
				print "x ValueError"

			try:
				point1.y = float(row[1])
			except ValueError:
				print "y ValueError"
			
			appendToList(point1)
	

	while not rospy.is_shutdown(): 
            dummyPointPub.publish(pathList)
            pathList.new = False

            naptime.sleep()
Пример #10
0
# set the rate the node runs at
RATE = 20.0

# this will store a Rate instance to keep the node running at the specified RATE
naptime = None  # this will be initialized first thing in main

# Current point to steer to
currPoint = None

# Waypoints to steer to
waypoints = []
completedPoints = []

# pose data
position = PointMsg()
orientation = QuaternionMsg()

# used when a centroid is not published
lastGoodYaw = None


def poseCallback(pose):
    '''
    Updates the robot's best estimate on position and orientation
    '''
    global position
    global orientation
    position = pose.pose.position
    orientation = pose.pose.orientation
Пример #11
0
#!/usr/bin/env python  
import roslib ; roslib.load_mainfest('goal_planner_alpha')
import rospy
import tf

from geometry_msgs.msg._PoseStamped import PoseStamped as PoseStampedMsg
from geometry_msgs.msg._Point import Point as PointMsg
from msg_alpha.msg.Goal import Goal
from msg_alpha.msg._PointList import PointList as PointListMsg

RATE = 20.0
goalPoint = PointMsg()
goalList = []

from tf.transformations import transformPoint

def poseCallback(poseData):
    global pose
    pose = poseData


def findMagnet():

	TransformListener.transformDATATYPE (map_frame, PointMsg) 

def findPrize():
	

def determineGoal():
	global goalPoint
Пример #12
0
def main():
    global RATE
    global lastVCmd
    global lastOCmd
    global obs
    global obsDist
    global obsExists
    global stopped
    global seg_number
    global currSeg
    global nextSeg
    global pose
    global ping_angle
    
    rospy.init_node('velocity_profiler_alpha')
    desVelPub = rospy.Publisher('des_vel',TwistMsg) # Steering reads this and adds steering corrections on top of the desired velocities
    segStatusPub = rospy.Publisher('seg_status', SegStatusMsg) # Lets the other nodes know what path segment the robot is currently executing
    rospy.Subscriber("motors_enabled", BoolMsg, eStopCallback) # Lets velocity profiler know the E-stop is enabled
    rospy.Subscriber("obstacles", ObstaclesMsg, obstaclesCallback) # Lets velocity profiler know where along the path there is an obstacle 
    rospy.Subscriber("cmd_vel", TwistMsg, velCmdCallback) # 
    rospy.Subscriber("path_seg", PathSegmentMsg, pathSegmentCallback)
    rospy.Subscriber("map_pos", PoseStampedMsg, poseCallback)
    
    naptime = rospy.Rate(RATE)
    
    vel_cmd = TwistMsg()
    point = PointMsg()

    
    # while(not ros.Time.isValid()):
        #pass
    
    print "Entering main loop"
    
    while not rospy.is_shutdown():
        if(currSeg is not None):
         #   print "seg type %i " % currSeg.seg_type
          #  print "ref_point %s " % currSeg.ref_point
           # print "curv %f" % currSeg.curvature
           print "dist done %f" % currState.segDistDone
        if stopped:
            stopForEstop(desVelPub,segStatusPub)
            continue
        if(currSeg is not None):
            # Eventually this should work with arcs, spins and lines, but right
            # now its only working with lines
            if(currSeg.seg_type == PathSegmentMsg.LINE):
                # if there is an obstacle and the obstacle is within the segment length
                print ping_angle
                if(obsExists and obsDist/currSeg.seg_length < 1.0-currState.segDistDone and ping_angle > 60 and ping_angle < 140):
                    stopForObs(desVelPub,segStatusPub)
                    continue
            
            vel_cmd.linear.x = lastVCmd
            vel_cmd.angular.z = lastOCmd
            
            point.x = pose.pose.position.x
            point.y = pose.pose.position.y
            point.z = pose.pose.position.z
            
            currState.updateState(vel_cmd, point, State.getYaw(pose.pose.orientation)) # update where the robot is at
            (sVAccel, sVDecel, sWAccel, sWDecel) = computeTrajectory(currSeg,nextSeg) # figure out the switching points in the trajectory
            
            #print "sVAccel: %f sVDecel: %f" % (sVAccel,sVDecel)
            #print "sWAccel: %f, sWDecel: %f" % (sWAccel,sWDecel)
            
            des_vel = getVelCmd(sVAccel, sVDecel, sWAccel, sWDecel) # figure out the robot commands given the current state and the desired trajectory
            desVelPub.publish(des_vel) # publish the commands
            
            publishSegStatus(segStatusPub) # let everyone else know the status of the segment
            
            # see if its time to switch segments yet
            if(currState.segDistDone > 1.0):
                print "Finished segment type %i" % (currState.pathSeg.seg_type)
                print "currState.segDistDone %f" % (currState.segDistDone)
                currSeg = None
        else:
            # try and get new segments
            if(nextSeg is not None):
                currSeg = nextSeg # move the nextSegment up in line
                nextSeg = None # assume no segment until code below is run
            else: # didn't have a next segment before
                try: # so try and get a new one from the queue
                    currSeg = segments.get(False)
                except QueueEmpty: # if the queue is still empty then 
                    currSeg = None # just set it to None
                
            try: # see if a next segment is specified
                nextSeg = segments.get(False) # try and get it
            except QueueEmpty: # if nothing specified
                nextSeg = None # set to None
            
            point = PointMsg()
            point.x = pose.pose.position.x
            point.y = pose.pose.position.y
            point.z = pose.pose.position.z
            
            currState.newPathSegment(currSeg, point, pose.pose.orientation)
            des_vel = TwistMsg()
            desVelPub.publish(des_vel) # publish all zeros for the des_vel
            publishSegStatus(segStatusPub) # publish that there is no segment
            if(currSeg is not None):
                rospy.logwarn("Starting a new segment, type %i" %currSeg.seg_type)
                rospy.logwarn("\tcurvature: %f" % currSeg.curvature)
                rospy.logwarn("\tref_point: %s" % currSeg.ref_point)
        naptime.sleep()
        continue
Пример #13
0
    def test_stop(self):
        '''
        Test the stop method
        '''
        pathSeg = PathSegmentMsg()
        pathSeg.seg_type = pathSeg.LINE
        pathSeg.seg_number = 1
        pathSeg.seg_length = math.sqrt(2) * 2

        pathSeg.ref_point.x = 0.0
        pathSeg.ref_point.y = 0.0
        pathSeg.ref_point.z = 0.0

        init_quat = quaternion_from_euler(0, 0, math.pi / 4.0)
        pathSeg.init_tan_angle.w = init_quat[3]
        pathSeg.init_tan_angle.x = init_quat[0]
        pathSeg.init_tan_angle.y = init_quat[1]
        pathSeg.init_tan_angle.z = init_quat[2]

        pathSeg.curvature = 0.0

        maxSpeed = TwistMsg()
        maxSpeed.linear.x = 1.0
        maxSpeed.angular.z = 1.0
        pathSeg.max_speeds = maxSpeed

        minSpeed = TwistMsg()
        pathSeg.min_speeds = minSpeed

        pathSeg.accel_limit = 1.0
        pathSeg.decel_limit = -1.0

        state = State(pathSeg)

        vel_cmd = TwistMsg()
        vel_cmd.linear.x = 0.5
        vel_cmd.angular.z = 1.5

        point = PointMsg()

        maxIter = 300
        count = 1
        # extrapolate next point
        while (state.segDistDone < 1.0 and maxIter > count):
            # create where the robot should have moved
            point.x = pathSeg.seg_length * (count /
                                            (maxIter / 2.0)) * math.cos(
                                                math.pi / 4.0)
            point.y = pathSeg.seg_length * (count /
                                            (maxIter / 2.0)) * math.sin(
                                                math.pi / 4.0)
            state.updateState(vel_cmd, point, 0.0)
            count += 1

        self.assertTrue(count < maxIter)
        self.assertTrue(state.segDistDone >= 1.0)

        self.assertEquals(state.v, 0.5)
        self.assertEquals(state.o, 1.5)

        state.stop()

        self.assertEquals(state.v, 0.0)
        self.assertEquals(state.o, 0.0)
Пример #14
0
def main():
    global corner1, corner2, numCells
    global searcher, newPath

    rospy.init_node('astar_alpha_main')

    # set the parameters specified within the launch files

    # corner 1 and corner 2 specify the area in the map
    # that astar will consider

    # Corner1
    if rospy.has_param('corner1x'):
        corner1x = rospy.get_param('corner1x')
    else:
        corner1x = -6.25

    if rospy.has_param('corner1y'):
        corner1y = rospy.get_param('corner1y')
    else:
        corner1y = 8.2

    # Corner2
    if rospy.has_param('corner2x'):
        corner2x = rospy.get_param('corner2x')
    else:
        corner2x = 15.75

    if rospy.has_param('corner2y'):
        corner2y = rospy.get_param('corner2y')
    else:
        corner2y = 28.2

    corner1 = (corner1x, corner1y)

    corner2 = (corner2x, corner2y)

    # numCells specifies the number of cells to divide the
    # specified astar search space into
    if rospy.has_param('numCells'):
        numCells = rospy.get_param('numCells')
    else:
        numCells = 100

    # topic that the node looks for the closed points on
    if rospy.has_param('inflatedTopic'):
        inflatedTopic = rospy.get_param('inflatedTopic')
    else:
        inflatedTopic = '/costmap_local_alpha/costmap_local/inflated_obstacles'

    # topic that the node looks for goal messages on
    if rospy.has_param('goalTopic'):
        goalTopic = rospy.get_param('goalTopic')
    else:
        goalTopic = 'goal_point'

    # initialize an instance of the Astar class
    searcher = Astar(corner1, corner2, numCells)
    naptime = rospy.Rate(RATE)

    print "corner1: "
    print corner1
    print ""
    print "corner2: "
    print corner2
    print ""
    print "numCells: %i" % numCells
    print ""
    print "goal topics: %s" % goalTopic
    print ""
    print "inflatedTopic: %s" % inflatedTopic

    rospy.Subscriber(goalTopic, GoalMsg, goalCallback)
    rospy.Subscriber(inflatedTopic, GridCellsMsg, inflatedObstaclesCallback)
    rospy.Subscriber('map_pos', PoseStampedMsg, poseCallback)

    pathPointPub = rospy.Publisher('point_list', PointListMsg)

    first_run = True
    pointList = PointListMsg()
    while not rospy.is_shutdown():
        pointList.new = newPath

        print "searcher.start"
        print searcher.start
        print ""
        print "searcher.goal"
        print searcher.goal
        print ""
        print "newPath"
        print newPath
        print ""
        print "searcher.path"
        print searcher.path
        print ""

        pointList.points = []
        for point in searcher.path:
            pathPoint = PointMsg()
            pathPoint.x = point[0]
            pathPoint.y = point[1]
            pointList.points.append(pathPoint)

        pathPointPub.publish(pointList)

        if newPath:
            newPath = False

        naptime.sleep()
Пример #15
0
    def updateState(self, vel_cmd, point, psi):
        """
        Integrates along the desired path vector and projects the actual path 
        vector onto the desired vector
        
        Inputs
        ------
        vel_cmd is expected to be of type Twist
        point is expected to be of type Point
        
        Returns
        -------
        True if everything went okay
        False if an error occurred
        """
        dt = 1.0 / 20.0
        if (self.pathSeg.seg_type == PathSegmentMsg.LINE):
            approx_equal = lambda a, b, t: abs(a - b) < t

            # grab the angle of the path
            angle = State.getYaw(self.pathSeg.init_tan_angle)

            # grab the starting point
            p0 = self.pathSeg.ref_point

            # calculate another point along the line
            p1 = PointMsg()
            p1.x = p0.x + self.pathSeg.seg_length * cos(angle)
            p1.y = p0.y + self.pathSeg.seg_length * sin(angle)

            # line segment
            tanVecMag = pow(p0.x - p1.x, 2) + pow(p0.y - p1.y, 2)

            # intersection point
            u = ((point.x - p0.x) * (p1.x - p0.x) + (point.y - p0.y) *
                 (p1.y - p0.y)) / tanVecMag

            intersect = PointMsg()
            intersect.x = point.x + u * cos(angle)
            intersect.y = point.y + u * sin(angle)

            d = sqrt(pow(intersect.x - p0.x, 2) + pow(intersect.y - p0.y, 2))

            # see where this point will lead if followed along the line for a distance d
            testX = intersect.x + d * cos(angle)
            testY = intersect.y + d * sin(angle)

            # if the distance gets smaller then the d should be negative
            # if the distance gets bigger then the d should be positive
            if (sqrt(pow(testX - p0.x, 2) + pow(testY - p0.y, 2)) < d):
                d = -d

            self.segDistDone = d / self.pathSeg.seg_length
        elif (self.pathSeg.seg_type == PathSegmentMsg.ARC):
            self.segDistDone += abs(
                (vel_cmd.angular.z * dt) /
                (self.pathSeg.seg_length / abs(self.pathSeg.curvature)))
            """
            tanAngStart = State.getYaw(self.pathSeg.init_tan_angle)
            rho = self.pathSeg.curvature
            r = 1/abs(rho)
            if(rho >= 0):
                startAngle = tanAngStart - pi/2
            else:
                startAngle = tanAngStart + pi/2
            
            ref_point = self.pathSeg.ref_point
            
            rVec = State.createVector(ref_point, point)
            theta = atan2(rVec.y,rVec.x)
            
            phi = startAngle % (2*pi)
            
            if(abs(phi-2*pi) < phi):
                phi = phi - 2*pi
                
            posPhi = phi % (2*pi)
            posTheta = theta % (2*pi)
                
            # figure out angle halfway between end and start angle
            if(rho >= 0):
                halfAngle = self.pathSeg.seg_length/(2*r)
                finAngle = self.pathSeg.seg_length/r
            else:
                halfAngle = self.pathSeg.seg_length/(2*r)
                finAngle = -self.pathSeg.seg_length/r
            
            # find theta in terms of starting angle
            if(rho >= 0):
                if(posTheta > posPhi):
                    beta = posTheta - posPhi
                else:
                    beta = 2*pi-posPhi+posTheta
            else:
                if(posTheta < posPhi):
                    beta = posTheta - posPhi
                else:
                    beta = posTheta-posPhi-(2*pi)
                    
                
            # figure out what region the angle is in
            if(rho >= 0):
                if(beta >= 0 and beta <= halfAngle+pi): # beta is in the specified arc
                    alpha = beta
                else:
                    alpha = -(2*pi-beta)
            else:
                if(beta >= halfAngle-pi and beta <= 0):
                    alpha = beta;
                else:
                    alpha = beta + (2*pi)
                    
            if(rho >= 0):
                self.segDistDone = r*alpha/self.pathSeg.seg_length
            else:
                self.segDistDone = -r*alpha/self.pathSeg.seg_length
            """

        elif (self.pathSeg.seg_type == PathSegmentMsg.SPIN_IN_PLACE):
            rho = self.pathSeg.curvature
            phi = State.getYaw(self.pathSeg.init_tan_angle)

            posPhi = phi % (2 * pi)
            posPsi = psi % (2 * pi)

            if (rho >= 0):
                halfAngle = self.pathSeg.seg_length / 2.0
            else:
                halfAngle = self.pathSeg.seg_length / 2.0 - pi

            # find beta in terms of starting angle

            if (posPsi > posPhi):
                beta = posPsi - posPhi
            else:
                beta = 2 * pi - posPhi + posPsi

            # figure out what region the angle is in
            if (beta >= 0 and
                    beta <= halfAngle + pi):  # beta is in the specified arc
                alpha = beta
            else:
                alpha = beta - 2 * pi

            self.segDistDone = alpha / self.pathSeg.seg_length
        else:
            pass  # should probably throw an unknown segment type error

        # update the current velocity
        self.v = vel_cmd.linear.x
        self.w = vel_cmd.angular.z

        # update the current point and heading
        self.point = point
        self.psi = psi