generated from lennartalff/mum-beamer-template
269 lines
7.9 KiB
TeX
269 lines
7.9 KiB
TeX
\documentclass[aspectratio=169]{beamer}
|
|
\usepackage{mum-theme-beamer/mum-theme}
|
|
\usepackage{graphicx}
|
|
\input{code-block-settings.tex}
|
|
\input{tikz-settings.tex}
|
|
|
|
\title{Getting Started}
|
|
\subtitle{Introduction into ROS}
|
|
\date{24.10.2024}
|
|
\author[\textbf{L. Alff}, N. Bauschmann, D.A. Duecker]{Lennart Alff, Nathalie Bauschmann, Daniel Duecker}
|
|
\institute[TUHH]{Hamburg University of Technology}
|
|
|
|
\renewcommand<>{\fbox}[1]{\alt#2{\fcolorbox{black}{white}{#1}}{\fcolorbox{white}{white}{#1}}}
|
|
|
|
\begin{document}
|
|
\begin{frame}
|
|
\titlepage
|
|
\end{frame}
|
|
|
|
\begin{frame}
|
|
\frametitle{Motivation}
|
|
|
|
\fbox<3->{\begin{minipage}[]{0.45\textwidth}
|
|
\onslide<1->{\textbf{Scenario:}}
|
|
\begin{itemize}
|
|
\item<1-> Mobile robot with a camera
|
|
\end{itemize}
|
|
\onslide<2->{\textbf{Goal:}}
|
|
\begin{itemize}
|
|
\item<2-> Autonomous navigation
|
|
\end{itemize}
|
|
\end{minipage}}
|
|
\begin{minipage}[]{0.45\textwidth}
|
|
\centering
|
|
\includegraphics<1->[width=0.7\textwidth]{images/robot-bin.png}
|
|
\end{minipage}\\
|
|
\vspace{2mm}
|
|
|
|
\visible<4->{\begin{minipage}{\textwidth}
|
|
\begin{tikzpicture}[node distance=8mm and 10mm]
|
|
\node[fill=white] (camera) [rosnode]{Camera};
|
|
\node[fill=white] (image) [rostopic, right=of camera, xshift=10mm]{Image};
|
|
\node[fill=white] (localization) [rosnode, right=of image]{Localization};
|
|
\node[fill=white] (position) [rostopic, right=of localization]{Position};
|
|
\node[fill=white] (controller) [rosnode, below=of position]{Controller};
|
|
\node[fill=white] (motor-commands) [rostopic, left=of controller]{Motor Commands};
|
|
\node[fill=white] (motor-drivers) [rosnode, below=of camera]{Motor Drivers};
|
|
\begin{scope}[on background layer]
|
|
\draw[thick, rounded corners=2mm, fill=blue!10] ($(camera.north west)+(-1.5, 0.5)$) rectangle ($(motor-drivers.south east)+(1.0,-0.5)$);
|
|
\draw[thick, rounded corners=2mm, fill=green!10] ($(image.north west)+(-0.5, 0.5)$) rectangle ($(controller.south east)+(0.5,-0.5)$);
|
|
\end{scope}
|
|
\path[-latex, thick] (camera) edge (image)
|
|
(image) edge (localization)
|
|
(localization) edge (position)
|
|
(position) edge (controller)
|
|
(controller) edge (motor-commands)
|
|
(motor-commands) edge (motor-drivers)
|
|
;
|
|
% align needed for line break
|
|
\node (env)[above=of camera, yshift=-4.5mm, align=center]{Interaction with\\Environment};
|
|
\node (env)[above=of localization, yshift=-4mm, align=center]{Internal Processing};
|
|
|
|
\end{tikzpicture}
|
|
\end{minipage}
|
|
}
|
|
\end{frame}
|
|
|
|
\begin{frame}
|
|
\frametitle{How to do it?}
|
|
|
|
\onslide<1->\textbf{\Large Naive Approach:}
|
|
\begin{itemize}
|
|
\item<2->Single monolithic program
|
|
\begin{itemize}
|
|
\item<3-> scales badly
|
|
\item<3->hard to introspect/debug
|
|
\item<3->what if multiple computers/devices used?
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\vspace{5mm}
|
|
|
|
\onslide<4->\textbf{\Large Better Approach:}
|
|
\begin{itemize}
|
|
\item<5-> Use ROS $\Rightarrow$ write small programs
|
|
\begin{itemize}
|
|
\item<6->solve big problems by subdividision (divide \& conquer)
|
|
\item<7->ROS brings a lot of utility
|
|
\begin{itemize}
|
|
\item<8-> plotting
|
|
\item<9-> logging
|
|
\item<10-> ...
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}
|
|
\frametitle{From Theory to Practice}
|
|
\centering
|
|
\textbf{\Huge From zero to depth!}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]
|
|
\frametitle{Hello World}
|
|
\begin{pythoncode}
|
|
print('hello world!')
|
|
\end{pythoncode}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]
|
|
\frametitle{Hello World With Good Practice}
|
|
\begin{pythoncode}
|
|
def main():
|
|
print('hello world')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
\end{pythoncode}
|
|
\pause
|
|
\vspace{5mm}
|
|
\begin{itemize}[<+->]
|
|
\item not strictly required but a convention
|
|
\item analog to the \texttt{int main()} in C/C++
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]
|
|
\frametitle{First Contact with ROS}
|
|
\begin{minipage}{0.48\textwidth}
|
|
\begin{pythoncode}
|
|
import rclpy
|
|
from rclpy.node import Node
|
|
|
|
|
|
def main():
|
|
rclpy.init()
|
|
node = Node(node_name='my_node')
|
|
rclpy.spin(node)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
\end{pythoncode}
|
|
\end{minipage}
|
|
\begin{minipage}{0.48\textwidth}
|
|
\begin{itemize}[<+->]
|
|
\item minimal ROS program
|
|
\item the generic \texttt{Node} does nothing on its own
|
|
\begin{itemize}[<+->]
|
|
\item not particularly useful
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\vspace{10mm}
|
|
\pause
|
|
\textbf{\Large $\Rightarrow$ we implement our own node!}
|
|
\end{minipage}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]
|
|
\frametitle{Our First Custom Node}
|
|
\begin{minipage}{0.48\textwidth}
|
|
\begin{pythoncode}
|
|
import rclpy
|
|
from rclpy.node import Node
|
|
|
|
class DepthCalculatorNode(Node):
|
|
|
|
def __init__(self):
|
|
super().__init__(node_name='my_node')
|
|
|
|
|
|
def main():
|
|
rclpy.init()
|
|
node = DepthCalculatorNode()
|
|
rlcpy.spin(node)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
\end{pythoncode}
|
|
\end{minipage}
|
|
\begin{minipage}{0.48\textwidth}
|
|
\pause
|
|
\begin{itemize}[<+->]
|
|
\small
|
|
\item our custom node does exactly the same as the generic \texttt{rclpy.Node} $\rightarrow$ \textbf{nothing}
|
|
\item this is the boilerplate code we need for every node we write
|
|
\item doing nothing $\neq$ not beeing able to do something
|
|
\end{itemize}
|
|
\vspace{5mm}
|
|
\pause
|
|
\textbf{Provides us with these functions:}
|
|
\begin{itemize}[<+->]
|
|
\small
|
|
\item \texttt{create\_publisher}
|
|
\item \texttt{create\_subscription}
|
|
\item \texttt{create\_timer}
|
|
\item \texttt{get\_logger}
|
|
\item \texttt{get\_clock}
|
|
\end{itemize}
|
|
\end{minipage}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]
|
|
\frametitle{Receiving Pressure Measurements}
|
|
\begin{pythoncode}
|
|
import rclpy
|
|
from rclpy.node import Node
|
|
from sensor_msgs.msg import FluidPressure
|
|
|
|
class DepthCalculatorNode(Node):
|
|
|
|
def __init__(self):
|
|
super().__init__(node_name='my_node')
|
|
|
|
self.pressure_sub = self.create_subscription(FluidPressure, 'pressure',
|
|
self.on_pressure, 1)
|
|
|
|
def on_pressure(self, msg: FluidPressure):
|
|
self.get_logger().info('Pressure measurement received')
|
|
|
|
|
|
def main():
|
|
...
|
|
\end{pythoncode}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]
|
|
\frametitle{Publishing Depth Values}
|
|
|
|
\begin{pythoncode}
|
|
import rclpy
|
|
from hippo_msgs.msg import DepthStamped
|
|
from rclpy.node import Node
|
|
from sensor_msgs.msg import FluidPressure
|
|
|
|
class DepthCalculatorNode(Node):
|
|
|
|
def __init__(self):
|
|
super().__init__(node_name='my_node')
|
|
|
|
self.pressure_sub = self.create_subscription(FluidPressure, 'pressure',
|
|
self.on_pressure, 1)
|
|
self.depth_pub = self.create_publisher(DepthStamped, 'depth', 1)
|
|
|
|
def on_pressure(self, msg: FluidPressure):
|
|
self.get_logger().info('Pressure measurement received')
|
|
pressure = msg.fluid_pressure
|
|
depth = self.pressure_to_detph(pressure)
|
|
|
|
depth_msg = DepthStamped() # do not forget the parentheses!
|
|
depth_msg.header.stamp = msg.header.stamp
|
|
depth_msg.depth = depth
|
|
|
|
self.depth_pub.publish(depth_msg)
|
|
|
|
def pressure_to_depth(self, pressure):
|
|
depth = ???
|
|
return depth
|
|
|
|
|
|
|
|
def main():
|
|
...
|
|
\end{pythoncode}
|
|
\end{frame}
|
|
|
|
\end{document}
|