[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control

Robot Motion:

Generate smooth paths

[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第1张图片
an executable path
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第2张图片
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第3张图片
get a single point and no path at all
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第4张图片
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第5张图片
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第6张图片
typos of the signs in GD
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第7张图片

The formula you need to use in the exercise is as follows. Note that it is a little different from the ones in the video.

yi <- yi + alpha *(xi - yi) + beta *(yi + 1 + yi - 1 - 2 * yi)

There is an error in the solution presented in this video. newpath[i][j] is updated two times in lines 37 and 38. This is incorrect: instead, newpath[i][j] should only be updated one time. An example fix would be to replace lines 37-39 with the single update:

For more information, please read the forum post:http://forums.udacity.com/questions/1024800/unit-5-5-solution-bug#cs373

# -----------
# User Instructions
#
# Define a function smooth that takes a path as its input
# (with optional parameters for weight_data, weight_smooth,
# and tolerance) and returns a smooth path. The first and 
# last points should remain unchanged.
#
# Smoothing should be implemented by iteratively updating
# each entry in newpath until some desired level of accuracy
# is reached. The update should be done according to the
# gradient descent equations given in the instructor's note
# below (the equations given in the video are not quite 
# correct).
# -----------

from copy import deepcopy

# thank you to EnTerr for posting this on our discussion forum
def printpaths(path,newpath):
    for old,new in zip(path,newpath):
        print '['+ ', '.join('%.3f'%x for x in old) + \
               '] -> ['+ ', '.join('%.3f'%x for x in new) +']'

# Don't modify path inside your function.
path = [[0, 0],
        [0, 1],
        [0, 2],
        [1, 2],
        [2, 2],
        [3, 2],
        [4, 2],
        [4, 3],
        [4, 4]]

def smooth(path, weight_data = 0.5, weight_smooth = 0.1, tolerance = 0.000001):

    # Make a deep copy of path into newpath
    newpath = deepcopy(path)

    #######################
    ### ENTER CODE HERE ###
    point_num = len(path)
    point_dim = 2
    if point_num > 2:
        max_change = tolerance+1
        while max_change > tolerance:
            change = []
            for i in range(1,point_num-1):
                for d in range(point_dim):
                    change.append(weight_data*(path[i][d] - newpath[i][d])\
                             + weight_smooth*(newpath[i-1][d] + newpath[i+1][d] - 2*newpath[i][d]))
                    newpath[i][d] += change[-1]
            max_change = max(change)
    #######################
    
    return newpath # Leave this line for the grader!

printpaths(path,smooth(path))

results:
[0.000, 0.000] -> [0.000, 0.000]
[0.000, 1.000] -> [0.021, 0.979]
[0.000, 2.000] -> [0.149, 1.851]
[1.000, 2.000] -> [1.021, 1.979]
[2.000, 2.000] -> [2.000, 2.000]
[3.000, 2.000] -> [2.979, 2.021]
[4.000, 2.000] -> [3.851, 2.149]
[4.000, 3.000] -> [3.979, 3.021]
[4.000, 4.000] -> [4.000, 4.000]

NOTE:

  • 没法import math,所以没法用math.inf,所以这里用change这个list的空间复杂度比较高。
  • 还有更高效的方法应该是用numpy整体操作,而不是用for循环
  • 对于weight的选取,应该有稳定性准则。这里weight太大相当于有限差分里的时间步长太大,相对path的点的数量(i.e. 空间步长)。或者可能需要用二阶的optimize、或者adam这类一阶的优化会更稳定。
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第8张图片
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第9张图片

PID control

[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第10张图片
no matter how small τ is, a p-controller will always overshoot
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第11张图片

Implement P controller:

# -----------
# User Instructions
#
# Implement a P controller by running 100 iterations
# of robot motion. The desired trajectory for the 
# robot is the x-axis. The steering angle should be set
# by the parameter tau so that:
#
# steering = -tau * crosstrack_error
#
# You'll only need to modify the `run` function at the bottom.
# ------------

import random
import numpy as np
import matplotlib.pyplot as plt

# ------------------------------------------------
# 
# this is the Robot class
#

class Robot(object):
    def __init__(self, length=20.0):
        """
        Creates robot and initializes location/orientation to 0, 0, 0.
        """
        self.x = 0.0
        self.y = 0.0
        self.orientation = 0.0
        self.length = length
        self.steering_noise = 0.0
        self.distance_noise = 0.0
        self.steering_drift = 0.0

    def set(self, x, y, orientation):
        """
        Sets a robot coordinate.
        """
        self.x = x
        self.y = y
        self.orientation = orientation % (2.0 * np.pi)

    def set_noise(self, steering_noise, distance_noise):
        """
        Sets the noise parameters.
        """
        # makes it possible to change the noise parameters
        # this is often useful in particle filters
        self.steering_noise = steering_noise
        self.distance_noise = distance_noise

    def set_steering_drift(self, drift):
        """
        Sets the systematical steering drift parameter
        """
        self.steering_drift = drift

    def move(self, steering, distance, tolerance=0.001, max_steering_angle=np.pi / 4.0):
        """
        steering = front wheel steering angle, limited by max_steering_angle
        distance = total distance driven, most be non-negative
        """
        if steering > max_steering_angle:
            steering = max_steering_angle
        if steering < -max_steering_angle:
            steering = -max_steering_angle
        if distance < 0.0:
            distance = 0.0

        # apply noise
        steering2 = random.gauss(steering, self.steering_noise)
        distance2 = random.gauss(distance, self.distance_noise)

        # apply steering drift
        steering2 += self.steering_drift

        # Execute motion
        turn = np.tan(steering2) * distance2 / self.length

        if abs(turn) < tolerance:
            # approximate by straight line motion
            self.x += distance2 * np.cos(self.orientation)
            self.y += distance2 * np.sin(self.orientation)
            self.orientation = (self.orientation + turn) % (2.0 * np.pi)
        else:
            # approximate bicycle model for motion
            radius = distance2 / turn
            cx = self.x - (np.sin(self.orientation) * radius)
            cy = self.y + (np.cos(self.orientation) * radius)
            self.orientation = (self.orientation + turn) % (2.0 * np.pi)
            self.x = cx + (np.sin(self.orientation) * radius)
            self.y = cy - (np.cos(self.orientation) * radius)

    def __repr__(self):
        return '[x=%.5f y=%.5f orient=%.5f]' % (self.x, self.y, self.orientation)

############## ADD / MODIFY CODE BELOW ####################
# ------------------------------------------------------------------------
#
# run - does a single control run
robot = Robot()
robot.set(0.0, 1.0, 0.0)

def run(robot, tau, n=100, speed=1.0):
    x_trajectory = []
    y_trajectory = []
    # TODO: your code here
    for i in range(n):
        steer = -tau*robot.y
        robot.move(steer,speed)
        x_trajectory.append(robot.x)
        y_trajectory.append(robot.y)
    return x_trajectory, y_trajectory
    
x_trajectory, y_trajectory = run(robot, 0.1)
n = len(x_trajectory)

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 8))
ax1.plot(x_trajectory, y_trajectory, 'g', label='P controller')
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第12张图片
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第13张图片
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第14张图片
# previous P controller
def run_p(robot, tau, n=100, speed=1.0):
    x_trajectory = []
    y_trajectory = []
    for i in range(n):
        cte = robot.y
        steer = -tau * cte
        robot.move(steer, speed)
        x_trajectory.append(robot.x)
        y_trajectory.append(robot.y)
    return x_trajectory, y_trajectory
    
robot = Robot()
robot.set(0, 1, 0)

def run(robot, tau_p, tau_d, n=100, speed=1.0):
    x_trajectory = []
    y_trajectory = []
    # TODO: your code here
    last_error = robot.y
    for i in range(n):
        steering = - tau_p*robot.y - tau_d*(robot.y-last_error)
        last_error = robot.y
        robot.move(steering,speed)
        x_trajectory.append(robot.x)
        y_trajectory.append(robot.y)
    return x_trajectory, y_trajectory
    
x_trajectory, y_trajectory = run(robot, 0.2, 3.0)
n = len(x_trajectory)

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 8))
ax1.plot(x_trajectory, y_trajectory, 'g', label='PD controller')
ax1.plot(x_trajectory, np.zeros(n), 'r', label='reference')
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第15张图片
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第16张图片
some unknown bias
eg. there's a 10° bias
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第17张图片
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第18张图片
robot = Robot()
robot.set(0.0, 1.0, 0.0)
robot.steering_drift = 10.0

def run(robot, tau, n=100, speed=1.0):
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第19张图片
P-controller with 10° steering drift
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第20张图片
def run(robot, tau_p, tau_d, tau_i, n=100, speed=1.0):
    x_trajectory = []
    y_trajectory = []
    # TODO: your code here
    last_error = robot.y
    sum_error = 0
    for i in range(n):
        steering = -tau_p*robot.y -tau_d*(robot.y-last_error) -tau_i*sum_error
        last_error = robot.y
        sum_error += last_error
        robot.move(steering,speed)
        x_trajectory.append(robot.x)
        y_trajectory.append(robot.y)
    return x_trajectory, y_trajectory


x_trajectory, y_trajectory = run(robot, 0.2, 3.0, 0.004)
n = len(x_trajectory)

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8,8))
ax1.plot(x_trajectory, y_trajectory, 'g', label='PID controller')
ax1.plot(x_trajectory, np.zeros(n), 'r', label='reference')
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第21张图片
# ----------------
# User Instructions
#
# Implement twiddle as shown in the previous two videos.
# Your accumulated error should be very small!
#
# You don't have to use the exact values as shown in the video
# play around with different values! This quiz isn't graded just see
# how low of an error you can get.
#
# Try to get your error below 1.0e-10 with as few iterations
# as possible (too many iterations will cause a timeout).
#
# No cheating!
# ------------

import random
import numpy as np
import matplotlib.pyplot as plt

# ------------------------------------------------
# 
# this is the Robot class
#

class Robot(object):
    def __init__(self, length=20.0):
        """
        Creates robot and initializes location/orientation to 0, 0, 0.
        """
        self.x = 0.0
        self.y = 0.0
        self.orientation = 0.0
        self.length = length
        self.steering_noise = 0.0
        self.distance_noise = 0.0
        self.steering_drift = 0.0

    def set(self, x, y, orientation):
        """
        Sets a robot coordinate.
        """
        self.x = x
        self.y = y
        self.orientation = orientation % (2.0 * np.pi)

    def set_noise(self, steering_noise, distance_noise):
        """
        Sets the noise parameters.
        """
        # makes it possible to change the noise parameters
        # this is often useful in particle filters
        self.steering_noise = steering_noise
        self.distance_noise = distance_noise

    def set_steering_drift(self, drift):
        """
        Sets the systematical steering drift parameter
        """
        self.steering_drift = drift

    def move(self, steering, distance, tolerance=0.001, max_steering_angle=np.pi / 4.0):
        """
        steering = front wheel steering angle, limited by max_steering_angle
        distance = total distance driven, most be non-negative
        """
        if steering > max_steering_angle:
            steering = max_steering_angle
        if steering < -max_steering_angle:
            steering = -max_steering_angle
        if distance < 0.0:
            distance = 0.0

        # apply noise
        steering2 = random.gauss(steering, self.steering_noise)
        distance2 = random.gauss(distance, self.distance_noise)

        # apply steering drift
        steering2 += self.steering_drift

        # Execute motion
        turn = np.tan(steering2) * distance2 / self.length

        if abs(turn) < tolerance:
            # approximate by straight line motion
            self.x += distance2 * np.cos(self.orientation)
            self.y += distance2 * np.sin(self.orientation)
            self.orientation = (self.orientation + turn) % (2.0 * np.pi)
        else:
            # approximate bicycle model for motion
            radius = distance2 / turn
            cx = self.x - (np.sin(self.orientation) * radius)
            cy = self.y + (np.cos(self.orientation) * radius)
            self.orientation = (self.orientation + turn) % (2.0 * np.pi)
            self.x = cx + (np.sin(self.orientation) * radius)
            self.y = cy - (np.cos(self.orientation) * radius)

    def __repr__(self):
        return '[x=%.5f y=%.5f orient=%.5f]' % (self.x, self.y, self.orientation)

############## ADD / MODIFY CODE BELOW ####################
# ------------------------------------------------------------------------
#
# run - does a single control run


def make_robot():
    """
    Resets the robot back to the initial position and drift.
    You'll want to call this after you call `run`.
    """
    robot = Robot()
    robot.set(0.0, 1.0, 0.0)
    robot.set_steering_drift(10.0 / 180.0 * np.pi)
    return robot


# NOTE: We use params instead of tau_p, tau_d, tau_i
def run(robot, params, n=100, speed=1.0):
    x_trajectory = []
    y_trajectory = []
    err = 0
    prev_cte = robot.y
    int_cte = 0
    for i in range(2 * n):
        cte = robot.y
        diff_cte = cte - prev_cte
        int_cte += cte
        prev_cte = cte
        steer = -params[0] * cte - params[1] * diff_cte - params[2] * int_cte
        robot.move(steer, speed)
        x_trajectory.append(robot.x)
        y_trajectory.append(robot.y)
        if i >= n:
            err += cte ** 2
    return x_trajectory, y_trajectory, err / n


# Make this tolerance bigger if you are timing out!
def twiddle(tol=0.2): 
    # Don't forget to call `make_robot` before every call of `run`!
    p = [0.0, 0.0, 0.0]
    dp = [1.0, 1.0, 1.0]
    robot = make_robot()
    x_trajectory, y_trajectory, best_err = run(robot, p)
    # TODO: twiddle loop here
    while sum(dp) > tol:
        for i in range(3):
            p[i] += dp[i]
            robot = make_robot()
            x_trajectory, y_trajectory, err = run(robot, p)
            if err < best_err:
                dp[i] *= 1.1
                best_err = err
            else:
                p[i] -= 2*dp[i]
                robot = make_robot()
                x_trajectory, y_trajectory, err = run(robot, p)
                if err < best_err:
                    dp[i] *=1.1
                    best_err = err
                else:
                    p[i] += dp[i]
                    dp[i] *= 0.9
    
    return p, best_err


params, err = twiddle()
print("Final twiddle error = {}".format(err))
robot = make_robot()
x_trajectory, y_trajectory, err = run(robot, params)
n = len(x_trajectory)

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 8))
ax1.plot(x_trajectory, y_trajectory, 'g', label='Twiddle PID controller')
ax1.plot(x_trajectory, np.zeros(n), 'r', label='reference')
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第22张图片
Final twiddle error = 6.48624842097e-16
[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第23张图片

Quiz

Q1: Missing Parameters

[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第24张图片
    1. no τd here, because τd makes the curve smooth
    1. no problem
    1. converges to a none 0 value, and τI wants the final value to converge to 0
    1. the only one starting to move to +Y direction firstly, which means τp is a small value

NOTE that there's a system bias here.

Q2: Cyclic Smoothing

[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第25张图片
# -------------
# User Instructions
#
# Here you will be implementing a cyclic smoothing
# algorithm. This algorithm should not fix the end
# points (as you did in the unit quizzes). You  
# should use the gradient descent equations that
# you used previously.
#
# Your function should return the newpath that it
# calculates.
#
# Feel free to use the provided solution_check function
# to test your code. You can find it at the bottom.
#
# --------------
# Testing Instructions
# 
# To test your code, call the solution_check function with
# two arguments. The first argument should be the result of your
# smooth function. The second should be the corresponding answer.
# For example, calling
#
# solution_check(smooth(testpath1), answer1)
#
# should return True if your answer is correct and False if
# it is not.

from math import *
from copy import deepcopy

# Do not modify path inside your function.
path=[[0, 0], 
      [1, 0],
      [2, 0],
      [3, 0],
      [4, 0],
      [5, 0],
      [6, 0],
      [6, 1],
      [6, 2],
      [6, 3],
      [5, 3],
      [4, 3],
      [3, 3],
      [2, 3],
      [1, 3],
      [0, 3],
      [0, 2],
      [0, 1]]

############# ONLY ENTER CODE BELOW THIS LINE ##########

# ------------------------------------------------
# smooth coordinates
# If your code is timing out, make the tolerance parameter
# larger to decrease run time.
#

def smooth(path, weight_data = 0.1, weight_smooth = 0.1, tolerance = 0.00001):

    # 
    # Enter code here
    #
    
    new_path = deepcopy(path)
    length = len(path)
    diff = tolerance + 1
    while diff > tolerance:
        diff = -float('inf')
        for i,p in enumerate(new_path):
            dp0 = weight_data*(path[i][0]-p[0]) + \
                    weight_smooth*(new_path[(i+1)%length][0]+new_path[i-1][0]-2*p[0])
            dp1 = weight_data*(path[i][1]-p[1]) + \
                    weight_smooth*(new_path[(i+1)%length][1]+new_path[i-1][1]-2*p[1])
            new_path[i][0] += dp0
            new_path[i][1] += dp1
            diff = max(dp0,dp1,diff)
    return new_path

# thank you - EnTerr - for posting this on our discussion forum

#newpath = smooth(path)
#for i in range(len(path)):
#    print '['+ ', '.join('%.3f'%x for x in path[i]) +'] -> ['+ ', '.join('%.3f'%x for x in newpath[i]) +']'


##### TESTING ######

# --------------------------------------------------
# check if two numbers are 'close enough,'used in
# solution_check function.
#
def close_enough(user_answer, true_answer, epsilon = 0.001):
    if abs(user_answer - true_answer) > epsilon:
        return False
    return True

# --------------------------------------------------
# check your solution against our reference solution for
# a variety of test cases (given below)
#
def solution_check(newpath, answer):
    if type(newpath) != type(answer):
        print "Error. You do not return a list."
        return False
    if len(newpath) != len(answer):
        print 'Error. Your newpath is not the correct length.'
        return False
    if len(newpath[0]) != len(answer[0]):
        print 'Error. Your entries do not contain an (x, y) coordinate pair.'
        return False
    for i in range(len(newpath)): 
        for j in range(len(newpath[0])):
            if not close_enough(newpath[i][j], answer[i][j]):
                print 'Error, at least one of your entries is not correct.'
                return False
    print "Test case correct!"
    return True

# --------------
# Testing Instructions
# 
# To test your code, call the solution_check function with
# two arguments. The first argument should be the result of your
# smooth function. The second should be the corresponding answer.
# For example, calling
#
# solution_check(smooth(testpath1), answer1)
#
# should return True if your answer is correct and False if
# it is not.
    
testpath1 = [[0, 0],
             [1, 0],
             [2, 0],
             [3, 0],
             [4, 0],
             [5, 0],
             [6, 0],
             [6, 1],
             [6, 2],
             [6, 3],
             [5, 3],
             [4, 3],
             [3, 3],
             [2, 3],
             [1, 3],
             [0, 3],
             [0, 2],
             [0, 1]]

answer1 = [[0.4705860385182691, 0.4235279620576893], 
           [1.1764695730296597, 0.16470408411716733], 
           [2.058823799247812, 0.07058633859438503], 
           [3.000001503542886, 0.04705708651959327], 
           [3.9411790099468273, 0.07058689299792453], 
           [4.8235326678889345, 0.16470511854183797], 
           [5.529415336860586, 0.4235293374365447], 
           [5.76470933698621, 1.1058829941330384], 
           [5.764708805535902, 1.8941189433780983], 
           [5.5294138118186265, 2.5764724018811056], 
           [4.823530348360371, 2.835296251305122], 
           [3.941176199414957, 2.929413985845729],
           [2.9999985709076413, 2.952943245204772], 
           [2.0588211310939526, 2.9294134622132018], 
           [1.1764675231284938, 2.8352952720424938], 
           [0.4705848811030855, 2.5764710948028178], 
           [0.23529088056307781, 1.8941174802285707], 
           [0.23529138316655338, 1.1058815684272394]]

testpath2 = [[1, 0], # Move in the shape of a plus sign
             [2, 0],
             [2, 1],
             [3, 1],
             [3, 2],
             [2, 2],
             [2, 3],
             [1, 3],
             [1, 2],
             [0, 2], 
             [0, 1],
             [1, 1]]

answer2 = [[1.2222234770374059, 0.4444422843711052],
           [1.7777807251383388, 0.4444432993123497], 
           [2.111114925633848, 0.8888894279539462], 
           [2.5555592020540376, 1.2222246475393077], 
           [2.5555580686154244, 1.7777817817879298], 
           [2.111111849558437, 2.1111159707965514], 
           [1.7777765871460525, 2.55556033483712], 
           [1.2222194640861452, 2.5555593592828543], 
           [0.8888853322565222, 2.111113321684573], 
           [0.44444105139827167, 1.777778212019149], 
           [0.44444210978390364, 1.2222211690821811], 
           [0.8888882042812255, 0.8888870211766268]]

solution_check(smooth(testpath1), answer1)
solution_check(smooth(testpath2), answer2)

Q3: Constrained Smoothing

[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第26张图片
def smooth(path, fix, weight_data = 0.0, weight_smooth = 0.1, tolerance = 0.00001):
    #
    # Enter code here. 
    # The weight for each of the two new equations should be 0.5 * weight_smooth
    #
    newpath = deepcopy(path)
    point_num = len(path)
    dim_num = len(path[0])
    max_diff = tolerance + 1
    
    while max_diff > tolerance:
        max_diff = -float("inf")
        for i in range(point_num):
            if fix[i] == 1:
                continue
            for j in range(dim_num):
                diff_ij = weight_smooth*(newpath[(i+1)%point_num][j] + newpath[(i-1)%point_num][j] - 2*newpath[i][j]) + \
                          (weight_smooth/2)*(2*newpath[(i+1)%point_num][j] - newpath[(i+2)%point_num][j] - newpath[i][j]) + \
                          (weight_smooth/2)*(2*newpath[(i-1)%point_num][j] - newpath[(i-2)%point_num][j] - newpath[i][j])
                max_diff = max(max_diff,diff_ij)
                newpath[i][j] += diff_ij
    return newpath

Note:

  • min(target); target = (path[i][j] - newpath[i][j])2 ~> 接近原始点,提供约束,避免所有点都集中在一起。没有fix的点的话有这一项,否则没有。
  • min(target); target = (newpath[i+1][j] - newpath[i][j])2 + (newpath[i-1][j] - newpath[i][j])2 = B2 + C2 ~> 相邻点更接近
  • min(target); target = (A-B)2 + (C-D)2 ~> 导数连续
  • A = (newpath[i+2][j] - newpath[i+1][j]); B = (newpath[i+1][j] - newpath[i][j]); C = (newpath[i-1][j] - newpath[i][j]); D = (newpath[i-2][j] - newpath[i-1][j]);
  • ~> gradient descent to minimize a target function

Q4: Racetrack Control

[Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control_第27张图片
Make sure CTE is negative inside the track and positive outside the track.
    def cte(self, radius):
        # 
        #
        # Add code here
        if radius < self.x and self.x < 3*radius:
            if cos(self.orientation) > 0:
                cte = self.y - 2*radius
            else:
                cte = - self.y
        elif self.x <= radius:
            cte = sqrt((self.x-radius)**2 + (self.y-radius)**2) - radius
        else:
            cte = sqrt((self.x-3*radius)**2 + (self.y-radius)**2) - radius
        #
        #            
        return cte

return:
[x=0.00000 y=26.00000 orient=1.57080]
[x=0.01365 y=26.99988 orient=1.54349]
[x=0.06592 y=27.99840 orient=1.49349]
[x=0.16804 y=28.99307 orient=1.44349]
[x=0.31973 y=29.98139 orient=1.39349]
[x=0.52064 y=30.96090 orient=1.34349]
[x=0.77025 y=31.92914 orient=1.29349]
[x=1.06793 y=32.88369 orient=1.24349]
......
[x=99.46649 y=19.51598 orient=4.49955]
[x=99.23092 y=18.54423 orient=4.44955]
[x=98.94707 y=17.58547 orient=4.39955]
[x=98.62399 y=16.63914 orient=4.36724]
[x=98.27383 y=15.70248 orient=4.34203]
[x=97.89398 y=14.77750 orient=4.30342]
[x=97.47355 y=13.87029 orient=4.25342]
[x=97.00830 y=12.98523 orient=4.20342]
[x=96.50351 y=12.12207 orient=4.16299]

Final parameters: [10.0, 15.0, 0]
-> 0.00586850481278

你可能感兴趣的:([Artificial Intelligence for Robotics] {cs373} Lesson 15: PID Control)