A ROS2 Projekt for Managing a Yahboom Tank (http://www.yahboom.net/study/G1-T-PI)
  • JavaScript 36.4%
  • Python 34.2%
  • CSS 28.7%
  • HTML 0.7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2023-12-16 12:05:33 +01:00
.github/ISSUE_TEMPLATE Delete bug_report.md 2020-05-01 18:20:31 +02:00
django Adding everything i had on py 2021-04-03 11:53:24 +00:00
files Delete helper.txt 2020-05-01 19:25:37 +02:00
rclpy Adding everything i had on py 2021-04-03 11:53:24 +00:00
src/rpi_gpio_tank/django/static/admin A Lot of Django Include 2021-01-16 01:36:26 +00:00
systemd_units make the config more generel again 2020-05-31 11:05:49 +00:00
.gitignore network config is privat i add it to ignore 2021-05-02 10:50:27 +02:00
.gitlab-ci.yml Add new file 2021-04-03 12:18:41 +00:00
CODE_OF_CONDUCT.md Create CODE_OF_CONDUCT.md 2020-05-01 18:11:23 +02:00
CONTRIBUTING.md Initial commit 2019-10-26 21:19:06 +00:00
LICENSE Initial commit 2019-10-26 21:19:06 +00:00
README.md Updating Readme to new way of Installation with the rpi-imager 2023-12-16 12:04:30 +01:00

ROS 2 RPI_GPIO Tank

This repo is a puzzle peace that i am currently writing to tinker with ROS2 and a Yaboom T1 Tank Robot. You can find the model here

My Focus is lerning about ROS2 and Python. I'm new to both Topics but i still want to share what i have done so far, so that others can look for examples and maybe start with ROS2 too. This is a Hobby Project. I have live and can't be here 24/7.

The code is provided as is, you know ;)

I guess beacuse i am mostly using the examples from ROS2 itself, i have to provide it under Apache 2 or a greater License O.o ? Im not sure about this. It's Public code and you can use it. Please don't build weapons with this.

Dependencys

ansible sshpass python3-pip

libfcl-dev ffmpeg2theora python-ogg libboost-python-dev django gunicorn nginx postgresql python-opencv

python3-pip

  • rclpy
  • os
  • sys
  • RPi.GPIO
  • timeout_decorator
  • serial
  • time
  • cv2
  • datetime

image_tools cam2image

web_video_server web_video_server

Preamble

I tryed more ways of installation and i'm now on installation number 3.

my target is now Building Docker container to get rid of the Dependencys of other Projekts like web_video_server or opencv.

it gives me also the advantage of building the container not on my Raspberpi Robot and instead build it else wehre.

( I use other pi's but i could be AWS or somewehre )

Next thing is, i now start to use ansible ( https://www.ansible.com/ ). The guid i wroth prewewsly, is long.

i run it 3 times now and change the method of deployment. So i decid to automated it. Its a bit overkill but its in the end easyer for someone who like to copy the project.

Preperration

Docker container can run very easy on a raspian so no extra here.

For better performance, i choose you "lite installation and 64bit" image

Download Raspberry Image

Follow the guide for installation:

Raspberry Pi - installation Guids

Windows User

Please consider using Windows Subsystem for Linux Installation

and openssh on windows Install OpenSSH

or a Linux VM

Additional needet

The guid is missing the headless installation. Further is a newer way to setup the user in the imager programm instead directly on the pi or the pi promts for a user configuration on the first run.

I noteced that the imager creates a firstrun.sh in the boot folder and this programm then configures the parameter the user gives in the imager.

We can use this as general preperation for the pi. You should save your first firstrun.sh after you configured it to deploy your ssh key and name the pi. If you have to redeploy you could copy this into the [bootfs] / folder of the mmc Please configure a ssh.pub key in the imager for the user, ansible needs later a passwordless login.

We need attional to put a empty ssh file in [bootfs] / and we put the preconfigured firstrun.sh byside of it.

Linux way to do this is: Mount the boot partion and then in terminal.

touch /media/[username]/bootfs/ssh
  • unmount the partition.

  • unplug the mmc and put the card in the raspberrypi

  • plugin a network cable and start the robot

The Plan

The Ansible roles is written to expect the Raspberry Pi with the default hostname in your network.

the firstlogin of the scripts starts with username and password.

creates the user tank and rename the Pi to tank1 (Defaut).

The script configures the network for you but you have to configure it in the host attributes first.

The checklist is like-

  • clone the Repro

  • install dependencys

sudo apt-get install python3-pip sshpass
  • install ansible on your workstation.
  python --version
  Python 3.7.3

  python -m pip install ansible

  ansible --version
  ansible 2.10.7
  • create a config .yml file in file [rpi_gpio_tank_repro_root]/ansible/host_vars/tank1/
  nano [rpi_gpio_tank_repro_root]/ansible/host_vars/tank1/network.yml
   ---
   hostname: tank1
   address: [192.168.X.X]
   netmask: [192.168.X.X]
   gateway: [192.168.X.1]
   dns-search: [intern or maybe fritz.box]
   nameservers: [192.168.X.1]
   ssid: [my own wifi name]
  • create a secret file for your wifi password
  nano [rpi_gpio_tank_repro_root]/ansible/host_vars/tank1/network-secret.yml
   ---
   ssid-password: [secret password]
  • deploy the role to the Robot with

 cd [rpi_gpio_tank_repro_root]/ansible/

 ansibel-playbook deploy.yml

Legency Dokumentation -- used for programming ansible role

Change the password to somthing secret.

Begin the configuration of the wireless network.

Reference

Normaly you want start by:

"Connecting to a WPA Personal wireless network"

sudo nano /etc/netplan/50-cloud-init.yaml

It should look like this:

  network:
      ethernets:
          eth0:
              dhcp4: true
              dhcp6: true
              optional: true
      wifis:
          wlan0:
              dhcp4: true
              dhcp6: true
              access-points:
                  "<your-wlan-ssid>":
                      band: 2.4GHz
                      password: "<your-wlan-password>"
      version: 2

Save the File and Apply the Config with:

sudo netplan apply

Now you can check with 'ip addr' in the section "3: wlan0:" what ip address you have. (X marks the address)

  3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
      link/ether dc:a6:32:85:f0:f1 brd ff:ff:ff:ff:ff:ff
      inet XXX.XXX.XXX.XXX/24 brd 192.168.176.255 scope global dynamic noprefixroute wlan0
         valid_lft 863501sec preferred_lft 863501sec
      inet6 fd00::e76c:2642:4420:c12d/64 scope global dynamic noprefixroute 
         valid_lft 7200sec preferred_lft 3600sec
      inet6 fe80::8b9:9181:1dca:1f43/64 scope link noprefixroute 
         valid_lft forever preferred_lft forever

Unplug now the Pi from the Network and reconnect over WLAN

ssh ubuntu@<ip address of your raspberry WLAN adapter>

Rename the py

I Like to have a more personal name of the device in the network.

@Work i would do thinks like SRV-DC-NTP-DNS or SRV-Nagios etc.

@Home i give it a name

sudo nano /etc/hostname

<a name you want>

Adding a user

My target is to have in the end a service that runs in a user space and have little rights as possible. Its maybe not posibble because of the access to Hardware but i start to create that environment with a seperat user.

I like to give him for now sudo rights and remove that later.


sudo useradd -m tank -s /bin/bash 

sudo passwd tank
<new password>
<new password>

Login in a new shell to the user

ssh tank@<ip address of your raspberry wifi adapter>

# and exit because the account exisist now

exit

Create a SSH key pair if you not have allready one

Reference

(on your local maschine)

ssh-keygen -t rsa -b 4096 << or longer up to 10.000 

Copy your public key

ssh-copy-id tank@<ip address of your raspberry wifi adapter>
<password of user tank that you have set>

####### You are now able to connect without password to the user tank.

Grant sudo rights to the tank user

Careful what you type in this file. Mistyping can cause breaking the permission system and may let you setup all from the beginning.
ssh ubuntu@<ip address of your raspberry wifi adapter>
<password for the ubuntu user that you set>

sudo visudo

It should look like this:

#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults        env_reset
Defaults        mail_badpass
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"

# Host alias specification

# User alias specification

# Cmnd alias specification

# User privilege specification
root    ALL=(ALL:ALL) ALL

# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL

tank   ALL=(ALL) NOPASSWD:ALL

# See sudoers(5) for more information on "#include" directives:

#includedir /etc/sudoers.d 

Test that nothing is broken with:

sudo su

root@ubuntu:/home/ubuntu# exit

####### if you become root everthing is fine

Remove user Ubuntu

ssh tank@<ip address of your raspberry wifi adapter>

sudo killall -u ubuntu

sudo userdel ubuntu

allow login only by ssh-key

sudo nano /etc/ssh/sshd_config

change the line from

PasswordAuthentication yes

to 

PasswordAuthentication no

Save it

Remove your password

sudo passwd -d tank

Reboot your pi

####### step to restart services.

sudo reboot

Relogin to the pi

ssh tank@<ip address of your raspberry wifi adapter>

In the next step is the installing of the ROS Meta OS with a workspace.

Reference: Install ROS2

Reference: Build your workspace

Reference: Django with Gunicorn

sudo apt update && sudo apt install curl gnupg2 lsb-release

curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -

sudo sh -c 'echo "deb http://packages.ros.org/ros2/ubuntu `lsb_release -cs` main" > /etc/apt/sources.list.d/ros2-latest.list'

sudo apt update

sudo apt-get dist-upgrade

sudo apt install ros-dashing-ros-base python3-colcon-common-extensions ros-dashing-image-tools ros-dashing-web-video-server python3-pip python3-opencv libopencv* postgresql nginx

# workspace

mkdir -p ~/ros_colcon_ws/src

Give the user the Rights to USB

sudo usermod -a -G dialout tank

Modding the GPIO Access

Add this in a new file to let the system create the gpio device with a group gpio instead of root.

sudo nano  /etc/udev/rules.d/99-gpio.rules
    
SUBSYSTEM=="bcm2835-gpiomem", KERNEL=="gpiomem", GROUP="gpio", MODE="0660"
SUBSYSTEM=="gpio", KERNEL=="gpiochip*", ACTION=="add", PROGRAM="/bin/sh -c 'chown root:gpio /sys/class/gpio/export    /sys/class/gpio/unexport ; chmod 220 /sys/class/gpio/export /sys/class/gpio/unexport'"
SUBSYSTEM=="gpio", KERNEL=="gpio*", ACTION=="add", PROGRAM="/bin/sh -c 'chown root:gpio /sys%p/active_low /sys%p/direction /sys%p/edge /sys%p/value ; chmod 660 /sys%p/active_low /sys%p/direction /sys%p/edge /sys%p/value'"

Give the user the Rights to GPIO

sudo groupadd gpio

sudo usermod -a -G gpio tank 

Give the user the Rights to Video

sudo usermod -a -G video tank       

Configure the pgsql Server

Referrence https://medium.com/coding-blocks/creating-user-database-and-adding-access-on-postgresql-8bfcd2f4a91e

sudo systemctl enable postgresql@10-main.service

sudo -u postgres createuser interface_frontend

sudo -u postgres createdb interface

sudo -u postgres psql

postgres=# alter user interface_frontend with encrypted password '<Password you write in the Django configuration>';

postgres=# grant all privileges on database interface to interface_frontend;

\q

Configure your own Django settings.py

The Django File ros_colcon_ws/src/rpi_gpio_tank/django/interface/settings.py has some settings like passwords and secrets. We have to make sure that this is individuel for every robot.

Please create a new file ros_colcon_ws/src/rpi_gpio_tank/django/interface/settings.py

First Block on Top

"""
Django settings for interface project.

Generated by 'django-admin startproject' using Django 3.0.3.

For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

First Change

Please create a new key

# SECURITY WARNING: keep the secret key used in production secret! - 50 symbols is Default
SECRET_KEY = '<password>'

Second Block

Allowed Hosts nee to be configured arcording to your robot IP and network konfiguration.

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['<Robot IP>','<Robot FQDN>','127.0.0.1','localhost']

Third Block

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles', 
    'interface'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'interface.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR,'interface/templates/'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'interface.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases

Fourth Block

This is the Django Database connection. We need this matching with the user configuration in the database.

Please create a new Password for the Database user.

# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'interface',
        'USER': 'interface_frontend',
        'PASSWORD': '<Database Password>',
        'HOST': 'localhost',
        'PORT': '',
    }
}

Fifth Block

# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    { 
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    { 
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    { 
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

BASE_DIR = '/home/tank/ros_colcon_ws/src/rpi_gpio_tank/django/'

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

Install pip Dependencies

pip3 install RPi.GPIO

pip3 install pyserial

pip3 install timeout_decorator

pip3 install opencv-python

pip3 install Django

pip3 install gunicorn

Intigrate Django to nginx

Create an new configuration for nginx

sudo nano /etc/nginx/sites-available/interface

server {
listen 80;
server_name <Robot IP or FQDN>;

location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
    root /home/tank/ros_colcon_ws/src/rpi_gpio_tank/django;
}

location / {
    include proxy_params;
    proxy_pass http://unix:/home/tank/ros_colcon_ws/src/rpi_gpio_tank/django/interface.sock;
}
}

Link it with

 sudo ln -s /etc/nginx/sites-available/interface /etc/nginx/sites-enabled

Enable and restart nginx

 sudo systemctl enable nginx
 sudo systemctl restart nginx

Configure gunicorn

Copy the gunicorn systemd unit form the repo to /etc/systemd/system/

modyfy it so that its matching with your network and ROS configuration.

Enable the Service and start it.

 sudo systemctl daemon-reload

 sudo systemctl enable gunicorn

 sudo systemctl restart gunicorn

You may want to see after the installation what is in my .bashrc

# this is needet because, at the moment of my build there was a bug that, the python Packages from ROS not get announced to ROS2 pkg list.
export AMENT_PREFIX_PATH=$AMENT_PREFIX_PATH:~/ros_colcon_ws/install/rpi_gpio_tank/

export ROS_DOMAIN_ID={Number}
export ROS_PYTHON_VERSION=3
export ROS_DISTRO=dashing
export ROS_MASTER_URI={IPADDRESS_of_ROBOT}:11311
export ROS_IP={IPADDRESS_of_ROBOT}
export ROS_HOSTNAME=$ROS_IP
export ROS_VERSION=2
     
source /opt/ros/dashing/setup.bash
source ~/ros_colcon_ws/install/local_setup.bash

And i work with this build script.

~/ros_colcon_ws$ cat ./build.sh
 
echo "changing to workspace"
cd ~/ros_colcon_ws

echo "source in to build"
source install/setup.bash

echo "building"
colcon build --parallel-workers 1 --symlink-install

echo "test"
colcon test

echo "install setup.bash"
source install/local_setup.bash && source install/setup.bash 

In the './src' directory of your worspace you can clone my repro.

git clone https://github.com/4PXKHF9IK8ZL7XKN/rpi_gpio_tank.git

Then you rebuild the workspace with the script and install the Projekt.

~/ros_colcon_ws$ /bin/bash ./build.sh

Now you should can run:

ros2 launch rpi_gpio_tank robot.launch.py

This brings up the basic services on the Robot, like driving, camera movement, etc.

For the Camera Picture Publishing, i use the external image_tools cam2image.

Extras

A Photo of the Build

I've got a GSM_GPRS_GNSS_HAT and adding support for GPS over this.

This is my Manual for the Device