fav-pid-slides/main.tex
2023-11-06 15:16:09 +01:00

251 lines
7.8 KiB
TeX

\documentclass[aspectratio=169]{beamer}
\usepackage{mum-theme-beamer/mum-theme}
\input{code-block-settings.tex}
\input{tikz-settings.tex}
\title{Formulas and Vehicles}
\subtitle{Implementation of a PID-Controller}
\date{03.11.2023}
\author[\textbf{L. Alff}, N. Bauschmann, D. Duecker]{Lennart Alff, Nathalie Bauschmann, Daniel Duecker}
\institute[TUHH]{Hamburg University of Technology}
\begin{document}
\begin{frame}
\titlepage
\end{frame}
\begin{frame}
\frametitle{How to Start?}
\pause
\textbf{\Large Starting from scratch\dots}\vskip0.5cm
\pause
\textbf{\Large Identify the challenges:}\vskip0.25cm
\pause
\begin{enumerate}
\item Communication/data flow -- the ROS perspective \pause
\item Implementing the control law -- the control perspective
\end{enumerate}
\end{frame}
\begin{frame}
\frametitle{ROS Graph}
\centering
\begin{tikzpicture}[node distance=10mm and 20mm]
\node (baro) [rosnode, alt=<2>{red}{}, alt=<3->{gray}{}] {Barometer};
\node (depth_calculator)
[
rosnode,
right=of baro,
alt=<4>{red}{},
alt=<5->{gray}{},
alt=<7->{mumgreen}{},
] {Depth\\Calculator};
\node (controller)[rosnode, right=of depth_calculator, alt=<6>{red}{}, alt=<7->{mumgreen}{}] {Controller};
\node (setpoint_publisher)[rosnode, below=of depth_calculator, alt=<5>{red}{}, alt=<6>{gray}{}, alt=<7->{mumgreen}{}] {Setpoint\\Publisher};
\draw[arrow] (baro) %
edge node [sloped, anchor=center, above] {\footnotesize pressure} %
node [sloped, anchor=center, below] {\tiny FluidPressure} %
(depth_calculator);
\draw[arrow] (depth_calculator)
edge node [sloped, anchor=center, above] {\footnotesize depth}
node [sloped, anchor=center, below] {\tiny DepthStamped}
(controller);
\draw[arrow] (setpoint_publisher)
edge node [sloped, anchor=center, above, xshift=-5mm] {\footnotesize depth\_setpoint}
node [sloped, anchor=center, below, xshift=-5mm] {\tiny Float64Stamped}
(controller);
\node (empty_right) [right=of controller] {};
\draw[arrow] (controller)
edge node [sloped, anchor=center, above] {\footnotesize thrust\_setpoint}
node [sloped, anchor=center, below] {\tiny ActuatorSetpoint}
(empty_right);
\end{tikzpicture}
\begin{itemize}
\color{mumgreen}
\item<7-> these nodes are included in our template for assignment 1 \pause
\item<8-> communication between them is already set up!
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Where to Start?}
% \begin{noindent}
\begin{pythoncode*}{label=depth\_controller.py}
class DepthControlNode(Node):
def __init__(self):
super().__init__(node_name='depth_controller')
self.thrust_pub = self.create_publisher(ActuatorSetpoint,
'thrust_setpoint', 1)
self.setpoint_sub = self.create_subscription(Float64Stamped,
'depth_setpoint',
self.on_setpoint, 1)
self.depth_sub = self.create_subscription(DepthStamped, 'depth',
self.on_depth, 1)
|\vdots|
\end{pythoncode*}
% \end{noindent}
\begin{itemize}
\item<2-> \color<4->{gray}{implement callbacks (\texttt{on\_setpoint}, \texttt{on\_depth})} \only<4->{\color{mumbluefont}{$\Rightarrow$ given in template!}}
\item<3-> \color<5->{red}{implement the control law}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Not Yet a PID Controller}
\textbf{\Large Again, starting point already provided in our template!}
\vskip0.5cm
% \begin{noindent}
\begin{pythoncode}
class DepthControlNode(Node):
|\vdots|
def compute_control_output(self, current_depth: float) -> float:
thrust = current_depth
return thrust
\end{pythoncode}
% \end{noindent}
\end{frame}
\begin{frame}
\frametitle{What was PID Control Again?}
\textbf{\Large Control law:}\vskip0.25cm
\begin{equation}
u = K_{\mathrm{p}} e + K_\mathrm{i} \int_0^{t} e\,\mathrm{d}\tau + K_{\mathrm{d}}\dot{e}
\end{equation}
\pause
\centering
\begin{tikzpicture}[node distance=10mm and 20mm]
\coordinate (start);
\coordinate[right=of start] (first_junction);
\node (integral)[right=of first_junction, rostopic]{$K_{\mathrm{i}}\int (\cdot)$};
\node (proportional)[above=of integral, rostopic]{$K_{\mathrm{p}}$};
\node (derivative)[below=of integral, rostopic]{$K_{\mathrm{d}}\frac{\mathrm{d}}{\mathrm{d}t}$};
%\coordinate[right=of integral] (second_junction);
\node (second_junction)[right=of integral, draw, circle]{$\sum$};
\coordinate[right=of second_junction] (end);
\draw[] (start) edge node[above]{$e$} (first_junction);
\draw (first_junction) |- (proportional);
\draw (first_junction) |- (integral);
\draw (first_junction) |- (derivative);
\draw (proportional) -| (second_junction);
\draw (integral) -- (second_junction);
\draw (derivative) -| (second_junction);
\draw (second_junction) edge node[above]{$u$} (end);
\end{tikzpicture}
\end{frame}
\begin{frame}[fragile]
\frametitle{Proportional Control}
\textbf{\Large Control law:}\vskip0.25cm
\begin{equation}
u = \textcolor{red}{K_{\mathrm{p}} e} + K_\mathrm{i} \int_0^{t} e\,\mathrm{d}\tau + K_{\mathrm{d}}\dot{e}
\end{equation}
\pause
\textbf{\Large Code:}\vskip0.25cm
% \begin{noindent}
\begin{pythoncode}
class DepthControlNode(Node):
|\vdots|
def compute_control_output(self, current_depth: float) -> float:
p_gain = 1.0
error = current_depth - self.current_setpoint
thrust = p_gain * error
return thrust
\end{pythoncode}
% \end{noindent}
\end{frame}
\begin{frame}[fragile]
\frametitle{PI-Control}
\begin{equation}
u = K_{\mathrm{p}} e + \textcolor{mumblue}{K_\mathrm{i} \int_0^{t} e\,\mathrm{d}\tau} + K_{\mathrm{d}}\dot{e}
\end{equation}
\pause
% \begin{noindent}
\begin{pythoncode}
class DepthControlNode(Node):
def __init__(self):
self.error_integral = 0.0
self.last_time = self.get_clock().now().nanoseconds * 1e-9
|\dots|
def compute_control_output(self, current_depth: float) -> float:
p_gain = 1.0
i_gain = 1.0
error = current_depth - self.current_setpoint
now = self.get_clock().now().nanoseconds * 1e-9
dt = now - self.last_time
self.error_integral = self.error_integral + dt * error
thrust = p_gain * error + i_gain * self.error_integral
self.last_time = now
return thrust
\end{pythoncode}
% \end{noindent}
\end{frame}
\begin{frame}[fragile]
\frametitle{PID-Control}
\alt<1>{
\begin{equation}
u = K_{\mathrm{p}} e + K_\mathrm{i} \int_0^{t} e\,\mathrm{d}\tau + \textcolor{mumgreen}{K_{\mathrm{d}}\dot{e}}
\end{equation}
}{}
\pause
% \begin{noindent}
\begin{pythoncode}
class DepthControlNode(Node):
def __init__(self):
self.error_integral = 0.0
self.last_time = self.get_clock().now().nanoseconds * 1e-9
self.last_error = 0.0
|\dots|
def compute_control_output(self, current_depth: float) -> float:
p_gain = 1.0
i_gain = 1.0
d_gain = 1.0
error = current_depth - self.current_setpoint
now = self.get_clock().now().nanoseconds * 1e-9
dt = now - self.last_time
self.error_integral = self.error_integral + dt * error
derror = (error - self._last_error) / dt
thrust = p_gain * error + i_gain * self.error_integral + d_gain * derror
self.last_time = now
self.last_error = error
return thrust
\end{pythoncode}
% \end{noindent}
\end{frame}
\begin{frame}
\frametitle{See the Controller in Action}
\centering
\textbf{\Large Time for the fun part?}
\end{frame}
\end{document}