- JavaScript 36.4%
- Python 34.2%
- CSS 28.7%
- HTML 0.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .github/ISSUE_TEMPLATE | ||
| django | ||
| files | ||
| rclpy | ||
| src/rpi_gpio_tank/django/static/admin | ||
| systemd_units | ||
| .gitignore | ||
| .gitlab-ci.yml | ||
| CODE_OF_CONDUCT.md | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| README.md | ||
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
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.
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
(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: 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
I've got a GSM_GPRS_GNSS_HAT and adding support for GPS over this.