A equipe do Solucionática, após um longo, muito longo intervalo resolveu concluir mais um projeto. Como não poderia ser diferente, usamos componentes simples e desenvolvemos nosso software tomando emprestado, modificando, reinterpretando e também corrigindo programas encontrados na web, O resultado foi surpreendentemente bom, mesmo com muito pouco esforço computacional.
Qual é a "problemática"? Fazer algo parecido com isso: https://youtu.be/CjzSeOg8oTs. O projeto é de Jose Julio, mas desde o início fizemos modificações profundas. A primeira foi a troca do motor de com correia por um servo motor. A segunda foi o uso de pyGame no lugar do OpenCV!
Vamos aos códigos:
Lado do Arduino:
// Serial Call and Response
// by Tom Igoe
// Language: Wiring/Arduino
// This program sends an ASCII A (byte of value 65) on startup
// and repeats that until it gets some data in.
// Then it waits for a byte in the serial port, and
// sends three sensor values whenever it gets a byte in.
// Thanks to Greg Shakar for the improvements
// Created 26 Sept. 2005
// Updated 18 April 2008
// Modified by Solucionática 24 July 2013.
// Be carefull with the commented lines below.
//Re-mod by Solucionática 12 July 2017.
//#include "Ultrasonic.h"
//#include <Nokia5110.h>
#include <Servo.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
int pos;
char valor[10];
char soma[1];
int ang;
int firstSensor = 0; // first analog sensor
int secondSensor = 0; // second analog sensor
int thirdSensor = 0; // digital sensor
int inByte = 0; // incoming serial byte
int i;
//ByteBuffer = buffer;
//LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
//Ultrasonic ultrasonic(10,9);
Servo myservo; // create servo object to control a servo
// a maximum of eight servo objects can be created
void setup()
{
lcd.begin(16, 2);
inputString.reserve(200);
// start serial port at 9600 bps:
myservo.attach(9); // attaches the servo on pin 7 to the servo object
Serial.begin(9600);
//myservo.write(90);
//establishContact(); // send a byte to establish contact //until Processing responds
lcd.print("Tracker!");
}
void loop()
{
if (stringComplete) {
lcd.print(inputString);
delay(10);
myservo.write(inputString.toInt());
// clear the string:
inputString = "";
stringComplete = false;
}
}
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}
Lado do Raspi:
#!/usr/bin/python
import os,math
import serial, time
import pygame
import pygame.camera
from pygame.locals import *
from math import atan2, degrees, pi
# guessing serial ports names. Linux or macosx.
#'/dev/tty.usbserial'
ser = serial.Serial('/dev/ttyACM0',
115200,
timeout = 0)
serial_buffer = ""
# an event number for the SERIAL
SERIAL = pygame.USEREVENT +1
class Capture(object):
a = []
allines = []
found = 0
def __init__(self):
self.size = (640,480)
# create a display surface. standard pygame stuff
pygame.camera.init()
self.display = pygame.display.set_mode(self.size, 0)
self.font = pygame.font.Font(None, 44)
# this is the same as what we saw before
self.clist = pygame.camera.list_cameras()
if not self.clist:
raise ValueError("Sorry, no cameras detected.")
self.cam = pygame.camera.Camera(self.clist[0], self.size)
self.cam.start()
a = []
allines = []
found = 0
def __init__(self):
self.size = (640,480)
# create a display surface. standard pygame stuff
pygame.camera.init()
self.display = pygame.display.set_mode(self.size, 0)
self.font = pygame.font.Font(None, 44)
# this is the same as what we saw before
self.clist = pygame.camera.list_cameras()
if not self.clist:
raise ValueError("Sorry, no cameras detected.")
self.cam = pygame.camera.Camera(self.clist[0], self.size)
self.cam.start()
# create a surface to capture to. for performance purposes
# bit depth is the same as that of the display surface.
self.snapshot = pygame.surface.Surface(self.size, 0, self.display)
def get_and_flip(self):
# if you don't want to tie the framerate to the camera, you can check
# if the camera has an image ready. note that while this works
# on most cameras, some will never return true.
if self.cam.query_image():
self.snapshot = self.cam.get_image(self.snapshot)
# blit it to the display surface. simple!
self.display.blit(self.snapshot, (0,0))
pygame.display.flip()
def main(self):
going = True
while going:
for event in pygame.event.get() :
if event.type == pygame.KEYDOWN :
# bit depth is the same as that of the display surface.
self.snapshot = pygame.surface.Surface(self.size, 0, self.display)
def get_and_flip(self):
# if you don't want to tie the framerate to the camera, you can check
# if the camera has an image ready. note that while this works
# on most cameras, some will never return true.
if self.cam.query_image():
self.snapshot = self.cam.get_image(self.snapshot)
# blit it to the display surface. simple!
self.display.blit(self.snapshot, (0,0))
pygame.display.flip()
def main(self):
going = True
while going:
for event in pygame.event.get() :
if event.type == pygame.KEYDOWN :
if event.key == pygame.K_SPACE :
print "Space bar pressed down."
elif event.key == pygame.K_ESCAPE :
print "Escape key pressed down."
elif event.type == pygame.KEYUP :
if event.key == pygame.K_SPACE :
del self.a[:]
print"Vermelho Detectado"
del self.allines[:]
elif event.key == pygame.K_ESCAPE :
pygame.quit()
self.get_and_flip()
def get_and_flip(self):
self.snapshot = self.cam.get_image(self.snapshot)
# threshold against the color we got before
print "Space bar pressed down."
elif event.key == pygame.K_ESCAPE :
print "Escape key pressed down."
elif event.type == pygame.KEYUP :
if event.key == pygame.K_SPACE :
del self.a[:]
print"Vermelho Detectado"
del self.allines[:]
elif event.key == pygame.K_ESCAPE :
pygame.quit()
self.get_and_flip()
def get_and_flip(self):
self.snapshot = self.cam.get_image(self.snapshot)
# threshold against the color we got before
crect = pygame.draw.rect(self.display, (255,0,0), (145,105,30,30), 4)
#self.ccolor = pygame.transform.average_color(self.snapshot, crect)
mask = pygame.mask.from_threshold(self.snapshot, (240, 111, 115), (60, 10, 10))
self.display.blit(self.snapshot,(0,0))
# keep only the largest blob of that color
connected = mask.connected_component()
# make sure the blob is big enough that it isn't just noise
if mask.count() > 30: #100
# find the center of the blob
coord = mask.centroid()
self.a.append(coord)
self.found = 0
else:
self.found = self.found+1
#if we not found the threshold color more then 15 times
#we create a new line
if self.found > 15:
self.allines.append(self.a[:])
del self.a[:]
#self.ccolor = pygame.transform.average_color(self.snapshot, crect)
mask = pygame.mask.from_threshold(self.snapshot, (240, 111, 115), (60, 10, 10))
self.display.blit(self.snapshot,(0,0))
# keep only the largest blob of that color
connected = mask.connected_component()
# make sure the blob is big enough that it isn't just noise
if mask.count() > 30: #100
# find the center of the blob
coord = mask.centroid()
self.a.append(coord)
self.found = 0
else:
self.found = self.found+1
#if we not found the threshold color more then 15 times
#we create a new line
if self.found > 15:
self.allines.append(self.a[:])
del self.a[:]
l = len(self.a)
for i in range(len(self.allines)):
if len(self.allines[i]) >1:
pygame.draw.aalines(self.display, (255,255,255), 0, self.allines[i], 1)
if l > 1:
pygame.draw.aalines(self.display, (255,255,255), 0, self.a, 1)
#cen = pygame.mask.from_threshold(self.snapshot,(240,240,255),(30,30,30)
cen = mask.centroid()
#Angle logic
dx,dy0 = cen
dx1,dy = self.a[1]
dist = math.sqrt((640-dx)**2+(480-dy0)**2)
i=0
rads = atan2(-(dy-dy0),(dx1-dx))
rads %= 2*pi
l = len(self.a)
for i in range(len(self.allines)):
if len(self.allines[i]) >1:
pygame.draw.aalines(self.display, (255,255,255), 0, self.allines[i], 1)
if l > 1:
pygame.draw.aalines(self.display, (255,255,255), 0, self.a, 1)
#cen = pygame.mask.from_threshold(self.snapshot,(240,240,255),(30,30,30)
cen = mask.centroid()
#Angle logic
dx,dy0 = cen
dx1,dy = self.a[1]
dist = math.sqrt((640-dx)**2+(480-dy0)**2)
i=0
rads = atan2(-(dy-dy0),(dx1-dx))
rads %= 2*pi
self.degs = degrees(rads)
w,h = mask.get_size()
pygame.draw.circle(self.display, (255,0,0),cen,w/12,6)
self.display.blit(self.font.render(str(cen)+" coord", True, (0,0,255)), (10, 440))
self.display.blit(self.font.render(str(rads)+" degrees", True, (0,255,0)), (10, 300))
#ser.flush()
#time.sleep(0.2)
# ser.write(str(self.degs/2))
ser.write(bytes(int(dist/2.7)))
ser.write('\n')
# ser.flush()
# time.sleep(10)
#ser.write(str(360-self.degs))
#ser.flushInput()
# print (360-self.degs)
print (bytes(int(dist/2.7)))
w,h = mask.get_size()
pygame.draw.circle(self.display, (255,0,0),cen,w/12,6)
self.display.blit(self.font.render(str(cen)+" coord", True, (0,0,255)), (10, 440))
self.display.blit(self.font.render(str(rads)+" degrees", True, (0,255,0)), (10, 300))
#ser.flush()
#time.sleep(0.2)
# ser.write(str(self.degs/2))
ser.write(bytes(int(dist/2.7)))
ser.write('\n')
# ser.flush()
# time.sleep(10)
#ser.write(str(360-self.degs))
#ser.flushInput()
# print (360-self.degs)
print (bytes(int(dist/2.7)))
#print (str(self.degs))
pygame.display.flip()
#ser.flush()
#ser.write(str(self.degs))
pygame.init()
pygame.camera.init()
x = Capture()
x.main()