rvlab 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rvlab-0.1.0/MANIFEST.in +1 -0
- rvlab-0.1.0/PKG-INFO +7 -0
- rvlab-0.1.0/pyproject.toml +19 -0
- rvlab-0.1.0/setup.cfg +4 -0
- rvlab-0.1.0/src/rvlab/__init__.py +0 -0
- rvlab-0.1.0/src/rvlab/ai_ml/Flocking_Bird.py +100 -0
- rvlab-0.1.0/src/rvlab/ai_ml/LR_Scalar_Method.py +29 -0
- rvlab-0.1.0/src/rvlab/ai_ml/LR_Vector_Method.py +26 -0
- rvlab-0.1.0/src/rvlab/ai_ml/Markov_Chain_Eigen_Vector.py +16 -0
- rvlab-0.1.0/src/rvlab/ai_ml/Markov_Chain_Linear_Chain.py +20 -0
- rvlab-0.1.0/src/rvlab/ai_ml/Markov_Chain_Power_Iteration.py +12 -0
- rvlab-0.1.0/src/rvlab/ai_ml/Simulated_annealing.py +62 -0
- rvlab-0.1.0/src/rvlab/ai_ml/__init__.py +0 -0
- rvlab-0.1.0/src/rvlab/control/__init__.py +0 -0
- rvlab-0.1.0/src/rvlab/control/lqr_matlab.py +100 -0
- rvlab-0.1.0/src/rvlab/control/p_pd_pi_pid_control_matlab.py +118 -0
- rvlab-0.1.0/src/rvlab/robotics/2_dof_circle_tracking_matlab.py +247 -0
- rvlab-0.1.0/src/rvlab/robotics/3_dof_circle_tracking_matlab.py +267 -0
- rvlab-0.1.0/src/rvlab/robotics/3_dof_helix_tracking_matlab.py +175 -0
- rvlab-0.1.0/src/rvlab/robotics/6_dof_matlab.py +691 -0
- rvlab-0.1.0/src/rvlab/robotics/__init__.py +0 -0
- rvlab-0.1.0/src/rvlab/robotics/astar_matlab.py +51 -0
- rvlab-0.1.0/src/rvlab/robotics/dijkistra_matlab.py +46 -0
- rvlab-0.1.0/src/rvlab/robotics/dtsar_matlab.py +71 -0
- rvlab-0.1.0/src/rvlab/robotics/rrt_matlab.py +67 -0
- rvlab-0.1.0/src/rvlab/robotics/sensor_fusion_kf_matlab.py +148 -0
- rvlab-0.1.0/src/rvlab/rpp/__init__.py +0 -0
- rvlab-0.1.0/src/rvlab/rpp/extended_kalman_filter_python.py +158 -0
- rvlab-0.1.0/src/rvlab/rpp/kalman_filter_python.py +83 -0
- rvlab-0.1.0/src/rvlab/rpp/particle_filter_matlab.py +86 -0
- rvlab-0.1.0/src/rvlab/vision/CV2_BGR_to_Plot_RGB.py +39 -0
- rvlab-0.1.0/src/rvlab/vision/Contrast_Streching.py +32 -0
- rvlab-0.1.0/src/rvlab/vision/Contrast_Streching_(automatic).py +22 -0
- rvlab-0.1.0/src/rvlab/vision/Edge_Detection_Laplacian.py +22 -0
- rvlab-0.1.0/src/rvlab/vision/Edge_Detection_Normal.py +20 -0
- rvlab-0.1.0/src/rvlab/vision/Edge_Detection_Sobel.py +30 -0
- rvlab-0.1.0/src/rvlab/vision/Histogram_Equalization.py +19 -0
- rvlab-0.1.0/src/rvlab/vision/Histogram_Equalization_Img.py +21 -0
- rvlab-0.1.0/src/rvlab/vision/Histogram_Equalization_manual.py +39 -0
- rvlab-0.1.0/src/rvlab/vision/Histogram_Plotting.py +38 -0
- rvlab-0.1.0/src/rvlab/vision/Image_Negative.py +23 -0
- rvlab-0.1.0/src/rvlab/vision/Lab_code_vision.pdf +0 -0
- rvlab-0.1.0/src/rvlab/vision/Logarithmic_Transformation.py +24 -0
- rvlab-0.1.0/src/rvlab/vision/Logical_Binary_Mask.py +39 -0
- rvlab-0.1.0/src/rvlab/vision/Meadian_filter.py +19 -0
- rvlab-0.1.0/src/rvlab/vision/Mean_Filter.py +17 -0
- rvlab-0.1.0/src/rvlab/vision/Mean_Median.py +26 -0
- rvlab-0.1.0/src/rvlab/vision/Power_Law_Transformation.py +23 -0
- rvlab-0.1.0/src/rvlab/vision/Sharpening_Image.py +25 -0
- rvlab-0.1.0/src/rvlab/vision/Unmask_Filterning.py +23 -0
- rvlab-0.1.0/src/rvlab/vision/__init__.py +0 -0
- rvlab-0.1.0/src/rvlab/vision/min_max_filter.py +26 -0
- rvlab-0.1.0/src/rvlab/vision/plotting_Histogram_of_an_image.py +30 -0
- rvlab-0.1.0/src/rvlab.egg-info/PKG-INFO +7 -0
- rvlab-0.1.0/src/rvlab.egg-info/SOURCES.txt +56 -0
- rvlab-0.1.0/src/rvlab.egg-info/dependency_links.txt +1 -0
- rvlab-0.1.0/src/rvlab.egg-info/requires.txt +3 -0
- rvlab-0.1.0/src/rvlab.egg-info/top_level.txt +1 -0
rvlab-0.1.0/MANIFEST.in
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
recursive-include src/rvlab *.pdf
|
rvlab-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "rvlab"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A clean, modern Python package for rvlab"
|
|
9
|
+
dependencies = [
|
|
10
|
+
"numpy",
|
|
11
|
+
"opencv-python",
|
|
12
|
+
"matplotlib"
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[tool.setuptools]
|
|
16
|
+
include-package-data = true
|
|
17
|
+
|
|
18
|
+
[tool.setuptools.packages.find]
|
|
19
|
+
where = ["src"]
|
rvlab-0.1.0/setup.cfg
ADDED
|
File without changes
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
from matplotlib.animation import FuncAnimation
|
|
4
|
+
|
|
5
|
+
#Initialization Parameters
|
|
6
|
+
N = 50 #no of boids
|
|
7
|
+
Width, Height = 800, 600 #Space Size
|
|
8
|
+
|
|
9
|
+
Max_Speed = 7
|
|
10
|
+
Max_Force = 0.05
|
|
11
|
+
Perception_Radius = 50
|
|
12
|
+
|
|
13
|
+
#Initialize Weights
|
|
14
|
+
W_Sep = 1.2
|
|
15
|
+
W_ALIGN = 1.0
|
|
16
|
+
W_COH = 1.0
|
|
17
|
+
|
|
18
|
+
#Initialize position and velocities
|
|
19
|
+
positions = np.random.rand(N,2)*[Width, Height]
|
|
20
|
+
velocities = (np.random.rand(N,2)-0.5)*10
|
|
21
|
+
|
|
22
|
+
#Limit Magnitude function to limit force, velocity and position
|
|
23
|
+
def limitMagnitude(vec, maxVal):
|
|
24
|
+
mag = np.linalg.norm(vec)
|
|
25
|
+
if mag>maxVal:
|
|
26
|
+
return (vec/mag)*maxVal
|
|
27
|
+
return vec
|
|
28
|
+
|
|
29
|
+
#Updating the velocity and position of each boid
|
|
30
|
+
def updateBoids():
|
|
31
|
+
global positions, velocities
|
|
32
|
+
newVelocities = np.copy(velocities)
|
|
33
|
+
for i in range(N):
|
|
34
|
+
|
|
35
|
+
posi = positions[i]
|
|
36
|
+
veli = velocities[i]
|
|
37
|
+
#initializing Separation, Alignment and cohesion
|
|
38
|
+
Separation = np.zeros(2)
|
|
39
|
+
Alignment = np.zeros(2)
|
|
40
|
+
Cohesion = np.zeros(2)
|
|
41
|
+
|
|
42
|
+
total = 0
|
|
43
|
+
for j in range(N):
|
|
44
|
+
|
|
45
|
+
if i==j:
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
diff = positions[j]-posi
|
|
49
|
+
dist = np.linalg.norm(diff)
|
|
50
|
+
|
|
51
|
+
if dist<Perception_Radius and dist>0:
|
|
52
|
+
#update Separation
|
|
53
|
+
Separation += -diff/(dist**2)
|
|
54
|
+
#update Alighnment
|
|
55
|
+
Alignment += velocities[j]
|
|
56
|
+
#update Cohesion
|
|
57
|
+
Cohesion += positions[j]
|
|
58
|
+
|
|
59
|
+
total +=1
|
|
60
|
+
|
|
61
|
+
if total>0:
|
|
62
|
+
|
|
63
|
+
Alignment /= total
|
|
64
|
+
Alignment -=veli
|
|
65
|
+
Alignment = limitMagnitude(Alignment, Max_Force)
|
|
66
|
+
|
|
67
|
+
Cohesion /= total
|
|
68
|
+
Cohesion -=veli
|
|
69
|
+
Cohesion = limitMagnitude(Cohesion, Max_Force)
|
|
70
|
+
|
|
71
|
+
Separation = limitMagnitude(Separation, Max_Force)
|
|
72
|
+
|
|
73
|
+
#Calculate Acceleration
|
|
74
|
+
Acceleration = (W_Sep*Separation+W_ALIGN*Alignment+W_COH*Cohesion)
|
|
75
|
+
|
|
76
|
+
newVelocities[i] += Acceleration
|
|
77
|
+
newVelocities[i] = limitMagnitude(newVelocities[i], Max_Speed)
|
|
78
|
+
|
|
79
|
+
velocities = newVelocities
|
|
80
|
+
positions += velocities
|
|
81
|
+
|
|
82
|
+
#Wrap Around Edges
|
|
83
|
+
positions[:,0] = positions[:,0]%Width
|
|
84
|
+
positions[:,1] = positions[:,1]%Height
|
|
85
|
+
|
|
86
|
+
#Visualization
|
|
87
|
+
fig, ax = plt.subplots()
|
|
88
|
+
scat = ax.scatter(positions[:,0], positions[:,1])
|
|
89
|
+
|
|
90
|
+
#Wrapping the boids within the plot
|
|
91
|
+
ax.set_xlim(0, Width)
|
|
92
|
+
ax.set_ylim(0,Height)
|
|
93
|
+
|
|
94
|
+
def animate(frame):
|
|
95
|
+
updateBoids()
|
|
96
|
+
scat.set_offsets(positions)
|
|
97
|
+
return scat
|
|
98
|
+
|
|
99
|
+
ani = FuncAnimation(fig, animate, interval=10)
|
|
100
|
+
plt.show()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
|
|
4
|
+
x = np.linspace(0,10,50)
|
|
5
|
+
y = 3*x+2+np.random.randn(50)*2
|
|
6
|
+
|
|
7
|
+
#Intializing Calculation terms
|
|
8
|
+
n = len(x)
|
|
9
|
+
sigmax = np.sum(x)
|
|
10
|
+
sigmay = np.sum(y)
|
|
11
|
+
sigmaxy = np.sum(x*y)
|
|
12
|
+
sigmaxsquare = np.sum(x**2)
|
|
13
|
+
|
|
14
|
+
#Calculating slome 'm' and intercept 'b'
|
|
15
|
+
m = ((n*sigmaxy) - (sigmax * sigmay))/(n*sigmaxsquare - sigmax**2)
|
|
16
|
+
b = (sigmay - m*sigmax)/n
|
|
17
|
+
|
|
18
|
+
y_pred = m*x+b
|
|
19
|
+
|
|
20
|
+
#plotting the data
|
|
21
|
+
plt.scatter(x,y, color='blue', label="Noisy Data")
|
|
22
|
+
plt.plot(x,y_pred, color="red", label= f"Predicted Line {m:.2f}x+{b:.2f}")
|
|
23
|
+
plt.xlabel("Independent (X)")
|
|
24
|
+
plt.title("Linear Regression using Least Squares Method")
|
|
25
|
+
plt.ylabel("Dependent Variable (Y)")
|
|
26
|
+
plt.gcf().text(0.5, 0.01, f"The Slope: {m:.2f} and Intercept: {b:.2f} of the predicted Line for noisy Data",
|
|
27
|
+
ha='center', fontsize=12)
|
|
28
|
+
plt.legend()
|
|
29
|
+
plt.show()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
import random
|
|
4
|
+
|
|
5
|
+
x = np.linspace(0,10,50)
|
|
6
|
+
y = 3*x + 2 + np.random.randn(50)*2
|
|
7
|
+
|
|
8
|
+
const = np.ones(50)
|
|
9
|
+
x_final = np.column_stack((const,x))
|
|
10
|
+
x_final_Transpose = x_final.T
|
|
11
|
+
|
|
12
|
+
Beta = np.linalg.inv(x_final_Transpose@x_final)@x_final_Transpose@y
|
|
13
|
+
|
|
14
|
+
print("Co-efficients (Intercept, Slope):",Beta[0], Beta[1])
|
|
15
|
+
#Predicted Line
|
|
16
|
+
y_pred = Beta[1]*x+Beta[0]
|
|
17
|
+
|
|
18
|
+
plt.scatter(x,y, color='blue', label="Noisy Data")
|
|
19
|
+
plt.plot(x,y_pred, color="red", label= f"Predicted Line {Beta[1]:.2f}x+{Beta[0]:.2f}")
|
|
20
|
+
plt.xlabel("Independent (X)")
|
|
21
|
+
plt.title("Linear Regression using Least Squares Method")
|
|
22
|
+
plt.ylabel("Dependent Variable (Y)")
|
|
23
|
+
plt.gcf().text(0.5, 0.01, f"The Slope: {Beta[1]:.2f} and Intercept: {Beta[0]:.2f} of the predicted Line for noisy Data",
|
|
24
|
+
ha='center', fontsize=12)
|
|
25
|
+
plt.legend()
|
|
26
|
+
plt.show()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
def eigenDecomposition(P):
|
|
4
|
+
eigenvals, eigenvecs = np.linalg.eig(P)
|
|
5
|
+
index = np.argmin(np.abs(eigenvals-1))
|
|
6
|
+
vectorPI = np.real(eigenvecs[:,index])
|
|
7
|
+
|
|
8
|
+
#normalize
|
|
9
|
+
vectorPI = vectorPI/np.sum(vectorPI)
|
|
10
|
+
|
|
11
|
+
return vectorPI
|
|
12
|
+
|
|
13
|
+
P = np.array([[0.2,0.6,0.2],
|
|
14
|
+
[0.3,0.0,0.7],
|
|
15
|
+
[0.5,0.3,0.2]])
|
|
16
|
+
print("The Final steady-state (stationary distribution) of a Markov chain is: ", eigenDecomposition(P))
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
def linearSystemModel(P):
|
|
4
|
+
n = P.shape[0]
|
|
5
|
+
|
|
6
|
+
A = P.T - np.eye(n)
|
|
7
|
+
b = np.zeros(n)
|
|
8
|
+
|
|
9
|
+
#Adding the sum equal to 1 constraing to filter the infinite solutions
|
|
10
|
+
A[-1] = np.ones(n)
|
|
11
|
+
b[-1] = 1
|
|
12
|
+
|
|
13
|
+
vectorPI = np.linalg.solve(A,b)
|
|
14
|
+
|
|
15
|
+
return vectorPI
|
|
16
|
+
|
|
17
|
+
P = np.array([[0.2,0.6,0.2],
|
|
18
|
+
[0.3,0.0,0.7],
|
|
19
|
+
[0.5,0.3,0.2]])
|
|
20
|
+
print("The Final steady-state (stationary distribution) of a Markov chain is: ", linearSystemModel(P))
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
def multiply(A,B):
|
|
4
|
+
return A@B
|
|
5
|
+
|
|
6
|
+
P = np.array([[0.2,0.6,0.2],[0.3,0.0,0.7],[0.5,0.3,0.2]])
|
|
7
|
+
vectorPI = np.array([0.3,0.4,0.3])
|
|
8
|
+
n = int(input("No of Iterations you want to run: "))
|
|
9
|
+
for i in range(0,n):
|
|
10
|
+
vectorPI=multiply(vectorPI, P)
|
|
11
|
+
|
|
12
|
+
print("The Final steady-state (stationary distribution) of a Markov chain PI Vector after implementing power iteration is: ", vectorPI)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import random
|
|
3
|
+
import matplotlib.pyplot as plt
|
|
4
|
+
|
|
5
|
+
#Solving a cubic equation using simulated annealing.
|
|
6
|
+
def simulated_Annealing(s0, T_max, T_min, alpha):
|
|
7
|
+
current_state= s0
|
|
8
|
+
T = T_max
|
|
9
|
+
E = []
|
|
10
|
+
states=[]
|
|
11
|
+
states.append(s0)
|
|
12
|
+
E.append(Energy(s0))
|
|
13
|
+
|
|
14
|
+
while T>T_min:
|
|
15
|
+
|
|
16
|
+
#Generate a random neighbour
|
|
17
|
+
next_state = getRandomNeighbour(current_state)
|
|
18
|
+
|
|
19
|
+
#Calculate the change in Energy
|
|
20
|
+
delta_E = Energy(next_state) - Energy(current_state)
|
|
21
|
+
|
|
22
|
+
#Decision rule
|
|
23
|
+
if delta_E < 0:
|
|
24
|
+
current_state = next_state
|
|
25
|
+
states.append(current_state)
|
|
26
|
+
E.append(Energy(current_state))
|
|
27
|
+
|
|
28
|
+
else:
|
|
29
|
+
r = random.random()
|
|
30
|
+
|
|
31
|
+
if r < pow(math.e, -delta_E/T):
|
|
32
|
+
current_state = next_state
|
|
33
|
+
states.append(current_state)
|
|
34
|
+
E.append(Energy(current_state))
|
|
35
|
+
T = T*alpha
|
|
36
|
+
plt.plot(states, E, label="Simulated Annealing Plot")
|
|
37
|
+
plt.plot(states[-1], E[-1], color='red', marker='o', label="Final Solution and Energy")
|
|
38
|
+
plt.text(states[-1], 0.5+E[-1], f"({states[-1]:.2f}, {E[-1]:.2f})")
|
|
39
|
+
plt.plot(states[E.index(min(E))], min(E), color='green', marker='o', label='Best Solution of the Run')
|
|
40
|
+
plt.text(states[E.index(min(E))], 0.5+min(E),f"({states[E.index(min(E))]:.2f},{min(E):.2f})")
|
|
41
|
+
plt.gcf().text(0.5, 0.01, f"The Final Solution state: {states[-1]:.2f} and Energy: {E[-1]:.2f}",
|
|
42
|
+
ha='center', fontsize=12)
|
|
43
|
+
plt.xlabel("States")
|
|
44
|
+
plt.ylabel("Energy")
|
|
45
|
+
plt.title("Simulated Annealing of x3-10x-2x2+10")
|
|
46
|
+
plt.legend()
|
|
47
|
+
plt.show()
|
|
48
|
+
return current_state
|
|
49
|
+
|
|
50
|
+
def getRandomNeighbour(currentState):
|
|
51
|
+
return random.uniform(-3,3)
|
|
52
|
+
|
|
53
|
+
def Energy(state):
|
|
54
|
+
return (state**3)-(10.0*state)-(2.0*(state**2))+10.0
|
|
55
|
+
|
|
56
|
+
print("******Welcome to simulated Annealing of x3-10x-2x2+10******")
|
|
57
|
+
Initial_State = float(input("What is the initial State:"))
|
|
58
|
+
Initial_Temparature = float(input("What is the initial Temparature:"))
|
|
59
|
+
Threshold_Temparature = float(input("What is the Threshold Temparature:"))
|
|
60
|
+
Cooling_Rate = float(input("What is the Cooling Rate:"))
|
|
61
|
+
|
|
62
|
+
Solution = simulated_Annealing(Initial_State, Initial_Temparature, Threshold_Temparature, Cooling_Rate)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
%% LQR-Based Control of a Unicycle System
|
|
2
|
+
clear; clc; close all;
|
|
3
|
+
%% ===== PARAMETERS =====
|
|
4
|
+
v_d = 0.5; % desired forward velocity (m/s)
|
|
5
|
+
dt = 0.01; % time step (s)
|
|
6
|
+
T = 15; % total time (s)
|
|
7
|
+
t = 0:dt:T;
|
|
8
|
+
N = length(t);
|
|
9
|
+
init = [0, 0, 0]; % [x, y, theta]
|
|
10
|
+
goal = [3, 3, pi/4]; % [xd, yd, thetad]
|
|
11
|
+
%% ===== PART b: LINEARIZED SYSTEM =====
|
|
12
|
+
A = [0, 0, 0;
|
|
13
|
+
0, 0, v_d;
|
|
14
|
+
0, 0, 0];
|
|
15
|
+
B = [-1, 0;
|
|
16
|
+
0, 0;
|
|
17
|
+
0, -1];
|
|
18
|
+
%% ===== PART c: LQR DESIGN =====
|
|
19
|
+
Q = diag([10, 10, 5]); % penalize position & heading errors
|
|
20
|
+
R = diag([1, 0.5]); % penalize control effort
|
|
21
|
+
% Check controllability
|
|
22
|
+
Co = ctrb(A, B);
|
|
23
|
+
fprintf('Controllability rank: %d / %d\n', rank(Co), size(A,1));
|
|
24
|
+
% Compute LQR gain matrix
|
|
25
|
+
[K, ~, ~] = lqr(A, B, Q, R);
|
|
26
|
+
fprintf('LQR Gain K =\n'); disp(K);
|
|
27
|
+
%% ===== PART d: SIMULATE UNICYCLE WITH LQR =====
|
|
28
|
+
x = init(1); y = init(2); th = init(3);
|
|
29
|
+
xd = goal(1); yd = goal(2); thd = goal(3);
|
|
30
|
+
x_log = zeros(1,N);
|
|
31
|
+
y_log = zeros(1,N);
|
|
32
|
+
th_log = zeros(1,N);
|
|
33
|
+
v_log = zeros(1,N);
|
|
34
|
+
w_log = zeros(1,N);
|
|
35
|
+
e_log = zeros(1,N);
|
|
36
|
+
for i = 1:N
|
|
37
|
+
% Log current state
|
|
38
|
+
x_log(i) = x;
|
|
39
|
+
y_log(i) = y;
|
|
40
|
+
th_log(i) = th;
|
|
41
|
+
% Error in robot body frame
|
|
42
|
+
ex = cos(th)*(xd - x) + sin(th)*(yd - y);
|
|
43
|
+
ey = -sin(th)*(xd - x) + cos(th)*(yd - y);
|
|
44
|
+
et = atan2(sin(thd - th), cos(thd - th));
|
|
45
|
+
e = [ex; ey; et];
|
|
46
|
+
% LQR control law: u = K*e
|
|
47
|
+
u = K * e;
|
|
48
|
+
v = v_d + u(1); % linear velocity
|
|
49
|
+
w = u(2); % angular velocity
|
|
50
|
+
% Saturate inputs
|
|
51
|
+
v = max(-1.0, min(1.0, v));
|
|
52
|
+
w = max(-2.0, min(2.0, w));
|
|
53
|
+
v_log(i) = v;
|
|
54
|
+
w_log(i) = w;
|
|
55
|
+
e_log(i) = sqrt(ex^2 + ey^2);
|
|
56
|
+
end
|
|
57
|
+
% Unicycle kinematics update
|
|
58
|
+
x = x + dt * v * cos(th);
|
|
59
|
+
y = y + dt * v * sin(th);
|
|
60
|
+
th = th + dt * w;
|
|
61
|
+
th = atan2(sin(th), cos(th)); % wrap angle
|
|
62
|
+
fprintf('Final position error: %.4f m\n', e_log(end));
|
|
63
|
+
%% ===== PART e: PLOTS =====
|
|
64
|
+
% --- 1. Robot Path ---
|
|
65
|
+
figure('Color','w');
|
|
66
|
+
plot(x_log, y_log, 'b-', 'LineWidth', 2); hold on;
|
|
67
|
+
plot(init(1), init(2), 'go', 'MarkerSize', 10, 'MarkerFaceColor','g');
|
|
68
|
+
plot(goal(1), goal(2), 'r*', 'MarkerSize', 12, 'LineWidth', 2);
|
|
69
|
+
xlabel('X (m)'); ylabel('Y (m)');
|
|
70
|
+
title('LQR - Robot Path');
|
|
71
|
+
legend('Path', 'Start', 'Goal');
|
|
72
|
+
grid on; axis equal;
|
|
73
|
+
% --- 2. Position Error ---
|
|
74
|
+
figure('Color','w');
|
|
75
|
+
plot(t, e_log, 'r-', 'LineWidth', 2);
|
|
76
|
+
xlabel('Time (s)'); ylabel('Position Error (m)');
|
|
77
|
+
title('LQR - Position Error vs Time');
|
|
78
|
+
grid on;
|
|
79
|
+
% --- 3. Control Inputs ---
|
|
80
|
+
figure('Color','w');
|
|
81
|
+
subplot(2,1,1);
|
|
82
|
+
plot(t, v_log, 'b-', 'LineWidth', 2);
|
|
83
|
+
ylabel('v (m/s)'); title('LQR - Linear Velocity');
|
|
84
|
+
grid on;
|
|
85
|
+
subplot(2,1,2);
|
|
86
|
+
plot(t, w_log, 'r-', 'LineWidth', 2);
|
|
87
|
+
xlabel('Time (s)'); ylabel('\omega (rad/s)');
|
|
88
|
+
title('LQR - Angular Velocity');
|
|
89
|
+
grid on;
|
|
90
|
+
% --- 4. X, Y, Theta over time ---
|
|
91
|
+
figure('Color','w');
|
|
92
|
+
subplot(3,1,1);
|
|
93
|
+
plot(t, x_log, 'b', 'LineWidth', 1.5); yline(goal(1),'r--');
|
|
94
|
+
ylabel('X (m)'); title('LQR - State Trajectories'); grid on;
|
|
95
|
+
subplot(3,1,2);
|
|
96
|
+
plot(t, y_log, 'b', 'LineWidth', 1.5); yline(goal(2),'r--');
|
|
97
|
+
ylabel('Y (m)'); grid on;
|
|
98
|
+
subplot(3,1,3);
|
|
99
|
+
plot(t, th_log, 'b', 'LineWidth', 1.5); yline(goal(3),'r--');
|
|
100
|
+
ylabel('\theta (rad)'); xlabel('Time (s)'); grid on;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
clc;
|
|
2
|
+
clear;
|
|
3
|
+
close all;
|
|
4
|
+
%% Simulation Parameters
|
|
5
|
+
dt = 0.1;
|
|
6
|
+
T = 25;
|
|
7
|
+
time = 0:dt:T;
|
|
8
|
+
%% Desired Goal Position
|
|
9
|
+
x_goal = 10;
|
|
10
|
+
y_goal = 10;
|
|
11
|
+
%% Controller Gains
|
|
12
|
+
% P
|
|
13
|
+
Kp_P = 0.8;
|
|
14
|
+
% PI
|
|
15
|
+
Kp_PI = 0.8;
|
|
16
|
+
Ki_PI = 0.02;
|
|
17
|
+
% PD
|
|
18
|
+
Kp_PD = 0.8;
|
|
19
|
+
Kd_PD = 0.3;
|
|
20
|
+
% PID
|
|
21
|
+
Kp_PID = 0.8;
|
|
22
|
+
Ki_PID = 0.02;
|
|
23
|
+
Kd_PID = 0.3;
|
|
24
|
+
controllers = {'P','PI','PD','PID'};
|
|
25
|
+
%% Create Figures
|
|
26
|
+
figure(1);
|
|
27
|
+
figure(2);
|
|
28
|
+
%% =========================================================
|
|
29
|
+
%% LOOP THROUGH CONTROLLERS
|
|
30
|
+
%% =========================================================
|
|
31
|
+
for c = 1:length(controllers)
|
|
32
|
+
%% Initial Conditions
|
|
33
|
+
x = 0;
|
|
34
|
+
y = 0;
|
|
35
|
+
theta = 0;
|
|
36
|
+
integral = 0;
|
|
37
|
+
prev_error = 0;
|
|
38
|
+
X = [];
|
|
39
|
+
Y = [];
|
|
40
|
+
E = [];
|
|
41
|
+
%% Simulation Loop
|
|
42
|
+
for k = 1:length(time)
|
|
43
|
+
%% Distance Error
|
|
44
|
+
error = sqrt((x_goal-x)^2 + (y_goal-y)^2);
|
|
45
|
+
%% Desired Heading
|
|
46
|
+
theta_d = atan2((y_goal-y),(x_goal-x));
|
|
47
|
+
%% Heading Error
|
|
48
|
+
omega = 2*(theta_d - theta);
|
|
49
|
+
%% Integral & Derivative Terms
|
|
50
|
+
integral = integral + error*dt;
|
|
51
|
+
derivative = (error - prev_error)/dt;
|
|
52
|
+
%% Controller Selection
|
|
53
|
+
switch controllers{c}
|
|
54
|
+
case 'P'
|
|
55
|
+
v = Kp_P*error;
|
|
56
|
+
case 'PI'
|
|
57
|
+
v = Kp_PI*error + ...
|
|
58
|
+
Ki_PI*integral;
|
|
59
|
+
case 'PD'
|
|
60
|
+
v = Kp_PD*error + ...
|
|
61
|
+
Kd_PD*derivative;
|
|
62
|
+
case 'PID'
|
|
63
|
+
v = Kp_PID*error + ...
|
|
64
|
+
Ki_PID*integral + ...
|
|
65
|
+
Kd_PID*derivative;
|
|
66
|
+
end
|
|
67
|
+
%% Velocity Saturation
|
|
68
|
+
v = min(v,2);
|
|
69
|
+
%% Unicycle Model
|
|
70
|
+
x = x + v*cos(theta)*dt;
|
|
71
|
+
y = y + v*sin(theta)*dt;
|
|
72
|
+
theta = theta + omega*dt;
|
|
73
|
+
%% Store Data
|
|
74
|
+
X = [X x];
|
|
75
|
+
Y = [Y y];
|
|
76
|
+
E = [E error];
|
|
77
|
+
prev_error = error;
|
|
78
|
+
end
|
|
79
|
+
%% =====================================================
|
|
80
|
+
%% FIGURE 1 : ROBOT TRAJECTORY
|
|
81
|
+
%% =====================================================
|
|
82
|
+
figure(1);
|
|
83
|
+
subplot(2,2,c);
|
|
84
|
+
plot(X,Y,'b','LineWidth',2);
|
|
85
|
+
hold on;
|
|
86
|
+
%% Start Position
|
|
87
|
+
plot(X(1),Y(1),...
|
|
88
|
+
'go','MarkerSize',10,'LineWidth',2);
|
|
89
|
+
%% Goal Position
|
|
90
|
+
plot(x_goal,y_goal,...
|
|
91
|
+
'kx','MarkerSize',12,'LineWidth',3);
|
|
92
|
+
%% Final Robot Position
|
|
93
|
+
plot(X(end),Y(end),...
|
|
94
|
+
'ro','MarkerSize',10,'LineWidth',2);
|
|
95
|
+
%% Robot Direction Arrow
|
|
96
|
+
quiver(X(end),Y(end),...
|
|
97
|
+
cos(theta),sin(theta),...
|
|
98
|
+
0.8,'r','LineWidth',2);
|
|
99
|
+
grid on;
|
|
100
|
+
axis equal;
|
|
101
|
+
xlabel('X Position');
|
|
102
|
+
ylabel('Y Position');
|
|
103
|
+
title([controllers{c} ' Controller']);
|
|
104
|
+
legend('Trajectory',...
|
|
105
|
+
'Start Position',...
|
|
106
|
+
'Goal Position',...
|
|
107
|
+
'Robot Position');
|
|
108
|
+
%% =====================================================
|
|
109
|
+
%% FIGURE 2 : ERROR vs TIME
|
|
110
|
+
%% =====================================================
|
|
111
|
+
figure(2);
|
|
112
|
+
subplot(2,2,c);
|
|
113
|
+
plot(time,E,'LineWidth',2);
|
|
114
|
+
grid on;
|
|
115
|
+
xlabel('Time (s)');
|
|
116
|
+
ylabel('Distance Error');
|
|
117
|
+
title([controllers{c} ' Error vs Time']);
|
|
118
|
+
end
|