From 4eac8734125e76971737573fca7698ea17be46b1 Mon Sep 17 00:00:00 2001 From: Cole Deck Date: Wed, 18 Mar 2020 13:52:51 -0500 Subject: [PATCH] Add consistent error and info messages, tweak image blurring. Remove penny requirement. --- __pycache__/detect.cpython-38.pyc | Bin 6489 -> 4881 bytes control_motor.py | 25 ++++++++++++------ control_pixel.py | 2 +- detect.py | 41 ++++++++++-------------------- pi_client.py | 4 +-- run_detect.py | 26 ++++++++++--------- 6 files changed, 47 insertions(+), 51 deletions(-) diff --git a/__pycache__/detect.cpython-38.pyc b/__pycache__/detect.cpython-38.pyc index 5bec0fd37e432a40629090b634941f26ed96c1a1..ad8d2cc47b1b58412bf79802cfc45447f55e1736 100644 GIT binary patch delta 1708 zcmZ8i%}*Og6rY)$1%I(N*v4xcgN^xGu!(_?gaAS5SENc!TD7TKi$qWckTEP|*`!MP zrarj6wUw*AMLpP3d#%*wmOr3>KyO7ow5JxShyDlYn*~%SyP7xeVXz@p0?-%8>6O*%BY)c zr#pynp1ay!rk#aohuQ&*4=D}fxxHbCil~Tv&14j!>kTervR@9!xH|$d=x?%hCKED= zRvZR=Yfz^ASlqWvnMSMsJeHAJTr%G-xViQ)Bp@mHj@F^RH3+FQ%OqHOs0(L8`U2O$ zvX$ocaK+PMUgdECXQ+U2@xu^>lf@q!gO=JxCr-7zSNV3Q$s9L6Az zYfRugj`O7Gms2<_n1IPTZ!zarF(55_LNo^C6fQFkVRr%wO^R}~Np~2|#U>ST5$x!c zsDp7QVHif5OishJoPimUSR!)9or0MrJ+pJlw$4!{D9JLEMG{eEM3oWc+lVT|R7-O< zaE-x6ohenM@Z`Cih45ZL5E1;6r3voxlB{5J(_r9f&Im3{VRrO&F6ZRDT#%Qs$%Qb1 z`2>NvEP=}@f<+e5TY&}hRsR)OgexWy3@Ro;POiE=?GiMu;@Mn-0vctw)}c^L5R=Fy z7)8%)m*@J+m=uxAFJsWN0!y%r^m1p#y`=OeqXf0qVk;S>xq1eVM(#xGcu+Rb) zA`tOcE{L#+{HOzlVv2|%#nw)PA+?u9P7GtoUP^35cz4>e7*Rk>TRBg8B?B+)Dn#(o z^7bP1btvw0s--*Cvvpt8c#46l=l3Ll?-#k9fPudR;jvmi?4~^URPSf~-I_bS@ z*X_ek?GsWfQM9$1?OL>|3-|HS_FErV+UW~~IT$(@LDWuTD0Xq+^Y_|`{_eJIKi>T; z@#C#OpM0@qX->iWD?0A=$BMnDQ;4yyJX?!>M9rS9nzOaP?c~wtB$Nm%k@PA9b$Y}5 zZeSx@<%dpfx7vI7$)4)KSM1G$?Gw7?>G2OkT+|M3R+aQVj&FMZ#K*jM5|8eiszJ(i z&SEsgLRv)&&=8H_Fx0CVG74RKP6HHY7GeP{qh^|?29KO)8qBLD zUt_%NohIL-A@A0pMQ=WPFt|$1Vb#9RO-5+}6sIrn@qS5JwB-Gp8lhz`W@bk7D(r98 zLhVF9aum;cwRh{#b`Kvq&YRxb=A^!e!42<`X{{>FiaT>EkD;jQ{?R$}N)K#0yGNVO j@wQV^@iK}N?$!>r9rg2Z*1X@%$)1}^UG#$KJ2dehbZN4{ delta 3326 zcmcImOKcn06`eOTq=tWqrY&0kzcjWaQy*LMN22wyWz>7olBs)lK1^H>7JhFxmobN$}47 zoOkbi_uY4g?~i;j9laBY1QmSlFXX=Ys|!DiKGb8^AWGc|e#PGhD(~q(tStHNxAc*A zz>0m9k9>v#C~g;$9w^CO-Iam5-5$61c@5k?$GPkGcG#`<9jQ=~e=;Wy8CjJNVY&Bqiw2m280qZD?=sJqNSd&(u2 zQ^E9>8GvmPh@F|_-!!nBQ#I8c@m!8j2+njK=P?hXRl{(jZJq{V6wh%Qr4fD%B_E>z zSGEis& zS>BH+A^CYehWY9*{*nez^AcDnhb86ak+Yq0&b=r*PHf6v#TlN$A+-n{cu;;C_&J)8 zR@lZp+qh>N=M%2^Vm(c?D_pkl6ooep4*p%#3q$XG$-RJ_=Lyq)^E?L3B%iGLFtabZ zm)r$+5u<4#q|hat{>4s(7G;6mG_)6JA^BDPWlGcKq{3CYkd#wp$?;b&&=N-TGIfK$ zNXs=wy$L0$xGU5H%_S|Wfc>1fmZ3N?uXKH9NcMT0@h@T+P5&|h?dak?qbQ1MJb$X~51)q`C!g$v#+^clLL)SHFJv z3?EYy4F75lpMf+uO>(^;Cadc^nc~)AD}+3L_{1;QTkhCfcHyyISFl#%yk!j%fY?NS znXdb8Wo>&u|Gn?Z&ljb1{?nd!|NQ!=-%nfq+q;?dtT?;~{NWu*d>~Ja>)G96-)nnL z{^3IKk3ZP`Je~hm;^VbHJ^c_%-pUjoWCijMi>$LJ>{|tFr`XKD5ng7K|NOV|^Ov;c zyS*;5kDKZIAw6Olx1Eg53%OiV_nWk(FFo1LHiLXSEjLs#Lc@5&D@tWNG!&|<8}{KC zBy;tXw?f}wr7#zn$14TfDeQ@&<rZ4 zeB<8o+8fi?Zog^iJK2malE8`Mk|ZPvfz*Aw0t>8gW_MQnbR(i*)t zE&746v54k^%k7W#&*HR zmc9He{ejHMC+W1+!W#)a&)3ctiTJFK$n2Gs6GN}Xr5IKs)p7f zJu`TW1wEHYA{waVW6O(%CRaAsA=VIl4X`9~(4{B%4y$p*i|Q#ENsVjB4{;?;u*#2P zuSbxTw+|0n`FqS{*FPC;U0}&Uc^2|Ui4I8&NqRsk)Mm1o%8%N5FU~@=jP=6qesLpj zTfXf=ekvtSNTlo^uNy>4a`JkZKC1->FZ)frR#D@lzC~yYmC3ldAUX4xn3q@;#PZpD vJG=YhyyT6H$nR!EF)L=IT}G|z&c;qwtV#J=<-_=>|GH!sE5C@}WP|?z`Lk{} diff --git a/control_motor.py b/control_motor.py index 9205a08..3546d39 100644 --- a/control_motor.py +++ b/control_motor.py @@ -10,15 +10,21 @@ pwm = gpio.PWM(13, 100) pwm.start(13) verbose = True -print("Initializing Grbl...") +print("[ INFO ] Initializing Grbl...") ser.write(b'\r\n\r\n') time.sleep(2) ser.write(b'$RST=#\n') time.sleep(1) ser.flushInput() +print("[ INFO ] Grbl is ready.") def goToBin(bin): + print("[ INFO ] Delivering item to bin: " + str(bin)) adjustedBin = math.floor(bin / 2) + if adjustedBin > 11: + print("[ INFO ] All bins full! Using overflow bin.") + bin = 0; + adjustedBin = 0; distance = adjustedBin * 18 delay = 0.5 + 0.93 * adjustedBin command = 'G0 X-' @@ -26,37 +32,40 @@ def goToBin(bin): command += '\n' ser.write(b'$X\n') time.sleep(1) - print(command) + print("[ INFO ] Sending command to Grbl: " + command) ser.write(command.encode('utf-8')) # s.write("$C\n") while True: grbl_out = str(ser.readline().strip()) # Wait for grbl response with carriage return print(grbl_out.find('error')) if int(grbl_out.find('error')) >= 0 : - print("REC:",grbl_out) - print(" Grbl reported error!") + print("[ EXIT ] Grbl reported an error.") quit() elif int(grbl_out.find('ok')) >= 0 : - if verbose: print('REC:',grbl_out) + if verbose: print('[ INFO ] Grbl message: ',grbl_out) break + print("[ INFO ] Waiting for " + str(delay) + " seconds.") time.sleep(delay) if bin % 2 == 0: # tilt to left + print("[ INFO ] Titling motor to left side.") pwm.ChangeDutyCycle(5) time.sleep(1) pwm.ChangeDutyCycle(14) else: + print("[ INFO ] Titling motor to right side.") pwm.ChangeDutyCycle(25) time.sleep(1) pwm.ChangeDutyCycle(13) time.sleep(1) + print("[ INFO ] Sending command to Grbl: G0 X0") ser.write(b'G0 X0\n') while True: grbl_out = str(ser.readline().strip()) # Wait for grbl response with carriage return if int(grbl_out.find('error')) >= 0 : - print("REC:",grbl_out) - print(" Grbl reported error!") + print("[ EXIT ] Grbl reported an error.") quit() elif int(grbl_out.find('ok')) >= 0 : - if verbose: print('REC:',grbl_out) + if verbose: print('[ INFO ] Grbl message: ',grbl_out) break + print("[ INFO ] Waiting for " + str(delay) + " seconds.") time.sleep(delay) \ No newline at end of file diff --git a/control_pixel.py b/control_pixel.py index 54a58b4..409bff5 100644 --- a/control_pixel.py +++ b/control_pixel.py @@ -4,4 +4,4 @@ pixels = neopixel.NeoPixel(board.D18, 24) def ledOff(): pixels.fill((0,0,0)) def ledOn(): - pixels.fill((50,50,50)) \ No newline at end of file + pixels.fill((0,0,0)) \ No newline at end of file diff --git a/detect.py b/detect.py index eb91b7e..302dc58 100644 --- a/detect.py +++ b/detect.py @@ -98,7 +98,7 @@ def detect(calibration_width, img_file, show, quick): cv2.waitKey(0) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (7, 7), 0) - + gray = cv2.GaussianBlur(gray, (7, 7), 0) # perform edge detection, then perform a dilation + erosion to # close gaps in between object edges edged = cv2.Canny(gray, 50, 100) @@ -107,6 +107,8 @@ def detect(calibration_width, img_file, show, quick): edged = cv2.dilate(edged, None, iterations=1) edged = cv2.erode(edged, None, iterations=1) edged = cv2.dilate(edged, None, iterations=1) + #edged = cv2.erode(edged, None, iterations=1) + #edged = cv2.dilate(edged, None, iterations=1) if show and not quick: cv2.imshow("Item Sorter", edged) cv2.waitKey(0) @@ -122,6 +124,7 @@ def detect(calibration_width, img_file, show, quick): num = 0 # Calibration loop + """ for c in cnts: # if the contour is not sufficiently large, ignore it if cv2.contourArea(c) < 100: @@ -170,8 +173,8 @@ def detect(calibration_width, img_file, show, quick): # and near(mean_val[0], 63, 40) is True and near(mean_val[1], 108, 40) is True and near(mean_val[2], 104, 40) is True: pixelsPerMetric = smaller(dA, dB) / calibration_width continue - - #pixelsPerMetric = 25 + """ + pixelsPerMetric = 25 orig = image.copy() objtype = "Unknown" objname = "" @@ -181,42 +184,22 @@ def detect(calibration_width, img_file, show, quick): num += 1 # if the contour is not sufficiently large, ignore it #pixelsPerMetric = 75 - if cv2.contourArea(c) < 100 or pixelsPerMetric is None: + if cv2.contourArea(c) < 300 or pixelsPerMetric is None: continue # compute the rotated bounding box of the contour - box = cv2.minAreaRect(c) box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box) box = np.array(box, dtype="int") - - # order the points in the contour such that they appear - # in top-left, top-right, bottom-right, and bottom-left - # order, then draw the outline of the rotated bounding - # box - #box = perspective.order_points(box) - - # loop over the original points and draw them - # for (x, y) in box: - #cv2.circle(orig, (int(x), int(y)), 5, (0, 0, 255), -1) - # unpack the ordered bounding box, then compute the midpoint # between the top-left and top-right coordinates, followed by # the midpoint between bottom-left and bottom-right coordinates (tl, tr, br, bl) = box (tltrX, tltrY) = midpoint(tl, tr) (blbrX, blbrY) = midpoint(bl, br) - # compute the midpoint between the top-left and top-right points, # followed by the midpoint between the top-right and bottom-right (tlblX, tlblY) = midpoint(tl, bl) (trbrX, trbrY) = midpoint(tr, br) - # draw the midpoints on the image - #cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1) - #cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1) - #cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1) - #cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1) - - # draw lines between the midpoints # compute the Euclidean distance between the midpoints dA = np.linalg.norm(np.array((tltrX, tltrY, 0)) - np.array((blbrX, blbrY, 0))) @@ -255,7 +238,7 @@ def detect(calibration_width, img_file, show, quick): if circular and itemwr == 0.75: objtype = "Penny" iteml = 0 - else: + """else: if circular and near(radius * 2 / pixelsPerMetric, 0.4, 0.03): # Keps nut or spacer @@ -298,6 +281,7 @@ def detect(calibration_width, img_file, show, quick): if itemhr == 0.1875 and rectangular: objtype = "Axle" iteml = (radius * 2 / pixelsPerMetric + itemw) / 2 + """ rows, cols = orig.shape[:2] [vx, vy, xx, yy] = cv2.fitLine(c, cv2.DIST_L2, 0, 0.01, 0.01) lefty = int((-xx*vy/vx) + yy) @@ -337,7 +321,7 @@ def detect(calibration_width, img_file, show, quick): 0.6, (50, 50, 220), 2) output = "" objname = objtype; - + """ if objtype == "Screw" or objtype == "Standoff": output = str(iteml) + "in" objname += str(iteml) @@ -345,6 +329,7 @@ def detect(calibration_width, img_file, show, quick): output = "{:.2f}in".format(iteml) objname += str(itemwr) #print(objname) + """ list.append(objname) if circular: cv2.putText(orig, output, # print data @@ -385,8 +370,8 @@ def magicSort(contour): name += ", " + str(abs(int(humoments[i][0]))) #magicNumber2 += abs(humoments[i][0]) #magicNumber += humoments[i][0] - print(str(humoments)) + #print(str(humoments)) #print(magicNumber) #name = "Unknown: " + str(int(magicNumber1)) + ", " + str(int(magicNumber2)) - print(name) + #print(name) return name \ No newline at end of file diff --git a/pi_client.py b/pi_client.py index 9100649..c066103 100644 --- a/pi_client.py +++ b/pi_client.py @@ -15,13 +15,13 @@ while True: data = s.recv(1024) #control_pixel.ledOn() if not data: break - print("Found "+str(data)) + print("[ INFO ] Item name: "+ str(data)[2:len(str(data))-1]) selectedBin = sort.sort(str(data)[2:len(str(data))-1]) control_pixel.ledOff() control_motor.goToBin(selectedBin) control_pixel.ledOn() s.sendall(b'Continue') except socket.error: - print("Error Occured.") + print("[ EXIT ] Socket connection error.") break s.close() \ No newline at end of file diff --git a/run_detect.py b/run_detect.py index a7fac46..01dda75 100644 --- a/run_detect.py +++ b/run_detect.py @@ -30,11 +30,11 @@ def go(): #control_motor.goToBin(selectedBin) def sendString(string): - print("Found " + string) + print("[ INFO ] Item found: " + string) try: conn.sendall(string.encode('utf-8')) except socket.error: - print("Error Occured.") + print("[ EXIT ] Socket connection error.") if not video: @@ -49,22 +49,22 @@ else : s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #s.setsockopt(s, socket.SOL_SOCKET, socket.SO_REUSEADDR) s.bind((host, port)) - print("waiting for connection") + print("[ INFO ] TCP stream initialized. Waiting for client...") s.listen(1) conn, addr = s.accept() - print('Connected to', addr) + print('[ INFO ] Connected to ', addr) time.sleep(2) waitForPi = True while waitForPi is True: try: - print("waiting for data") + print("[ INFO ] Waiting for confirmation message.") data = conn.recv(1024) if not data: break encoding = 'utf-8' - print ("Client: "+str(data)) + print ("[ INFO ] Message recieved: "+str(data)) waitForPi = False except socket.error: - print("Error Occured.") + print("[ EXIT ] Socket connection error.") break # server command for imx135 camera ./video2stdout | gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=192.168.43.152 port=5001 # server command for udp: ./video2stdout | gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=10 pt=96 ! udpsink host=192.168.43.40 port=9000 @@ -75,7 +75,7 @@ else : ret = capture.grab() x+=1 if not ret: - print('empty frame') + print('[ EXIT ] Empty frame received.') break #print('frame') if x > 1: @@ -84,13 +84,13 @@ else : items,output = detect.detect(calibration_width, frame, True, True) cv2.imshow('Item Sorter', output) x = 0 - if "Penny" in items and len(items) > 1: - items.remove("Penny") + if len(items) > 0: + #items.remove("Penny") itema = items[0] valid = True for item in items: if item != itema: - print("Too many items!") + print("[ INFO ] More than one object present.") valid = False break if valid: @@ -113,10 +113,12 @@ else : waitForPi = False capture = cv2.VideoCapture('udpsrc port=9000 caps="application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264" ! rtph264depay ! avdec_h264 ! videoconvert ! appsink sync=false', cv2.CAP_GSTREAMER) except socket.error: - print("Error Occured.") + print("[ EXIT ] Socket connection error.") break if cv2.waitKey(1)&0xFF == ord('q'): + print("[ EXIT ] Shutting down.") + s.shutdown(1) s.close() break