Commit 210a553a authored by Felix Kettner's avatar Felix Kettner

Merge branch 'master' into 'feature-add-linesensor-and-gripper'

Master to feature branch

See merge request !4
parents 3b156fc2 e9e00bc3
Pipeline #34317 passed with stage
in 30 seconds
......@@ -10,9 +10,11 @@ test:
script:
- python3 --version
- pip3 install --user -r requirements.txt
- pip3 install --user pycodestyle
- echo "Start testing..."
- bash scripts/pep8.sh
# - python3 harware_test.py
- echo "No tests available yet."
- echo "No more tests available yet."
#build:
# stage: build
......
......@@ -32,7 +32,7 @@ Durch den Anschluss von Maus, Tastatur und Bildschirm kann der PiBot wie ein nor
sudo ifconfig wlan0 | grep "inet " | cut -c 14-28
```
5. Öffnen Sie auf Ihrem PC ein Terminal.
6. Mit dem folgenden Befehl können Sie sich nun auf dem PiBot einloggen. XXX.XXX.XXX.XXX ist dabei durch die notierte IP Adresse zu ersetzen. Das Passwort lautet "raspberrypi".
6. Mit dem folgenden Befehl können Sie sich nun auf dem PiBot einloggen. XXX.XXX.XXX.XXX ist dabei durch die notierte IP Adresse zu ersetzen. Das Passwort lautet "ok".
```bash
ssh pi@XXX.XXX.XXX.XXX
```
......
# -*- coding: utf-8 -*-
#from simBot import Nano
import sys
from pibot.nano import Nano
########################################
# !!! WICHTIG !!! #
########################################
# ###################################### #
# !!! WICHTIG !!! #
# ###################################### #
# Bearbeiten Sie nicht diese Datei.
# Das Verändern der bereits vorhandenen Dateien
# kann zu Komplikationen bei Aktualisierungen des
......@@ -15,17 +14,17 @@ from pibot.nano import Nano
# Legen Sie sich eine eigene Kopie (oder mehrere) dieser Datei
# mit einem beliebigen Namen in DIESEM Verzeichnis an und
# bearbeiten Sie die Aufgaben in Ihrer Kopie.
########################################
# !!! WICHTIG !!! #
########################################
# ###################################### #
# !!! WICHTIG !!! #
# ###################################### #
# Sie finden hier alle zu bewältigenden Aufgaben für dieses Semester.
# Die Inhalte bauen aufeinander auf und sollten daher in der entsprechenden
# Reihenfolge bearbeitet werden.
# Wenn Sie mit der Bearbeitung der Aufgabe "Task Parcours" fertig sind,
# schreiben Sie bitte eine Mail an felix.kettner@informati.tu-chemnitz.de.
# Wir werden dann einen Termin für die Abnahme der Prüfungsleistung vereinbaren.
# Die Modalitäten dafür sind in "Task Parcours" näher beschrieben.
# Wir werden dann einen Termin für die Abnahme der Prüfungsleistung
# vereinbaren. Die Modalitäten dafür sind in "Task Parcours" näher beschrieben.
# Task 1:
# Machen Sie sich mit dem unten stehenden Code vertraut.
......@@ -35,53 +34,58 @@ from pibot.nano import Nano
# Ihre Antwort direkt in ihre Kopie dieses Pythonfiles.
# Task 2:
# Füllen Sie die Funktion drive_along_wall mit Code! Ziel soll es sein,
# Füllen Sie die Funktion drive_along_wall mit Code! Ziel soll es sein,
# dass der Roboter sich mit Hilfe des rechten Ultraschallsensors
# in einem bestimmten Abstand parallel zu einer Wand bewegt.
# Nutzen Sie dafür die Grundlagen aus dem Python Tutorial und die Hinweise zur
# Nutzen Sie dafür die Grundlagen aus dem Python Tutorial und die Hinweise zur
# Programmierung des PiBots.
# Task 3:
# Da die Motoren des Roboters nicht absolut gleich laufen, fährt dieser auf
# Da die Motoren des Roboters nicht absolut gleich laufen, fährt dieser auf
# freiem Feld über eine entsprechend lange Strecke einen Kreis.
# Um dem entgegen zu wirken stehen uns die Radencoder zur Verfügung, welche die
# Radumdrehungen zählen. Eine Radmdrehung entspricht dabei 180 "Ticks".
# Schreiben Sie eine Funktion drive_straight, welche dafür Sorge trägt, dass der
# Roboter geradeaus fährt.
# Um dem entgegen zu wirken stehen uns die Radencoder zur Verfügung, welche die
# Radumdrehungen zählen. Eine Radmdrehung entspricht dabei 180 "Ticks".
# Schreiben Sie eine Funktion drive_straight, welche dafür Sorge trägt, dass
# der Roboter geradeaus fährt.
# Ein leichtes Pendel um die Ideallinie ist dabei vertretbar.
# Schreiben Sie eine einfache Lösung. Sie müssen keinen PID-Regler implementieren.
# Schreiben Sie eine einfache Lösung. Sie müssen keinen PID-Regler
# implementieren.
# Inzwischen sollten Sie einigermaßen mit dem Roboter und dessen Funktionalitäten
# vertraut sein. Wenn dies der Fall ist, fahren Sie mit Aufgabe 4 fort.
# Inzwischen sollten Sie einigermaßen mit dem Roboter und dessen
# Funktionalitäten vertraut sein. Wenn dies der Fall ist, fahren Sie mit
# Aufgabe 4 fort.
# Falls nicht, fahren Sie trotzdem mit Aufgabe 4 fort und sehen Sie sich danach
# nochmals die Aufgaben 1 bis 3 an.
# Task 4:
# Machen Sie Pause. Mindestens eine Stunde - oder auch den restlichen Tag.
# Machen Sie Pause. Mindestens eine Stunde - oder auch den restlichen Tag.
# Idealerweise mit einem Getränk und analoger Lektüre Ihrer Wahl.
# Verbuchen Sie die Zeit ohne schlechtes Gewissen unter "Aufgaben für die Uni erledigt".
# Verbuchen Sie die Zeit ohne schlechtes Gewissen unter "Aufgaben für die Uni
# erledigt".
# Task Parcours:
# Diese Aufgabe dient der Vorbereitung Ihres Roboters auf den Prüfungsparcours.
# Diesen muss der Roboter ohne Ihr weiteres Eingreifen bewältigen.
# Schreiben Sie dazu ein Programm, welches die folgenden Rahmenbedingungen
# Schreiben Sie dazu ein Programm, welches die folgenden Rahmenbedingungen
# berücksichtigt:
#
# Im Normalzustand soll der Roboter in einem festgelegten Abstand parallel zu
# Im Normalzustand soll der Roboter in einem festgelegten Abstand parallel zu
# einer Wand fahren.
# Diese befindet sich auf der rechten Seite in Fahrtrichtung.
# Beim folgen der Wand wird der Roboter dabei auf verschiedene Situationen stoßen:
# Beim folgen der Wand wird der Roboter dabei auf verschiedene Situationen
# stoßen:
#
# Hindernisse
# Hindernisse, welche vor dem Roboter auftauchen, soll dieser umfahren.
# Die Hindernisse können dabei in Breite, Länge und Anzahl variieren.
# Ob die Fahrkurve beim Umfahren "eckig", mit 90° Winkeln, oder wellenförmig
# verläuft ist dabei Ihrer Fantasie und ihren Programmierfähigkeiten überlassen.
# Ob die Fahrkurve beim Umfahren "eckig", mit 90° Winkeln, oder wellenförmig
# verläuft ist dabei Ihrer Fantasie und ihren Programmierfähigkeiten
# überlassen.
#
# Tunnel
# Sollte sich sowohl auf der rechten, als auch auf der linken Seite des Roboters
# eine Wand befinden, gilt diese Situation als Tunnel.
# Hier sollen die frontalen LEDs angeschaltet und beim Verlassen des Tunnels
# Sollte sich sowohl auf der rechten, als auch auf der linken Seite des
# Roboters eine Wand befinden, gilt diese Situation als Tunnel.
# Hier sollen die frontalen LEDs angeschaltet und beim Verlassen des Tunnels
# wieder abgeschaltet werden.
#
# Garage
......@@ -99,24 +103,24 @@ from pibot.nano import Nano
#
# Die benötigte Zeitdauer für das Bewältigen des Parcours hat keinen Einfluss
# auf die Bewertung.
# Allerdings wird der Versuch nach maximal 5 Minuten als fehlgeschlagen gewertet.
# (Üblicherweise ist der Parcours in 30 bis 60 Sekunden zu bewältigen)
# Allerdings wird der Versuch nach maximal 5 Minuten als fehlgeschlagen
# gewertet.
#
# Ein Fehlschlag bei allen Versuchen führt nicht automatisch zum Nichtbestehen
# der Prüfungsleistung, da Codelogik und -qualität, beispielsweise
# struktureller Aufbau, aussagekräftige Benennung von Variablen und Funktionen,
# Ein Fehlschlag bei allen Versuchen führt nicht automatisch zum Nichtbestehen
# der Prüfungsleistung, da Codelogik und -qualität, beispielsweise
# struktureller Aufbau, aussagekräftige Benennung von Variablen und Funktionen,
# sowie Robustheit der Lösung und die Ergebnisse der
# Aufgaben 1 bis 3 ebenso berücksichtigt werden.
#
#
# Als abgegebener Code zählt die letzte auf dem PiBot von Ihnen ausgeführte
# Pythondatei zur Bewältigung des Parcours.
#
# Im Ordner assets finden Sie eine beispielhafte Darstellung des Parcours (Parcoursbeispiel.png).
#
# Im Ordner assets finden Sie eine beispielhafte Darstellung des Parcours
# (Parcoursbeispiel.png).
# Viel Erfolg!
def drive_until_obstacle():
free = True
while free:
......@@ -138,11 +142,11 @@ def main():
nano.set_motors(0, 0)
nano.reset_encoders()
drive_until_obstacle() # you should comment this line
# drive_along_wall() # and uncomment this line in order to run the
# drive_along_wall() function
drive_until_obstacle() # you should comment this line
# drive_along_wall() # and uncomment this line in order to run the
# drive_along_wall() function
if __name__ == "__main__":
nano = Nano()
main()
\ No newline at end of file
main()
......@@ -7,17 +7,17 @@ from pibot import colorsensor
def test_motors():
print(nano.get_encoders())
print(nano.get_encoders())
nano.set_motors(50, 50)
sleep(1)
nano.set_motors(0, 0)
print(nano.get_encoders())
print(nano.get_encoders())
nano.set_motors(-50, -50)
sleep(1)
nano.set_motors(0, 0)
print(nano.get_encoders())
print(nano.get_encoders())
def test_front_leds():
leds.init_leds()
leds.set_led(c.LED_FRONT_LEFT, c.ON)
......@@ -25,8 +25,8 @@ def test_front_leds():
sleep(2)
leds.set_led(c.LED_FRONT_LEFT, c.OFF)
leds.set_led(c.LED_FRONT_RIGHT, c.OFF)
def test_mid_button():
buttons.init_buttons()
buttons.wait_for_button(c.BUTTON_MID)
......@@ -69,7 +69,7 @@ def main():
nano.reset_encoders()
test_motors()
test_front_leds()
test_ultrasonics()
......
......@@ -15,6 +15,7 @@ from pibot import leds
MENU_TOGGLE_PIN = 21
def background():
GPIO.setmode(GPIO.BCM)
GPIO.setup(MENU_TOGGLE_PIN, GPIO.IN, GPIO.PUD_UP)
......@@ -36,14 +37,14 @@ def menu(lcd):
('Sensor Test', sensor_test),
('LED Test', led_test),
('Camera Test', camera_test),
('Buzzer Test', buzzer_test) ]
('Buzzer Test', buzzer_test)]
current = 1
in_menu = True
while in_menu:
message = [ str(menu_entries[current][0]),
"",
"<- ok ->"]
message = [str(menu_entries[current][0]),
"",
"<- ok ->"]
lcd.print(message)
button = wait_for_any()
if button == c.BUTTON_LEFT:
......@@ -64,15 +65,15 @@ def exit_menu(lcd):
def poweroff(lcd):
message = [ "Are you sure?",
"",
"Yes No"]
message = ["Are you sure?",
"",
"Yes No"]
lcd.print(message)
button = wait_for_any()
if button == c.BUTTON_LEFT:
message = [ " Shutdown...",
"",
""]
message = [" Shutdown...",
"",
""]
lcd.print(message)
sleep(1)
popen("sudo poweroff")
......@@ -83,9 +84,9 @@ def show_ip(lcd):
ip = (subprocess.check_output(cmd, shell=True)).decode("utf-8")
leds.init_leds()
leds.set_led(c.LED_MID, c.GREEN)
message = [ "IP:",
str(ip),
" "]
message = ["IP:",
str(ip),
" "]
lcd.set_fontsize(17)
lcd.print(message)
lcd.set_fontsize(21)
......@@ -94,21 +95,21 @@ def show_ip(lcd):
def actuator_test(lcd):
message = [ "Requesting",
"Nano!",
""]
message = ["Requesting",
"Nano!",
""]
lcd.print(message)
nano = Nano()
while nano.get_battery_voltage() == 0:
message = [ "Please plug in",
"the 9V battery!",
" "]
message = ["Please plug in",
"the 9V battery!",
" "]
lcd.print(message)
sleep(0.5)
message = [ "Make sure the",
"motors are",
"powered on!"]
message = ["Make sure the",
"motors are",
"powered on!"]
lcd.print(message)
leds.init_leds()
leds.set_led(c.LED_MID, c.GREEN)
......@@ -130,25 +131,25 @@ def actuator_test(lcd):
def sensor_test(lcd):
message = [ "Requesting",
"Nano!",
""]
message = ["Requesting",
"Nano!",
""]
lcd.print(message)
nano = Nano()
leds.init_leds()
leds.set_led(c.LED_MID, c.GREEN)
while not is_pressed(c.BUTTON_MID):
message = [ str(nano.get_distances()),
"",
" ok"]
message = [str(nano.get_distances()),
"",
" ok"]
lcd.print(message)
leds.set_led(c.LED_MID, c.OFF)
def led_test(lcd):
message = [ "Testing",
"LED's!",
""]
message = ["Testing",
"LED's!",
""]
lcd.print(message)
leds.init_leds()
leds.check_leds()
......@@ -156,6 +157,7 @@ def led_test(lcd):
IMAGE_PATH = "/home/pi/Pictures/"
def camera_test(lcd):
leds.init_leds()
with PiCamera() as cam:
......@@ -178,9 +180,9 @@ def camera_test(lcd):
def buzzer_test(lcd):
message = [ "Requesting",
"Nano!",
""]
message = ["Requesting",
"Nano!",
""]
lcd.print(message)
nano = Nano()
lcd.clear()
......@@ -198,4 +200,3 @@ def buzzer_test(lcd):
sleep(0.550)
nano.set_buzzer(380, 100)
sleep(0.575)
......@@ -27,6 +27,7 @@ def wait_for_button(button):
wait_for_button_press(button)
wait_for_button_release(button)
def wait_for_any():
while True:
if is_pressed(c.BUTTON_LEFT):
......
......@@ -70,8 +70,10 @@ class Camera:
Checks if the image contains a ball with the specified color
:param image: (2d color array) The image to be checked
:param color: (str) Either red or blue
:param radius: (int or float) The radius which the ball needs to be recognized as a ball (in px)
:return: (tuple) returns two values: boolean whether the ball is detected or not and the (manipulated) image
:param radius: (int or float) The radius which the ball needs to be
recognized as a ball (in px)
:return: (tuple) returns two values: boolean whether the ball is
detected or not and the (manipulated) image
"""
if image is not None:
rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
......@@ -86,7 +88,8 @@ class Camera:
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
else:
raise Exception("Only check for red or blue ball is supported. Given: {}".format(color))
raise Exception("Only check for red or blue ball is \
supported. Given: {}".format(color))
if len(cnts) > 0:
# find the largest contour in the mask, then use
......@@ -96,15 +99,20 @@ class Camera:
((x, y), r) = cv2.minEnclosingCircle(c)
M = cv2.moments(c)
if M["m00"] > 0:
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
center = (int(M["m10"] /
M["m00"]), int(M["m01"] /
M["m00"]))
# only proceed if the radius meets a minimum size
if r > radius:
# draw the circle and centroid on the frame,
# then update the list of tracked points
image_manipulated = image.copy()
cv2.circle(image_manipulated, (int(x), int(y)), int(r), (0, 255, 255), 2)
cv2.circle(image_manipulated, center, 5, (0, 0, 255), -1)
cv2.circle(image_manipulated,
(int(x), int(y)),
int(r), (0, 255, 255), 2)
cv2.circle(image_manipulated,
center, 5, (0, 0, 255), -1)
return True, image_manipulated
return False, image
else:
......@@ -114,7 +122,8 @@ class Camera:
"""
Views an image
:param image: The image to be viewed
:param window_name: The name of the window where the image should be put in
:param window_name: The name of the window where the image should
be put in
"""
cv2.imshow(window_name, image)
if window_name not in self.windows:
......
......@@ -7,7 +7,9 @@ from PIL import ImageOps
class LCD:
def __init__(self, fonttype="/home/pi/.fonts/Roboto-Regular.ttf", fontsize=14):
def __init__(self,
fonttype="/home/pi/.fonts/Roboto-Regular.ttf",
fontsize=14):
self.disp = Adafruit_SSD1306.SSD1306_128_64(rst=None)
# Initialize library.
......@@ -19,12 +21,16 @@ class LCD:
image = Image.new('1', (self.disp.width, self.disp.height))
draw = ImageDraw.Draw(image)
for i in range(len(text)):
draw.text((0, -2 + i * (self.font.size + 2) ), text[i], font=self.font, fill=255)
draw.text((0, -2 + i * (self.font.size + 2)),
text[i],
font=self.font,
fill=255)
self.disp.image(image)
self.disp.display()
def view_image(self, source, invert):
image = Image.open(source).resize((self.disp.width, self.disp.height), Image.ANTIALIAS)
image = Image.open(source).resize((self.disp.width, self.disp.height),
Image.ANTIALIAS)
if invert:
image = image.convert('L')
image = ImageOps.invert(image)
......
......@@ -2,12 +2,14 @@ import time
import RPi.GPIO as GPIO
from time import sleep
from pibot.serial_comm import write_order, Order, read_i16, write_i8, read_ui8, write_ui16
from pibot.serial_comm import (write_order,
Order,
read_i16,
write_i8,
read_ui8,
write_ui16)
from pibot.utils import open_serial_port, clamp
import pibot.constants as c
# from OS import popen
import struct
......
......@@ -37,4 +37,5 @@ class Pid:
self.m_left_new += val_corr
nano.set_motors(int(m_left + self.m_left_new), int(m_right + self.m_right_new))
nano.set_motors(int(m_left + self.m_left_new),
int(m_right + self.m_right_new))
from __future__ import print_function, division, unicode_literals, absolute_import
from __future__ import (print_function,
division,
unicode_literals,
absolute_import)
import struct
......
......@@ -36,9 +36,9 @@ def startup():
nano = Nano()
voltage = nano.get_battery_voltage()
message = [ "IP: ",
str(ip), # on newline for IP's with mostly 3 digits (xxx.xxx.xxx.xxx)
"Battery: {} mV".format(voltage)]
message = ["IP: ",
str(ip), # on newline for IP's with mostly 3 digits
# (xxx.xxx.xxx.xxx)
"Battery: {} mV".format(voltage)]
lcd.print(message)
sleep(2)
\ No newline at end of file
......@@ -11,7 +11,8 @@ except ImportError:
from serial import Serial, SerialException
# From https://stackoverflow.com/questions/12090503/listing-available-com-ports-with-python
# From https://stackoverflow.com/questions/12090503/
# listing-available-com-ports-with-python
def get_serial_ports():
"""
Lists serial ports.
......@@ -38,7 +39,10 @@ def get_serial_ports():
return results
def open_serial_port(serial_port=None, baudrate=115200, timeout=None, write_timeout=0):
def open_serial_port(serial_port=None,
baudrate=115200,
timeout=None,
write_timeout=0):
"""
Try to open serial port with Arduino
If not port is specified, it will be automatically detected
......@@ -51,9 +55,12 @@ def open_serial_port(serial_port=None, baudrate=115200, timeout=None, write_time
# Open serial port (for communication with Arduino)
if serial_port is None:
serial_port = get_serial_ports()[0]
# timeout=0 non-blocking mode, return immediately in any case, returning zero or more,
# up to the requested number of bytes
return Serial(port=serial_port, baudrate=baudrate, timeout=timeout, writeTimeout=write_timeout)
# timeout=0 non-blocking mode, return immediately in any case,
# returning zero or more, up to the requested number of bytes
return Serial(port=serial_port,
baudrate=baudrate,
timeout=timeout,
writeTimeout=write_timeout)
def clamp(value, minimun, maximum):
......
#!/bin/bash
printf " \n\e[32m \e[1mChecking for PEP8 compliance...\e[0m\n"
echo "PATH=$PATH:/home/gitlab-runner/.local/bin" >> .bashrc
source .bashrc
for file in $(find . -name "*.py")
do
if [[ ${file: -3} == ".py" ]]
then
echo $file | tr -d '\n'
if [[ $(pycodestyle $file) ]]
then
printf ".....\e[31m \e[1mcheck:\e[0m\n"
pycodestyle $file
else
printf ".....\e[32m \e[1mok!\e[0m\n"
fi
fi
done
printf "\e[32m \e[1mPEP8 check done.\e[0m\n \n "
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment