Skip to content

creating_a_package

Sam 'snaens' Pelz edited this page Sep 29, 2026 · 1 revision

TOC


In diesem Tutorial wird schritt für schritt ein Beispiel Paket für georg_at_home erstellt.

Es wird davon ausgegangen, dass eine Linux-Umgebung (zb Ubuntu oder WSL) mit funktionierender Docker Installation verwendet wird.
Zudem sollen die Pakete sudo apt install nano make git tree lazygit
und das Paket gh Anleitung

ℹ️ Lazygit auf Ubuntu ≤ 25.04 → Anleitung
Lazygit ist optional - wird verwendet weil Git commands diktieren/merken kacke ist :(

Note

Alle Schritte sind im pkg_tutorial Branch dieses Repos einsehbar.

00 Setup

Zunächst holen wir uns das Repo:

cd gerne zuvor in einen beliebigen Ordner, je nach deiner Organisationsweise.

git clone https://github.com/autonohm/georg_at_home.git
cd georg_at_home

Dann müssen wir git sagen wer wir sind, dafür:

git config --global user.name "Sam 'snaens' Pelz"
git config --global user.email "snaens@snaens.net"

Name und Email natürlich personalisieren!

Das --global kann weggelassen werden. Damit gelten die Änderungen nur für dieses Repo / diesen Ordner.

Und für später werden wir die push-Berechtigungen auf das Repo brauchen:

gh auth login

Und dem Anmeldevorgang folgen.
Wir sind auf GitHub.com, wollen HTTPS, und nutzen web browser

(optional) Dann richten wir autocomplete für das projectctl.bash Skript ein.

./projectctl.bash install_completion
source ~/.bashrc

Als letztes builden wir das base Image für alle Container.
Dieses Image baut auf das offizielle ROS Image auf, und enthält häufig gebrauchte Software für alle unserer Pakete.

./projectctl.bash build_base_image

01 Das erste Paket

Jetzt machen wir unseren eigenen Branch.
Den Branch werden wir später auf Github pushen, daher bitte etwas einzigartiges (zb den Nutzernamen) verwenden.

Öffne nun

lazygit

Tip

In der untersten Zeile stehen hilfreiche Tipps, und die Tasten für die häufigsten Funktionen

Drücke ENTER um die wilkommensnachricht zu schließen.
Drücke nun die 3 oder mehrfach TAB um zu "Local branches" zu kommen und danach n für "New branch".
Gebe nun einen Branch-Namen ein, beende die Eingabe mit ENTER.
image
Glückwunsch! Du hast einen Branch erstellt.
Schließe nun lazygit mit q.

Das war äquivalent zu den git commands:

git branch snaens/pkg_tutorial
git checkout snaens/pkg_tutorial

Jetzt erstellen wir die Ordnerstruktur.

mkdir software/pkg_tutorial

Öffne einen neuen Tab, und cd-e zu dem neuen Ordner.

cd software/pkg_tutorial

Nun erstellen wir die docker-compose.yaml

nano docker-compose.yaml

rein kommt:

services:
  tutorial:
    image: georg-ros:humble
    command: 'ros2 topic pub /hello std_msgs/msg/String "data: hello world"'

Na dann probieren wir es aus!

docker compose up

Wenn alles bislang geklappt hat kommt jetzt das bekannte "publishing ..."
Fertig zugeschaut? Würge den Container mit STRG+C ab.

Um das ganze in Git zu committen wieder lazygit öffnen (geht in allen georg_at_home Ordnern).
Dann Auf Schaltfläche 2: "Files" navigieren
Mit den Pfeiltasten oder j und k die zu committenden Dateien anfahren und mit LEERTASTE auswählen.
Danach auf c für commit drücken, und einen Titel (und Beschreibung) angeben.
Mit TAB zwischen den beiden Feldern wechseln, und im Titelfeld mit ENTER absenden. Commit ist fertig! image

Das war äquivalent zu den git commands:

git add software/pkg_tutorial/docker-compose.yaml
git commit --message="01 Das erste Paket"

02 verwaltetes Starten

In georg_at_home sind mehr als nur ein Paket, wie können wir sie alle auf einmal starten?
Dafür gibt es die Makefile im georg_at_home Ordner.
Für dieses Tutorial wollen wir aber nur unser Demo Paket starten. Also disablen wir alle anderen.

Im ersten Tab, führe aus:

./projectctl.bash check_pkgs

Wir erwarten etwas wie das hier:
image
Kopiere die "found pkgs", es kann gut sein dass die Liste bei dir durch neue Pakete länger ist.

Nun Öffne die "projectctl.bash":

nano projectctl.bash

Wir haben es auf diesen Teil abgesehen:

#SKIP_PACKAGES=("drive" "examples")
SKIP_PACKAGES=( )

ändere ihn sodass steht:

SKIP_PACKAGES=("drive" "examples" "<weitere Pakete>")
SKIP_PACKAGES=( )

Danach speichern und schließeb

Nun erwarten wir aus ./projectctl.bash check_pkgs etwas wie das hier:
image

Tobe dich nun mit den Verwaltungsfunktionen aus!

./projectctl.bash help
./projectctl.bash up
./projectctl.bash down
./projectctl.bash build
./projectctl.bash start
./projectctl.bash stop
./projectctl.bash logs # nur bei laufendem Container
./projectctl.bash logs tutorial # nur bei laufendem Container

Important

Nicht vergessen zu committen!

03 Extra Software

Nun wollen wir eine weiteres ROS Paket mit apt in den container installieren.
Dies wollen wir bei build-time machen, damit dies im Image eingebacken ist und nicht bei jedem container-start gemacht werden muss. Dazu werden wir eine Dockerfile mit weiteren Bauanleitungen für das Image verfassen.

Erstelle die Datei "Dockerfile" im pkg_tutorial Ordner:

FROM georg-ros:humble

WORKDIR /ws


RUN apt-get update && apt-get install --no-install-recommends -y \
    ros-humble-examples-rclcpp-minimal-subscriber \
    ros-humble-examples-rclcpp-minimal-publisher \
    && rm -rf /var/lib/apt/lists/*


ENTRYPOINT ["/ros_entrypoint.sh"]
CMD ["bash"]

Und modifiziere die "docker-compose.yaml":

services:
  tutorial:
    image: tutorial
    build:
      context: .
      dockerfile: ./Dockerfile
    command: 'ros2 run examples_rclcpp_minimal_publisher publisher_member_function'

Im georg_at_home Ordner, mache nun

./projectctl.bash down
./projectctl.bash up
```.  
Docker wird jetzt das Image automatisch builden und starten.

<img width="1141" height="310" alt="image" src="https://github.com/user-attachments/assets/86726d13-c8be-499d-bc8e-a8ca8ce6b7e4" />

Das Verzeichnis schaut an diesem Punkt so aus:
```console
$ tree software/pkg_tutorial/
software/pkg_tutorial/
├── docker-compose.yaml
└── Dockerfile

1 directory, 2 files

Important

Nicht vergessen zu committen!

04 Eigener Code

Nun wollen wir unseren eigenen Node coden.
Wir wollen ihn mit colcon build ins Image backen.
Hierfür kopieren wir das ROS tutorial: Writing-A-Simple-Py-Publisher-And-Subscriber

Folge dem Tutorial bis vor Schritt 4: "Build and Run", im pkg_tutorial Ordner.
Wenn du fertig bist sollte die Struktur wie folgt aussehen:

software/pkg_tutorial/
├── docker-compose.yaml
├── Dockerfile
└── py_pubsub
    ├── LICENSE
    ├── package.xml
    ├── py_pubsub
    │   ├── __init__.py
    │   ├── publisher_member_function.py
    │   └── subscriber_member_function.py
    ├── resource
    │   └── py_pubsub
    ├── setup.cfg
    ├── setup.py
    └── test
        └── ...

Danach brauchen wir wieder die Dockerfile.
Die muss wie folgt ausgebaut werden:

FROM georg-ros:humble

WORKDIR /ws


RUN apt-get update && apt-get install --no-install-recommends -y \
    ros-humble-examples-rclcpp-minimal-subscriber \
    ros-humble-examples-rclcpp-minimal-publisher

# copy directly into ws folder, src folder is optional
COPY py_pubsub/ src/py_pubsub/

RUN rosdep install --from-paths . --ignore-src -r -y && \
    rm -rf /var/lib/apt/lists/*

RUN /bin/bash -c "\
    source /opt/ros/humble/setup.bash && \
    colcon build --symlink-install \
    "


ENTRYPOINT ["/ros_entrypoint.sh"]
CMD ["bash"]

Und um unseren Node zu starten noch die "docker-compose.yaml"

services:
  tutorial:
    image: tutorial
    build:
      context: .
      dockerfile: ./Dockerfile
    command: 'ros2 run py_pubsub talker'

dann zurück zum georg_at_home Ordner und einen Rebuild des images triggern. Danach den aten container sauber schießen und neu starten.

./projectctl.bash build
./projectctl.bash down
./projectctl.bash up
./projectctl.bash logs tutorial

Important

Nicht vergessen zu committen!

05 Eigene Launchfile

In der Regel wollen wir mehr als nur einen ROS Node in unserem Paket starten.
Hierfür integrieren wir eine Launchfile.

dafür erstellen wir in unserem Paket ein neuen Ordner: config/.
Hierfür wieder in den pkg_tutorial Ordner zurück (Tab 2)

mkdir config

Nun erstellen wir eine Launchfile. Diese kann man in XML, Yaml oder Python schreiben → Creating-Launch-Files
Mit python ist man aber eintschieden flexibler.

nano config/pubsub.launch.py

Und rein kommt:

from launch import LaunchDescription
from launch_ros.actions import Node


def generate_launch_description():
    return LaunchDescription([
        Node(
            package='py_pubsub',
            executable='talker',
            name='pub',
            emulate_tty=True,
        ),
        Node(
            package='py_pubsub',
            executable='listener',
            name='sub',
            emulate_tty=True,
        )
    ])

Das Paket soll nun wie folgt aussehen:

software/pkg_tutorial/
├── config
│   └── pubsub.launch.py
├── docker-compose.yaml
├── Dockerfile
└── py_pubsub
    ├── ...

Die Compose des Containers muss den Neuen Ordner und Launchfile befassen:

services:
  tutorial:
    image: tutorial
    build:
      context: .
      dockerfile: ./Dockerfile
    volumes:      
      - ./config:/config:ro
    privileged: true
    init: true
    command: 'ros2 launch /config/pubsub.launch.py'
  • privileged: true ist nötig weil Programme im Container sonst keine (lese)-Berechtigungen auf die Dateien haben
  • init: true ermöglicht, dass das abwürgen über den container an die Launchfile übertragen wird. Ohne gibt es kein clean shutdown.

dann wieder zurück zu georg_at_home und

./projectctl.bash down
./projectctl.bash up
./projectctl.bash logs tutorial

Important

Nicht vergessen zu committen!

06 Pushen auf github

Kommt noch - Permissions fehlen :)

Commits aus altem Repo übernehmen

Note

Unwichtig für alle die kein git in ihrem Paket verwendet haben.

Tip

Ich empfehle zuerst ein Paket mit den Grundlagen in georg_at_home hergestellt zu haben,
und erst danach die ganzen Commits zu übertragen. Sonst kann es sehr wirr werden!

Altes Repo verlinken

Im georg_at_home Ordner ausführen:

git remote add oldrepo ../<pfad-zu-altem-repo>
# z.B. git remote add oldrepo ../demorepo
git remote update  

So was sollte rauskommen:
image

Danach

git checkout oldrepo/HEAD

Jetzt sind die alten Commits im neuen Repo drin.

lazygit
image

Commits übertragen

In Lazygit auf die Schaltfläche 4 - "Commits" navigieren.
Dann mit SHIFT + Pfeiltasten alle Commits anwählen
und mit SHIFT + c cherry-picken.

Sollte so aussehen:
image

Jetzt auf die Schaltfläche 3 - "Local Branches" navigieren,
und mit LEERTASTE zu dem main branch wechseln.
Nun zurück auf die Schaltfläche 4 - "Commits", und mit SHIFT + v die commits oben rein pasten. Mit ENTER bestätigen.

Jetzt sollten die Commits übertragen sein!
image

Dateien verschieben

Die Commits sind nun am richtigen Ort, aber die Dateien noch nicht.
Hierfür können wir die Commits einfach abändern.
(Alternativ kann man die Dateien einfach so verschieben und daraus einen riesen commit machen, der alles verschiebt.)

In Lazygit auf Schaltfläche 4 - "Commits" den ersten commit drücken in der eine Datei vorkommt.
Dann auf e Edit drücken.

In einem weiteren Tab die Datei beliebig verschieben.

Jetzt wieder in Lazygit auf Schaltfläche 2 - "Files" die änderungen mit Pfeiltasten und LEERTASTE übernehmen.
Sobald alles übernommen ist auf SHIFT + a drücken, um die Änderungen dem Commit anzuhängen (amend). Mit ENTER bestätigen.

Um die Änderung jetzt endgültig anzuwenden m - "Rebase options" und dann c continue drücken.

Falls es zu merge errors kommt, die fehlerhafte Teile aus den Dateien entfernen, und wieder mit SHIFT + a den Commit amenden.

Die Dateien sollten jetzt an ihrem neuen Ort sein, und der Commit Verlauf sei derselbe!

Tipps

  • Statt die projectctl.bash zu nutzen kann man zum debuggen genauso gut im Paket-Ordner docker compose up usw machen.
    Alle Pakete sind ihre eigene Docker Projekte. (Die projectctl.bash macht das intern genauso, nur halt mit allen Paketen auf einmal.)