first test push
This commit is contained in:
commit
c98972e4a9
4
Links.md
Normal file
4
Links.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Links for during ROS Workshop
|
||||
|
||||
ros_tutorials: https://github.com/ros/ros_tutorials.git
|
||||
|
50
README.md
Normal file
50
README.md
Normal file
@ -0,0 +1,50 @@
|
||||
# pubsub - Publisher & Subscriber Package
|
||||
Publisher & Subscriber package as template package and source code.
|
||||
|
||||
Created for ROS Workshop 2020
|
||||
Roverentwicklung für Explorationsaufgaben
|
||||
Institute for Space Systems
|
||||
University of Stuttgart.
|
||||
|
||||
Created by Patrick Winterhalder,
|
||||
[IRS](https://www.irs.uni-stuttgart.de/en/), University of Stuttgart.
|
||||
|
||||
|
||||
|
||||
|
||||
## Workshop Prerequisites
|
||||
* Install [Ubuntu 20.04]()
|
||||
* Install Visual Studio Code using [Ubuntu Software](https://wiki.ubuntuusers.de/Ubuntu_Software/)
|
||||
* Install [Git](https://linuxconfig.org/how-to-install-git-on-ubuntu-20-04-lts-focal-fossa-linux) (no account required yet)
|
||||
* Install [ROS2](https://index.ros.org/doc/ros2/Installation/Foxy/Linux-Install-Debians/) ("desktop" on PC, "base" on Raspberry Pi). Do install _argcomplete_, no need for _ROS 1 bridge_ or _RMW implementations_.
|
||||
* Install and update _rosdep_:
|
||||
* `sudo apt install python3-rosdep2 -y`
|
||||
* `rosdep update`
|
||||
* (`sudo rosdep init`)
|
||||
* Work through ["Beginner: CLI Tools"](https://index.ros.org/doc/ros2/Tutorials/) tutorial
|
||||
* [Configuring your ROS 2 environment](https://index.ros.org/doc/ros2/Tutorials/Configuring-ROS2-Environment/):
|
||||
* Source setup files (underlay, overlay)
|
||||
* Configure .bashrc (shell startup script)
|
||||
* Add colcon_cd to .bashrc (shell startup script)
|
||||
* Check environment variables (check for correct installation)
|
||||
* Configure ROS_DOMAIN_ID (DDS Network Number)
|
||||
* Cover turtlesim, rqt, topics, services, actions
|
||||
|
||||
## Install Instructions
|
||||
* Move to colcon workspace: `cd <workspace_path>`
|
||||
* Clone repository: `git clone git://github.com/patrickw135/pubsub.git .` (include the . at the end)
|
||||
* Build workspace: `colcon build`
|
||||
__Note:__ Only the files inside _src/_ are of importance.
|
||||
* Remember to run `source ~/<workspace_path>/install/local_setup.sh` after every build. Best would be to [add this command to _.bashrc_](https://github.com/patrickw135/pubsub/blob/master/bashrc_addons.txt) which is run everytime you start a new console.
|
||||
|
||||
|
||||
## During Workshop
|
||||
* Create workspace:
|
||||
* Install [_colcon_](https://index.ros.org/doc/ros2/Tutorials/Colcon-Tutorial/#colcon): `sudo apt install python3-colcon-common-extensions -y`
|
||||
* Create packag inside _~/{workspace_name}/src_:
|
||||
* `ros2 pkg create --build-type [ament_cmake, ament-python] <package_name>`
|
||||
* Go back up one layer: `cd ..`
|
||||
* Build workspace: `colcon build --symlink-install`
|
||||
* Add [this](https://github.com/patrickw135/pubsub/blob/main/bashrc_addons.txt) to end of .bashrc (`sudo nano .bashrc`), find all instances of "`~/ws_overlay_foxy`" and replace it with your local path to your colcon workspace
|
||||
* [Instruction](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md) on how to create a custom message to interface between nodes
|
||||
|
73
bashrc_addons.bash
Normal file
73
bashrc_addons.bash
Normal file
@ -0,0 +1,73 @@
|
||||
# Add these lines to .bashrc, do this:
|
||||
# Add the the following in between "#----" to the end of your .bashrc script
|
||||
|
||||
# To do this open .bashrc:
|
||||
# sudo nano ~/.bashrc
|
||||
|
||||
# Move to end of .bashrc (arrow down)
|
||||
# Highlight the lines below and copy (Ctrl+C)
|
||||
# Paste into console at the end of .bashrc (Right click, paste or CTRL+LShift+V)
|
||||
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------------
|
||||
# ROS 2 SETUP
|
||||
echo "ROS 2 Setup:"
|
||||
|
||||
# Source Underlay
|
||||
cmd="/opt/ros/foxy/setup.bash"
|
||||
source $cmd
|
||||
echo "ROS Underlay: "$cmd
|
||||
|
||||
# Source Overlay
|
||||
# Change to the path of your workspace's "install/local_setup.bash" file
|
||||
cmd="$HOME/colcon_ws/install/local_setup.bash"
|
||||
source $cmd
|
||||
echo "ROS Overlay: "$cmd
|
||||
|
||||
# You can add other workspaces
|
||||
#cmd="$HOME/colcon_libs/install/local_setup.bash"
|
||||
#source $cmd
|
||||
#echo "ROS Overlay: "$cmd
|
||||
echo "******************************************************"
|
||||
|
||||
# ROS 2 Settings
|
||||
# Print ROS Variables
|
||||
#printenv | grep -i ROS
|
||||
echo "ROS_VERSION: "$ROS_VERSION
|
||||
echo "ROS_PYTHON_VERSION: "$ROS_PYTHON_VERSION
|
||||
echo "ROS_DISTRO: "$ROS_DISTRO
|
||||
echo "******************************************************"
|
||||
|
||||
# Define DDS Channel
|
||||
# (this is the channel your ROS system communicates at over your local network)
|
||||
# To change the channel open the ROS Underlay setup file:
|
||||
# sudo nano /opt/ros/foxy/setup.bash
|
||||
# Here, add the following command
|
||||
# export ROS_DOMAIN_ID=<your_channel_nr>
|
||||
# eg.: export ROS_DOMAIN_ID=69
|
||||
# Important: no spaces before and after "=" (in bash)
|
||||
|
||||
# Print DDS Settings
|
||||
echo "ROS 2 DDS Settings:"
|
||||
export ROS_DOMAIN_ID=69
|
||||
echo "ROS_DOMAIN_ID: "$ROS_DOMAIN_ID
|
||||
echo "To change: sudo nano /opt/ros/foxy/setup.bash"
|
||||
echo "******************************************************"
|
||||
|
||||
# Source colcon directory jump:
|
||||
#source /usr/share/colcon_cd/function/colcon_cd.sh
|
||||
#export _colcon_cd_root=~/colcon_ws
|
||||
|
||||
# Print active Node & Topics
|
||||
echo "ROS 2 Topics active:"
|
||||
ros2 topic list
|
||||
echo "******************************************************"
|
||||
#echo "ROS 2 Nodes active:"
|
||||
#ros2 node list
|
||||
echo "******************************************************"
|
||||
printf "\n"
|
||||
echo "If your package is not listed (ros2 pkg list):"
|
||||
echo " * make sure you are sourcing the correct workspace: .bashrc"
|
||||
echo " * delete build/, install/ and rebuild w/o errors"
|
||||
#----------------------------------------------------------------------------------
|
186
instructions_custom_topics.md
Normal file
186
instructions_custom_topics.md
Normal file
@ -0,0 +1,186 @@
|
||||
# How to create custom ROS topics
|
||||
This is a short instruction on how to create custom interfaces using ROS topics.
|
||||
|
||||
For this at least two packages will be required:
|
||||
* The python package contains your scripts (eg. ROS nodes)
|
||||
* The CMake package contains the custom msg/srv/act files
|
||||
|
||||
The CMake package is required because the custom msg/srv/act files cannot be created inside the python package as this is not supported yet.
|
||||
|
||||
__Table of Content__
|
||||
* [CMake Package (eg. /pubsub_msg)](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#cmake-package-eg-pubsub_msg)
|
||||
* [Create CMake Package](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#1-create-cmake-package)
|
||||
* [Create Message Files](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#2-create-message-files)
|
||||
* [Configure CMakeLists.txt](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#3-configure-cmakeliststxt)
|
||||
* [Configure package.xml](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#4-configure-packagexml)
|
||||
* [Build Package](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#5-build-package)
|
||||
* [Source newly built workspace](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#6-source-newly-built-workspace)
|
||||
* [Check functionality](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#7-check-functionality)
|
||||
* [Python Package (eg. /pubsub)](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#python-package-eg-pubsub)
|
||||
* [Create Python Package](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#1-create-python-package)
|
||||
* [Write Python Scripts](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#2-write-python-scripts)
|
||||
* [Configure package.xml](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#3-configure-packagexml)
|
||||
* [Build Package](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#4-build-package)
|
||||
* [Source newly built workspace](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#5-source-newly-built-workspace)
|
||||
* [Run scripts](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#6-run-scripts)
|
||||
* [Sources](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#sources)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## CMake Package (eg. /pubsub_msg)
|
||||
This package makes up the basis for custom ROS interfaces and contains all custom msg/srv/act files. Additionally, the special files (_CMakeLists.txt_ and _package.xml_) describe how these interface files are to be used.
|
||||
|
||||
This package must be created as a CMake package: `ros2 pkg create --build-type ament-cmake <package_name>`
|
||||
|
||||
This will result in an empty package structure:
|
||||
* msg/srv/act directory:
|
||||
* This directory contains the custom msg files (eg. CustomMsg1.msg)
|
||||
* CMakeLists.txt:
|
||||
* This file describes how to build this package
|
||||
* Configure this file according to this [instruction](https://index.ros.org/doc/ros2/Tutorials/Custom-ROS2-Interfaces/#cmakelists-txt)
|
||||
* package.xml:
|
||||
* This file contains meta information about this package
|
||||
* Configure this file according to this [instruction](https://index.ros.org/doc/ros2/Tutorials/Custom-ROS2-Interfaces/#package-xml)
|
||||
|
||||
|
||||
### 1. Create CMake Package
|
||||
* Move to your colcon workspace's src directory: `cd <workspace_path>/src`
|
||||
* (For example: `cd ~/colcon_ws/src`)
|
||||
* Create CMake package: `ros2 pkg create --build-type ament_cmake <package_name>
|
||||
* (Here: `ros2 pkg create --build-type ament_cmake pubsub_msg`)
|
||||
|
||||
|
||||
### 2. Create Message Files
|
||||
* If not already available create msg directory inside package directory.
|
||||
Resulting structure: <workspace_name>/src/<package_name>/msg
|
||||
* Move to newly created msg direcrory
|
||||
* Create your own custom message files, eg. _CustomMsg1.msg_.
|
||||
Give your files comprehensible names, eg. _Epossetvalues.msg_
|
||||
|
||||
|
||||
### 3. Configure CMakeLists.txt
|
||||
Open CMakeLists.txt and ad these lines before `if(BUILD_TESTING)`:
|
||||
`find_package(builtin_interfaces REQUIRED)`
|
||||
`find_package(rosidl_default_generators REQUIRED)`
|
||||
`find_package(std_msgs REQUIRED)`
|
||||
`find_package(rclcpp REQUIRED)`
|
||||
Then also add custom lines depending your package, here the custom message/service files are added:
|
||||
`rosidl_generate_interfaces(${PROJECT_NAME}`
|
||||
` "msg/CustomMsg1.msg"`
|
||||
` "msg/CustomMsg2.msg"`
|
||||
` DEPENDENCIES builtin_interfaces`
|
||||
` )`
|
||||
|
||||
### 4. Configure package.xml
|
||||
In order to let the build system know what this package depends on add these lines to _package.xml_:
|
||||
```xml
|
||||
<!-- ADD THESE LINES: START HERE -->
|
||||
<build_depend>builtin_interfaces</build_depend>
|
||||
<build_depend>rosidl_default_generators</build_depend>
|
||||
<exec_depend>builtin_interfaces</exec_depend>
|
||||
<exec_depend>rosidl_default_runtime</exec_depend>
|
||||
<member_of_group>rosidl_interface_packages</member_of_group>
|
||||
<!-- END HERE -->
|
||||
```
|
||||
|
||||
### 5. Build Package
|
||||
* Move back to the workspace's most top layer: `cd ~/<workspace_path>`
|
||||
* Build workspace: `colcon build`
|
||||
* Sucessful response:
|
||||
_Starting >>> pubsub
|
||||
Starting >>> pubsub_msg
|
||||
Finished <<< pubsub [0.85s]
|
||||
Finished <<< pubsub_msg [1.09s]
|
||||
Summary: 2 packages finished [1.56s]_
|
||||
|
||||
|
||||
### 6. Source newly built workspace
|
||||
* Run: `source ~/<workspace_path>/install/local_setup.bash`
|
||||
* If you already [updated your .bashrc file](https://github.com/patrickw135/pubsub/blob/master/bashrc_addons.txt) you can close all open consoles and start a new console (Ctrl+Alt+T). This will source your workspace automatically, as .bashrc is run every time you start a console.
|
||||
__Important__: If you use multiple workspaces make sure you have the wanted workspace defined in .bashrc! Otherwise the changes introduced when building will not be available.
|
||||
|
||||
|
||||
### 7. Check functionality
|
||||
Check functionality of your messages by creataing a topic using your newly created message:
|
||||
* CustomMsg1:
|
||||
`ros2 topic pub /chatter1 pubsub_msg/CustomMsg1 "{temperature: {24.1234, 25.9876}, pressure: {1012.556, 1013.987}, humidity: {0.002, 0.001}}" --rate 1`
|
||||
* Response:
|
||||
_publisher: beginning loop
|
||||
publishing #1: pubsub_msg.msg.CustomMsg1(temperature=[24.12339973449707, 25.987600326538086], pressure=[1012.5560302734375, 1013.9869995117188], humidity=[0.0020000000949949026, 0.0010000000474974513])..._
|
||||
|
||||
* CustomMsg2:
|
||||
`ros2 topic pub /chatter2 pubsub_msg/CustomMsg2 "{pitch_ctrl: 33.33, yaw_ctrl: 0.5}" --rate 1`
|
||||
* Response:
|
||||
_publisher: beginning loop
|
||||
publishing #1: pubsub_msg.msg.CustomMsg2(pitch_ctrl=33.33, yaw_ctrl=0.5)..._
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Python Package (eg. /pubsub)
|
||||
This package contains your scripts, programs and libraries. After building the workspace (`colcon build`) the custom messages are available to all other packages.
|
||||
|
||||
This package can be created as a CMake (C++) package or as a python package depending on your coding preference.
|
||||
* C++: `ros2 pkg create --build-type ament-cmake <package_name>`
|
||||
* Python: `ros2 pkg create --build-type ament-python <package_name>`
|
||||
|
||||
|
||||
<package_name> directory:
|
||||
* This directory contains your python scripts (eg. listener.py)
|
||||
* Also place the non-standard libraries in this directory and import the library in your python scripts
|
||||
|
||||
|
||||
### 1. Create Python Package
|
||||
* Move to your workspace's source directory: `cd <workspace_path>/src`
|
||||
* Create python package: `rps2 pkg create --build-type ament_python <pkg_name>`
|
||||
|
||||
### 2. Write Python Scripts
|
||||
When using custom interfaces in python scripts these must be imported into the python script first
|
||||
```python
|
||||
from <package_name>.msg import <message_name>
|
||||
```
|
||||
replacing `<package_name>` with the package containing the custom message and `<message_name>` with the message file name (excluding the file ending .msg).
|
||||
However, in order to be able to import the custom message types, `<message_name>` must first be known to the ROS system. This was established when creating the [CMake package](https://github.com/patrickw135/pubsub/blob/master/instructions_custom_topics.md#cmake-package-eg-pubsub_msg) containing the custom message. Additionally, you must add this dependency to the _package.xml_ of this package as stated in the next chapter.
|
||||
|
||||
### 3. Configure package.xml
|
||||
In addition to importing the message type into your python script you must also configure _package.xml_ adding the package dependency of where you inherite the custom message from. Add this line to _package.xml_:
|
||||
```xml
|
||||
<depend>std_msgs</depend>
|
||||
<!-- CUSTOM LINE -->
|
||||
<!-- This is custom for the package you depend on -->
|
||||
<exec_depend>package_name</exec_depend>
|
||||
```
|
||||
exchanging _package_name_ with the source package of the custom message type (here _pubsub_msg_), e.g.:
|
||||
```xml
|
||||
<depend>std_msgs</depend>
|
||||
<!-- CUSTOM LINE -->
|
||||
<!-- This is custom for the package you depend on -->
|
||||
<exec_depend>pubsub_msg</exec_depend>
|
||||
```
|
||||
|
||||
### 4. Build Package
|
||||
Now you can build the Python package.
|
||||
* Move to your workspace's root: `cd ~/<workspace_path>`
|
||||
* Build workspace: `colcon build --symlink-install`
|
||||
|
||||
### 5. Source newly built workspace
|
||||
* Run: `source ~/<workspace_path>/install/local_setup.bash`
|
||||
* If you already [updated your .bashrc file](https://github.com/patrickw135/pubsub/blob/master/bashrc_addons.txt) you can close all open consoles and start a new console (Ctrl+Alt+T). This will source your workspace automatically, as .bashrc is run every time you start a console.
|
||||
__Important__: If you use multiple workspaces make sure you have the wanted workspace defined in .bashrc! Otherwise the changes introduced when building will not be available.
|
||||
|
||||
### 6. Run scripts
|
||||
* Run Talker: `ros2 run pubsub talker`
|
||||
* Run Listener: `ros2 run pubsub listener`
|
||||
|
||||
The talker console should print the sent data while the listener console should print the received data. These should match.
|
||||
|
||||
If anything is unclear, compare this instruction material to the files in `/pubsub` and `/pubsub_msg`.
|
||||
|
||||
## Sources
|
||||
[ROS2 Tutorial](https://index.ros.org/doc/ros2/Tutorials/Custom-ROS2-Interfaces/#creating-custom-ros-2-msg-and-srv-files)
|
||||
[theconstructsim custom messages](https://www.theconstructsim.com/ros2-tutorials-7-how-to-create-a-ros2-custom-message-new/)
|
125
rpi_install.bash
Normal file
125
rpi_install.bash
Normal file
@ -0,0 +1,125 @@
|
||||
# Go through these bash commands one by one
|
||||
# Prerequisite is a fresh Ubuntu 20.04 !! 64bit !! OS
|
||||
# Only the password was changed after first boot
|
||||
# Everything else is stock
|
||||
|
||||
# First Update
|
||||
sudo apt-get update && sudo apt-get upgrade -y && sudo apt-get dist-upgrade -y
|
||||
|
||||
# Install ROS2 Foxy Fitzroy Desktop
|
||||
sudo apt update && sudo apt install locales
|
||||
sudo locale-gen en_US en_US.UTF-8
|
||||
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
|
||||
sudo apt update && sudo apt install -y curl gnupg2 lsb-release
|
||||
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
|
||||
sudo sh -c 'echo "deb [arch=$(dpkg --print-architecture)] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/ros2-latest.list'
|
||||
sudo apt update && sudo apt install -y ros-foxy-ros-base
|
||||
source /opt/ros/foxy/setup.bash
|
||||
# Check to see if installed correctly
|
||||
echo "ROS_VERSION: "$ROS_VERSION
|
||||
|
||||
|
||||
# Install rosdep
|
||||
sudo apt install -y python3-rosdep2
|
||||
rosdep update
|
||||
|
||||
|
||||
# Install colcon
|
||||
sudo apt install -y python3-colcon-common-extensions
|
||||
|
||||
|
||||
# Install pip and argcomplete
|
||||
sudo apt install -y python3-pip
|
||||
pip3 install -U argcomplete
|
||||
|
||||
|
||||
# in between
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
|
||||
# Create workspace
|
||||
mkdir -p ~/colcon_ws/src
|
||||
cd colcon_ws
|
||||
colcon build
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Configure .bashrc:
|
||||
# The the following in between "#----" to the end of your .bashrc script
|
||||
#----------------------------------------------------------------------
|
||||
# ROS 2 SETUP
|
||||
echo "ROS 2 Setup:"
|
||||
|
||||
# Source Underlay
|
||||
cmd="/opt/ros/foxy/setup.bash"
|
||||
source $cmd
|
||||
echo "ROS Underlay: "$cmd
|
||||
|
||||
# Source Overlay
|
||||
# Change to the path of your workspace's "install/local_setup.bash" file
|
||||
cmd="$HOME/colcon_ws/install/local_setup.bash"
|
||||
source $cmd
|
||||
echo "ROS Overlay: "$cmd
|
||||
|
||||
# You can add other workspaces
|
||||
#cmd="$HOME/colcon_libs/install/local_setup.bash"
|
||||
#source $cmd
|
||||
#echo "ROS Overlay: "$cmd
|
||||
echo "******************************************************"
|
||||
|
||||
# ROS 2 Settings
|
||||
# Print ROS Variables
|
||||
#printenv | grep -i ROS
|
||||
echo "ROS_VERSION: "$ROS_VERSION
|
||||
echo "ROS_PYTHON_VERSION: "$ROS_PYTHON_VERSION
|
||||
echo "ROS_DISTRO: "$ROS_DISTRO
|
||||
export ROS_DOMAIN_ID=69
|
||||
echo "ROS_DOMAIN_ID: "$ROS_DOMAIN_ID
|
||||
echo "To change: sudo nano /opt/ros/foxy/setup.bash"
|
||||
echo "******************************************************"
|
||||
echo "Topics active:"
|
||||
ros2 topic list
|
||||
echo "******************************************************"
|
||||
printf "\n"
|
||||
echo "If your package is not listed (ros2 pkg list):"
|
||||
echo " * make sure you are sourcing the correct workspace: .bashrc"
|
||||
echo " * delete build/, install/ and rebuild w/o errors"
|
||||
# Parsing of git branch
|
||||
parse_git_branch() {
|
||||
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
|
||||
}
|
||||
export PS1="\u@\h \[\e[32m\]\w \[\e[91m\]\$(parse_git_branch)\[\e[00m\]$ "
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Install network tools
|
||||
sudo apt install -y wireless-tools
|
||||
|
||||
|
||||
# Install Git
|
||||
sudo apt install -y git
|
||||
|
||||
# Setup remote git from inside workspace
|
||||
cd ~/colcon_ws
|
||||
git init
|
||||
git remote add origin https://github.com/patrickw135/pubsub.git
|
||||
git fetch --all
|
||||
git reset --hard origin/master
|
||||
|
||||
|
||||
# Install your project specific python packages
|
||||
# You can use pip3 as the install tool, eg:
|
||||
pip3 install picamera
|
||||
# Or you can use the software installer:
|
||||
sudo apt install python3-picamera
|
||||
|
||||
|
||||
# again
|
||||
sudo apt update && sudo apt upgrade -y
|
31
src/pubsub/package.xml
Normal file
31
src/pubsub/package.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>pubsub</name>
|
||||
<version>0.0.0</version>
|
||||
<description>TODO: Package description</description>
|
||||
<maintainer email="winterhalder.p@googlemail.com">patrick</maintainer>
|
||||
<license>TODO: License declaration</license>
|
||||
|
||||
<!-- ADD THESE LINES -->
|
||||
<!-- Package not listed when using this: <exec_depend>rclpy</exec_depend> -->
|
||||
<!-- <exec_depend>std_msgs</exec_depend> -->
|
||||
<!-- <build_depend>std_msgs</build_depend> -->
|
||||
<depend>std_msgs</depend>
|
||||
|
||||
<!-- CUSTOM LINE -->
|
||||
<!-- This is custom for the package you depend on -->
|
||||
<exec_depend>pubsub_msg</exec_depend>
|
||||
<!-- END HERE -->
|
||||
|
||||
|
||||
|
||||
<test_depend>ament_copyright</test_depend>
|
||||
<test_depend>ament_flake8</test_depend>
|
||||
<test_depend>ament_pep257</test_depend>
|
||||
<test_depend>python3-pytest</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_python</build_type>
|
||||
</export>
|
||||
</package>
|
0
src/pubsub/pubsub/__init__.py
Normal file
0
src/pubsub/pubsub/__init__.py
Normal file
83
src/pubsub/pubsub/listener.py
Normal file
83
src/pubsub/pubsub/listener.py
Normal file
@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#********************************************#
|
||||
# Listener Template
|
||||
|
||||
# Creted for:
|
||||
# ROS2 Workshop 2020
|
||||
# Roverentwicklung für Explorationsaufgaben
|
||||
# Institute for Space Systems
|
||||
# University of Stuttgart
|
||||
|
||||
# Created by Patrick Winterhalder
|
||||
# IRS, University of Stuttgart
|
||||
#********************************************#
|
||||
|
||||
import rclpy
|
||||
from rclpy.node import Node
|
||||
|
||||
# Import Subscriber Library
|
||||
from .pubsub_library import CustomMsg1_sub
|
||||
from .pubsub_library import CustomMsg2_sub
|
||||
|
||||
# Import Message Types
|
||||
from pubsub_msg.msg import CustomMsg1
|
||||
from pubsub_msg.msg import CustomMsg2
|
||||
|
||||
|
||||
def main(args=None):
|
||||
rclpy.init(args=args)
|
||||
|
||||
# Start nodes here, should create object <node_name> for every node
|
||||
listener_1 = CustomMsg1_sub(NODE_NAME="pubsub_listener_1", TOPIC_NAME="/chatter1",MSG_TYPE=CustomMsg1, NUM_MSGS=0)
|
||||
listener_2 = CustomMsg2_sub(NODE_NAME="pubsub_listener_2", TOPIC_NAME="/chatter2",MSG_TYPE=CustomMsg2, NUM_MSGS=0)
|
||||
|
||||
|
||||
while rclpy.ok():
|
||||
try:
|
||||
# Insert main looping script here...
|
||||
|
||||
# Receive Topics by running nodes
|
||||
rclpy.spin_once(listener_1, timeout_sec=0.01)
|
||||
rclpy.spin_once(listener_2, timeout_sec=0.01)
|
||||
|
||||
# Do sth if message was received
|
||||
if listener_1.topic_received is True:
|
||||
listener_1.topic_received = False # zurücksetzen
|
||||
msg_1 = listener_1.return_msg()
|
||||
#*********************************
|
||||
# Do sth based on received message
|
||||
#*********************************
|
||||
if listener_2.topic_received is True:
|
||||
listener_2.topic_received = False # zurücksetzen
|
||||
msg_2 = listener_2.return_msg()
|
||||
#*********************************
|
||||
# Do sth based on received message
|
||||
#*********************************
|
||||
|
||||
|
||||
# Check if "msg_1" or "msg_2" is available as a local variable
|
||||
if 'msg_1' in locals():
|
||||
# Print msg_1
|
||||
listener_1.print_msg()
|
||||
if 'msg_2' in locals():
|
||||
# Print msg_2
|
||||
listener_2.print_msg()
|
||||
|
||||
# Here, you can now also publish/pass on the results of this script by
|
||||
# using the "MinimalPublisher" class. For this please refer to "talker.py".
|
||||
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
print("\n\nShutting down...")
|
||||
|
||||
# Insert "<node_name>.destroy_node()" here for all running nodes in this script
|
||||
# eg:
|
||||
listener_1.destroy_node()
|
||||
listener_2.destroy_node()
|
||||
rclpy.shutdown()
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
284
src/pubsub/pubsub/pubsub_library.py
Normal file
284
src/pubsub/pubsub/pubsub_library.py
Normal file
@ -0,0 +1,284 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#********************************************#
|
||||
# Publisher/Subscriber Class Library
|
||||
|
||||
# Creted for:
|
||||
# ROS2 Workshop 2020
|
||||
# Roverentwicklung für Explorationsaufgaben
|
||||
# Institute for Space Systems
|
||||
# University of Stuttgart
|
||||
|
||||
# Created by Patrick Winterhalder
|
||||
# IRS, University of Stuttgart
|
||||
#********************************************#
|
||||
|
||||
import rclpy
|
||||
from rclpy.node import Node
|
||||
|
||||
# How to use:
|
||||
# from pubsub_library import MinimalPublisher
|
||||
# from pubsub_library import MinimalSubscriber
|
||||
# minimal_publisher = MinimalPublisher(NODE_NAME='minimal_pub', TOPIC_NAME='user_controller', MSG_TYPE=Usercontroller, MSG_PERIOD=0.5)
|
||||
# minimal_subscriber = MinimalSubscriber(NODE_NAME='minimal_sub', TOPIC_NAME='epos_feedback', MSG_TYPE=Eposreturn)
|
||||
# See --> talker.py, listener.py
|
||||
|
||||
|
||||
|
||||
#******************************************************************************#
|
||||
# Definition of Parent Classes
|
||||
|
||||
class MinimalPublisher(Node):
|
||||
|
||||
def __init__(self, NODE_NAME, TOPIC_NAME, MSG_TYPE, MSG_PERIOD):
|
||||
self.PUBLISHER_NAME= NODE_NAME
|
||||
self.TOPIC_NAME = TOPIC_NAME
|
||||
self.CUSTOM_MSG = MSG_TYPE
|
||||
self.timer_period = MSG_PERIOD # [seconds]
|
||||
# Init above laying class Node
|
||||
super().__init__(self.PUBLISHER_NAME)
|
||||
print("\t- " + str(TOPIC_NAME) + "\n")
|
||||
self.publisher_ = self.create_publisher(
|
||||
self.CUSTOM_MSG,
|
||||
self.TOPIC_NAME,
|
||||
10)
|
||||
self.new_msg = False
|
||||
# Define Node Frequency, equivalent to ~rospy.rate()
|
||||
self.timer = self.create_timer(self.timer_period, self.publisher_timer)
|
||||
return
|
||||
|
||||
def publisher_timer(self):
|
||||
if self.new_msg is True:
|
||||
try:
|
||||
#self.get_logger().info('Pub:')
|
||||
self.publisher_.publish(self.msg)
|
||||
self.new_msg = False
|
||||
except TypeError:
|
||||
print("[ERROR] Msg-Data-Types do not match")
|
||||
return
|
||||
|
||||
# Publish using Timer
|
||||
def timer_publish(self, msg):
|
||||
self.msg=msg
|
||||
self.new_msg = True
|
||||
return
|
||||
|
||||
# Publish directly without Timer
|
||||
def direct_publish(self, msg):
|
||||
try:
|
||||
#self.get_logger().info('Pub:')
|
||||
self.publisher_.publish(msg)
|
||||
except TypeError:
|
||||
print("[ERROR] Msg-Data-Types do not match")
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class MinimalSubscriber(Node):
|
||||
|
||||
def __init__(self, NODE_NAME, TOPIC_NAME, MSG_TYPE, NUM_MSGS):
|
||||
self.NODE_NAME= NODE_NAME
|
||||
self.TOPIC_NAME = TOPIC_NAME
|
||||
self.CUSTOM_MSG = MSG_TYPE
|
||||
self.NUM_MSGS = NUM_MSGS
|
||||
self.topic_received = False
|
||||
# Init above laying class Node
|
||||
super().__init__(self.NODE_NAME)
|
||||
self.subscription = self.create_subscription(
|
||||
self.CUSTOM_MSG, # Message Type
|
||||
self.TOPIC_NAME, # Topic Name
|
||||
self.listener_callback, # Callback Function
|
||||
self.NUM_MSGS) # List of saved messages
|
||||
self.subscription # prevent unused variable warning
|
||||
return
|
||||
|
||||
def listener_callback(self, msg):
|
||||
self.get_logger().info('I heard: "%s"' % msg.data)
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#***************************************************************************#
|
||||
# Child Classes inherite through super().__init__(...) from parent class
|
||||
# Child's purpose is to simplify subscribing to custom messages
|
||||
# For this to work you must customize "listener_callback", "return_msg" (and "print_msg")
|
||||
|
||||
|
||||
|
||||
# Exemplary Subscriber Class: Inheriting from MinimalSubscriber Class
|
||||
# This class is custom made for receiving the specific msg type but uses MinimalSubscriber as foundation
|
||||
# Create a new class of this type for every custom msg you want to receive, customizing the listener_callback,
|
||||
# return_msg (and print_msg) functions to correspond to your message
|
||||
|
||||
class example_subscriber(MinimalSubscriber):
|
||||
|
||||
def __init__(self, NODE_NAME, TOPIC_NAME, MSG_TYPE, NUM_MSGS):
|
||||
# Init MinimalSubscriber:
|
||||
super().__init__(NODE_NAME, TOPIC_NAME, MSG_TYPE, NUM_MSGS)
|
||||
print("\t- " + str(TOPIC_NAME))
|
||||
# !!! CUSTOMIZE THESE VARIABLES TO WORK WITH YOUR MESSAGE FILE !!!
|
||||
self.pos_actual = None
|
||||
self.vel_actual = None
|
||||
self.baffle_switch = None
|
||||
self.current = None
|
||||
self.temp = None
|
||||
|
||||
|
||||
# !!! CUSTOMIZE THIS FUNCTION TO WORK WITH YOUR MESSAGE FILE !!!
|
||||
def listener_callback(self, msg): # Overwrites callback from inherited class
|
||||
self.topic_received = True
|
||||
self.pos_actual = msg.pos_actual
|
||||
self.vel_actual = msg.vel_actual
|
||||
self.baffle_switch = msg.baffle_switch
|
||||
self.current = msg.epos_current
|
||||
self.temp = msg.epos_temp
|
||||
#print_msg(self) # activate to print the received data --> customize print_msg(self) !
|
||||
return
|
||||
|
||||
# !!! CUSTOMIZE THIS FUNCTION TO WORK WITH YOUR MESSAGE FILE !!!
|
||||
def return_msg(self): # Extract only msg variables from "self" object
|
||||
msg = self.CUSTOM_MSG()
|
||||
msg.pos_actual = self.pos_actual
|
||||
msg.vel_actual = self.vel_actual
|
||||
msg.baffle_switch = self.baffle_switch
|
||||
msg.epos_current = self.current
|
||||
msg.epos_temp = self.temp
|
||||
return msg
|
||||
|
||||
# !!! CUSTOMIZE THIS FUNCTION TO WORK WITH YOUR MESSAGE FILE !!! (optional)
|
||||
def print_msg(self):
|
||||
print("[SUBSCRIBER] %s received topic:\t/%s" %(self.NODE_NAME, self.TOPIC_NAME))
|
||||
string = "Received:\t"
|
||||
|
||||
# Check length of all transmitted value lists to be equal (equal number of parameters)
|
||||
length = len(self.pos_actual)
|
||||
if any(len(lst) != length for lst in [self.vel_actual, self.current, self.temp]):
|
||||
print("[TRANSMISSION ERROR] Length of lists inside topic %s do not match" %(self.TOPIC_NAME))
|
||||
else:
|
||||
complete_list = []
|
||||
complete_list.append(self.pos_actual)
|
||||
complete_list.append(self.vel_actual)
|
||||
complete_list.append(self.current)
|
||||
complete_list.append(self.temp)
|
||||
#print(complete_list)
|
||||
for i in range(len(complete_list)):
|
||||
for y in range(len(complete_list[0])):
|
||||
string += "%.2f,\t" %(complete_list[i][y])
|
||||
string += str(self.baffle_switch)
|
||||
print(string)
|
||||
return
|
||||
|
||||
|
||||
#************************************************************************************#
|
||||
# CustomMsg1 Subscriber Class
|
||||
class CustomMsg1_sub(MinimalSubscriber):
|
||||
|
||||
def __init__(self, NODE_NAME, TOPIC_NAME, MSG_TYPE, NUM_MSGS):
|
||||
# Init MinimalSubscriber:
|
||||
super().__init__(NODE_NAME, TOPIC_NAME, MSG_TYPE, NUM_MSGS)
|
||||
print("\t- " + str(TOPIC_NAME))
|
||||
# CustomMsg1 Variables
|
||||
self.temperature = None
|
||||
self.pressure = None
|
||||
self.humidity = None
|
||||
return
|
||||
|
||||
|
||||
# !!! CUSTOMIZE THIS FUNCTION TO WORK WITH YOUR MESSAGE FILE !!!
|
||||
def listener_callback(self, msg): # Overwrites callback from inherited class
|
||||
self.topic_received = True
|
||||
self.temperature = msg.temperature
|
||||
self.pressure = msg.pressure
|
||||
self.humidity = msg.humidity
|
||||
#print_msg(self) # activate to print the received data --> customize print_msg(self) !
|
||||
return
|
||||
|
||||
# !!! CUSTOMIZE THIS FUNCTION TO WORK WITH YOUR MESSAGE FILE !!!
|
||||
def return_msg(self): # Extract only msg variables from "self" object
|
||||
msg = self.CUSTOM_MSG()
|
||||
msg.temperature = self.temperature
|
||||
msg.pressure = self.pressure
|
||||
msg.humidity = self.humidity
|
||||
return msg
|
||||
|
||||
# !!! CUSTOMIZE THIS FUNCTION TO WORK WITH YOUR MESSAGE FILE !!! (optional)
|
||||
def print_msg(self):
|
||||
print("[SUBSCRIBER] %s received topic:\t/%s" %(self.NODE_NAME, self.TOPIC_NAME))
|
||||
string = "Received:\t"
|
||||
|
||||
# Check length of all transmitted value lists to be equal (equal number of parameters)
|
||||
length = len(self.temperature)
|
||||
if any(len(lst) != length for lst in [self.temperature, self.pressure, self.humidity]):
|
||||
print("[TRANSMISSION ERROR] Length of lists inside topic %s do not match" %(self.TOPIC_NAME))
|
||||
else:
|
||||
complete_list = []
|
||||
complete_list.append(self.temperature)
|
||||
complete_list.append(self.pressure)
|
||||
complete_list.append(self.humidity)
|
||||
#print(complete_list)
|
||||
for i in range(len(complete_list)):
|
||||
for y in range(len(complete_list[0])):
|
||||
string += "%.2f,\t" %(complete_list[i][y])
|
||||
print(string)
|
||||
return
|
||||
|
||||
|
||||
|
||||
#************************************************************************************#
|
||||
# CustomMsg2 Subscriber Class
|
||||
class CustomMsg2_sub(MinimalSubscriber):
|
||||
|
||||
def __init__(self, NODE_NAME, TOPIC_NAME, MSG_TYPE, NUM_MSGS):
|
||||
# Init MinimalSubscriber:
|
||||
super().__init__(NODE_NAME, TOPIC_NAME, MSG_TYPE, NUM_MSGS)
|
||||
print("\t- " + str(TOPIC_NAME))
|
||||
# CustomMsg1 Variables
|
||||
self.pitch_ctrl = None
|
||||
self.yaw_ctrl = None
|
||||
return
|
||||
|
||||
|
||||
# !!! CUSTOMIZE THIS FUNCTION TO WORK WITH YOUR MESSAGE FILE !!!
|
||||
def listener_callback(self, msg): # Overwrites callback from inherited class
|
||||
self.topic_received = True
|
||||
self.pitch_ctrl = msg.pitch_ctrl
|
||||
self.yaw_ctrl = msg.yaw_ctrl
|
||||
#print_msg(self) # activate to print the received data --> customize print_msg(self) !
|
||||
return
|
||||
|
||||
# !!! CUSTOMIZE THIS FUNCTION TO WORK WITH YOUR MESSAGE FILE !!!
|
||||
def return_msg(self): # Extract only msg variables from "self" object
|
||||
msg = self.CUSTOM_MSG()
|
||||
msg.pitch_ctrl = self.pitch_ctrl
|
||||
msg.yaw_ctrl = self.yaw_ctrl
|
||||
return msg
|
||||
|
||||
# !!! CUSTOMIZE THIS FUNCTION TO WORK WITH YOUR MESSAGE FILE !!! (optional)
|
||||
def print_msg(self):
|
||||
print("[SUBSCRIBER] %s received topic:\t/%s" %(self.NODE_NAME, self.TOPIC_NAME))
|
||||
string = "Received:\t"
|
||||
|
||||
# Check length of all transmitted value lists to be equal (equal number of parameters)
|
||||
complete_list = []
|
||||
complete_list.append([self.pitch_ctrl])
|
||||
complete_list.append([self.yaw_ctrl])
|
||||
#print(complete_list)
|
||||
for i in range(len(complete_list)):
|
||||
for y in range(len(complete_list[0])):
|
||||
string += "%.2f,\t" %(complete_list[i][y])
|
||||
print(string)
|
||||
return
|
69
src/pubsub/pubsub/talker.py
Normal file
69
src/pubsub/pubsub/talker.py
Normal file
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#********************************************#
|
||||
# Talker Template
|
||||
|
||||
# Creted for:
|
||||
# ROS2 Workshop 2020
|
||||
# Roverentwicklung für Explorationsaufgaben
|
||||
# Institute for Space Systems
|
||||
# University of Stuttgart
|
||||
|
||||
# Created by Patrick Winterhalder
|
||||
# IRS, University of Stuttgart
|
||||
#********************************************#
|
||||
|
||||
import rclpy
|
||||
from rclpy.node import Node
|
||||
|
||||
# Import Publisher Library (Python Library)
|
||||
from .pubsub_library import MinimalPublisher
|
||||
|
||||
# Import Message Types (Message Files)
|
||||
from pubsub_msg.msg import CustomMsg1
|
||||
from pubsub_msg.msg import CustomMsg2
|
||||
|
||||
|
||||
def main(args=None):
|
||||
rclpy.init(args=args)
|
||||
|
||||
# Start nodes here, should create object <node_name> for every node
|
||||
talker_1 = MinimalPublisher(NODE_NAME="pubsub_talker_1", TOPIC_NAME="/chatter1", MSG_TYPE=CustomMsg1, MSG_PERIOD=0.25)
|
||||
talker_2 = MinimalPublisher(NODE_NAME="pubsub_talker_2", TOPIC_NAME="/chatter2", MSG_TYPE=CustomMsg2, MSG_PERIOD=0.5)
|
||||
|
||||
while rclpy.ok():
|
||||
try:
|
||||
# Insert main looping script here...
|
||||
|
||||
# Eg. create custom msgs, fill and send them
|
||||
# CustomMsg1 to talker_1
|
||||
msg_1 = CustomMsg1()
|
||||
msg_1.temperature = [24.5, 25.5, 26.5]
|
||||
msg_1.pressure = [1011.5, 1012.55, 1010.11]
|
||||
msg_1._humidity = [0.002, 0.0019, 0.0021]
|
||||
talker_1.timer_publish(msg_1)
|
||||
|
||||
# CustomMsg2 to talker_2
|
||||
msg_2 = CustomMsg2()
|
||||
msg_2.pitch_ctrl = 0.0
|
||||
msg_2.yaw_ctrl = 0.22
|
||||
talker_2.timer_publish(msg_2)
|
||||
|
||||
|
||||
# Insert "rclpy.spin_once(<node_name>, timeout_sec=0.1)" at the end of
|
||||
# "try" for every node running in this script
|
||||
rclpy.spin_once(talker_1, timeout_sec=0.1)
|
||||
rclpy.spin_once(talker_2, timeout_sec=0.1)
|
||||
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
print("\n\nShutting down...")
|
||||
# Insert "<node_name>.destroy_node()" here once for every node running in this script
|
||||
talker_1.destroy_node()
|
||||
talker_2.destroy_node()
|
||||
rclpy.shutdown()
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
src/pubsub/resource/pubsub
Normal file
0
src/pubsub/resource/pubsub
Normal file
4
src/pubsub/setup.cfg
Normal file
4
src/pubsub/setup.cfg
Normal file
@ -0,0 +1,4 @@
|
||||
[develop]
|
||||
script-dir=$base/lib/pubsub
|
||||
[install]
|
||||
install-scripts=$base/lib/pubsub
|
27
src/pubsub/setup.py
Normal file
27
src/pubsub/setup.py
Normal file
@ -0,0 +1,27 @@
|
||||
from setuptools import setup
|
||||
|
||||
package_name = 'pubsub'
|
||||
|
||||
setup(
|
||||
name=package_name,
|
||||
version='0.0.0',
|
||||
packages=[package_name],
|
||||
data_files=[
|
||||
('share/ament_index/resource_index/packages',
|
||||
['resource/' + package_name]),
|
||||
('share/' + package_name, ['package.xml']),
|
||||
],
|
||||
install_requires=['setuptools'],
|
||||
zip_safe=True,
|
||||
maintainer='patrick',
|
||||
maintainer_email='winterhalder.p@googlemail.com',
|
||||
description='TODO: Package description',
|
||||
license='TODO: License declaration',
|
||||
tests_require=['pytest'],
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'talker = pubsub.talker:main',
|
||||
'listener = pubsub.listener:main'
|
||||
],
|
||||
},
|
||||
)
|
23
src/pubsub/test/test_copyright.py
Normal file
23
src/pubsub/test/test_copyright.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_copyright.main import main
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.copyright
|
||||
@pytest.mark.linter
|
||||
def test_copyright():
|
||||
rc = main(argv=['.', 'test'])
|
||||
assert rc == 0, 'Found errors'
|
25
src/pubsub/test/test_flake8.py
Normal file
25
src/pubsub/test/test_flake8.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Copyright 2017 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_flake8.main import main_with_errors
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.flake8
|
||||
@pytest.mark.linter
|
||||
def test_flake8():
|
||||
rc, errors = main_with_errors(argv=[])
|
||||
assert rc == 0, \
|
||||
'Found %d code style errors / warnings:\n' % len(errors) + \
|
||||
'\n'.join(errors)
|
23
src/pubsub/test/test_pep257.py
Normal file
23
src/pubsub/test/test_pep257.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_pep257.main import main
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.linter
|
||||
@pytest.mark.pep257
|
||||
def test_pep257():
|
||||
rc = main(argv=['.', 'test'])
|
||||
assert rc == 0, 'Found code style errors / warnings'
|
59
src/pubsub_msg/CMakeLists.txt
Normal file
59
src/pubsub_msg/CMakeLists.txt
Normal file
@ -0,0 +1,59 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(pubsub_msg)
|
||||
|
||||
# Default to C99
|
||||
if(NOT CMAKE_C_STANDARD)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
endif()
|
||||
|
||||
# Default to C++14
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
# find dependencies
|
||||
find_package(ament_cmake REQUIRED)
|
||||
# uncomment the following section in order to fill in
|
||||
# further dependencies manually.
|
||||
# find_package(<dependency> REQUIRED)
|
||||
|
||||
|
||||
|
||||
|
||||
# -->
|
||||
# ADD THESE LINES: START HERE
|
||||
|
||||
find_package(builtin_interfaces REQUIRED)
|
||||
find_package(rosidl_default_generators REQUIRED)
|
||||
find_package(std_msgs REQUIRED)
|
||||
find_package(rclcpp REQUIRED)
|
||||
|
||||
# CUSTOM LINES: CHANGE FOR YOUR FILENAMES
|
||||
rosidl_generate_interfaces(${PROJECT_NAME}
|
||||
"msg/CustomMsg1.msg"
|
||||
"msg/CustomMsg2.msg"
|
||||
DEPENDENCIES builtin_interfaces
|
||||
)
|
||||
|
||||
# END HERE
|
||||
# <--
|
||||
|
||||
|
||||
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_lint_auto REQUIRED)
|
||||
# the following line skips the linter which checks for copyrights
|
||||
# uncomment the line when a copyright and license is not present in all source files
|
||||
#set(ament_cmake_copyright_FOUND TRUE)
|
||||
# the following line skips cpplint (only works in a git repo)
|
||||
# uncomment the line when this package is not in a git repo
|
||||
#set(ament_cmake_cpplint_FOUND TRUE)
|
||||
ament_lint_auto_find_test_dependencies()
|
||||
endif()
|
||||
|
||||
ament_package()
|
8
src/pubsub_msg/msg/CustomMsg1.msg
Normal file
8
src/pubsub_msg/msg/CustomMsg1.msg
Normal file
@ -0,0 +1,8 @@
|
||||
# Header data, eg timestamp
|
||||
# Problem: "header__struct.hpp: No such file or directory"
|
||||
#Header header
|
||||
|
||||
# Sensor Data coming back from an array of atmospheric sensors
|
||||
float32[] temperature
|
||||
float32[] pressure
|
||||
float32[] humidity
|
7
src/pubsub_msg/msg/CustomMsg2.msg
Normal file
7
src/pubsub_msg/msg/CustomMsg2.msg
Normal file
@ -0,0 +1,7 @@
|
||||
# Header data, eg timestamp
|
||||
# Problem: "header__struct.hpp: No such file or directory"
|
||||
#Header header
|
||||
|
||||
# User inputs, eg. for controlling a camera mast , eg. set angles [rad]
|
||||
float32 pitch_ctrl
|
||||
float32 yaw_ctrl
|
34
src/pubsub_msg/package.xml
Normal file
34
src/pubsub_msg/package.xml
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>pubsub_msg</name>
|
||||
<version>0.0.0</version>
|
||||
<description>TODO: Package description</description>
|
||||
<maintainer email="winterhalder.p@googlemail.com">patrick</maintainer>
|
||||
<license>TODO: License declaration</license>
|
||||
|
||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- ADD THESE LINES: START HERE -->
|
||||
<build_depend>builtin_interfaces</build_depend>
|
||||
<build_depend>rosidl_default_generators</build_depend>
|
||||
|
||||
<exec_depend>builtin_interfaces</exec_depend>
|
||||
<exec_depend>rosidl_default_runtime</exec_depend>
|
||||
|
||||
<member_of_group>rosidl_interface_packages</member_of_group>
|
||||
<!-- END HERE -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
41
workshopinstall.sh
Normal file
41
workshopinstall.sh
Normal file
@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
sudo apt-get update && sudo apt-get upgrade -y
|
||||
sudo apt-get dist-upgrade -y
|
||||
|
||||
# Install Visual Studio Code
|
||||
sudo apt install -y software-properties-common apt-transport-https wget
|
||||
wget -q https://packages.microsoft.com/keys/microsoft.asc -O- | sudo apt-key add -
|
||||
sudo add-apt-repository "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main"
|
||||
sudo apt update && sudo apt install -y code
|
||||
|
||||
# Install Git
|
||||
sudo apt install -y git
|
||||
|
||||
# Install ROS2 Foxy Fitzroy Desktop
|
||||
#sudo apt update && sudo apt install locales
|
||||
#sudo locale-gen en_US en_US.UTF-8
|
||||
#sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
|
||||
sudo apt update && sudo apt install -y curl gnupg2 lsb-release
|
||||
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
|
||||
sudo sh -c 'echo "deb [arch=$(dpkg --print-architecture)] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/ros2-latest.list'
|
||||
sudo apt update && sudo apt install -y ros-foxy-desktop
|
||||
source /opt/ros/foxy/setup.bash
|
||||
|
||||
# Install pip and argcomplete
|
||||
sudo apt install -y python3-pip
|
||||
pip3 install -U argcomplete
|
||||
|
||||
# If colcon does not build: Install pytest version>=5.0 ???
|
||||
|
||||
# Install rosdep
|
||||
sudo apt install -y python3-rosdep2
|
||||
rosdep update
|
||||
|
||||
# in between
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
# Install colcon
|
||||
sudo apt install -y python3-colcon-common-extensions
|
||||
|
||||
# At the end again
|
||||
sudo apt update && sudo apt upgrade -y
|
Loading…
x
Reference in New Issue
Block a user