Commit 4ab64905 authored by Andreas Schmidt's avatar Andreas Schmidt

Merge branch 'develop'

parents 0eb580a7 c6fc52f3
ubuntu-16.04.2-minimal-odroid-xu4-20170516.img.xz filter=lfs diff=lfs merge=lfs -text
* text=auto
*.sh text eol=lf
*.c text eol=lf
*.cpp text eol=lf
*.h text eol=lf
*.py text eol=lf
*.mp4 binary
img/ubuntu-16.04.2-minimal-odroid-xu4-20170516.img.xz filter=lfs diff=lfs merge=lfs -text
img/emmc_recovery.img.xz filter=lfs diff=lfs merge=lfs -text
2017-11-29-raspbian-stretch.img.xz filter=lfs diff=lfs merge=lfs -text
img/ubuntu-18.04-4.14-minimal-odroid-xu4-20180531.img.xz filter=lfs diff=lfs merge=lfs -text
img/2017-11-29-raspbian-stretch.zip filter=lfs diff=lfs merge=lfs -text
rna.img.xz filter=lfs diff=lfs merge=lfs -text
.vagrant/
rna.img.xz
__pycache__/
*.pyc
*.log
[submodule "salt/apps/files/RNA-Apps"]
path = salt/apps/files/RNA-Apps
url = git@git.nt.uni-saarland.de:LARN/RNA-Apps.git
[submodule "salt/prrt/files/PRRT"]
path = salt/prrt/files/PRRT
url = git@git.nt.uni-saarland.de:LARN/PRRT.git
[submodule "salt/car/files/Adafruit-Motor-HAT-Python-Library"]
path = salt/car/files/Adafruit-Motor-HAT-Python-Library
url = https://github.com/adafruit/Adafruit-Motor-HAT-Python-Library.git
[submodule "salt/video/files/gst-prrt"]
path = salt/video/files/gst-prrt
url = git@git.nt.uni-saarland.de:LARN/gst-prrt.git
[submodule "salt/drone/crazyflie-clients-python"]
path = salt/drone/crazyflie-clients-python
url = https://github.com/bitcraze/crazyflie-clients-python.git
[submodule "salt/drone/crazyflie-lib-python"]
path = salt/drone/crazyflie-lib-python
url = https://github.com/bitcraze/crazyflie-lib-python.git
# Reliable Networking Atom (RNA)
\ No newline at end of file
# Reliable Networking Atom (RNA)
## Network Setup
* Subnet: `10.8.0.0/24`
* Hosts:
* Gateway: `10.8.0.1`
* Master: `10.8.0.1`
* Hosts: `10.8.0.10` - `10.8.0.50`
## RNA-Master Virtual Machine
### Idea
We administer the network using a master-machine, which includes DHCP, DNS and a SaltStack master.
The virtual machine is bridged to the physical interface where the hosts are attached to.
### Usage
* Start using `vagrant up`.
### Deploying Files
* Execute e.g. `salt '*' state.sls video.deploy`.
* Make sure to run `salt-run fileserver.clear_file_list_cache()` if files are not found.
### States
#### Common
##### WLAN
* Execute `common.wlan` to setup wireless LAN on the RNAs. The devices automatically connect to the LARN network.
* Check for present WLAN networks: `sudo iwlist wlan0 scan | grep ESSID`
#### Demo
* Execute `demo.control` to deploy the control demo.
* Execute `demo.video` to deploy the video demo.
#### Gstreamer
Gstreamer is installed from the sources, which are fetched from GitHub. We are using `gst-uninstalled`, a environment system much as virtualenv for Python. As we are using many different gstreamer elements, we build all plugins together with Gstreamer.
#### Video
Contains everything for the video demonstrations.
* `video.apps` (Gstreamer application, featuring a fully synced split-screen).
* `video.deploy` (Sets up everything for demonstrations).
* `video` (Create directory, copy files, build PRRT, plugin etc.).
* `video.scripts` (Copies scripts for send/recv the demonstration streams).
* `video.videos` (Copies all video files to the host).
## Odroid
### Images
* Images are built based on `ubuntu-16.04.2-minimal-odroid-xu4-20170516.img`.
* The latest image can be found under "Pipelines."
* Deploy image on eMMC module.
### Initial Setup
* The RNA comes with SaltStack and SSH installed.
* You can login using the `rna` user with the same password.
* Upon first startup:
* Make sure that the hostname is updated (edit `/etc/hostname`) and the Salt `minion_id` is set appropriately (edit `/etc/salt/minion_id`).
* Enter root mode with `sudo -i`
* Run `salt-call test.ping` once.
* Inside the RNA-Master, accept the key using `salt-key -L` and afterwards `salt-key -a` for the specific key.
* Afterwards, the system can be administered from the RNA-Master.
### eMMC Recovery
1. Flash emmc_recovery.img to a MicroSD card.
2. Connect both the eMMC and MicroSD to XU4.
3. Set the dip-switchs near the ethernet Jack to "SD boot mode".
4. Connect Power and watch the LED status
5. One the Blue led goes out and only RED is on. This may take 40seconds ~ 3minutes. And remove the power supply.
6. Set the dip switchs back to eMMC.
7. Remove the microSD card.
8. Proceed with normal power up with your peripherals attached.
9. After checking the eMMC, you can install other Linux OS images on the eMMC later.
# -*- mode: ruby -*-
# vi: set ft=ruby :
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
# Every Vagrant development environment requires a box. You can search for
# boxes at https://atlas.hashicorp.com/search.
config.vm.box = "ubuntu/xenial64"
config.vm.hostname = "rna-master"
config.vm.provider "virtualbox" do |vb|
vb.name = "rna-master"
vb.cpus = 2
vb.memory = 2048
vb.gui = false
end
config.ssh.forward_agent = true
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
config.vm.network "forwarded_port", guest: 4505, host: 4505
config.vm.network "forwarded_port", guest: 4506, host: 4506
# Create a private network, which allows host-only access to the machine
# using a specific IP.
# config.vm.network "private_network", ip: "192.168.33.10"
config.vm.network "public_network",
ip: "10.8.0.1",
:netmask => "255.255.255.0",
auto_config: true
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
config.vm.synced_folder "salt", "/srv/salt"
config.vm.synced_folder "pillar", "/srv/pillar"
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
# config.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
# vb.memory = "1024"
# end
#
# View the documentation for the provider you are using for more
# information on available options.
# Define a Vagrant Push strategy for pushing to Atlas. Other push strategies
# such as FTP and Heroku are also available. See the documentation at
# https://docs.vagrantup.com/v2/push/atlas.html for more information.
# config.push.define "atlas" do |push|
# push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME"
# end
# Enable provisioning with a shell script. Additional provisioners such as
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
# documentation for more information about their specific syntax and use.
config.vm.provision "shell", inline: <<-SHELL
export DEBIAN_FRONTEND=noninteractive
apt update
apt upgrade -y
curl -L https://bootstrap.saltstack.com -o install_salt.sh
sh ./install_salt.sh -P -M -N
cp /vagrant/master/master.* /etc/salt/pki/master/
apt install -y dnsmasq nmap htop git tshark
salt-call --local state.sls ptp.master
ln -s /vagrant/master/dnsmasq.conf /etc/dnsmasq.d/dnsmasq.conf
printf "Host 10.8.0*\n User rna\n ForwardAgent yes\n" >> /etc/ssh/ssh_config
echo "conf-dir=/etc/dnsmasq.d,*.conf" >> /etc/dnsmasq.conf
service dnsmasq restart
SHELL
# Ensure that dnsmasq starts when synced folders are mounted and the symlink works.
config.vm.provision "shell", run: "always", inline: <<-SHELL
service dnsmasq restart
SHELL
unless Vagrant::Util::Platform.windows? then
config.vm.provision "shell", run: "always", inline: <<-SHELL
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE
SHELL
end
end
#!/bin/bash
FILE="ubuntu-18.04-4.14-minimal-odroid-xu4-20180531"
apt-get update
apt-get install qemu-user-static pixz -y
pixz -d ubuntu-16.04.2-minimal-odroid-xu4-20170516.img.xz ubuntu-16.04.2-minimal-odroid-xu4-20170516.img
md5sum -c ubuntu-16.04.2-minimal-odroid-xu4-20170516.img.md5
limit=$(sfdisk -l --bytes ubuntu-16.04.2-minimal-odroid-xu4-20170516.img | tail -n 1 | awk '{print $2}')
pixz -d img/$FILE.img.xz img/$FILE.img
md5sum -c img/$FILE.img.md5
LIMIT=$(sfdisk -l --bytes img/$FILE.img | tail -n 1 | awk '{print $2}')
DIR=/mnt/rna
mkdir $DIR
mount -o loop,offset=$((512 * $LIMIT)) img/$FILE.img $DIR
mount --bind /proc $DIR/proc/
mount --bind /sys $DIR/sys/
mount --bind /dev $DIR/dev/
mount --bind /dev/pts $DIR/dev/pts
mkdir $DIR/srv/salt
mount --bind salt $DIR/srv/salt
echo 'nameserver 9.9.9.9' >> $DIR/etc/resolv.conf
dir=/mnt/rna
cp $(which qemu-arm-static) $DIR/usr/bin
cp provision.sh $DIR/root
cp setup.sh $DIR/root
chroot $DIR qemu-arm-static /bin/bash /root/provision.sh
mkdir $dir
mount -o loop,offset=$((512 * $limit)) ubuntu-16.04.2-minimal-odroid-xu4-20170516.img $dir
mount --bind /proc $dir/proc/
mount --bind /sys $dir/sys/
mount --bind /dev $dir/dev/
echo 'nameserver 8.8.4.4' >> $dir/etc/resolv.conf
rm $DIR/root/provision.sh
cp $(which qemu-arm-static) $dir/usr/bin
cp provision.sh $dir/root
chroot $dir qemu-arm-static /bin/bash /root/provision.sh
sync
umount $dir/dev
umount $dir/proc
umount $dir/sys
umount -l $DIR/srv/salt
umount -l $DIR/dev/pts
umount -l $DIR/dev
umount -l $DIR/proc
umount -l $DIR/sys
umount $dir
umount -l $DIR
mv ubuntu-16.04.2-minimal-odroid-xu4-20170516.img rna.img
mv img/$FILE.img rna.img
pixz rna.img rna.img.xz
rm rna.img
no-resolv
server=9.9.9.9
# Gateway
dhcp-option=3,10.8.0.1
# MAC-IP Bindings
dhcp-range=10.8.0.20,10.8.0.50,255.255.255.0,72h
# DNS Server Entries
dhcp-option=6,10.8.0.1,8.8.8.8
# DNS Zone
host-record=salt,10.8.0.1
# RNAs
dhcp-host=00:1e:06:30:a4:0a,10.8.0.101,72h
host-record=rna-01,10.8.0.101
# RNA 2
# LAN
dhcp-host=00:1e:06:30:a4:38,10.8.0.102,72h
host-record=rna-02,10.8.0.102
# RNA 3
# LAN
dhcp-host=00:1e:06:30:a4:35,10.8.0.103,72h
host-record=rna-03,10.8.0.103
# WLAN
dhcp-host=40:a5:ef:db:86:b8,10.8.0.203,72h
host-record=rna-03,10.8.0.203
# RNA 4
# LAN
dhcp-host=00:1e:06:30:a4:33,10.8.0.104,72h
host-record=rna-04,10.8.0.104
# WLAN
dhcp-host=40:a5:ef:db:86:6a,10.8.0.204,72h
host-record=rna-04,10.8.0.204
# RNA 5
dhcp-host=00:1e:06:30:a5:04,10.8.0.105,72h
host-record=rna-05,10.8.0.105
# RNA 6 - Raspi 3B
# LAN
dhcp-host=b8:27:eb:5d:8e:30,10.8.0.106,72h
host-record=rna-06,10.8.0.106
# WLAN
dhcp-host=b8:27:eb:08:db:65,10.8.0.206,72h
host-record=rna-06,10.8.0.206
# RNA 8 - Raspi Zero W (Drone)
# WLAN
dhcp-host=b8:27:eb:e1:5b:16,10.8.0.208,72h
host-record=rna-08,10.8.0.208
# RNA 9 - Raspi Zero W
# WLAN
dhcp-host=b8:27:eb:e3:ad:fa,10.8.0.209,72h
host-record=rna-09,10.8.0.209
# APs
dhcp-host=40:9b:cd:25:2a:f8,10.8.0.10,72h
host-record=rna-ap-01,10.8.0.10
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAqF4MANhATt4HlrcjYccl5b0Si7VeqqXZ+98fTaFODFnd1qEe
B5jti1shChOFaEPs0tfK5fVmMr+zkHYlP9QqzXYtteLcFVJoxDWnQveg8Pb1mqXW
VnZpMxRVaKSgNg9srOcnBJxwQ8uybB7ln+k2bG3VdAXip6RkFIBMJadfuGkoAvH1
v05NS6kJVQylG9NHIx5Td9hU8ZqKjJhw3Qlx3MOVRxmGvOTUJx55mIMRMjTfY9Cv
PnYYY0T/rK3CWMT5wfwtPbMtv5KqpCdRuiKqNiil78sS6FJUADFkJ/hHpj4/KGwP
IRHyO+g+frQ4TgI2gyeqV3REUROEzhmkJe/XXQIDAQABAoIBAQCXmBY2rH86g69R
hJPW9fipYhPQtv0FqU8b+Um2HAaqGEAlf+wJ6yf20ZZt/CWiO4aAUMvfQZVDHFgR
Ok9PqTjgxgdiPWDr0ceC4sw2/79pNvLsy2SxdOxDkYtVLOUTx8+R3o7DGBf88usz
bp5R3Smjd0E5thLd3qY9z0bAoHMPFicYTqdZ/aqP89CbaiPmuinpUFIR0j11oIeQ
6YBy2EwTLselk2kQ/Eoo1BXWwKk2jRamNrjv4r9/X1oTgS/00C3G39H+mT0tpWTh
ctD7SW5iagLOD4YUPj1YARtRqTNatv3bFVgfh6SaOUsHTr67HxaTAGfk1BhKqtOY
WTb04RABAoGBALkE1e3e/525m475mHW5AG1gDx+CBJoJwf0pdUlqx7PKDWBfZTfQ
QHpunJJpKxnoHBT2dWa9NLVRCPZfcq/10VATM4XUg4FkhTfI1ql0GjEcSVAjIKGJ
9MXNY+HNJo3ynKY7REVhwF+KQVStYxfgw/3/5sqyddl4c5FIZlWVyQNJAoGBAOj1
0wIlj6NLZVqjY85pFE45XczNIa980Vhq+fxJVXX4omBospQuSOIqxWErFMXnkhHX
FgLsT56emGLDrBA1almeELyolQlXSwIZITyexNJRBTZ1ZuJ/Y09Z9Yv9yNGQL1+m
jBPuGttLERgvDaE3hpzOrS6dg7SRzwWOZBuwz591AoGAP17fozTBGpXLKSJmTNQL
yGqhY2pWByiWcA62JGpVckgfYsXp1j8XBphCOoeZAquUir2Lop/loMDbr/8rOgeZ
JLMe75TFYhk648t/ctTYb7+/gJo3f/zPgLyDnIB21yGk8+7SyGzdxhuFmuo0SaZr
muD+fKi5Yr413yoMGv5NtjkCgYEA27Kpkwa1VbzPExGwGIOEwNjdGz4BnKxMCeSp
aUIHtMAM8nsKnzCfT5wilSa56oIfgW+ktJED7YWIFOyQIqEdcPLeue0K0MpgVNQ6
Qh9BY09BaUCDDOwyTi16otFuSCSAaOZ6iHkvHszGjFYjtnzVGKDZNnMaOHqiEI1e
37Z5t9kCgYADVztfSMMt3LVHmvj/HNYG2YkEiLC/I2hvC+x1pbh33Oe42/Vl12gF
QS4KtJIMPQhK06Sbt8rKXxt5ydn4ynPTfFx8wbCiDGgE4mBrqpyvEk2PwiT7htEM
92jnYbcyG1ZA7wHZGb6cyHI/W35frRahZ9CL9MEQyUpy9VINvoYrEQ==
-----END RSA PRIVATE KEY-----
\ No newline at end of file
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqF4MANhATt4HlrcjYccl
5b0Si7VeqqXZ+98fTaFODFnd1qEeB5jti1shChOFaEPs0tfK5fVmMr+zkHYlP9Qq
zXYtteLcFVJoxDWnQveg8Pb1mqXWVnZpMxRVaKSgNg9srOcnBJxwQ8uybB7ln+k2
bG3VdAXip6RkFIBMJadfuGkoAvH1v05NS6kJVQylG9NHIx5Td9hU8ZqKjJhw3Qlx
3MOVRxmGvOTUJx55mIMRMjTfY9CvPnYYY0T/rK3CWMT5wfwtPbMtv5KqpCdRuiKq
Niil78sS6FJUADFkJ/hHpj4/KGwPIRHyO+g+frQ4TgI2gyeqV3REUROEzhmkJe/X
XQIDAQAB
-----END PUBLIC KEY-----
\ No newline at end of file
gstreamer:
{%- if grains['osrelease'] == '16.04' %}
version: "1.10"
{%- elif grains['osrelease'] == '18.04' %}
version: "1.14"
{%- endif %}
video:
role: receiver
video:
role: sender
base:
'*':
- gstreamer
'rna-01':
- sender
'rna-02':
- receiver
'rna-03':
- sender
'rna-04':
- sender
'rna-05':
- sender
'rna-06':
- sender
'rna-07':
- sender
#!/bin/bash
# Divert
dpkg-divert --local --rename --add /sbin/initctl
ln -sf /bin/true sbin/initctl
# Packages
wget -O - https://repo.saltstack.com/apt/debian/9/amd64/latest/SALTSTACK-GPG-KEY.pub | sudo apt-key add -
echo "deb http://repo.saltstack.com/apt/debian/8/armhf/latest jessie main" > /etc/apt/sources.list.d/saltstack.list
apt-get update
apt-get install -y htop tmux vim
apt-get install -y salt-minion
# Salt Provision
salt-call -l warning --local state.highstate
# Undo Divert
dpkg-divert --local --rename --remove /sbin/initctl
rm /sbin/initctl
include:
- prrt.dependencies
- apps
Subproject commit bb3aaed240bcac33643fa36c750f8c9bf215d508
#!/bin/bash
rounds=180
killall python3
if [ "$1" != "plant" ] && [ "$1" != "controller" ]; then
echo "Usage: control_demo.sh [mode]"
echo " mode = plant, controller"
exit;
fi
while true; do
if [[ $1 == "controller" ]]; then
python3 /opt/rna/apps/sine.py ctrl -t 10.8.0.102 -c udp -r $rounds &
python3 /opt/rna/apps/sine.py ctrl -t 10.8.0.102 -c prrt -r $rounds &
wait
sleep 1;
fi
if [[ $1 == "plant" ]]; then
tmux new-session -d "python3 /opt/rna/apps/sine.py plant -t 10.8.0.102 -c prrt -r $rounds"
tmux split-window -h "python3 /opt/rna/apps/sine.py plant -t 10.8.0.102 -c udp -r $rounds"
tmux -2 attach-session -d
fi
sleep 1;
done
rna_apps:
file.recurse:
- name: /opt/rna/apps
- source: salt://apps/files/RNA-Apps
- user: rna
- group: rna
- file_mode: keep
dependencies:
cmd.run:
- name: pip3 install drawille
demo_script:
file.managed:
- name: /home/rna/control_demo.sh
- source: salt://apps/files/control_demo.sh
- user: rna
- group: rna
- file_mode: keep
prrt_build_ext:
cmd.run:
- name: python setup.py install && python3 setup.py install
- cwd: /opt/rna/apps/PRRT
- require:
- pip: pip_modules
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
enable_bbr:
file.managed:
- name: /etc/sysctl.d/99-bbr.conf
- source: salt://bbr/files/99-bbr.conf
Subproject commit f9e7c2592c5c720207b4e5040eb28e1628b48f49
from Adafruit_MotorHAT import Adafruit_MotorHAT, Adafruit_DCMotor
import time
import atexit
# create a default object, no changes to I2C address or frequency
mh = Adafruit_MotorHAT(addr=0x60)
# recommended for auto-disabling motors on shutdown!
def turnOffMotors():
mh.getMotor(1).run(Adafruit_MotorHAT.RELEASE)
mh.getMotor(2).run(Adafruit_MotorHAT.RELEASE)
mh.getMotor(3).run(Adafruit_MotorHAT.RELEASE)
mh.getMotor(4).run(Adafruit_MotorHAT.RELEASE)
atexit.register(turnOffMotors)
def _speedToDirection(speed):
if speed > 0:
return Adafruit_MotorHAT.FORWARD
elif speed < 0:
return Adafruit_MotorHAT.BACKWARD
else:
return Adafruit_MotorHAT.RELEASE
def setSpeed(left, right):
right = int(right * 1.1)
mh.getMotor(1).run(_speedToDirection(left))
mh.getMotor(2).run(_speedToDirection(left))
mh.getMotor(3).run(_speedToDirection(right))
mh.getMotor(4).run(_speedToDirection(right))
mh.getMotor(1).setSpeed(abs(left))
mh.getMotor(2).setSpeed(abs(left))
mh.getMotor(3).setSpeed(abs(right))
mh.getMotor(4).setSpeed(abs(right))
if __name__ == "__main__":
X = 255
Y = 4
while True:
print("right")
setSpeed(X/Y, X)
time.sleep(1)
print("stop")
setSpeed(0, 0)
time.sleep(1)
print("left")
setSpeed(-X/Y, 0-X)
time.sleep(1)
# #print("right")
# #setSpeed(50,100)
# #time.sleep(0.5)
# #setSpeed(100,200)
# #time.sleep(0.5)
# #setSpeed(50,100)
# #time.sleep(1)
# #print("left")
# #setSpeed(100,50)
# #time.sleep(1)
# #setSpeed(200,100)
# #time.sleep(1)
# #setSpeed(100,50)
# #time.sleep(1)
# setSpeed(100,120)
# time.sleep(0.1)
# setSpeed(100,140)
# time.sleep(0.1)
# setSpeed(100,160)
# time.sleep(0.1)
# setSpeed(100,180)
# time.sleep(0.1)
# setSpeed(100,200)
# time.sleep(0.1)
# setSpeed(100,180)
# time.sleep(0.1)
# setSpeed(100,160)
# time.sleep(0.1)
# setSpeed(100,140)
# time.sleep(0.1)
# setSpeed(100,120)
# time.sleep(0.1)
import prrt
import pickle
from MotorControl import *
socket = prrt.PrrtSocket(7000, isSender=False)
while True:
u = socket.receive_asap_wait()
u_v = pickle.loads(u)
left = u_v[0]
right = u_v[1]
setSpeed(int(left), int(right))
import gi
gi.require_version("Gst", "1.0")
from gi.repository import Gst, GObject
import cv2
import numpy as np
import logging
import prrt
import pickle
from controller.lineDetect import *
class Controller:
def __init__(self, port=5000, actor=("10.8.0.106", 8000)):
self.mainloop = GObject.MainLoop()
self.pipeline = None
self.main_loop = None
self.port = port
self.actor_socket = prrt.PrrtSocket(actor[1], True, target_delay=0.05)
self.actor_socket.connect(actor[0], actor[1])
Gst.init(None)
@staticmethod
def control(mean_angle):
v_d = 100
t_a = 1
p = .1 # gain, stability ensured with t_a as above
L = 12 # distance between left and right wheel (in cm)
# use a simple P controller approach for given sampling rate
u = np.empty(2)
u[0] = int(v_d - p * t_a * mean_angle * L / 2)
u[0] = min(255, max(0, u[0]))
u[1] = int(2 * v_d - u[0])
u[1] = min(255, max(0, u[1]))
return u
@staticmethod
def angle_from_image(img):
detected = detect_lines(img, 8)
# detected contains horizontal offsets (in pixels) from the x position of the red anchor,
# starting from the bottom
num_rows, num_cols, _ = img.shape
anchor_x = int(num_cols / 2)
anchor_y = int(num_rows / 16)
# compute the angle from the (pixel) differences
# use three anchor points
displacement = np.array([15, 13, 11, 9, 7, 5, 3, 1])
angles = np.arctan(detected / (num_rows - anchor_y * displacement))
sines = np.nansum(np.sin(angles))
cosines = np.nansum(np.cos(angles))
print(angles)