Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration tests with gazebo #18

Merged
merged 16 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 24 additions & 24 deletions .github/workflows/build-arm32v7.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,44 @@ jobs:
runs-on: [self-hosted, Linux, ARM]

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4

- name: build core container
working-directory: ./PiCar-X
run: |
TAG=latest-arm32v7 ARCH=arm32v7 docker compose -f docker-compose-core.yml build --no-cache
- name: build core container
working-directory: ./PiCar-X
run: |
TAG=latest-arm32v7 ARCH=arm32v7 docker compose -f docker-compose-core.yml build --no-cache

- name: build dtp containers without gazebo
working-directory: ./PiCar-X
run: |
TAG=latest-arm32v7 ARCH=arm32v7 docker compose -f docker-compose-dtp-no-gazebo.yml build --no-cache
- name: build dtp containers without gazebo
working-directory: ./PiCar-X
run: |
TAG=latest-arm32v7 ARCH=arm32v7 docker compose -f docker-compose-dtp-no-gazebo.yml build --no-cache

unit-tests:
runs-on: [self-hosted, Linux, ARM]
needs: [build]
steps:
- uses: actions/checkout@v4
- name: Run pytest in Docker container
working-directory: ./PiCar-X
run: |
docker run --rm --name picarx-unittest abarbie/picarx:latest-arm32v7 pytest ./src/core/picarx/tests
- uses: actions/checkout@v4
- name: Run pytest in Docker container
working-directory: ./PiCar-X
run: |
docker run --rm --name picarx-unittest abarbie/picarx:latest-arm32v7 pytest ./src/core/picarx/tests

integration-tests:
runs-on: [self-hosted, Linux, ARM]
needs: [unit-tests]
steps:
- uses: actions/checkout@v4
- name: Start roslaunch in Docker container
working-directory: ./PiCar-X
run: |
docker run --rm --name dcmotor-integration-test -v /sys/class/gpio:/sys/class/gpio -v /dev/i2c-11:/dev/i2c-11 --privileged abarbie/picarx-dcmotor-driver:latest-arm32v7 rostest picarx_dcmotor_driver integration_tests.test i2c_port:=/dev/i2c-11
- uses: actions/checkout@v4
- name: Integration Test dcmotor
working-directory: ./PiCar-X
run: |
docker run --rm --name dcmotor-integration-test -v /sys/class/gpio:/sys/class/gpio -v /dev/i2c-11:/dev/i2c-11 --privileged abarbie/picarx-dcmotor-driver:latest-arm32v7 rostest picarx_dcmotor_driver integration_tests.test i2c_port:=/dev/i2c-11

release:
runs-on: [self-hosted, Linux, ARM]
needs: [integration-tests]
steps:
- uses: actions/checkout@v4
- name: Push to Docker Hub
working-directory: ./PiCar-X
run: |
TAG=latest-arm32v7 docker compose -f docker-compose-dtp-no-gazebo.yml push
- uses: actions/checkout@v4
- name: Push to Docker Hub
working-directory: ./PiCar-X
run: |
TAG=latest-arm32v7 docker compose -f docker-compose-dtp-no-gazebo.yml push
48 changes: 24 additions & 24 deletions .github/workflows/build-arm64v8.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,43 @@ jobs:
runs-on: [self-hosted, Linux, ARM64]

steps:
- uses: actions/checkout@v4
- name: build core container
working-directory: ./PiCar-X
run: |
TAG=latest-arm64v8 ARCH=arm64v8 docker compose -f docker-compose-core.yml build --no-cache
- uses: actions/checkout@v4
- name: build core container
working-directory: ./PiCar-X
run: |
TAG=latest-arm64v8 ARCH=arm64v8 docker compose -f docker-compose-core.yml build --no-cache

- name: build dtp containers without gazebo
working-directory: ./PiCar-X
run: |
TAG=latest-arm64v8 ARCH=arm64v8 docker compose -f docker-compose-dtp-no-gazebo.yml build --no-cache
- name: build dtp containers without gazebo
working-directory: ./PiCar-X
run: |
TAG=latest-arm64v8 ARCH=arm64v8 docker compose -f docker-compose-dtp-no-gazebo.yml build --no-cache

unit-tests:
runs-on: [self-hosted, Linux, ARM64]
needs: [build]
steps:
- uses: actions/checkout@v4
- name: Run pytest in Docker container
working-directory: ./PiCar-X
run: |
docker run --rm --name picarx-unittest abarbie/picarx:latest-arm64v8 pytest ./src/core/picarx/tests
- uses: actions/checkout@v4
- name: Run pytest in Docker container
working-directory: ./PiCar-X
run: |
docker run --rm --name picarx-unittest abarbie/picarx:latest-arm64v8 pytest ./src/core/picarx/tests

integration-tests:
runs-on: [self-hosted, Linux, ARM64]
needs: [unit-tests]
steps:
- uses: actions/checkout@v4
- name: Start roslaunch in Docker container
working-directory: ./PiCar-X
run: |
docker run --rm --name dcmotor-integration-test -v /sys/class/gpio:/sys/class/gpio -v /dev/i2c-11:/dev/i2c-11 --privileged abarbie/picarx-dcmotor-driver:latest-arm64v8 rostest picarx_dcmotor_driver integration_tests.test i2c_port:=/dev/i2c-11
- uses: actions/checkout@v4
- name: Integration Test dcmotor
working-directory: ./PiCar-X
run: |
docker run --rm --name dcmotor-integration-test -v /sys/class/gpio:/sys/class/gpio -v /dev/i2c-11:/dev/i2c-11 --privileged abarbie/picarx-dcmotor-driver:latest-arm64v8 rostest picarx_dcmotor_driver integration_tests.test i2c_port:=/dev/i2c-11

release:
runs-on: [self-hosted, Linux, ARM64]
needs: [integration-tests]
steps:
- uses: actions/checkout@v4
- name: Push to Docker Hub
working-directory: ./PiCar-X
run: |
TAG=latest-arm64v8 docker compose -f docker-compose-dtp-no-gazebo.yml push
- uses: actions/checkout@v4
- name: Push to Docker Hub
working-directory: ./PiCar-X
run: |
TAG=latest-arm64v8 docker compose -f docker-compose-dtp-no-gazebo.yml push
61 changes: 37 additions & 24 deletions .github/workflows/build-x64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,57 @@ jobs:
runs-on: [self-hosted, Linux, X64]

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4

- name: build core container
working-directory: ./PiCar-X
run: |
TAG=latest docker compose -f docker-compose-core.yml build --no-cache
- name: build core container
working-directory: ./PiCar-X
run: |
TAG=latest docker compose -f docker-compose-core.yml build --no-cache

- name: build dtp containers without gazebo
working-directory: ./PiCar-X
run: |
TAG=latest docker compose -f docker-compose-dtp-no-gazebo.yml build --no-cache
- name: build dtp containers without gazebo
working-directory: ./PiCar-X
run: |
TAG=latest docker compose -f docker-compose-dtp-no-gazebo.yml build --no-cache

unit-tests:
runs-on: [self-hosted, Linux, X64]
needs: [build]
steps:
- uses: actions/checkout@v4
- name: Run pytest in Docker container
working-directory: ./PiCar-X
run: |
docker run --rm --name picarx-unittest abarbie/picarx:latest pytest ./src/core/picarx/tests
- uses: actions/checkout@v4
- name: Run pytest in Docker container
working-directory: ./PiCar-X
run: |
docker run --rm --name picarx-unittest abarbie/picarx:latest pytest ./src/core/picarx/tests

integration-tests:
runs-on: [self-hosted, Linux, X64]
needs: [unit-tests]
steps:
- uses: actions/checkout@v4
- name: Start roslaunch in Docker container
working-directory: ./PiCar-X
run: |
docker run --rm --name dcmotor-integration-test -v /sys/class/gpio:/sys/class/gpio -v /dev/i2c-0:/dev/i2c-0 --privileged abarbie/picarx-dcmotor-driver:latest rostest picarx_dcmotor_driver integration_tests.test i2c_port:=/dev/i2c-0
- uses: actions/checkout@v4

- name: Integration Test dcmotor
working-directory: ./PiCar-X
run: |
docker run --rm --name dcmotor-integration-test -v /sys/class/gpio:/sys/class/gpio -v /dev/i2c-0:/dev/i2c-0 --privileged abarbie/picarx-dcmotor-driver:latest rostest picarx_dcmotor_driver integration_tests.test i2c_port:=/dev/i2c-0

- name: Speed tests using Gazebo headless
working-directory: ./PiCar-X
run: |
i2c=/dev/i2c-0 docker compose -f docker-compose-dtp-inttest.yml up -d
docker exec picar-x-picarx-gazebo-control-1 /bin/bash -c "source ./install/setup.bash && sleep 30; python3 ./src/simulation/picarx_control/tests/steering_integration_test.py"

- name: Remove running containers after tests
if: success() || failure()
working-directory: ./PiCar-X
run: |
docker compose -f docker-compose-dtp-inttest.yml down

release:
runs-on: [self-hosted, Linux, X64]
needs: [integration-tests]
steps:
- uses: actions/checkout@v4
- name: Push to Docker Hub
working-directory: ./PiCar-X
run: |
TAG=latest docker compose -f docker-compose-dtp.yml push
- uses: actions/checkout@v4
- name: Push to Docker Hub
working-directory: ./PiCar-X
run: |
TAG=latest docker compose -f docker-compose-dtp.yml push
7 changes: 6 additions & 1 deletion IEEE Internet Computing/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
[![DOI:10.1109/MIC.2021.3065245](https://zenodo.org/badge/doi/10.1109/MIC.2021.3065245.svg)](https://doi.org/10.1109/MIC.2021.3065245)
# This Video was recorded during the ARCHES Demonstration Mission
On the left side of the video, the digital twins of Mansio - a stationary sensor hub - and Viator, a crawler equipped with a camera, are displayed. In the captured scenario, we broadcast a command to the network, altering the behavior of all systems. The video captures Mansio activating its lights and Viator slowly moving backward. A split-screen format is used to show that the digital twins replicate the actions of their physical counterparts with a small delay

**More details in the demo mission report:**

A.Barbie,N.Pech,W.Hasselbring,S.Flogel,F.Wenzhofer,M. Walter, E. Shchekinova, M. Busse, M. Turk, M. Hofbauer, and S. Sommer. Developing an Underwater Network of Ocean Observation Systems with Digital Twin Prototypes - A Field Report from the Baltic Sea. IEEE Internet Computing, 2021. [![DOI:10.1109/MIC.2021.3065245](https://zenodo.org/badge/doi/10.1109/MIC.2021.3065245.svg)](https://doi.org/10.1109/MIC.2021.3065245)
2 changes: 1 addition & 1 deletion PiCar-X/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ RUN /bin/bash -c "source /opt/ros/noetic/setup.bash && catkin config --isolate-d
&& touch /root/.bashrc \
&& echo "source /opt/ros/noetic/setup.bash" >> /root/.bashrc \
&& echo "source ./install/setup.bash" >> /root/.bashrc
ENTRYPOINT [ "/root/catkin_ws/src/arches/arches_core/ENTRYPOINT.sh" ]
ENTRYPOINT [ "/root/catkin_ws/src/arches/arches_core/ENTRYPOINT.sh" ]
77 changes: 53 additions & 24 deletions PiCar-X/README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,63 @@
# Digital Twin Prototype of a PiCar-X
The goal of this project is to give an insight into practice and how the developed of IIoT applications changes.We demonstrate the basic idea of a Digital Twin (Prototype) by the example of a PiCar-X by Sunfounder.
This project was implemented with via ROS packages, which can be connected to a Gazebo simulation.
The goal of this project is to exemplify my research on digital twins. All concepts presented and formalized in the paper:

**A. Barbie and W. Hasselbring. From Digital Twins to Digital Twin Prototypes: Concepts, Formalization, and Applications. IEEE Access, 12:75337–75365, 2024.** [![DOI:10.1109/access.2024.3406510](https://zenodo.org/badge/doi/10.1109/access.2024.3406510.svg)](https://doi.org/10.1109/access.2024.3406510)

The basic ideas of a Digital Twin Prototype are implemented for a PiCar-X by Sunfounder. All modules are implemented using the middleware Robot Operating System (ROS). All nodes are encapsulated in Docker. The digital thread is realized using the ARCHES Digital Twin Framework (ADTF).

<img style="display: block; margin: auto;" src="./docs/picarx-gazebo.gif" width="500" />

**!!! This demo will not work on Ubuntu 24.04, since the character devices fully replace the sysfs GPIO functionallity.**

# Activate GPIO and I2C on Your System
This project based on ROS and Docker. Due to the used interfaces on the RPi, we have to use Linux Kernel functions for GPIO and I2C. Before you can start this project you have to activate GPIO and I2C. If you already activated these modules, you can proceed with ##. Otherwise you have to build these modules first.

- [Install on Ubuntu 20.04](#build-new-linux-kernel)
- [Install on Windows (with WSL2)](#build-new-windows-wsl2-kernel)

<strong>If you are using this project with WSL2, you also have to [install and start the XLaunch](#xlaunch-for-windows). Otherwise you can start Gazebo with Docker.</strong>
**If you are using this project with WSL2, you also have to [install and start the XLaunch](#xlaunch-for-windows). Otherwise you can start Gazebo with Docker.**

If you already have built the modules, you can activate them via
If you already have built the modules, you can activate them via:
```console
sudo modprobe gpio-mockup gpio_mockup_ranges=1,41
sudo modprobe i2c-dev
sudo modprobe i2c-stub chip_addr=0x14
```

# Start with Docker compose

You can start the whole Digital Twin Prototype with the <em>docker-compose</em> file in this folder. We use a core container, where all other containers are built on. When you built the containers the first time, you have to build the core container first.
If you want to run the Digital Twin Prototype without the Gazebo Simulation on a RaspberryPi, you only need to active the I2C stub:
```console
sudo modprobe i2c-stub chip_addr=0x14
```

```console
# Start with Docker compose
It is possible to run the DTP on a common x64 processcor architecture, but also ARM32v7 (RPI 3) and ARM 64 (RPI 4). Notice that you cannot run Gazebo on an ARM architecture.

docker compose -f docker-compose-dtp.yml build picarx
## On x64 Linux
The default TAG is latest. If you want to change the docker container version, add the environment variable TAG infront of docker compose
```console
docker compose -f docker-compose-core.yml build --no-cache
docker compose -f docker-compose-dtp.yml build --no-cache
```

Create a Docket network.

```console
docker network create picarx
## On ARM32 Linux
The RaspberryPi 3 needs to use the arm32v7 docker container. Use the ARCH environment variable to build on the correct base container.
```console
TAG=latest ARCH=arm32v7 docker compose -f docker-compose-core.yml build --no-cache
TAG=latest ARCH=arm32v7 docker compose -f docker-compose-dtp-no-gazebo.yml build --no-cache
```

Afterwards, you can build all containers and start the Digital Twin Prototype when all containers are built.
## On ARM64 Linuy
The RaspberryPi 4 needs to use the arm64v8 docker container. Use the ARCH environment variable to build on the correct base container.
```console
TAG=latest ARCH=arm64v8 docker compose -f docker-compose-core.yml build --no-cache
TAG=latest ARCH=arm64v8 docker compose -f docker-compose-dtp-no-gazebo.yml build --no-cache
```

## Build and start the Physical Twin on a RPI
```console
docker compose -f docker-compose-dtp.yml build
docker compose -f docker-compose-dtp.yml up
TAG=latest ARCH=<SELECT ARM VERSION> docker compose -f docker-compose-core.yml build --no-cache
TAG=latest ARCH=<SELECT ARM VERSION> docker compose -f docker-compose-pt.yml build --no-cache
TAG=latest ARCH=<SELECT ARM VERSION> docker compose -f docker-compose-pt.yml up -d
```

## Let the DTP drive
Expand All @@ -64,14 +83,24 @@ After you start all Docker containers, you can switch into one of the containers
In this project we also demonstrate how to execute small integration tests with ROS and Docker. The drivers of the clutchgear and the DC Motor have integration tests
in their <em>tests</em> folders.

**Replace the I2C devices with the device your created on your system.**

## Integration Test for the DCMotor driver
```console
# CLUTCHGEAR DRIVER (Steering)
docker run --rm --name test -v /sys/class/gpio:/sys/class/gpio -v /dev/i2c-0:/dev/i2c-0 --privileged -it abarbie/picarx-clutchgear-emulator:${TAG} /bin/bash -c "source ./devel/picarx_clutchgear_driver/setup.bash
&& rostest picarx_clutchgear_driver integration_tests.test""
docker run --rm --name dcmotor-integration-test -v /sys/class/gpio:/sys/class/gpio -v /dev/i2c-0:/dev/i2c-0 --privileged abarbie/picarx-dcmotor-driver:latest rostest picarx_dcmotor_driver integration_tests.test i2c_port:=/dev/i2c-0
```

## Speed test with data from Gazebo in headless mode
For this integration test, you have to first start the entire DTP with Gazebo in headless mode. Afterwards, you execute the test. Do not forget to shutdown all containers after the tests.
```console
i2c=/dev/i2c-0 docker compose -f docker-compose-dtp-inttest.yml up -d

# DC MOTOR DRIVER
docker run --rm --name test -v /sys/class/gpio:/sys/class/gpio -v /dev/i2c-0:/dev/i2c-0 --privileged -it abarbie/picarx-dcmotor-driver:${TAG} /bin/bash -c "source ./devel/picarx_dcmotor_driver/setup.bash && rostest picarx_dcmotor_driver integration_tests.test"
docker exec picar-x-picarx-gazebo-control-1 /bin/bash -c "source ./install/setup.bash && sleep 30; python3 ./src/simulation/picarx_control/tests/steering_integration_test.py"

docker compose -f docker-compose-dtp-inttest.yml down
```
This test was also autoamted in the x64 Github Actions workflow.


# Build new Windows WSL2 Kernel

Expand Down Expand Up @@ -121,7 +150,7 @@ wsl --shutdown
```

Back on Windows you know have to copy the <em>bzImage</em> to the kernel folder <em>C:\Windows\System32\lxss\tools</em>
Then rename the <em>kernel</em> file to <em>kernel.old</em>, <strong>do not delete it</strong>! If something went wrong, you can just restore the old working kernel.
Then rename the <em>kernel</em> file to <em>kernel.old</em>, **do not delete it**! If something went wrong, you can just restore the old working kernel.

After you copied the <em>bzImage</em> into the folder, rename <em>bzImage</em> to <em>kernel</em>. Afterwards, start Ubuntu again and go into the WSL2 Kernel folder from the privious steps and install the modules via:

Expand Down Expand Up @@ -223,7 +252,7 @@ Start the application with following configuration:

# Troubleshooting

<strong>Problem 1: /dev/I2C-X is busy:</strong>
**Problem 1: /dev/I2C-X is busy:**

If you started the Docker compose file before you activated I2C, than a folder named /dev/I2C-X was created on your system, due to the mounting of volumes.

Expand All @@ -235,7 +264,7 @@ sudo rm -r /dev/i2c-x

And [activate I2C](#activate-gpio-and-i2c-on-your-system)

<strong>Problem 2: GPIO ports exist after the containers crashed/were killed.</strong>
**Problem 2: GPIO ports exist after the containers crashed/were killed.**

If you use CTRL+C more than once, you kill the containers instead of stopping them. Although deleting the GPIO pins is part of the shutdown routine, this is skipped if the containers crash or get killed.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,10 @@ def test_dt_pub_data(self):
right_wheel_stop_position = self.final_message.pose[right_wheel_stop_index]
left_wheel_stop_position = self.final_message.pose[left_wheel_stop_index]
rospy.loginfo(right_wheel_start_position)
self.assertAlmostEqual(right_wheel_start_position.position.x + 1, right_wheel_stop_position.position.x, delta=0.03)
self.assertAlmostEqual(left_wheel_start_position.position.x + 1, left_wheel_stop_position.position.x, delta=0.03)
self.assertAlmostEqual(right_wheel_start_position.position.x + 1, right_wheel_stop_position.position.x, delta=0.04)
self.assertAlmostEqual(left_wheel_start_position.position.x + 1, left_wheel_stop_position.position.x, delta=0.04)


if __name__ == '__main__':
rosunit.unitrun("ackermann_skill", 'test_pt_speed',
Test_Speed)

# python3 src/simulation/picarx_control/tests/steering_integration_test.py
Test_Speed)