50 Commits

Author SHA1 Message Date
fb31ab0d73 Add LED animations to runtime 2024-04-24 14:42:47 -05:00
302d275c64 Update config 2024-04-24 14:42:47 -05:00
43392fa3ca Freeze math3d version 2024-04-24 14:42:47 -05:00
660fe29236 Update camera image parser 2024-04-24 14:42:47 -05:00
275cbd027e Added open gripper to init routine 2024-04-24 14:42:07 -05:00
f4e43f33d2 Created functions for routines 2024-04-24 14:40:38 -05:00
ae97ed1a14 Made pickup and dropoff routines for tray and holder. Adjusted home position 2024-04-23 18:56:11 -05:00
237319db14 Fixed drop off routine to not hit walls 2024-04-22 21:56:07 -05:00
a698c4a753 Add more routines 2024-04-18 20:33:55 -05:00
939474378a Add open and close gripper functions 2024-04-12 22:05:34 -05:00
145f51d08c Update IPs for LED system 2024-04-12 20:28:34 -05:00
4973fc79be Merge branch 'main' of https://git.myitr.org/Jukebox/jukebox-software 2024-04-12 20:28:33 -05:00
ff2269193b small dimensions fixes 2024-04-12 20:28:31 -05:00
5edd7f4592 Remove extraneous pass 2024-03-27 20:41:07 -05:00
4dd6f7649a Implement cable_search 2024-03-27 20:40:20 -05:00
dc1e568a96 Add basic cable_map implementation 2024-03-27 20:33:21 -05:00
1ec6d92cfa Deploy docker containers 2024-03-27 19:50:01 -05:00
e21ded46f1 Update juekbox-web 2024-03-27 19:47:17 -05:00
672507f498 Add jukebox web 2024-03-27 19:46:45 -05:00
64bb50f055 Add setup-alpine-vm.sh 2024-03-28 00:44:57 +00:00
5016b4e99f Update compose.yml 2024-03-28 00:44:35 +00:00
efbda23c38 Fix docker runtime support 2024-03-27 18:53:50 -05:00
19ce328596 Correctly parse results from get_specs 2024-03-27 17:49:02 -05:00
ad216f21fa Implement cable_details call 2024-03-26 18:42:01 -05:00
6d6c2030a9 Merge branch 'main' of https://git.myitr.org/Jukebox/jukebox-software 2024-03-26 15:24:20 -05:00
9893222335 Pick-up routine 2024-03-26 15:24:18 -05:00
82a52dea5a Add cables to meilisearch db 2024-03-26 15:09:26 -05:00
77fdc43fce Add missing robot pass-ins 2024-03-24 15:35:46 -05:00
3de59f5985 Convert ur5_control to class based (untested) 2024-03-24 15:31:58 -05:00
6887fa943b Merge branch 'main' of https://git.myitr.org/Jukebox/jukebox-software 2024-03-24 13:50:17 -05:00
2ec7906ee4 Basic move restrictions and flip routine 2024-03-23 15:47:10 -05:00
069d2175d9 Convert led code to class based for multithreading 2024-03-23 15:33:51 -05:00
9b1b92e21d Re-add https:// format, needed for most devices 2024-03-21 19:48:46 -05:00
ee0f8f4250 Remove cairosvg VERSION patch 2024-03-21 19:41:46 -05:00
9c9435570b Remove cairosvg as it doesn't have pip-only lib. Use png instead. 2024-03-21 19:39:43 -05:00
1bf10f7349 Update label generator to include belden logo, use QR code, URL matching 2024-03-21 18:57:59 -05:00
3c8d6c7ad3 Remove debug print 2024-03-20 16:31:29 -05:00
cbe7225fc9 Fix bug with part name in query_search 2024-03-20 16:27:43 -05:00
44efc4006e Correct flip rz orientation 2024-03-19 17:48:32 -05:00
218303e92b Try different moves 2024-03-17 22:01:34 -05:00
e5d3f87b5c Go to home position first 2024-03-17 20:49:39 -05:00
2ab1d0dbb3 Add flip around mode to fit edge slots 2024-03-17 20:48:26 -05:00
1338c3f440 Added tool z rotation for angled gripper 2024-03-17 20:07:25 -05:00
83b077b4df Make limb lengths and offsets global 2024-03-17 19:59:17 -05:00
f16242f5be Re-merge calculate_theta into get_joints_from_xyz_rel 2024-03-17 19:53:49 -05:00
2f28a01b7c Add basic kinematics for gripper angle 2024-03-17 19:50:04 -05:00
fb85a56d47 Use movejs to go to all cable positions 2024-03-17 16:21:57 -05:00
bec0c63763 Fix ur5_control bugs, fully working IK!! Thanks Nadeem 2024-03-17 16:13:53 -05:00
4ae30b82a0 Cleaned up notebook 2024-03-17 15:43:06 -05:00
4bc3e30116 Fixed edge cases when calculating base angle 2024-03-17 01:01:39 -05:00
32 changed files with 2164 additions and 1131 deletions

2
.gitignore vendored
View File

@ -15,7 +15,7 @@ output.mp4
# log files # log files
output.log output.log
# images # images
*.png map*.png
# Built app # Built app
build build
# Generated label images # Generated label images

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "jukebox-web"]
path = jukebox-web
url = https://git.myitr.org/Jukebox/jukebox-web

View File

@ -3,11 +3,11 @@ FROM python:3.11-slim
# Get runtime dependencies # Get runtime dependencies
# glx for OpenCV, ghostscript for datasheet PDF rendering, zbar for barcode scanning, git for cloning repos # glx for OpenCV, ghostscript for datasheet PDF rendering, zbar for barcode scanning, git for cloning repos
RUN apt-get update && apt-get install -y libgl1-mesa-glx ghostscript libzbar0 git && apt-get clean && rm -rf /var/lib/apt/lists RUN apt-get update && apt-get install -y libgl1-mesa-glx ghostscript libzbar0 git && apt-get clean && rm -rf /var/lib/apt/lists
COPY *.py *.yml *.sh *.txt *.html static templates ./ COPY requirements.txt ./
#COPY config-server.yml config.yml #COPY config-server.yml config.yml
RUN pip3 install -r requirements.txt RUN pip3 install -r requirements.txt
COPY *.py *.yml *.sh *.txt *.html static templates ./
CMD ["python3", "run.py"] CMD ["sh", "-c", "python3 run.py"]
EXPOSE 5000 EXPOSE 5000
EXPOSE 8000 EXPOSE 8000
EXPOSE 9000 EXPOSE 9000

BIN
GothamCond-Medium.otf Normal file

Binary file not shown.

View File

@ -40,13 +40,16 @@ class DriveImg():
self.onLine = False self.onLine = False
fprint("Offline") fprint("Offline")
def close(self):
self.trans.close()
def read_img(self): def read_img(self):
resposta = 'Falha' resposta = 'Falha'
try: try:
if not self.onLine: if not self.onLine:
#print(f'tentando Conectar camera {self.ip}...') #print(f'tentando Conectar camera {self.ip}...')
gravaLog(ip=self.ip,msg=f'Trying to connect...') gravaLog(ip=self.ip,msg=f'Trying to connect...')
sleep(2) #sleep(2)
try: try:
self.trans = socket.socket(socket.AF_INET,socket.SOCK_STREAM) self.trans = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.trans.connect((self.ip,self.PORT)) self.trans.connect((self.ip,self.PORT))
@ -63,13 +66,13 @@ class DriveImg():
if valida.find("TC IMAGE")<0: if valida.find("TC IMAGE")<0:
self.onLine = False self.onLine = False
self.trans.close() self.trans.close()
sleep(2) #sleep(2)
gravaLog(ip=self.ip,tipo="Falha",msg=f'Unable to find TC IMAGE bookmark') gravaLog(ip=self.ip,tipo="Falha",msg=f'Unable to find TC IMAGE bookmark')
return "Error" return "Error"
except Exception as ex: except Exception as ex:
self.onLine = False self.onLine = False
self.trans.close() self.trans.close()
sleep(2) #sleep(2)
gravaLog(ip=self.ip,tipo="Falha",msg=f'Error - {str(ex)}') gravaLog(ip=self.ip,tipo="Falha",msg=f'Error - {str(ex)}')
return "Error" return "Error"
if ret: if ret:
@ -113,7 +116,7 @@ class DriveImg():
#print(f'erro {str(ex)}') #print(f'erro {str(ex)}')
self.onLine = False self.onLine = False
self.trans.close() self.trans.close()
sleep(2) #sleep(2)
return resposta return resposta
class DriveData(): class DriveData():
@ -139,7 +142,7 @@ class DriveData():
if not self.onLine: if not self.onLine:
#print(f'tentando Conectar...\n') #print(f'tentando Conectar...\n')
gravaLog(ip=self.ip,msg=f'tentando Conectar...',file="log_data.txt") gravaLog(ip=self.ip,msg=f'tentando Conectar...',file="log_data.txt")
sleep(2) #sleep(2)
try: try:
self.trans = socket.socket(socket.AF_INET,socket.SOCK_STREAM) self.trans = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.trans.connect((self.ip,self.PORT)) self.trans.connect((self.ip,self.PORT))
@ -154,7 +157,7 @@ class DriveData():
except Exception as ex: except Exception as ex:
self.onLine = False self.onLine = False
gravaLog(ip=self.ip,tipo="Falha Generica",msg=f'erro {str(ex)}',file="log_data.txt") gravaLog(ip=self.ip,tipo="Falha Generica",msg=f'erro {str(ex)}',file="log_data.txt")
sleep(2) #sleep(2)
return resposta return resposta

BIN
belden-logo-superhires.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

41
belden-logo.svg Normal file
View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 446.6 151.4" style="enable-background:new 0 0 446.6 151.4;" xml:space="preserve">
<style type="text/css">
.st0{fill:#004990;}
</style>
<g>
<g>
<path class="st0" d="M21.2,32.1h-1.4v87.2H55c20.3,0,32-9.1,32-24.9c0-12.3-5.6-19.7-15.8-22.1c5.1-3.6,7.8-9.1,7.8-16.9
c0-15.5-8.9-23.3-26.5-23.3H21.2z M44.7,51.6c7.4,0,11.4,1.1,11.4,6.8c0,4.8-3.1,6.8-10.5,6.8c0,0-0.6,0-1.1,0
c0-2.1,0-11.5,0-13.6C44.5,51.6,44.7,51.6,44.7,51.6z M45.4,84.4l1.8,0c4.6,0,10.3-0.1,13,2.6c1.2,1.2,1.8,2.9,1.8,5.2
c0,2-0.6,3.5-1.7,4.7c-3,3-9.2,2.9-13.8,2.9c0,0-1.4,0-2.1,0c0-2.1,0-13.3,0-15.4C44.9,84.4,45.4,84.4,45.4,84.4z"/>
<g>
<path class="st0" d="M139.8,32.1H90.4v87.2h50.8V98c0,0-23.7,0-26.1,0c0-2,0-9.8,0-11.8c2.4,0,24.8,0,24.8,0V64.8
c0,0-22.3,0-24.8,0c0-2,0-9.4,0-11.4c2.5,0,26.1,0,26.1,0V32.1H139.8z"/>
</g>
<g>
<path class="st0" d="M169.3,32.1H146v87.2h51V98c0,0-23.9,0-26.3,0c0-2.6,0-65.9,0-65.9H169.3z"/>
</g>
<g>
<path class="st0" d="M332.4,32.1H283v87.2h50.8V98c0,0-23.7,0-26.1,0c0-2,0-9.8,0-11.8c2.4,0,24.8,0,24.8,0V64.8
c0,0-22.3,0-24.8,0c0-2,0-9.4,0-11.4c2.5,0,26.1,0,26.1,0V32.1H332.4z"/>
</g>
<g>
<path class="st0" d="M424.6,32.1h-23.3c0,0,0,43,0,49.3c-4-5.1-38.4-49.3-38.4-49.3h-24v87.2h24.7c0,0,0-43.1,0-49.5
c4,5.1,38.4,49.5,38.4,49.5h24V32.1H424.6z"/>
</g>
<g>
<g>
<path class="st0" d="M233.8,32.1h-32.5v87.2h32.5c24.4,0,44.3-19.6,44.3-43.6C278.1,51.7,258.2,32.1,233.8,32.1z M226,53.5
c13.6,0.3,22,8.7,22,22.2c0,13.6-8.2,21.9-22,22.2V53.5z M231.5,101.3c12.5-3,20.7-10.7,20.8-25.7c-0.2-15-8.3-22.7-20.8-25.7
c14,2.1,25,9.5,25,25.6v0.1C256.5,91.8,245.5,99.2,231.5,101.3z M260.2,75.6c-0.2-18-10-29.8-24.9-33.3
c16.7,2.5,29.6,14,29.6,33.3c0,0,0,0,0,0.1h0c0,19.3-13,30.7-29.7,33.2C250.1,105.3,260,93.6,260.2,75.6z M240.3,115.7
c16.7-4.7,28.3-19.2,28.5-39.9v-0.3c-0.2-20.7-11.9-35.1-28.5-39.8c19,3.9,33.5,17.7,33.6,39.7v0.4
C273.9,97.9,259.4,111.8,240.3,115.7z"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

13
compose-search-only.yml Normal file
View File

@ -0,0 +1,13 @@
services:
meilisearch:
image: "getmeili/meilisearch:v1.6.2"
ports:
- "7700:7700"
environment:
MEILI_MASTER_KEY: fluffybunnyrabbit
MEILI_NO_ANALYTICS: true
volumes:
- "meili_data:/meili_data"
volumes:
meili_data:

View File

@ -9,5 +9,22 @@ services:
volumes: volumes:
- "meili_data:/meili_data" - "meili_data:/meili_data"
jukebox-software:
build: .
init: true
ports:
- "5000:5000"
- "8000:8000"
- "9000:9000"
environment:
- PYTHONUNBUFFERED=1
depends_on:
- meilisearch
jukebox-web:
build: jukebox-web
ports:
- "3000:3000"
volumes: volumes:
meili_data: meili_data:

View File

@ -3,9 +3,21 @@ core:
serverip: 172.26.178.114 serverip: 172.26.178.114
clientip: 172.26.176.1 clientip: 172.26.176.1
server: Hyper-Vd server: Hyper-Vd
loopspeed: 60 # fps
arm: arm:
ip: 192.168.1.145 ip: 192.168.1.145
tool:
offset_x: 0
offset_y: 0
offset_z: 0.14
limbs:
limb_base: 0.11
limb1: 0.425
limb2: 0.39225
limb3: 0.1
limb_wrist: 0.0997
#cable_map: #cable_map:
cameras: cameras:
@ -15,55 +27,55 @@ cameras:
led: led:
fps: 90 fps: 90
timeout: 0 timeout: 1
controllers: controllers:
- universe: 9 - universe: 0
ip: 192.168.68.131 ip: 192.168.1.200
ledstart: 0 ledstart: 0
ledend: 143 ledend: 143
mode: rgb mode: rgb
- universe: 3 - universe: 1
ip: 192.168.68.131 ip: 192.168.1.201
ledstart: 144 ledstart: 144
ledend: 287 ledend: 287
mode: rgb mode: rgb
- universe: 2 - universe: 2
ip: 192.168.68.131 ip: 192.168.1.202
ledstart: 288 ledstart: 288
ledend: 431 ledend: 431
mode: rgb mode: rgb
- universe: 4 - universe: 3
ip: 192.168.5.40 ip: 192.168.1.203
ledstart: 432 ledstart: 432
ledend: 575 ledend: 575
mode: rgb mode: rgb
- universe: 1 - universe: 4
ip: 192.168.5.4 ip: 192.168.1.204
ledstart: 576 ledstart: 576
ledend: 719 ledend: 719
mode: rgb mode: rgb
- universe: 5 - universe: 5
ip: 192.168.68.131 ip: 192.168.1.205
ledstart: 720 ledstart: 720
ledend: 863 ledend: 863
mode: rgb mode: rgb
- universe: 6 - universe: 6
ip: 192.168.68.131 ip: 192.168.1.206
ledstart: 864 ledstart: 864
ledend: 1007 ledend: 1007
mode: rgb mode: rgb
- universe: 7 - universe: 7
ip: 192.168.68.131 ip: 192.168.1.207
ledstart: 1008 ledstart: 1008
ledend: 1151 ledend: 1151
mode: rgb mode: rgb
- universe: 8 - universe: 8
ip: 192.168.68.131 ip: 192.168.1.208
ledstart: 1152 ledstart: 1152
ledend: 1295 ledend: 1295
mode: rgb mode: rgb
- universe: 0 - universe: 9
ip: 192.168.68.130 ip: 192.168.1.209
ledstart: 1296 ledstart: 1296
ledend: 1365 ledend: 1365
mode: rgbw mode: rgbw

View File

@ -70,6 +70,8 @@ def query_search(partnum, source):
if idx < 0: if idx < 0:
fprint("Could not find part in API: " + partnum) fprint("Could not find part in API: " + partnum)
return False return False
name = a["results"][idx]["title"]
#fprint("Search result found: result " + str(idx) + ", for ID " + name) #fprint("Search result found: result " + str(idx) + ", for ID " + name)
#urlname = a["results"][0]["raw"]["catalogitemurlname"] #urlname = a["results"][0]["raw"]["catalogitemurlname"]
img = a["results"][idx]["raw"]["catalogitemimageurl"] img = a["results"][idx]["raw"]["catalogitemimageurl"]
@ -157,8 +159,8 @@ def touch(path):
def get_multi(partnums, delay=0.25, dir="cables/", cache=True): def get_multi(partnums, delay=0.25, dir="cables/", cache=True, bar=None):
with alive_bar(len(partnums) * 2, dual_line=True, calibrate=30, bar="classic2", spinner="classic") as bar: #with alive_bar(len(partnums) * 2, dual_line=True, calibrate=30, bar="classic2", spinner="classic", disable=True, file=sys.stdout) as bar:
failed = list() failed = list()
actualpartnums = list() actualpartnums = list()
def _try_download_datasheet(partnum, output_dir, dstype): # Guess datasheet URL def _try_download_datasheet(partnum, output_dir, dstype): # Guess datasheet URL
@ -186,7 +188,7 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
# and set chunk_size parameter to None. # and set chunk_size parameter to None.
#if chunk: #if chunk:
bartext = bartext + "." bartext = bartext + "."
bar.text = bartext # bar.text = bartext
f.write(chunk) f.write(chunk)
#fprint("") #fprint("")
return output_dir + "/datasheet.pdf" return output_dir + "/datasheet.pdf"
@ -215,7 +217,7 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
# and set chunk_size parameter to None. # and set chunk_size parameter to None.
#if chunk: #if chunk:
bartext = bartext + "." bartext = bartext + "."
bar.text = bartext # bar.text = bartext
f.write(chunk) f.write(chunk)
#fprint("") #fprint("")
return output_dir + "/datasheet.pdf" return output_dir + "/datasheet.pdf"
@ -242,7 +244,7 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
# and set chunk_size parameter to None. # and set chunk_size parameter to None.
#if chunk: #if chunk:
bartext = bartext + "." bartext = bartext + "."
bar.text = bartext # bar.text = bartext
f.write(chunk) f.write(chunk)
#fprint("") #fprint("")
return output_dir + "/part-hires." + url.split(".")[-1] return output_dir + "/part-hires." + url.split(".")[-1]
@ -253,32 +255,33 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
def __use_cached_datasheet(partnum, path, output_dir, dstype): def __use_cached_datasheet(partnum, path, output_dir, dstype):
fprint("Using cached datasheet for " + partnum) fprint("Using cached datasheet for " + partnum)
bar.text = "Using cached datasheet for " + partnum # bar.text = "Using cached datasheet for " + partnum
bar(skipped=True) # bar(skipped=True)
if not os.path.exists(output_dir + "/parsed"): if not os.path.exists(output_dir + "/parsed"):
fprint("Parsing Datasheet contents of " + partnum) fprint("Parsing Datasheet contents of " + partnum)
bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..." # bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..."
out = read_datasheet.parse(path, output_dir, partnum, dstype) out = read_datasheet.parse(path, output_dir, partnum, dstype)
bar(skipped=False) # bar(skipped=False)
return out return out
else: else:
fprint("Datasheet already parsed for " + partnum) fprint("Datasheet already parsed for " + partnum)
bar.text = "Datasheet already parsed for " + partnum + ".pdf" # bar.text = "Datasheet already parsed for " + partnum + ".pdf"
bar(skipped=True) # bar(skipped=True)
def __downloaded_datasheet(partnum, path, output_dir, dstype): def __downloaded_datasheet(partnum, path, output_dir, dstype):
fprint("Downloaded " + path) fprint("Downloaded " + path)
bar.text = "Downloaded " + path # bar.text = "Downloaded " + path
bar(skipped=False) # bar(skipped=False)
fprint("Parsing Datasheet contents of " + partnum) fprint("Parsing Datasheet contents of " + partnum)
bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..." # bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..."
out = read_datasheet.parse(path, output_dir, partnum, dstype) out = read_datasheet.parse(path, output_dir, partnum, dstype)
bar(skipped=False) # bar(skipped=False)
return out return out
def run_search(partnum): def run_search(partnum):
partnum = partnum.replace("%20", " ") # undo URL encoding
oldpartnum = partnum oldpartnum = partnum
if dstype == "Alphawire": if dstype == "Alphawire":
# For alphawire, sanitize the part number for only the final result check, because their API is very wierd # For alphawire, sanitize the part number for only the final result check, because their API is very wierd
@ -287,7 +290,7 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
output_dir = dir + partnum output_dir = dir + partnum
path = output_dir + "/datasheet.pdf" path = output_dir + "/datasheet.pdf"
bartext = "Downloading files for part " + partnum bartext = "Downloading files for part " + partnum
bar.text = bartext # bar.text = bartext
partnum = oldpartnum.replace("_","/") partnum = oldpartnum.replace("_","/")
returnval = [partnum, dstype, False, False] returnval = [partnum, dstype, False, False]
if (not os.path.exists(output_dir + "/found_part_hires")) or not (os.path.exists(path) and os.path.getsize(path) > 1) or not cache: if (not os.path.exists(output_dir + "/found_part_hires")) or not (os.path.exists(path) and os.path.getsize(path) > 1) or not cache:
@ -302,7 +305,7 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
output_dir = dir + partnum output_dir = dir + partnum
path = output_dir + "/datasheet.pdf" path = output_dir + "/datasheet.pdf"
bartext = "Downloading files for part " + partnum bartext = "Downloading files for part " + partnum
bar.text = bartext # bar.text = bartext
if not os.path.exists(output_dir + "/found_part_hires") or not cache: if not os.path.exists(output_dir + "/found_part_hires") or not cache:
if _download_image(search_result["image"], output_dir): if _download_image(search_result["image"], output_dir):
@ -341,9 +344,13 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
fprint("Using cached hi-res part image for " + partnum) fprint("Using cached hi-res part image for " + partnum)
out = __use_cached_datasheet(partnum, path, output_dir, dstype) out = __use_cached_datasheet(partnum, path, output_dir, dstype)
returnval = [partnum, dstype, False, out] returnval = [partnum, dstype, False, out]
actualpartnums.append(returnval)
return True return True
for fullpartnum in partnums: for fullpartnum in partnums:
if fullpartnum is False:
actualpartnums.append(False)
continue
if fullpartnum[0:2] == "BL": # catalog.belden.com entry if fullpartnum[0:2] == "BL": # catalog.belden.com entry
partnum = fullpartnum[2:] partnum = fullpartnum[2:]
dstype = "Belden" dstype = "Belden"
@ -370,10 +377,10 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
time.sleep(delay) time.sleep(delay)
if not success: if not success:
fprint("Failed to download datasheet for part " + partnum) fprint("Failed to download datasheet for part " + partnum)
bar.text = "Failed to download datasheet for part " + partnum # bar.text = "Failed to download datasheet for part " + partnum
failed.append((partnum, dstype)) failed.append((partnum, dstype))
bar(skipped=True) # bar(skipped=True)
bar(skipped=True) # bar(skipped=True)
time.sleep(delay) time.sleep(delay)
if len(failed) > 0: if len(failed) > 0:
@ -405,6 +412,7 @@ if __name__ == "__main__":
# ] # ]
partnums = [ partnums = [
# Actual cables in Jukebox # Actual cables in Jukebox
"BL3092A",
"AW86104CY", "AW86104CY",
"AW3050", "AW3050",
"AW6714", "AW6714",
@ -434,10 +442,11 @@ if __name__ == "__main__":
"BL6300FE 009Q", "BL6300FE 009Q",
"BLRA500P 006Q", "BLRA500P 006Q",
]
# Some ones I picked, including some invalid ones # Some ones I picked, including some invalid ones
a = [
"BL10GXS12", "BL10GXS12",
"BLRST 5L-RKT 5L-949", "BLRST%205L-RKT%205L-949",
"BL10GXS13", "BL10GXS13",
"BL10GXW12", "BL10GXW12",
"BL10GXW13", "BL10GXW13",
@ -448,13 +457,18 @@ if __name__ == "__main__":
"BLFISD012R9", "BLFISD012R9",
"BLFDSD012A9", "BLFDSD012A9",
"BLFSSL024NG", "BLFSSL024NG",
"BLFISX006W0", "BLFISX006W0", # datasheet only
"BLFISX00103", "BLFISX00103", # invalid
"BLC6D1100007" "BLC6D1100007" # invalid
] ]
print(query_search("74002", "Belden")) #print(query_search("TT-SLG-024-HTNN", "Belden"))
#get_multi(partnums, 0.25) from label_generator import gen_label
gen_label("BLTF-SD9-006-RI5")
gen_label("BLRA500P")
gen_label("AWFIT-221-1_4")
gen_label("BLRST 5L-RKT 5L-949")
get_multi(partnums, 0.25)
#query_search("10GXS13", "Belden") #query_search("10GXS13", "Belden")

View File

@ -1 +0,0 @@
<html> <head> <title>RGB Controller Configuration</title> <style> body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; } </style> </head> <body> <h1>RGB Controller Configuration</h1><br> <h2>Set IP address</h2> Needs reboot to apply<br> Set to 0.0.0.0 for DHCP <form method="post" enctype="application/x-www-form-urlencoded" action="/postform/"> <input type="text" name="ipa" value="0" size="3">. <input type="text" name="ipb" value="0" size="3">. <input type="text" name="ipc" value="0" size="3">. <input type="text" name="ipd" value="0" size="3"> <input type="submit" value="Set"> </form><br> <h2>Set Hostname</h2> Needs reboot to apply<br> Max 64 characters <form method="post" enctype="application/x-www-form-urlencoded" action="/postform/"> <input type="text" name="hostname" value="RGBController" size="20"> <input type="submit" value="Set"> </form><br> <h2>DMX512 Start Universe</h2> Applies immediately<br> Between (inclusive) 1-65000 <form method="post" enctype="application/x-www-form-urlencoded" action="/postform/"> <input type="text" name="universe" value="1" size="5"> <input type="submit" value="Set"> </form><br> <form method="post" enctype="application/x-www-form-urlencoded" action="/postform/"> <input type="submit" name="reboot" value="Reboot"> </form><br> </body></html>

File diff suppressed because one or more lines are too long

1
jukebox-web Submodule

Submodule jukebox-web added at f3d8ec0cc4

View File

@ -61,9 +61,15 @@ def input_cable():
imgstr = "BL" imgstr = "BL"
elif output[1] == "Alphawire": elif output[1] == "Alphawire":
imgstr = "AW" imgstr = "AW"
img = generate_code(imgstr + output[0]) gen_label(imgstr + output[0])
os.makedirs("labels", exist_ok=True) #img = generate_code(imgstr + output[0])
img.save("labels/" + imgstr + output[0] + ".png") #os.makedirs("labels", exist_ok=True)
#img.save("labels/" + imgstr + output[0] + ".png")
def gen_label(partnum, path="labels"):
img = generate_code(partnum)
os.makedirs(path, exist_ok=True)
img.save(path + "/" + partnum + ".png")
def delete_folder(path): def delete_folder(path):
# Check if the path is a directory # Check if the path is a directory

View File

@ -3,8 +3,13 @@ from util import fprint
from PIL import Image from PIL import Image
from PIL import ImageDraw from PIL import ImageDraw
from PIL import ImageFont
#import cv2 #import cv2
import numpy as np import numpy as np
from util import find_data_file
import segno
import io
#import cairosvg
#import math #import math
@ -134,7 +139,8 @@ for charset in (CODE128A, CODE128B):
def generate_code(data, show=False, check=False): def generate_code(data, show=False, check=False):
img = code128_image(data) #img = code128_image(data)
img = qr_image(data)
if show: if show:
img.show() img.show()
#img.show() #img.show()
@ -198,6 +204,7 @@ def code128_format(data):
return codes return codes
def code128_image(data, height=100, thickness=3, quiet_zone=False): def code128_image(data, height=100, thickness=3, quiet_zone=False):
partnum = data
if not data[-1] == CODE128B['Stop']: if not data[-1] == CODE128B['Stop']:
data = code128_format(data) data = code128_format(data)
@ -227,12 +234,86 @@ def code128_image(data, height=100, thickness=3, quiet_zone=False):
#draw.arc(((width - width/5, width - width/5), (width*9 + width/5, width*9 + width/5)),0,360,fill='blue', width = int(width/8)) #draw.arc(((width - width/5, width - width/5), (width*9 + width/5, width*9 + width/5)),0,360,fill='blue', width = int(width/8))
draw.arc(((width+int(width / 1.4), width+int(width / 1.4)), (width*9-int(width / 1.4), width*9-int(width / 1.4))),0,360,fill='blue', width = int(width/8)) draw.arc(((width+int(width / 1.4), width+int(width / 1.4)), (width*9-int(width / 1.4), width*9-int(width / 1.4))),0,360,fill='blue', width = int(width/8))
font_path = find_data_file("OCRAEXT.TTF")
font_size = width/2
font = ImageFont.truetype(font_path, font_size)
text_width = font.getlength(partnum)
while text_width > width*4:
font_size -= 1
font = ImageFont.truetype(font_path, font_size)
text_width = font.getlength(partnum)
txtx = (int(width * 10) - text_width) / 2
txty = (int(width * 10)) / 2 + width / 2
draw.text((txtx,txty),partnum, "black", font)
return img
def qr_image(data, width=600):
partnum = data
# Monochrome Image
img = Image.new('RGB', (int(width * 10), int(width * 10)), 'white')
draw = ImageDraw.Draw(img)
#svg_path = find_data_file("belden-logo.svg")
#with open(svg_path, 'rb') as svg_file:
# png_image = cairosvg.svg2png(file_obj=svg_file,dpi=width*30, scale=30, background_color="white")
#with open("output.png", 'wb') as file:
# file.write(png_image)
png_image_io = "belden-logo-superhires.png"
png_image_pillow = Image.open(png_image_io)
png_width, png_height = png_image_pillow.size
png_image_pillow = png_image_pillow.resize((int(width*5.2), int(width*5.2/png_width*png_height)))
png_width, png_height = png_image_pillow.size
# paste belden logo first because it has a big border that would cover stuff up
img.paste(png_image_pillow, (int(width*5-png_width/2), int(width*4.25 - png_height/2)))
# draw circle border
#draw.arc(((width - width/5, width - width/5), (width*9 + width/5, width*9 + width/5)),0,360,fill='blue', width = int(width/8))
draw.arc(((width+int(width / 1.4), width+int(width / 1.4)), (width*9-int(width / 1.4), width*9-int(width / 1.4))),0,360,fill=(0, 73,144), width = int(width/8))
font_path = find_data_file("GothamCond-Medium.otf")
font_size = width/2
font = ImageFont.truetype(font_path, font_size)
text_width = font.getlength(partnum[2:])
# shrink font dynamically if it's too long of a name
while text_width > width*4:
font_size -= 1
font = ImageFont.truetype(font_path, font_size)
text_width = font.getlength(partnum[2:])
txtx = (int(width * 10) - text_width) / 2
txty = (int(width * 10)) / 2
# draw part number text
draw.text((txtx,txty),partnum[2:], "black", font)
# Draw QR code
partnum = partnum.replace(" ", "%20")
qrcode = segno.make('HTTPS://BLDN.APP/' + partnum,micro=False,boost_error=False,error="L",mask=3)
out = io.BytesIO()
qrx, _ = qrcode.symbol_size(1,0)
qrcode.save(out, scale=width*2/qrx, kind="PNG", border=0)
qrimg = Image.open(out)
img.paste(qrimg, box=(int(width*4),int(width*5.75)))
return img return img
if __name__ == "__main__": if __name__ == "__main__":
#print(generate_code("BL10GXS13")) #print(generate_code("BL10GXS13"))
#print(generate_code("BL10GXgd35j35S13")) #print(generate_code("BL10GXgd35j35S13"))
#print(generate_code("BL10GX54hS13")) #print(generate_code("BL10GX54hS13"))
print(generate_code("BL10Gj34qXS13", False, False)) #print(generate_code("BL10Gj34qXS13", False, False))
#print(generate_code("BL104w5545dp7bfwp43643534/4563G-XS13")) #print(generate_code("BL104w5545dp7bfwp43643534/4563G-XS13"))
#adjust_image(cv2.imread('test_skew.jpg')) #adjust_image(cv2.imread('test_skew.jpg'))
path = "labels"
img = generate_code("BL10GXS13")
import os
os.makedirs(path, exist_ok=True)
img.save(path + "/" + "BL10GXS13" + ".png")

View File

@ -14,24 +14,32 @@ import cv2
import numpy as np import numpy as np
from uptime import uptime from uptime import uptime
sender = None
debug = True
config = None
leds = None
leds_size = None
leds_normalized = None
controllers = None
data = None
exactdata = None
rings = None
ringstatus = None
mode = "Startup"
firstrun = True
changecount = 0
animation_time = 0
start = uptime()
def ping(host):
class LEDSystem():
sender = None
debug = True
config = None
leds = None
leds_size = None
leds_normalized = None
controllers = None
data = None
exactdata = None
rings = None
ringstatus = None
mode = "Startup"
firstrun = True
changecount = 0
animation_time = 0
start = uptime()
def __init__(self):
self.start = uptime()
#self.init()
#return self
def ping(self, host):
#Returns True if host (str) responds to a ping request. #Returns True if host (str) responds to a ping request.
# Option for the number of packets as a function of # Option for the number of packets as a function of
@ -49,32 +57,24 @@ def ping(host):
return subprocess.call(command, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) == 0 return subprocess.call(command, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) == 0
def map(): def map(self):
global config
global leds
global leds_size
global leds_normalized
global controllers
global rings
global ringstatus
global animation_time
with open('config.yml', 'r') as fileread: with open('config.yml', 'r') as fileread:
#global config #global config
config = yaml.safe_load(fileread) self.config = yaml.safe_load(fileread)
animation_time = config["animation_time"] self.animation_time = self.config["animation_time"]
leds = list() self.leds = list()
leds_size = list() self.leds_size = list()
controllers = list() self.controllers = list()
rings = list(range(len(config["position_map"]))) self.rings = list(range(len(self.config["position_map"])))
ringstatus = list(range(len(config["position_map"]))) print("Setting ring status")
self.ringstatus = list(range(len(self.config["position_map"])))
#print(rings) #print(rings)
#fprint(config["led"]["map"]) #fprint(config["led"]["map"])
generate_map = False generate_map = False
map = list() map = list()
for shape in config["led"]["map"]: for shape in self.config["led"]["map"]:
if shape["type"] == "circle": if shape["type"] == "circle":
if generate_map: if generate_map:
@ -84,22 +84,22 @@ def map():
angle = 0 angle = 0
radius = shape["diameter"] / 2 radius = shape["diameter"] / 2
lednum = shape["start"] lednum = shape["start"]
for item in config['position_map']: for item in self.config['position_map']:
# Check if the current item's position matches the target position # Check if the current item's position matches the target position
#print(item['pos'],(shape["pos"][1],shape["pos"][0])) #print(item['pos'],(shape["pos"][1],shape["pos"][0]))
if tuple(item['pos']) == (shape["pos"][1],shape["pos"][0]): if tuple(item['pos']) == (shape["pos"][1],shape["pos"][0]):
rings[item["index"]] = (shape["pos"][1],shape["pos"][0],lednum,lednum+shape["size"]) # rings[index] = x, y, startpos, endpos self.rings[item["index"]] = (shape["pos"][1],shape["pos"][0],lednum,lednum+shape["size"]) # rings[index] = x, y, startpos, endpos
ringstatus[item["index"]] = [None, None] self.ringstatus[item["index"]] = [None, None]
break break
if len(leds) < lednum + shape["size"]: if len(self.leds) < lednum + shape["size"]:
for x in range(lednum + shape["size"] - len(leds)): for x in range(lednum + shape["size"] - len(self.leds)):
leds.append(None) self.leds.append(None)
leds_size.append(None) self.leds_size.append(None)
while angle < 359.999: while angle < 359.999:
tmpangle = angle + shape["angle"] tmpangle = angle + shape["angle"]
x = math.cos(tmpangle * (math.pi / 180.0)) * radius + shape["pos"][1] # flip by 90 degress when we changed layout x = math.cos(tmpangle * (math.pi / 180.0)) * radius + shape["pos"][1] # flip by 90 degress when we changed layout
y = math.sin(tmpangle * (math.pi / 180.0)) * radius + shape["pos"][0] y = math.sin(tmpangle * (math.pi / 180.0)) * radius + shape["pos"][0]
leds[lednum] = (x,y) self.leds[lednum] = (x,y)
lednum = lednum + 1 lednum = lednum + 1
angle = angle + anglediv angle = angle + anglediv
@ -112,13 +112,13 @@ def map():
xmov = math.cos(angle * (math.pi / 180.0)) * distdiv xmov = math.cos(angle * (math.pi / 180.0)) * distdiv
ymov = math.sin(angle * (math.pi / 180.0)) * distdiv ymov = math.sin(angle * (math.pi / 180.0)) * distdiv
pos = shape["pos"] pos = shape["pos"]
if len(leds) < lednum + shape["size"]: if len(self.leds) < lednum + shape["size"]:
for x in range(lednum + shape["size"] - len(leds)): for x in range(lednum + shape["size"] - len(self.leds)):
leds.append(None) self.leds.append(None)
leds_size.append(None) self.leds_size.append(None)
while dist < length: while dist < length:
leds[lednum] = (pos[0], pos[1]) self.leds[lednum] = (pos[0], pos[1])
pos[0] += xmov pos[0] += xmov
pos[1] += ymov pos[1] += ymov
dist += distdiv dist += distdiv
@ -140,276 +140,266 @@ def map():
yaml_str = yaml.dump(data, default_flow_style=False) yaml_str = yaml.dump(data, default_flow_style=False)
print(yaml_str) print(yaml_str)
print(rings) print(self.rings)
flag = 0 flag = 0
for x in leds: for x in self.leds:
if x is None: if x is None:
flag = flag + 1 flag = flag + 1
if flag > 0: if flag > 0:
fprint("Warning: Imperfect LED map ordering. Hiding undefined lights.") fprint("Warning: Imperfect LED map ordering. Hiding undefined lights.")
for x in range(len(leds)): for x in range(len(self.leds)):
if leds[x] is None: if self.leds[x] is None:
leds[x] = (0, 0) self.leds[x] = (0, 0)
#leds = tmpleds.reverse() #leds = tmpleds.reverse()
#fprint(leds) #fprint(leds)
# controller mapping # controller mapping
for ctrl in config["led"]["controllers"]: for ctrl in self.config["led"]["controllers"]:
if len(controllers) < ctrl["universe"]+1: if len(self.controllers) < ctrl["universe"]+1:
for x in range(ctrl["universe"]+1 - len(controllers)): for x in range(ctrl["universe"]+1 - len(self.controllers)):
controllers.append(None) self.controllers.append(None)
controllers[ctrl["universe"]] = (ctrl["ledstart"],ctrl["ledend"]+1,ctrl["ip"]) self.controllers[ctrl["universe"]] = (ctrl["ledstart"],ctrl["ledend"]+1,ctrl["ip"])
for x in range(ctrl["ledstart"],ctrl["ledend"]+1): for x in range(ctrl["ledstart"],ctrl["ledend"]+1):
leds_size[x] = len(ctrl["mode"]) self.leds_size[x] = len(ctrl["mode"])
#fprint(controllers) #fprint(controllers)
if(debug): if(self.debug):
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
plt.axis('equal') plt.axis('equal')
for ctrl in controllers: for ctrl in self.controllers:
plt.scatter(*zip(*leds[ctrl[0]:ctrl[1]]), s=2) plt.scatter(*zip(*self.leds[ctrl[0]:ctrl[1]]), s=2)
#plt.scatter(*zip(*leds), s=3) #plt.scatter(*zip(*leds), s=3)
plt.savefig("map.png", dpi=600, bbox_inches="tight") plt.savefig("map.png", dpi=600, bbox_inches="tight")
leds_adj = [(x-min([led[0] for led in leds]), # push to zero start leds_adj = [(x-min([led[0] for led in self.leds]), # push to zero start
y-min([led[1] for led in leds]) ) y-min([led[1] for led in self.leds]) )
for x, y in leds] for x, y in self.leds]
leds_normalized = [(x / max([led[0] for led in leds_adj]), self.leds_normalized = [(x / max([led[0] for led in leds_adj]),
y / max([led[1] for led in leds_adj])) y / max([led[1] for led in leds_adj]))
for x, y in leds_adj] for x, y in leds_adj]
#return leds, controllers #return leds, controllers
def init(): def init(self):
map() self.map()
global sender self.sender = sacn.sACNsender(fps=self.config["led"]["fps"], universeDiscovery=False)
global config self.sender.start() # start the sending thread
global leds for x in range(len(self.controllers)):
global leds_size print("Waiting for the controller at", self.controllers[x][2], "to be online...", end="", flush=True)
global controllers
global data
global exactdata
sender = sacn.sACNsender(fps=config["led"]["fps"], universeDiscovery=False)
sender.start() # start the sending thread
"""for x in range(len(controllers)):
print("Waiting for the controller at", controllers[x][2], "to be online...", end="")
count = 0 count = 0
while not ping(controllers[x][2]): while not self.ping(self.controllers[x][2]):
count = count + 1 count = count + 1
if count >= config["led"]["timeout"]: if count >= self.config["led"]["timeout"]:
fprint(" ERROR: controller still offline after " + str(count) + " seconds, continuing...") print(" ERROR: controller still offline after " + str(count) + " seconds, continuing...")
break break
if count < config["led"]["timeout"]: else:
fprint(" done")""" print(" done")
for x in range(len(controllers)): #if count < self.config["led"]["timeout"]:
print("Activating controller", x, "at", controllers[x][2], "with", controllers[x][1]-controllers[x][0], "LEDs.")
sender.activate_output(x+1) # start sending out data time.sleep(1)
sender[x+1].destination = controllers[x][2] for x in range(len(self.controllers)):
sender.manual_flush = True print("Activating controller", x, "at", self.controllers[x][2], "with", self.controllers[x][1]-self.controllers[x][0], "LEDs.")
self.sender.activate_output(x+1) # start sending out data
self.sender[x+1].destination = self.controllers[x][2]
self.sender.manual_flush = True
# initialize global pixel data list # initialize global pixel data list
data = list() self.data = list()
exactdata = list() self.exactdata = list()
for x in range(len(leds)): for x in range(len(self.leds)):
if leds_size[x] == 3: if self.leds_size[x] == 3:
exactdata.append(None) self.exactdata.append(None)
data.append((20,20,127)) self.data.append((20,20,127))
elif leds_size[x] == 4: elif self.leds_size[x] == 4:
exactdata.append(None) self.exactdata.append(None)
data.append((50,50,255,0)) self.data.append((50,50,255,0))
else: else:
exactdata.append(None) self.exactdata.append(None)
data.append((0,0,0)) self.data.append((0,0,0))
sendall(data) self.sendall(self.data)
#time.sleep(50000) #time.sleep(50000)
fprint("Running start-up test sequence...") # fprint("Running start-up test sequence...")
for y in range(1): # for y in range(1):
for x in range(len(leds)): # for x in range(len(self.leds)):
setpixel(0,60,144,x) # self.setpixel(0,60,144,x)
sendall(data) # self.sendall(self.data)
#time.sleep(2) # #time.sleep(2)
alloffsmooth() # self.alloffsmooth()
self.startup_animation(show=False)
def sendall(datain): def sendall(self, datain):
# send all LED data to all controllers # send all LED data to all controllers
# data must have all LED data in it as [(R,G,B,)] tuples in an array, 1 tuple per pixel # data must have all LED data in it as [(R,G,B,)] tuples in an array, 1 tuple per pixel
global controllers self.sender.manual_flush = True
global sender for x in range(len(self.controllers)):
sender.manual_flush = True self.sender[x+1].dmx_data = list(sum(datain[self.controllers[x][0]:self.controllers[x][1]] , ())) # flatten the subsection of the data array
for x in range(len(controllers)):
sender[x+1].dmx_data = list(sum(datain[controllers[x][0]:controllers[x][1]] , ())) # flatten the subsection of the data array
sender.flush() self.sender.flush()
time.sleep(0.002) time.sleep(0.002)
#sender.flush() # 100% reliable with 2 flushes, often fails with 1 #sender.flush() # 100% reliable with 2 flushes, often fails with 1
#time.sleep(0.002) #time.sleep(0.002)
#sender.flush() #sender.flush()
def fastsendall(datain): def fastsendall(self, datain):
# send all LED data to all controllers # send all LED data to all controllers
# data must have all LED data in it as [(R,G,B,)] tuples in an array, 1 tuple per pixel # data must have all LED data in it as [(R,G,B,)] tuples in an array, 1 tuple per pixel
global controllers self.sender.manual_flush = False
global sender print(datain[self.controllers[0][0]:self.controllers[0][1]])
sender.manual_flush = False for x in range(len(self.controllers)):
print(datain[controllers[0][0]:controllers[0][1]]) self.sender[x+1].dmx_data = list(sum(datain[self.controllers[x][0]:self.controllers[x][1]] , ())) # flatten the subsection of the data array
for x in range(len(controllers)):
sender[x+1].dmx_data = list(sum(datain[controllers[x][0]:controllers[x][1]] , ())) # flatten the subsection of the data array
sender.flush() self.sender.flush()
def senduniverse(datain, lednum): def senduniverse(self, datain, lednum):
# send all LED data for 1 controller/universe # send all LED data for 1 controller/universe
# data must have all LED data in it as [(R,G,B,)] tuples in an array, 1 tuple per pixel # data must have all LED data in it as [(R,G,B,)] tuples in an array, 1 tuple per pixel
global controllers for x in range(len(self.controllers)):
global sender if lednum >= self.controllers[x][0] and lednum < self.controllers[x][1]:
for x in range(len(controllers)): self.sender[x+1].dmx_data = list(sum(datain[self.controllers[x][0]:self.controllers[x][1]] , ())) # flatten the subsection of the data array
if lednum >= controllers[x][0] and lednum < controllers[x][1]:
sender[x+1].dmx_data = list(sum(datain[controllers[x][0]:controllers[x][1]] , ())) # flatten the subsection of the data array
sender.flush() self.sender.flush()
time.sleep(0.004) time.sleep(0.004)
#sender.flush() # 100% reliable with 2 flushes, often fails with 1 #sender.flush() # 100% reliable with 2 flushes, often fails with 1
#time.sleep(0.002) #time.sleep(0.002)
#sender.flush() #sender.flush()
def alloff(): def alloff(self):
tmpdata = list() tmpdata = list()
for x in range(len(leds)): for x in range(len(self.leds)):
if leds_size[x] == 3: if self.leds_size[x] == 3:
tmpdata.append((0,0,0)) tmpdata.append((0,0,0))
elif leds_size[x] == 4: elif self.leds_size[x] == 4:
tmpdata.append((0,0,0,0)) tmpdata.append((0,0,0,0))
else: else:
tmpdata.append((0,0,0)) tmpdata.append((0,0,0))
sendall(tmpdata) self.sendall(tmpdata)
#sendall(tmpdata) #sendall(tmpdata)
#sendall(tmpdata) #definitely make sure it's off #sendall(tmpdata) #definitely make sure it's off
return self
def allon(): def allon(self):
global data self.sendall(self.data)
sendall(data) return self
def alloffsmooth(): def alloffsmooth(self):
tmpdata = data tmpdata = self.data
for x in range(256): for x in range(256):
for x in range(len(data)): for x in range(len(self.data)):
setpixel(tmpdata[x][0]-1,tmpdata[x][1]-1,tmpdata[x][2]-1, x) self.setpixel(tmpdata[x][0]-1,tmpdata[x][1]-1,tmpdata[x][2]-1, x)
sendall(tmpdata) self.sendall(tmpdata)
alloff() self.alloff()
return self
def setpixelnow(r, g, b, num): def setpixelnow(self, r, g, b, num):
# slight optimization: send only changed universe # slight optimization: send only changed universe
# unfortunately no way to manual flush data packets to only 1 controller with this sACN library # unfortunately no way to manual flush data packets to only 1 controller with this sACN library
global data self.setpixel(r,g,b,num)
setpixel(r,g,b,num) self.senduniverse(self.data, num)
senduniverse(data, num) return self
def setmode(stmode, r=0,g=0,b=0): def setmode(self, stmode, r=0,g=0,b=0):
global mode
global firstrun
if stmode is not None: if stmode is not None:
if mode != stmode: if self.mode != stmode:
firstrun = True self.firstrun = True
mode = stmode self.mode = stmode
return self
def setring(r,g,b,idx): def setring(self, r,g,b,idx):
ring = rings[idx] ring = self.rings[idx]
for pixel in range(ring[2],ring[3]): for pixel in range(ring[2],ring[3]):
setpixel(r,g,b,pixel) self.setpixel(r,g,b,pixel)
#global data #global data
#senduniverse(data, ring[2]) #senduniverse(data, ring[2])
return self
def runmodes(ring = -1, speed = 1): def runmodes(self, ring = -1, speed = 1):
global mode fprint("Mode: " + str(self.mode))
global firstrun if self.mode == "Startup":
global changecount
fprint("Mode: " + str(mode))
if mode == "Startup":
# loading animation. cable check # loading animation. cable check
if firstrun: if self.firstrun:
changecount = animation_time * 3 self.changecount = self.animation_time * 3
firstrun = False self.firstrun = False
for x in range(len(ringstatus)): for x in range(len(self.ringstatus)):
ringstatus[x] = [True, animation_time] self.ringstatus[x] = [True, self.animation_time]
if changecount > 0: if self.changecount > 0:
fprint(changecount) fprint(self.changecount)
changecount = fadeorder(0,len(leds), changecount, 0,50,100) self.changecount = self.fadeorder(0,len(self.leds), self.changecount, 0,50,100)
else: else:
setmode("Startup2") self.setmode("Startup2")
elif mode == "Startup2": elif self.mode == "Startup2":
if firstrun: if self.firstrun:
firstrun = False self.firstrun = False
else: else:
for x in range(len(ringstatus)): for x in range(len(self.ringstatus)):
if ringstatus[x][0]: if self.ringstatus[x][0]:
setring(0, 50, 100, x) self.setring(0, 50, 100, x)
else: else:
ringstatus[x][1] = fadeall(rings[x][2],rings[x][3], ringstatus[x][1], 100,0,0) # not ready self.ringstatus[x][1] = self.fadeall(self.rings[x][2],self.rings[x][3], self.ringstatus[x][1], 100,0,0) # not ready
elif mode == "StartupCheck": elif self.mode == "StartupCheck":
if firstrun: if self.firstrun:
firstrun = False self.firstrun = False
for x in range(len(ringstatus)): for x in range(len(self.ringstatus)):
ringstatus[x] = [False, animation_time] self.ringstatus[x] = [False, self.animation_time]
else: else:
for x in range(len(ringstatus)): for x in range(len(self.ringstatus)):
if ringstatus[x][0]: if self.ringstatus[x][0]:
ringstatus[x][1] = fadeall(rings[x][2],rings[x][3], ringstatus[x][1], 0,50,100) # ready self.ringstatus[x][1] = self.fadeall(self.rings[x][2],self.rings[x][3], self.ringstatus[x][1], 0,50,100) # ready
else: else:
setring(100, 0, 0, x) self.setring(100, 0, 0, x)
elif mode == "GrabA": elif self.mode == "GrabA":
if firstrun: if self.firstrun:
firstrun = False self.firstrun = False
changecount = animation_time # 100hz self.changecount = self.animation_time # 100hz
if changecount > 0: if self.changecount > 0:
changecount = fadeall(rings[ring][2],rings[ring][3], changecount, 100,0,0) self.changecount = self.fadeall(self.rings[ring][2],self.rings[ring][3], self.changecount, 100,0,0)
else: else:
setring(100,0,0,ring) self.setring(100,0,0,ring)
setmode("GrabB") self.setmode("GrabB")
elif mode == "GrabB": elif self.mode == "GrabB":
if firstrun: if self.firstrun:
firstrun = False self.firstrun = False
changecount = animation_time # 100hz self.changecount = self.animation_time # 100hz
if changecount > 0: if self.changecount > 0:
changecount = fadeorder(rings[ring][2],rings[ring][3], changecount, 0,100,0) self.changecount = self.fadeorder(self.rings[ring][2],self.rings[ring][3], self.changecount, 0,100,0)
else: else:
setring(0,100,0,ring) self.setring(0,100,0,ring)
setmode("idle") self.setmode("idle")
elif mode == "GrabC": elif self.mode == "GrabC":
if firstrun: if self.firstrun:
firstrun = False self.firstrun = False
changecount = animation_time # 100hz self.changecount = self.animation_time # 100hz
if changecount > 0: if self.changecount > 0:
changecount = fadeall(rings[ring][2],rings[ring][3], changecount, 0,50,100) self.changecount = self.fadeall(self.rings[ring][2],self.rings[ring][3], self.changecount, 0,50,100)
else: else:
setring(0,50,100,ring) self.setring(0,50,100,ring)
setmode("idle") self.setmode("idle")
elif mode == "idle": elif self.mode == "idle":
time.sleep(0) time.sleep(0)
sendall(data) self.sendall(self.data)
return self
def fadeall(idxa,idxb,sizerem,r,g,b): def fadeall(self, idxa,idxb,sizerem,r,g,b):
if sizerem < 1: if sizerem < 1:
return 0 return 0
global exactdata
sum = 0 sum = 0
for x in range(idxa,idxb): for x in range(idxa,idxb):
if exactdata[x] is None: if self.exactdata[x] is None:
exactdata[x] = data[x] self.exactdata[x] = self.data[x]
old = exactdata[x] old = self.exactdata[x]
dr = (r - old[0])/sizerem dr = (r - old[0])/sizerem
sum += abs(dr) sum += abs(dr)
dr += old[0] dr += old[0]
@ -419,27 +409,26 @@ def fadeall(idxa,idxb,sizerem,r,g,b):
db = (b - old[2])/sizerem db = (b - old[2])/sizerem
db += old[2] db += old[2]
sum += abs(db) sum += abs(db)
exactdata[x] = (dr, dg, db) self.exactdata[x] = (dr, dg, db)
#print(new) #print(new)
setpixel(dr, dg, db, x) self.setpixel(dr, dg, db, x)
if sizerem == 1: if sizerem == 1:
exactdata[x] = None self.exactdata[x] = None
if sum == 0 and sizerem > 2: if sum == 0 and sizerem > 2:
sizerem = 2 sizerem = 2
return sizerem - 1 return sizerem - 1
def fadeorder(idxa,idxb,sizerem,r,g,b): def fadeorder(self, idxa,idxb,sizerem,r,g,b):
if sizerem < 1: if sizerem < 1:
return 0 return 0
global exactdata
drs = 0 drs = 0
dgs = 0 dgs = 0
dbs = 0 dbs = 0
sum = 0 sum = 0
for x in range(idxa,idxb): for x in range(idxa,idxb):
if exactdata[x] is None: if self.exactdata[x] is None:
exactdata[x] = data[x] self.exactdata[x] = self.data[x]
old = exactdata[x] old = self.exactdata[x]
dr = (r - old[0]) dr = (r - old[0])
dg = (g - old[1]) dg = (g - old[1])
db = (b - old[2]) db = (b - old[2])
@ -453,7 +442,7 @@ def fadeorder(idxa,idxb,sizerem,r,g,b):
sum += abs(drs) + abs(dgs) + abs(dbs) sum += abs(drs) + abs(dgs) + abs(dbs)
print(drs,dgs,dbs) print(drs,dgs,dbs)
for x in range(idxa,idxb): for x in range(idxa,idxb):
old = exactdata[x] old = self.exactdata[x]
new = list(old) new = list(old)
if drs > 0: if drs > 0:
if old[0] + drs > r: if old[0] + drs > r:
@ -500,20 +489,18 @@ def fadeorder(idxa,idxb,sizerem,r,g,b):
dbs = 0 dbs = 0
if drs != 0 or dgs != 0 or dbs != 0: if drs != 0 or dgs != 0 or dbs != 0:
exactdata[x] = new self.exactdata[x] = new
setpixel(new[0],new[1],new[2],x) self.setpixel(new[0],new[1],new[2],x)
if sizerem == 1: if sizerem == 1:
exactdata[x] = None self.exactdata[x] = None
if sum == 0 and sizerem > 2: if sum == 0 and sizerem > 2:
sizerem = 2 sizerem = 2
return sizerem - 1 return sizerem - 1
def setpixel(r, g, b, num): def setpixel(self, r, g, b, num):
global data
global leds_size
# constrain values # constrain values
if r < 0: if r < 0:
r = 0 r = 0
@ -528,29 +515,28 @@ def setpixel(r, g, b, num):
elif b > 255: elif b > 255:
b = 255 b = 255
if leds_size[num] == 3: if self.leds_size[num] == 3:
data[num] = (int(r), int(g), int(b)) self.data[num] = (int(r), int(g), int(b))
elif leds_size[num] == 4: # cut out matching white and turn on white pixel instead elif self.leds_size[num] == 4: # cut out matching white and turn on white pixel instead
data[num] = (( int(r) - int(min(r,g,b)), int(g) - int(min(r,g,b)), int(b) - int(min(r,g,b)), int(min(r,g,b))) ) self.data[num] = (( int(r) - int(min(r,g,b)), int(g) - int(min(r,g,b)), int(b) - int(min(r,g,b)), int(min(r,g,b))) )
else: else:
data[num] = (int(r), int(g), int(b)) self.data[num] = (int(r), int(g), int(b))
return self
def close(self):
def close():
global sender
time.sleep(0.5) time.sleep(0.5)
sender.stop() self.sender.stop()
return self
def mapimage(image, fps=90): def mapimage(self, image, fps=90):
global start while uptime() - self.start < 1/fps:
while uptime() - start < 1/fps:
time.sleep(0.00001) time.sleep(0.00001)
fprint(1 / (uptime() - start)) fprint(1 / (uptime() - self.start))
start = uptime() self.start = uptime()
minsize = min(image.shape[0:2]) minsize = min(image.shape[0:2])
leds_normalized2 = [(x * minsize, leds_normalized2 = [(x * minsize,
y * minsize) y * minsize)
for x, y in leds_normalized] for x, y in self.leds_normalized]
cv2.imshow("video", image) cv2.imshow("video", image)
cv2.waitKey(1) cv2.waitKey(1)
@ -567,39 +553,39 @@ def mapimage(image, fps=90):
#avgx += x #avgx += x
#avgy += y #avgy += y
color = tuple(image[y, x]) color = tuple(image[y, x])
setpixel(color[2]/2,color[1]/2,color[0]/2,xx) # swap b & r self.setpixel(color[2]/2,color[1]/2,color[0]/2,xx) # swap b & r
#print(color) #print(color)
else: else:
#avgx += x #avgx += x
#avgy += y #avgy += y
setpixel(0,0,0,xx) self.setpixel(0,0,0,xx)
#avgx /= len(leds) #avgx /= len(leds)
#avgy /= len(leds) #avgy /= len(leds)
#print((avgx,avgy, max([led[0] for led in leds_adj]), max([led[1] for led in leds_adj]) , min(image.shape[0:2]) )) #print((avgx,avgy, max([led[0] for led in leds_adj]), max([led[1] for led in leds_adj]) , min(image.shape[0:2]) ))
global data self.fastsendall(self.data)
fastsendall(data) return self
def mainloop(stmode, ring = -1, fps = 100, preview = False): def mainloop(self, stmode, ring = -1, fps = 100, preview = False):
global start while uptime() - self.start < 1/fps:
while uptime() - start < 1/fps:
time.sleep(0.00001) time.sleep(0.00001)
fprint(1 / (uptime() - start)) fprint(1 / (uptime() - self.start))
start = uptime() self.start = uptime()
if mode is not None: if self.mode is not None:
setmode(stmode) self.setmode(stmode)
runmodes(ring) self.runmodes(ring)
if preview: if preview:
drawdata() self.drawdata()
return self
def drawdata(): def drawdata(self):
#tmp = list() #tmp = list()
#for x in len(leds): #for x in len(leds):
# led = leds[x] # led = leds[x]
# tmp.append((led[0], led[1], data[x])) # tmp.append((led[0], led[1], data[x]))
x = [led[0] for led in leds] x = [led[0] for led in self.leds]
y = [led[1] for led in leds] y = [led[1] for led in self.leds]
colors = data colors = self.data
colors_normalized = [(x[0]/255, x[1]/255, x[2]/255) for x in colors] colors_normalized = [(x[0]/255, x[1]/255, x[2]/255) for x in colors]
# Plot the points # Plot the points
plt.scatter(x, y, c=colors_normalized) plt.scatter(x, y, c=colors_normalized)
@ -612,42 +598,48 @@ def drawdata():
plt.show() plt.show()
plt.savefig("map3.png", dpi=50, bbox_inches="tight") plt.savefig("map3.png", dpi=50, bbox_inches="tight")
plt.clf() plt.clf()
return self
def startup_animation(show): def startup_animation(self, show):
stmode = "Startup" stmode = "Startup"
mainloop(stmode, preview=show) self.mainloop(stmode, preview=show)
while mode == "Startup": while self.mode == "Startup":
mainloop(None, preview=show) self.mainloop(None, preview=show)
for x in range(54): for x in range(54):
ringstatus[x][0] = False self.ringstatus[x][0] = False
mainloop(None, preview=show) self.mainloop(None, preview=show)
for x in range(animation_time): for x in range(self.animation_time):
mainloop(None, preview=show) self.mainloop(None, preview=show)
clear_animations() self.clear_animations()
stmode = "StartupCheck" stmode = "StartupCheck"
mainloop(stmode, preview=show) self.mainloop(stmode, preview=show)
clear_animations() self.clear_animations()
return self
def clear_animations(): def clear_animations(self):
for x in range(len(leds)): for x in range(len(self.leds)):
exactdata[x] = None self.exactdata[x] = None
return self
def do_animation(stmode, ring=-1): def do_animation(self, stmode, ring=-1):
mainloop(stmode, ring, preview=show) self.mainloop(stmode, ring, preview=show)
wait_for_animation(ring) self.wait_for_animation(ring)
return self
def start_animation(stmode, ring=-1): def start_animation(self, stmode, ring=-1):
mainloop(stmode, ring, preview=show) self.mainloop(stmode, ring, preview=show)
return self
def wait_for_animation(ring=-1): def wait_for_animation(self, ring=-1):
while mode != "idle": while self.mode != "idle":
mainloop(None, ring, preview=show) self.mainloop(None, ring, preview=show)
return self
if __name__ == "__main__": if __name__ == "__main__":
init()
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
"""cap = cv2.VideoCapture('badapple.mp4') """cap = cv2.VideoCapture('badapple.mp4')
while cap.isOpened(): while cap.isOpened():
@ -655,24 +647,26 @@ if __name__ == "__main__":
if not ret: if not ret:
break break
mapimage(frame, fps=30)""" mapimage(frame, fps=30)"""
show = True show = False
ring = 1 ring = 1
startup_animation(show) ledsys = LEDSystem()
ledsys.init()
ledsys.startup_animation(show)
for x in range(54): for x in range(54):
ringstatus[x][0] = True ledsys.ringstatus[x][0] = True
mainloop(None, preview=show) ledsys.mainloop(None, preview=show)
for x in range(animation_time): for x in range(ledsys.animation_time):
mainloop(None, preview=show) ledsys.mainloop(None, preview=show)
do_animation("GrabA", 1) ledsys.do_animation("GrabA", 1)
do_animation("GrabA", 5) ledsys.do_animation("GrabA", 5)
start_animation("GrabC", 1) ledsys.start_animation("GrabC", 1)
wait_for_animation(1) ledsys.wait_for_animation(1)
do_animation("GrabC", 5) ledsys.do_animation("GrabC", 5)
close() ledsys.close()
#sys.exit(0) #sys.exit(0)

BIN
map.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 KiB

After

Width:  |  Height:  |  Size: 370 KiB

BIN
map3.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -8,13 +8,18 @@ from util import fprint
class qr_reader(): class qr_reader():
camera = None camera = None
def __init__(self, ip, port): def __init__(self, ip, port):
self.camera = banner_ivu_export.DriveImg(ip, port) self.ip = ip
self.port = port
#self.camera = banner_ivu_export.DriveImg(ip, port)
def read_qr(self, tries=1): def read_qr(self, tries=1):
print("Trying " + str(tries) + " frames.") print("Trying " + str(tries) + " frames.")
self.camera = banner_ivu_export.DriveImg(self.ip, self.port)
for x in range(tries): for x in range(tries):
try: print(str(x) + " ", end="", flush=True)
imgtype, img = self.camera.read_img() imgtype, img = self.camera.read_img()
if True:
#fprint(imgtype) #fprint(imgtype)
image_array = np.frombuffer(img, np.uint8) image_array = np.frombuffer(img, np.uint8)
img = cv2.imdecode(image_array, cv2.IMREAD_COLOR) img = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
@ -22,9 +27,13 @@ class qr_reader():
#cv2.waitKey(1) #cv2.waitKey(1)
detect = cv2.QRCodeDetector() detect = cv2.QRCodeDetector()
value, points, straight_qrcode = detect.detectAndDecode(img) value, points, straight_qrcode = detect.detectAndDecode(img)
if value != "":
self.camera.close()
return value return value
except:
continue
self.camera.close()
return False return False
@ -41,5 +50,7 @@ class video_streamer():
if __name__ == "__main__": if __name__ == "__main__":
test = qr_reader("192.168.1.125", 32200) test = qr_reader("192.168.1.125", 32200)
import time
while True: while True:
fprint(test.read_qr(5)) fprint(test.read_qr(300))
time.sleep(1)

View File

@ -177,7 +177,7 @@ def parse(filename, output_dir, partnum, dstype):
if dstype == "Alphawire" and table_name_2.find("\n") >= 0: if dstype == "Alphawire" and table_name_2.find("\n") >= 0:
torename[table_name_2] = table_name_2[0:table_name_2.find("\n")] torename[table_name_2] = table_name_2[0:table_name_2.find("\n")]
if table_name_2.find(table.iloc[-1, 0]) >= 0: if dstype == "Alphawire" and table_name_2.find(table.iloc[-1, 0]) >= 0:
# Name taken from table directly above - this table does not have a name # Name taken from table directly above - this table does not have a name
torename[table_name_2] = "Specs " + str(len(tables)) torename[table_name_2] = "Specs " + str(len(tables))
#table_list["Specs " + str(len(tables))] = table_list[table_name_2] # rename table to arbitrary altername name #table_list["Specs " + str(len(tables))] = table_list[table_name_2] # rename table to arbitrary altername name
@ -251,9 +251,6 @@ def parse(filename, output_dir, partnum, dstype):
#fprint(table_name) #fprint(table_name)
#fprint(previous_table) #fprint(previous_table)
main_key = previous_table main_key = previous_table
cont_key = table_name cont_key = table_name
#fprint(tables) #fprint(tables)
@ -267,15 +264,21 @@ def parse(filename, output_dir, partnum, dstype):
del tables[table_name] del tables[table_name]
else: else:
#print(tables)
#print(main_key)
#print(cont_key)
for key in tables[cont_key].keys(): for key in tables[cont_key].keys():
tables[main_key][key] = tables[cont_key][key] tables[main_key][key] = tables[cont_key][key]
del tables[table_name] del tables[table_name]
else:
previous_table = table_name
else:
previous_table = table_name previous_table = table_name
# remove & rename tables # remove & rename tables
#print(torename)
for table_name in torename.keys(): for table_name in torename.keys():
tables[torename[table_name]] = tables[table_name] tables[torename[str(table_name)]] = tables[str(table_name)]
del tables[table_name] del tables[table_name]
# remove multi-line values that occasionally squeak through # remove multi-line values that occasionally squeak through
def replace_newlines_in_dict(d): def replace_newlines_in_dict(d):
@ -298,7 +301,7 @@ def parse(filename, output_dir, partnum, dstype):
output_table["id"] = id output_table["id"] = id
#output_table["position"] = id #output_table["position"] = id
#output_table["brand"] = brand #output_table["brand"] = brand
output_table["fullspecs"] = tables output_table["fullspecs"] = {"partnum": partnum, "id": id, **tables}
output_table["searchspecs"] = {"partnum": partnum, **flatten(tables)} output_table["searchspecs"] = {"partnum": partnum, **flatten(tables)}
output_table["searchspecs"]["id"] = id output_table["searchspecs"]["id"] = id
@ -313,9 +316,9 @@ def parse(filename, output_dir, partnum, dstype):
for file_path in json_files: for file_path in json_files:
os.remove(file_path) os.remove(file_path)
#print(f"Deleted {file_path}") #print(f"Deleted {file_path}")
with open(output_dir + "/search_" + output_table["searchspecs"]["id"] + ".json", 'w') as json_file: with open(output_dir + "/search.json", 'w') as json_file:
json.dump(output_table["searchspecs"], json_file) json.dump(output_table["searchspecs"], json_file)
with open(output_dir + "/specs_" + output_table["partnum"] + ".json", 'w') as json_file: with open(output_dir + "/specs.json", 'w') as json_file:
json.dump(output_table["fullspecs"], json_file) json.dump(output_table["fullspecs"], json_file)
#print(json.dumps(output_table, indent=2)) #print(json.dumps(output_table, indent=2))
@ -346,12 +349,20 @@ def flatten(tables):
fullkeyname = (table + ": " + keyname).replace(".","") fullkeyname = (table + ": " + keyname).replace(".","")
if type(tables[table][key]) is not tuple: if type(tables[table][key]) is not tuple:
if len(tables[table][key]) > 0:
out[fullkeyname] = convert_to_number(tables[table][key]) out[fullkeyname] = convert_to_number(tables[table][key])
#print("\"" + keyname + "\":", "\"" + str(out[fullkeyname]) + "\",") #print("\"" + keyname + "\":", "\"" + str(out[fullkeyname]) + "\",")
elif len(tables[table][key]) == 1: elif len(tables[table][key]) == 1:
if len(tables[table][key][0]) > 0:
out[fullkeyname] = convert_to_number(tables[table][key][0]) out[fullkeyname] = convert_to_number(tables[table][key][0])
#print("\"" + keyname + "\":", "\"" + str(out[fullkeyname]) + "\",") #print("\"" + keyname + "\":", "\"" + str(out[fullkeyname]) + "\",")
else:
tmp = []
for x in range(len(tables[table][key])):
if len(tables[table][key][x]) > 0:
tmp.append(tables[table][key][x].strip())
#out[fullkeyname + " " + str(x+1)] = convert_to_number(tables[table][key][x])
out[fullkeyname] = tmp
# if the item has at least two commas in it, split it # if the item has at least two commas in it, split it
if tables[table][key].count(',') > 0: if tables[table][key].count(',') > 0:
out[fullkeyname] = list(map(lambda x: x.strip(), tables[table][key].split(","))) out[fullkeyname] = list(map(lambda x: x.strip(), tables[table][key].split(",")))

View File

@ -4,6 +4,7 @@ opencv-python
pypdf2==2.12.1 pypdf2==2.12.1
alive-progress alive-progress
requests requests
math3d==4.0.0
git+https://github.com/Byeongdulee/python-urx.git git+https://github.com/Byeongdulee/python-urx.git
meilisearch meilisearch
pyyaml pyyaml
@ -19,7 +20,8 @@ pandas
pyarrow pyarrow
ghostscript ghostscript
pyzbar pyzbar
segno
pyModbusTCP
# Development # Development
matplotlib matplotlib

474
run.py
View File

@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from alive_progress import alive_bar
import get_specs import get_specs
import traceback import traceback
#import logging #import logging
@ -12,19 +13,25 @@ from util import fprint
from util import run_cmd from util import run_cmd
import sys import sys
import ur5_control import ur5_control
from ur5_control import Rob
import os import os
import signal import signal
import socket import socket
from flask import Flask, render_template, request from flask import Flask, render_template, request
import requests import requests
import led_control from led_control import LEDSystem
import server import server
import asyncio import asyncio
import json import json
import process_video import process_video
import search
from search import JukeboxSearch
#multiprocessing.set_start_method('spawn', True)
from pyModbusTCP.client import ModbusClient
from uptime import uptime
mbconn = None
config = None config = None
keeprunning = True keeprunning = True
arm_ready = False arm_ready = False
@ -32,25 +39,45 @@ led_ready = False
camera_ready = False camera_ready = False
sensor_ready = False sensor_ready = False
vm_ready = False vm_ready = False
cable_search_ready = False
killme = None killme = None
#pool = None #pool = None
serverproc = None serverproc = None
camera = None camera = None
ledsys = None
arm = None
to_server_queue = Queue() to_server_queue = Queue()
from_server_queue = Queue() from_server_queue = Queue()
mainloop_get = Queue()
mode = "Startup"
counter = 0
jbs = None
scan_value = None
arm_state = None
cable_list = list()
parse_res = None
cable_list_state = list()
just_placed = -1
ring_animation = None
led_set_mode = None
def arm_start_callback(res): def arm_start_callback(res):
fprint("Arm action complete.")
global arm_ready global arm_ready
arm_ready = True arm_ready = True
def led_start_callback(res): def led_start_callback(res):
global led_ready global led_ready
led_ready = True led_ready = True
global ledsys
ledsys = res
def camera_start_callback(res): def camera_start_callback(res):
global camera_ready global camera_ready
camera_ready = True camera_ready = True
global scan_value
scan_value = res
def sensor_start_callback(res): def sensor_start_callback(res):
global sensor_ready global sensor_ready
@ -60,6 +87,12 @@ def vm_start_callback(res):
global vm_ready global vm_ready
vm_ready = True vm_ready = True
def cable_search_callback(res):
global cable_search_ready
cable_search_ready = True
global parse_res
parse_res = res
def wait_for(val, name): def wait_for(val, name):
#global val #global val
if val is False: if val is False:
@ -67,7 +100,15 @@ def wait_for(val, name):
while val is False: while val is False:
sleep(0.1) sleep(0.1)
def start_server_socket(): def send_data(type, call, data, client_id="*"):
out = dict()
out["type"] = type
out["call"] = call
out["data"] = data
to_server_queue.put((client_id, json.dumps(out)))
def start_server_socket(cable_list):
global jbs
"""app = Flask(__name__) """app = Flask(__name__)
@app.route('/report_ip', methods=['POST']) @app.route('/report_ip', methods=['POST'])
@ -99,6 +140,10 @@ def start_server_socket():
# Message handler # Message handler
try: try:
decoded = json.loads(message) decoded = json.loads(message)
except:
fprint("Non-JSON message recieved")
continue
if "type" not in decoded: if "type" not in decoded:
fprint("Missing \"type\" field.") fprint("Missing \"type\" field.")
continue continue
@ -108,35 +153,38 @@ def start_server_socket():
if "data" not in decoded: if "data" not in decoded:
fprint("Missing \"data\" field.") fprint("Missing \"data\" field.")
continue continue
# if we get here, we have a "valid" data packet # if we get here, we have a "valid" data packet
data = decoded["data"] data = decoded["data"]
call = decoded["call"] call = decoded["call"]
try:
match decoded["type"]: match decoded["type"]:
case "log": case "log":
fprint("log message") fprint("log message")
if call == "send": if call == "send":
fprint("webapp: " + str(data), sendqueue=to_server_queue) fprint("webapp: " + str(data), sendqueue=to_server_queue)
elif call == "request": elif call == "request":
fprint("") pass
case "cable_map": case "cable_map":
fprint("cable_map message") fprint("cable_map message")
if call == "send": if call == "send":
fprint("") pass
elif call == "request": elif call == "request":
fprint("") tmp = list()
for idx in range(len(cable_list)):
if cable_list[idx] is not False:
tmp1 = {"part_number": cable_list[idx], "position": idx, "name": cable_list[idx], "brand": "Belden", "description": "Blah", "short_description": "Bla"}
tmp.append(tmp1)
out = {"map": tmp}
fprint(out)
send_data(decoded["type"], "send", out, client_id)
case "ping": case "ping":
fprint("Pong!!!") fprint("Pong!!!")
# Lucas' notes # Lucas' notes
# Add a ping pong :) response/handler # Add a ping pong :) response/handler
# Add a get cable response/handler # Add a get cable response/handler
# this will tell the robot arm to move # this will tell the robot arm to move
# Call for turning off everything # Call for turning off everything
# TODO Helper for converting Python Dictionaries to JSON # TODO Helper for converting Python Dictionaries to JSON
# make function: pythonData --> { { "type": "...", "call": "...", "data": pythonData } } # make function: pythonData --> { { "type": "...", "call": "...", "data": pythonData } }
@ -145,23 +193,39 @@ def start_server_socket():
case "cable_details": case "cable_details":
fprint("cable_details message") fprint("cable_details message")
if call == "send": if call == "send":
fprint("") pass
elif call == "request": elif call == "request":
fprint("") dataout = dict()
dataout["cables"] = list()
print(data)
if "part_number" in data:
for part in data["part_number"]:
#print(part)
#print(jbs.get_partnum(part))
dataout["cables"].append(jbs.get_partnum(part)["fullspecs"])
if "position" in data:
for pos in data["position"]:
#print(pos)
#print(jbs.get_position(str(pos)))
dataout["cables"].append(jbs.get_position(str(pos))["fullspecs"])
send_data(decoded["type"], "send", dataout, client_id)
case "cable_search": case "cable_search":
fprint("cable_search message") fprint("cable_search message")
if call == "send": if call == "send":
fprint("") pass
elif call == "request": elif call == "request":
fprint("") results = jbs.search(data["string"])["hits"]
dataout = dict()
dataout["cables"] = list()
for result in results:
dataout["cables"].append(result["fullspecs"])
send_data(decoded["type"], "send", dataout, client_id)
case "keyboard": case "keyboard":
fprint("keyboard message") fprint("keyboard message")
if call == "send": if call == "send":
fprint("") pass
elif call == "request": elif call == "request":
fprint("")
if data["enabled"] == True: if data["enabled"] == True:
# todo : send this to client # todo : send this to client
p = Process(target=run_cmd, args=("./keyboard-up.ps1",)) p = Process(target=run_cmd, args=("./keyboard-up.ps1",))
@ -169,21 +233,32 @@ def start_server_socket():
elif data["enabled"] == False: elif data["enabled"] == False:
p = Process(target=run_cmd, args=("./keyboard-down.ps1",)) p = Process(target=run_cmd, args=("./keyboard-down.ps1",))
p.start() p.start()
case "machine_settings": case "machine_settings":
fprint("machine_settings message") fprint("machine_settings message")
if call == "send": if call == "send":
fprint("") pass
elif call == "request": elif call == "request":
fprint("") pass
case "cable_get":
fprint("cable_get message")
if call == "send":
global mainloop_get
if "part_number" in data:
for cableidx in range(len(cable_list)):
cable = cable_list[cableidx]
if cable == data["part_number"]:
mainloop_get.put(("pickup", cableidx))
elif "position" in data:
mainloop_get.put(("pickup", data["position"]))
case _: case _:
fprint("Unknown/unimplemented data type: " + decoded["type"]) fprint("Unknown/unimplemented data type: " + decoded["type"])
except Exception as e:
fprint(traceback.format_exc())
fprint(e)
except:
fprint("Non-JSON message recieved")
continue
sleep(0.001) # Sleep to prevent tight loop sleep(0.001) # Sleep to prevent tight loop
@ -231,57 +306,352 @@ def setup_server(pool):
global arm_ready global arm_ready
global serverproc global serverproc
global camera global camera
global arm
global jbs
pool.apply_async(ur5_control.init, (config["arm"]["ip"],), callback=arm_start_callback) arm = Rob(config)
pool.apply_async(led_control.init, callback=led_start_callback) pool.apply_async(ur5_control.powerup_arm, (arm,), callback=arm_start_callback, error_callback=handle_error)
global ledsys
ledsys = LEDSystem()
#pool.apply_async(ledsys.init, callback=led_start_callback)
#pool.apply_async(sensor_control.init, callback=sensor_start_callback) #pool.apply_async(sensor_control.init, callback=sensor_start_callback)
serverproc = Process(target=start_server_socket) jbs = JukeboxSearch()
serverproc.start()
if led_ready is False: if led_ready is False:
fprint("waiting for " + "LED controller initialization" + " to complete...", sendqueue=to_server_queue) fprint("waiting for " + "LED controller initialization" + " to complete...", sendqueue=to_server_queue)
while led_ready is False: ledsys.init()
sleep(0.1) led_ready = True
fprint("LED controllers initialized.", sendqueue=to_server_queue) fprint("LED controllers initialized.", sendqueue=to_server_queue)
#to_server_queue.put("[log] LED controllers initialized.")
sensor_ready = True
if sensor_ready is False: if sensor_ready is False:
fprint("waiting for " + "Sensor Initialization" + " to complete...", sendqueue=to_server_queue) fprint("waiting for " + "Sensor Initialization" + " to complete...", sendqueue=to_server_queue)
while sensor_ready is False: global mbconn
sleep(0.1) mbconn = ModbusClient(host="localhost", port=502, unit_id=1, auto_open=True, auto_close=True)
fprint("Sensors initialized.", sendqueue=to_server_queue) fprint("Sensors initialized.", sendqueue=to_server_queue)
if camera_ready is False: if camera_ready is False:
fprint("waiting for " + "Camera initilization" + " to complete...", sendqueue=to_server_queue) fprint("waiting for " + "Camera initilization" + " to complete...", sendqueue=to_server_queue)
# camera = process_video.qr_reader(config["cameras"]["banner"]["ip"], config["cameras"]["banner"]["port"]) camera = process_video.qr_reader(config["cameras"]["banner"]["ip"], int(config["cameras"]["banner"]["port"]))
fprint("Camera initialized.", sendqueue=to_server_queue) fprint("Camera initialized.", sendqueue=to_server_queue)
arm_ready = True #arm_ready = True
if arm_ready is False: if arm_ready is False:
fprint("waiting for " + "UR5 initilization" + " to complete...", sendqueue=to_server_queue) fprint("waiting for " + "UR5 powerup" + " to complete...", sendqueue=to_server_queue)
while arm_ready is False: while arm_ready is False:
sleep(0.1) sleep(0.1)
fprint("Arm initialized.", sendqueue=to_server_queue)
ur5_control.init_arm(arm)
fprint("Arm initialized.", sendqueue=to_server_queue)
return True return True
def handle_error(error):
print(error, flush=True)
def get_sensors():
global mbconn
global sensors
oldsens = sensors
"""
port 1: 256
port 2: 272
port 3: 288
port 4: 304
port 5: 320
port 6: 336
port 7: 352
port 8: 368
"""
out = list()
for reg in [352, 288, 304, 368]:
val = mbconn.read_holding_registers(reg)
if val == 1:
out.append(1)
else:
out.append(0)
sensors = out
for x in range(len(oldsens)):
if oldsens[x] == 0 and out[x] == 1:
# cable newly detected on tray
return x
return -1
def get_open_spot(sensordata):
for x in range(len(sensordata)):
sens = sensordata[x]
if not sens:
return x
# if we get here, every spot is full
return False
def mainloop_server(pool): def mainloop_server(pool):
# NON-blocking loop
global ring_animation
global led_set_mode
global just_placed
global config global config
global counter global counter
global killme global killme
global mode
global jbs
global arm
global ledsys
global camera
global arm_ready
global arm_state
global camera_ready
global cable_search_ready
global cable_list
global mainloop_get
global cable_list_state
if killme.value > 0: if killme.value > 0:
killall() killall()
counter = counter + 1
# fprint("Looking for QR code...") if mode == "Startup":
# print(camera.read_qr(30)) #counter = 54 # remove for demo
if counter < 54:
# scanning cables
ring_animation = counter
led_set_mode = "GrabA"
if arm_state is None:
#pool.apply_async(arm_start_callback, ("",))
arm_ready = False
pool.apply_async(ur5_control.to_camera, (arm,counter), callback=arm_start_callback, error_callback=handle_error)
fprint("Getting cable index " + str(counter) + " and scanning...")
arm_state = "GET"
#ur5_control.to_camera(arm, counter)
#arm_ready = True
elif arm_ready and arm_state == "GET":
fprint("Looking for QR code...")
pool.apply_async(camera.read_qr, (10,), callback=camera_start_callback, error_callback=handle_error)
arm_ready = False
elif camera_ready:
fprint("Adding cable to list...")
global scan_value
if scan_value is False:
cable_list.append(scan_value)
elif scan_value.find("bldn.app/") > -1:
scan_value = scan_value[scan_value.find("bldn.app/")+9:]
else:
cable_list.append(scan_value)
fprint(scan_value)
pool.apply_async(ur5_control.return_camera, (arm,counter), callback=arm_start_callback, error_callback=handle_error)
#ur5_control.return_camera(arm, counter)
#arm_ready = True
arm_state = "RETURN"
camera_ready = False
elif arm_ready and arm_state == "RETURN":
counter += 1
arm_state = None
else:
# just wait til arm/camera is ready
pass
else:
# scanned everything
ring_animation = None
led_set_mode == "idle"
tmp = [
# Actual cables in Jukebox
"BLTF-1LF-006-RS5",
"BLTF-SD9-006-RI5",
"BLTT-SLG-024-HTN",
"BLFISX012W0",
"BLFI4X012W0",
"BLSPE101",
"BLSPE102",
"BL7922A",
"BL7958A",
"BLIOP6U",
"BL10GXW13",
"BL10GXW53",
"BL29501F",
"BL29512",
"BL3106A",
"BL9841",
"BL3105A",
"BL3092A",
"BL8760",
"BL6300UE",
"BL6300FE",
"BLRA500P",
"AW86104CY",
"AW3050",
"AW6714",
"AW1172C",
"AWFIT-221-1_4"
]
while len(tmp) < 54:
tmp.append(False) # must have 54 entries
#cable_list = tmp # comment out for real demo
for idx in range(len(cable_list)):
cable_list_state.append(True)
pool.apply_async(get_specs.get_multi, (cable_list, 0.3), callback=cable_search_callback, error_callback=handle_error)
mode = "Parsing"
fprint("All cables scanned. Finding & parsing datasheets...")
if mode == "Parsing":
# waiting for search & parse to complete
#cable_search_ready = True
if cable_search_ready is False:
pass
else:
# done
global parse_res
success, partnums = parse_res
for idx in range(len(partnums)):
if partnums[idx] is not False:
cable_list[idx] = partnums[idx][0].replace("/", "_")
else:
cable_list[idx] = False
print(partnums)
if success:
# easy mode
fprint("All cables inventoried and parsed.")
fprint("Adding to database...")
for idx in range(len(cable_list)):
partnum = cable_list[idx]
if partnum is not False:
with open("cables/" + partnum + "/search.json", "rb") as f:
searchdata = json.load(f)
searchdata["position"] = idx
with open("cables/" + partnum + "/specs.json", "rb") as f:
specs = json.load(f)
searchdata["fullspecs"] = specs
searchdata["fullspecs"]["position"] = idx
jbs.add_document(searchdata)
#sleep(0.5)
#print(jbs.get_position("1"))
fprint("All cables added to database.")
mode = "Idle"
serverproc = Process(target=start_server_socket, args=(cable_list,), error_callback=handle_error)
serverproc.start()
else:
# TODO: manual input
pass
if mode == "Idle":
# do nothing
if arm_ready is False:
pool.apply_async(ur5_control.move_to_home, (arm,), callback=arm_start_callback, error_callback=handle_error)
#arm_ready = True
else:
global mainloop_get
newtube = get_sensors()
if newtube >= 0 and newtube != just_placed:
# need to return a cable
mainloop_get.put(("return", newtube))
just_placed = -1
if not mainloop_get.empty():
action, get_cable = mainloop_get.get()
if get_cable > -1:
global sensors
if action == "pickup":
spot = get_open_spot(sensors)
if spot is not False:
arm_ready = False
pool.apply_async(ur5_control.pick_up_routine, (arm, get_cable, True, spot), callback=arm_start_callback, error_callback=handle_error)
mode = "Pickup"
cable_list_state[get_cable] = False # mark as removed
get_sensors(sensors,flag=get_open_spot(sensors))
if action == "return":
arm_ready = False
pool.apply_async(ur5_control.return_routine, (arm, get_cable), callback=arm_start_callback, error_callback=handle_error)
mode = "ReturnC"
else:
# LED idle anim
pass
if mode == "Pickup":
# complete
if arm_ready == True:
mode = "Idle"
arm_ready = False
else:
# getting cable and bringing to tray
# led animation
pass
if mode == "ReturnC":
# complete
if arm_ready == True:
mode = "Scan"
arm_ready = False
camera_ready = False
pool.apply_async(camera.read_qr, (10,), callback=camera_start_callback, error_callback=handle_error)
else:
# getting cable from and bringing to camera
# led animation
pass
if mode == "Scan":
if camera_ready == True:
global scan_value
if scan_value is False:
# unable to scan ???? not good
fprint("Unable to scan cable. Gonna retry.")
camera_ready = False
pool.apply_async(camera.read_qr, (10,), callback=camera_start_callback, error_callback=handle_error)
pass
elif scan_value.find("bldn.app/") > -1:
scan_value = scan_value[scan_value.find("bldn.app/")+9:]
fprint("Got cable: " + scan_value)
for idx in range(len(cable_list)):
cable = cable_list[idx]
if cable == scan_value and cable_list_state[idx] == False:
cable_list_state[idx] = True # mark cable as returned
arm_ready = False
pool.apply_async(ur5_control.return_camera, (arm, idx), callback=arm_start_callback, error_callback=handle_error)
mode = "Return"
break
if mode == "Return":
if arm_ready == True:
mode = "Idle"
arm_ready = False
# movement finished
else:
# cable going from camera to holder
# led animation
pass
if True:
# do every loop!
if ring_animation is not None and ledsys.mode != "idle":
ledsys.mainloop(None, ring_animation)
elif ring_animation is not None:
ledsys.mainloop(led_set_mode, ring_animation)
def run_loading_app(): def run_loading_app():
@ -389,19 +759,20 @@ class LogExceptions(object):
return result return result
class LoggingPool(Pool): class LoggingPool(Pool):
def apply_async(self, func, args=(), kwds={}, callback=None): def apply_async(self, func, args=(), kwds={}, callback=None, error_callback=None):
return Pool.apply_async(self, LogExceptions(func), args, kwds, callback) return Pool.apply_async(self, LogExceptions(func), args, kwds, callback, error_callback)
if __name__ == "__main__": if __name__ == "__main__":
#sys.stdout = Logger(filename="output.log") #sys.stdout = Logger(filename="output.log")
#sys.stderr = Logger(filename="output.log") #sys.stderr = Logger(filename="output.log")
#log_to_stderr(logging.DEBUG) #log_to_stderr(logging.DEBUG)
fprint("Starting Jukebox control system...") fprint("Starting Jukebox control system...")
with open('config.yml', 'r') as fileread: with open('config.yml', 'r') as fileread:
#global config #global config
config = yaml.safe_load(fileread) config = yaml.safe_load(fileread)
fprint("Config loaded.")
with Manager() as manager: with Manager() as manager:
fprint("Spawning threads...") fprint("Spawning threads...")
pool = LoggingPool(processes=10) pool = LoggingPool(processes=10)
@ -422,5 +793,18 @@ if __name__ == "__main__":
fprint("Entering main loop...") fprint("Entering main loop...")
while(keeprunning): while(keeprunning):
mainloop_server(pool) mainloop_server(pool)
else:
fprint("Mode unspecified - assuming server")
fprint("Starting in server mode.")
if setup_server(pool):
fprint("Entering main loop...")
start = 0
speed = config["loopspeed"]
while(keeprunning):
start = uptime()
mainloop_server(pool)
# limit to certain "framerate"
while start + 1.0/speed < uptime():
pass

View File

@ -1,10 +1,12 @@
#!/usr/bin/env python3
"""Interactions with the Meilisearch API for adding and searching cables.""" """Interactions with the Meilisearch API for adding and searching cables."""
from meilisearch import Client from meilisearch import Client
from meilisearch.task import TaskInfo from meilisearch.task import TaskInfo
from meilisearch.errors import MeilisearchApiError from meilisearch.errors import MeilisearchApiError
import json import time
DEFAULT_URL = "http://localhost:7700" DEFAULT_URL = "http://127.0.0.1:7700"
DEFAULT_APIKEY = "fluffybunnyrabbit" # I WOULD RECOMMEND SOMETHING MORE SECURE DEFAULT_APIKEY = "fluffybunnyrabbit" # I WOULD RECOMMEND SOMETHING MORE SECURE
DEFAULT_INDEX = "cables" DEFAULT_INDEX = "cables"
DEFAULT_FILTERABLE_ATTRS = ["partnum", "uuid", "position"] # default filterable attributes DEFAULT_FILTERABLE_ATTRS = ["partnum", "uuid", "position"] # default filterable attributes
@ -34,12 +36,15 @@ class JukeboxSearch:
# create the index if it does not exist already # create the index if it does not exist already
try: try:
self.client.get_index(self.index) self.client.get_index(self.index)
self.client.delete_index(self.index)
self.client.create_index(self.index)
except MeilisearchApiError as _: except MeilisearchApiError as _:
self.client.create_index(self.index) self.client.create_index(self.index)
# make a variable to easily reference the index # make a variable to easily reference the index
self.idxref = self.client.index(self.index) self.idxref = self.client.index(self.index)
time.sleep(0.05)
# update filterable attributes if needed # update filterable attributes if needed
self.idxref.update_distinct_attribute('partnum')
self.update_filterables(filterable_attrs) self.update_filterables(filterable_attrs)
def add_document(self, document: dict) -> TaskInfo: def add_document(self, document: dict) -> TaskInfo:
@ -65,11 +70,10 @@ class JukeboxSearch:
:param filterables: List of all filterable attributes""" :param filterables: List of all filterable attributes"""
existing_filterables = self.idxref.get_filterable_attributes() #existing_filterables = self.idxref.get_filterable_attributes()
if len(set(existing_filterables).difference(set(filterables))) > 0: #if len(set(existing_filterables).difference(set(filterables))) > 0:
taskref = self.idxref.update_filterable_attributes(filterables) taskref = self.idxref.update_filterable_attributes(filterables)
#self.client.wait_for_task(taskref.index_uid)
self.client.wait_for_task(taskref.index_uid)
def search(self, query: str, filters: str = None): def search(self, query: str, filters: str = None):
"""Execute a search query on the Meilisearch index. """Execute a search query on the Meilisearch index.
@ -90,7 +94,7 @@ class JukeboxSearch:
:returns: A dict containing the results; If no results found, an empty dict.""" :returns: A dict containing the results; If no results found, an empty dict."""
q = self.search("", filter) q = self.search("", filter)
if q["estimatedTotalHits"] != 0: if q["estimatedTotalHits"] != 0:
return ["hits"][0] return q["hits"][0]
else: else:
return dict() return dict()

20
setup-alpine-vm.sh Normal file
View File

@ -0,0 +1,20 @@
#!/bin/sh
# This script must run as root!
echo "https://dl-cdn.alpinelinux.org/alpine/latest-stable/main
https://dl-cdn.alpinelinux.org/alpine/latest-stable/community" > /etc/apk/repositories
apk upgrade
apk add git docker docker-cli-compose
rc-update add docker
service docker start
git clone https://git.myitr.org/Jukebox/jukebox-software
cd jukebox-software
git submodule init
git submodule update
docker compose build
docker compose up -d

View File

@ -10,7 +10,7 @@ import opcode
import os import os
import distutils import distutils
#distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'distutils') #distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'distutils')
build_exe_options = {"include_msvcr": True, "packages": ["camelot", "setuptools"], "optimize": 0, "silent": True, "include_files": ["gs10030w64.exe"], "excludes": ["scipy", "torch"]} build_exe_options = {"include_msvcr": True, "packages": ["camelot", "setuptools", "segno"], "optimize": 0, "silent": True, "include_files": ["gs10030w64.exe", "GothamCond-Medium.otf", "belden-logo-superhires.png"], "excludes": ["scipy", "torch"]}
# base="Win32GUI" should be used only for Windows GUI app # base="Win32GUI" should be used only for Windows GUI app
base = "console" base = "console"

2
tempCodeRunnerFile.py Normal file
View File

@ -0,0 +1,2 @@
drop_off_tray(robot, 0)

BIN
test.pdf

Binary file not shown.

44
test.py
View File

@ -1,4 +1,46 @@
print("\u001b[37m") from pyModbusTCP.client import ModbusClient
def get_sensors():
mbconn = ModbusClient(host="192.168.1.20", port=502, auto_open=True, auto_close=True)
"""
port 1: 256
port 2: 272
port 3: 288
port 4: 304
port 5: 320
port 6: 336
port 7: 352
port 8: 368
"""
out = list()
for reg in [352, 288, 304, 368]:
val = mbconn.read_holding_registers(reg)[0] # read only one register
print(val)
if val == 1:
out.append(True)
else:
out.append(False)
return out
def get_open_spot(sensordata):
for x in range(len(sensordata)):
sens = sensordata[x]
if not sens:
return x
# if we get here, every spot is full
return False
testmb = get_sensors()
print(testmb)
print("Spot open", get_open_spot(testmb))
exit()
class Ring: class Ring:
def __init__(self) -> None: def __init__(self) -> None:

BIN
test2.pdf

Binary file not shown.

View File

@ -5,53 +5,109 @@ import math
import numpy as np import numpy as np
import time import time
import os import os
import logging #import logging
from urx.robotiq_two_finger_gripper import Robotiq_Two_Finger_Gripper import yaml
import sys import sys
from util import fprint from util import fprint
from pyModbusTCP.client import ModbusClient
import subprocess
from util import win32
class Rob():
robot = None
#offset_x, offset_y, offset_z = (0, 0, 0.14) # Tool offset
#
def __init__(self, config):
self.config = config
armc = config["arm"]
self.ip = armc["ip"]
tool = armc["tool"]
limbs = armc["limbs"]
self.offset_x, self.offset_y, self.offset_z = (tool["offset_x"], tool["offset_y"], tool["offset_z"])
self.limb_base = limbs["limb_base"]
self.limb1 = limbs["limb1"]
self.limb2 = limbs["limb2"]
self.limb3 = limbs["limb3"]
self.limb_wrist = limbs["limb_wrist"]
#self.init_arm()
rob = None def ping(host):
#Returns True if host (str) responds to a ping request.
# Option for the number of packets as a function of
if win32:
param1 = '-n'
param2 = '-w'
param3 = '250'
else:
param1 = '-c'
param2 = '-W'
param3 = '0.25'
def init(ip): # Building the command. Ex: "ping -c 1 google.com"
global rob command = ['ping', param1, '1', param2, param3, host]
return subprocess.call(command, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) == 0
def powerup_arm(robot):
#sys.stdout = Logger() #sys.stdout = Logger()
fprint("Starting UR5 power up...") fprint("Starting UR5 power up...")
# power up robot here via PCB
# power up robot here #
# wait for power up (this function runs async) # wait for power up (this function runs async)
while not ping(robot.ip):
time.sleep(0.5)
# trigger auto-initialize # trigger auto-initialize
fprint("Arm online. Waiting for calibration.")
# wait for auto-initialize # wait for auto-initialize
def connect(robot):
# init urx if robot.robot is None:
newrobot = Rob(robot.config)
robot = newrobot
ip = robot.ip
fprint("Connecting to arm at " + ip) fprint("Connecting to arm at " + ip)
trying = True trying = True
while trying: while trying:
try: try:
rob = urx.Robot(ip) robot.robot = urx.Robot(ip)
trying = False trying = False
except: except:
time.sleep(1) time.sleep(1)
robotiqgrip = Robotiq_Two_Finger_Gripper(rob)
# Sets robot arm endpoint offset (x,y,z,rx,ry,rz) # Sets robot arm endpoint offset (x,y,z,rx,ry,rz)
rob.set_tcp((0, 0, 0.15, 0, 0, 0)) robot.robot.set_tcp((robot.offset_x, robot.offset_y, robot.offset_z, 0, 0, 0))
# Set weight # Set weight
rob.set_payload(2, (0, 0, 0.1)) robot.robot.set_payload(2, (0, 0, 0.1))
return robot
def init_arm(robot):
robot = connect(robot)
# init urx
#rob.set_payload(2, (0, 0, 0.1)) #rob.set_payload(2, (0, 0, 0.1))
time.sleep(0.2) time.sleep(0.2)
fprint("UR5 ready.") fprint("UR5 ready.")
#return robot.robot
def set_pos_abs(x, y, z, xb, yb, zb, threshold=None): # setup - in case of fail. open gripper, move up, then go home.
global rob rob = robot.robot
open_gripper()
curr_pos = rob.getl()
new_pos = curr_pos
new_pos[2] += 0.025
rob.movel(new_pos, vel=0.05, acc=1)
move_to_home(robot, speed=0.5)
return True
def set_pos_abs(robot, x, y, z, xb, yb, zb, threshold=None):
rob = robot.robot
new_orientation = m3d.Transform() new_orientation = m3d.Transform()
new_orientation.orient.rotate_xb(xb) # Replace rx with the desired rotation around X-axis new_orientation.orient.rotate_xb(xb) # Replace rx with the desired rotation around X-axis
new_orientation.orient.rotate_yb(yb) # Replace ry with the desired rotation around Y-axis new_orientation.orient.rotate_yb(yb) # Replace ry with the desired rotation around Y-axis
@ -67,8 +123,8 @@ def set_pos_abs(x, y, z, xb, yb, zb, threshold=None):
#rob.speedj(0.2, 0.5, 99999) #rob.speedj(0.2, 0.5, 99999)
rob.set_pose(new_trans, acc=2, vel=2, command="movej", threshold=threshold) # apply the new pose rob.set_pose(new_trans, acc=2, vel=2, command="movej", threshold=threshold) # apply the new pose
def set_pos_rel_rot_abs(x, y, z, xb, yb, zb): def set_pos_rel_rot_abs(robot, x, y, z, xb, yb, zb):
global rob rob = robot.robot
new_orientation = m3d.Transform() new_orientation = m3d.Transform()
new_orientation.orient.rotate_xb(xb) # Replace rx with the desired rotation around X-axis new_orientation.orient.rotate_xb(xb) # Replace rx with the desired rotation around X-axis
new_orientation.orient.rotate_yb(yb) # Replace ry with the desired rotation around Y-axis new_orientation.orient.rotate_yb(yb) # Replace ry with the desired rotation around Y-axis
@ -85,8 +141,8 @@ def set_pos_rel_rot_abs(x, y, z, xb, yb, zb):
#rob.speedj(0.2, 0.5, 99999) #rob.speedj(0.2, 0.5, 99999)
rob.set_pose(new_trans, acc=0.1, vel=0.4, command="movej") # apply the new pose rob.set_pose(new_trans, acc=0.1, vel=0.4, command="movej") # apply the new pose
def set_pos_abs_rot_rel(x, y, z, xb, yb, zb): def set_pos_abs_rot_rel(robot, x, y, z, xb, yb, zb):
global rob rob = robot.robot
new_orientation = m3d.Transform() new_orientation = m3d.Transform()
new_orientation.orient.rotate_xb(xb) # Replace rx with the desired rotation around X-axis new_orientation.orient.rotate_xb(xb) # Replace rx with the desired rotation around X-axis
new_orientation.orient.rotate_yb(yb) # Replace ry with the desired rotation around Y-axis new_orientation.orient.rotate_yb(yb) # Replace ry with the desired rotation around Y-axis
@ -131,9 +187,8 @@ def polar_to_cartesian(r, theta):
y = r * np.sin(theta) y = r * np.sin(theta)
return x, y return x, y
def move_to_polar(robot, start_pos, end_pos):
def move_to_polar(start_pos, end_pos): rob = robot.robot
global rob
# Convert to polar coordinates # Convert to polar coordinates
start_r, start_theta = cartesian_to_polar(start_pos[0], start_pos[1]) start_r, start_theta = cartesian_to_polar(start_pos[0], start_pos[1])
@ -190,19 +245,34 @@ def move_to_polar(start_pos, end_pos):
return rx_intermediate return rx_intermediate
def move_to_home():
global rob def move_to_home(robot, keep_flip=False, speed=2):
rob = robot.robot
if is_flipped(robot) and not keep_flip:
flip(robot)
# Move robot to home position
rob.movej(offset_gripper_angle(robot, *(-0.18, -0.108, 0.35), flip=is_flipped(robot)), vel=2, acc=2) # Move to safe position
return True
def move_to_packup(robot, speed=0.25):
rob = robot.robot
# known good starting point to reach store position
goto_holder_index(robot, 12, 0.3, flip=False, use_closest_path=False)
# Home position in degrees # Home position in degrees
home_pos = [0.10421807948612624, store_pos = [-1.5708,
-2.206111555015423, -1.3,
1.710679229503537, 2.362,
-1.075834511928354, 0.7056,
-1.569301366430687, -1.425,
1.675098295930943] 1.5708]
# Move robot # Move robot
rob.movej(home_pos, acc=2, vel=2) rob.movej(store_pos, acc=0.1, vel=speed)
return True
def normalize_degree(theta): def normalize_degree(theta):
# Normalizes degree theta from -1.5pi to 1.5pi # Normalizes degree theta from -1.5pi to 1.5pi
@ -216,13 +286,14 @@ def normalize_degree(theta):
# Return angle # Return angle
return normalized_theta return normalized_theta
def get_joints_from_xyz_rel(robot, x, y, z, rx=0, ry=-math.pi/2, rz=0, initial_guess = (math.pi/2, math.pi/2, 0), l3offset=0):
def get_joints_from_xyz_rel(x, y, z, rx=0, ry=-math.pi/2, rz=0, initial_guess = (math.pi/2, math.pi/2, 0)):
# Get limbs and offsets # Get limbs and offsets
offset_x, offset_y, offset_z = (0, 0, 0.14) # Tool offset
l_bs, l1, l2, l3, l_wt = (0.1333, .425, .39225, .1267, .0997) # Limb lengths
#l3=0.15 #l3=0.15
l_bs, l1, l2, l3, l_wt = (robot.limb_base, robot.limb1, robot.limb2, robot.limb3, robot.limb_wrist) # Limb lengths
l3 += l3offset # add wrist offset, used for gripper angle calculations
offset_x = robot.offset_x
offset_y = robot.offset_y
offset_z = robot.offset_z
# Calculate base angle and r relative to shoulder joint # Calculate base angle and r relative to shoulder joint
def calculate_theta(x, y, a): def calculate_theta(x, y, a):
# Calculate if we need the + or - in our equations # Calculate if we need the + or - in our equations
@ -238,19 +309,16 @@ def get_joints_from_xyz_rel(x, y, z, rx=0, ry=-math.pi/2, rz=0, initial_guess =
# Calculate tangent line y = mx + b # Calculate tangent line y = mx + b
m = (x*y - math.sqrt(x*x*y*y-(x*x-a*a)*(y*y-a*a)))/(x*x-a*a) m = (x*y - math.sqrt(x*x*y*y-(x*x-a*a)*(y*y-a*a)))/(x*x-a*a)
b = flip * a * math.sqrt(1+m*m) b = flip * a * math.sqrt(1+m*m)
# Calculate equivalent tangent point on circle # Calculate equivalent tangent point on circle
cx = (-flip*m*b)/(1+m*m) cx = (-flip*m*b)/(1+m*m)
cy = m*cx + flip*b cy = m*cx + flip*b
# Calculate base angle, make angle negative if flip=1 # Calculate base angle, make angle negative if flip=1
theta = math.atan2(cy, cx) + (-math.pi if flip==1 else 0) theta = math.atan2(cy, cx) + (-math.pi if flip==1 else 0)
return theta return theta
base_theta = calculate_theta(x, y, l_bs) base_theta = calculate_theta(x, y, l_bs)
cx, cy = l_bs*math.cos(base_theta), l_bs*math.sin(l_bs) cx, cy = l_bs*math.cos(base_theta), l_bs*math.sin(base_theta)
r = math.sqrt((x-cx)**2 + (y-cy)**2) r = math.sqrt((x+offset_x+cx)**2 + (y+offset_y+cy)**2)
# Formulas to find out joint positions for (r, z) # Formulas to find out joint positions for (r, z)
@ -264,98 +332,399 @@ def get_joints_from_xyz_rel(x, y, z, rx=0, ry=-math.pi/2, rz=0, initial_guess =
# Normalize angles # Normalize angles
base, shoulder, elbow, wrist1 = [normalize_degree(deg) for deg in [base_theta, *fsolve(inv_kin_r_z, initial_guess)]] base, shoulder, elbow, wrist1 = [normalize_degree(deg) for deg in [base_theta, *fsolve(inv_kin_r_z, initial_guess)]]
wrist1 += rx
# Return result # Return result
return base, shoulder, elbow, wrist1, ry, rz return base, shoulder, elbow, wrist1, ry, rz
def get_joints_from_xyz_abs(x, y, z, rx=0, ry=-math.pi/2, rz=math.pi/2): def get_joints_from_xyz_abs(robot, x, y, z, rx=0, ry=-math.pi/2, rz=math.pi/2, l3offset=0, use_closest_path=True):
joints = get_joints_from_xyz_rel(x, y, z, rx, ry, rz) rob = robot.robot
joints = get_joints_from_xyz_rel(robot, x, y, z, rx, ry, rz, l3offset=l3offset)
# Return current positions if coordinates don't make sense
if z<0:
return rob.getj()
# Joint offsets # Joint offsets
# Base, Shoulder, Elbow, Wrist # Base, Shoulder, Elbow, Wrist
inverse = [1, -1, 1, 1, 1, 1] inverse = [1, -1, 1, 1, 1, 1]
offsets = [-math.pi/2, 0, 0, -math.pi/2, 0, 0] offsets = [-math.pi/2, 0, 0, -math.pi/2, 0, 0]
# Return adjusted joint positions if math.degrees(joints[1]) > 137:
return [o+j*i for j, o, i in zip(joints, offsets, inverse)] print("CRASH! Shoulder at", joints[1] * 180/math.pi)
#else:
#print("Shoulder at", joints[1] * 180/math.pi)
# Get adjusted joint positions
adjusted_joints = [o+j*i for j, o, i in zip(joints, offsets, inverse)]
curr_joints = rob.getj()
def get_complimentary_angle(joint_angle):
if joint_angle<0:
new_angle = joint_angle + 2*math.pi
else:
new_angle = joint_angle - 2*math.pi
if abs(new_angle) > math.radians(350):
return joint_angle
else:
return new_angle
# Use closest path (potentially going beyond 180 degrees)
if use_closest_path:
if abs(get_complimentary_angle(adjusted_joints[0])-curr_joints[0]) < abs(adjusted_joints[0]-curr_joints[0]):
adjusted_joints[0] = get_complimentary_angle(adjusted_joints[0])
# final_joint_positions = []
# for curr_joint, adjusted_joint in zip(curr_joints, adjusted_joints):
# if abs(curr_joint - adjusted_joint) < abs(curr_joint - get_complimentary_angle(adjusted_joint)):
# final_joint_positions.append(adjusted_joint)
# else:
# final_joint_positions.append(get_complimentary_angle(adjusted_joint))
# return final_joint_positions
return adjusted_joints
def move_arc(robot, x, y, z, rx=0, ry=-math.pi/2, rz=math.pi/2):
rob = robot.robot
start_joints = rob.getj()
end_joint = get_joints_from_xyz_abs(robot, x, y, z, rx, ry, rz)
n_points = 50
intermediate_joints = []
for i in range(0, 6):
intermediate_joints.append(np.linspace(start_joints[i], end_joint[i], n_points))
joints = [joint_position for joint_position in zip(*intermediate_joints)]
rob.movejs(joints, acc=2, vel=2, radius=0.1)
def offset_gripper_angle(robot, x, y, z, gripperangle=30, gripperlength=0.20+0.018, flip=False, use_closest_path=True, rzoffset=0):
# gripper angle: from vertical
# gripper length: from joint to start of grip
# to flip, you can use flip=True or make gripper angle negative
limb3 = robot.limb3
# Determine tool rotation depending on gripper angle
if gripperangle < 0:
rz = - math.pi / 2
else:
rz = math.pi / 2
if flip:
gripperangle = -math.radians(gripperangle)
grippery = gripperlength - math.cos(gripperangle) * gripperlength
grippery += math.sin(gripperangle) * limb3
gripperx = math.sin(gripperangle) * gripperlength + limb3 * 2
gripperx -= (1-math.cos(gripperangle)) * limb3
rz = math.pi / 2
# flip the whole wrist
return get_joints_from_xyz_abs(robot, x, y, z-grippery, rx=gripperangle + math.radians(180), l3offset=-gripperx, ry=-3*math.pi/2, rz=rz + rzoffset, use_closest_path=use_closest_path)
else:
gripperangle = math.radians(gripperangle)
grippery = gripperlength - math.cos(gripperangle) * gripperlength
grippery -= math.sin(gripperangle) * limb3
gripperx = math.sin(gripperangle) * gripperlength
gripperx += (1-math.cos(gripperangle)) * limb3
return get_joints_from_xyz_abs(robot, x, y, z-grippery, rx=gripperangle, l3offset=-gripperx, rz=rz, use_closest_path=use_closest_path)
def goto_holder_index(robot, idx, z=0.05, gripperangle=30, flip=False, use_closest_path=True, verbose=False):
joint = robot.config["position_map"][idx]
if verbose:
print("Going to cable holder index", joint["index"], "at position", joint["pos"])
safe_move(robot, joint["pos"][0]/1000, joint["pos"][1]/1000, z, use_closest_path=use_closest_path)
#angles = offset_gripper_angle(joint["pos"][1]/1000, joint["pos"][0]/1000, z, gripperangle=gripperangle, flip=flip)
#rob.movej(angles, acc=2, vel=2)
#return angles
#angles = get_joints_from_xyz_abs(joint["pos"][1]/1000, joint["pos"][0]/1000, 0.05, )
return True
def is_flipped(robot):
rob = robot.robot
wrist1 = rob.getj()[3]
if wrist1 > 0:
return True
else:
return False
def flip(robot):
rob = robot.robot
# A list of safe positions to flip
safe_positions = [(-0.18, -0.108, 0.35),
(0.18, -0.108, 0.35)]
# Find the closest safe position
curr_pos = rob.getl()[:3]
def dist_from_robot(pos):
x, y, z = pos
rx, ry, rz = curr_pos
return math.sqrt((rx-x)**2+(ry-y)**2+(rz-z)**2)
pos_dist_pairs = zip(safe_positions, [dist_from_robot(pos) for pos in safe_positions])
safe_pos = min(pos_dist_pairs, key=lambda x:x[1])[0]
# Flip at safe position
rob.movej(offset_gripper_angle(robot, *safe_pos, flip=is_flipped(robot)), vel=2, acc=2) # Move to safe position
rob.movej(offset_gripper_angle(robot, *safe_pos, flip=(not is_flipped(robot))), vel=2, acc=2) # Flip gripper
# print('flip?: ', is_flipped(robot))
return True
def safe_move(robot, x, y, z, use_closest_path=True):
rob = robot.robot
flip_radius = 0.22 # Min radius on which to flip
r = math.sqrt(x**2 + y**2) # Get position radius
# Flip gripper if needed
if (r <= flip_radius and is_flipped(robot)) or (r > flip_radius and not is_flipped(robot)):
flip(robot)
rob.movej(offset_gripper_angle(robot, x, y, z, flip=is_flipped(robot), use_closest_path=use_closest_path), vel=4, acc=3)
return True
def holder_routine(robot, holder_index, pick_up, verbose=False):
robot = connect(robot)
rob = robot.robot
# Don't attempt to place a tube in the camera slot
if holder_index == 49:
return
if verbose:
fprint('Pickup routine for index' + str(holder_index))
# Go to the correct holder
if pick_up:
goto_holder_index(robot, holder_index, 0.05, use_closest_path=False)
else:
goto_holder_index(robot, holder_index, 0.2, use_closest_path=False)
if pick_up:
open_gripper()
# Move down
curr_pos = rob.getl()
new_pos = curr_pos
new_pos[2] = 0.005
rob.movel(new_pos, vel=0.1, acc=1)
# Pick up or drop off
if pick_up:
close_gripper()
else:
open_gripper()
# Move up
new_pos[2] = 0.2
rob.movel(new_pos, vel=2, acc=1)
was_flipped = is_flipped(robot)
# goto_holder_index(robot, 25, z=0.2)
def pick_up_holder(robot, holder_index, verbose=False):
holder_routine(robot, holder_index, True, verbose=verbose)
def drop_off_holder(robot, holder_index, verbose=False):
holder_routine(robot, holder_index, False, verbose=verbose)
def tray_routine(robot, slot=0, pick_up=True):
robot = connect(robot)
rob = robot.robot
# Default to 0 if invalid value
if slot not in [0, 1, 2, 3]:
slot = 0
slot_prepositions = [(-9.93, -112.67, 144.02, -116.69, -54.13, -10.29),
(-12.35, -124.95, 148.61, -107.27, -54.36, -13.26),
(-16.45, -96.97, 137.85, 58.39, -305.08, 161.75),
(-16.66, -97.28, 138.16, 58.54, -305.05, 161.50)]
# Initial position depending on slot and robot orientation
if slot in [0, 1]:
if is_flipped(robot):
flip(robot)
else:
move_to_home(robot, keep_flip=True)
else:
goto_holder_index(robot, 25, z=0.3)
# Align robot to the slot
if slot in [2,3]:
angles = [(-2.77, -99.64, 131.02, 67.67, 70.04-360, 153.03),
slot_prepositions[slot]]
else:
angles = [(-58, -114.45, 100.52, -45.24, -96.95, 120),
(-39.98, -124.92, 132.28, -61.56, -55.60, -50.77),
slot_prepositions[slot]]
angles = [[x*math.pi/180 for x in move] for move in angles]
rob.movejs(angles,vel=2,acc=1)
# Positions for each slot
slot_distance = .052
slot_height = -.015-.0095
first_slot = -0.3084+0.02
slot_position = [
[first_slot, -0.3426, slot_height, 1.5899, 1.5526, -0.9411],
[first_slot+slot_distance, -0.3426, slot_height, 1.5899, 1.5526, -0.9411],
[first_slot+2*slot_distance, -0.3426, slot_height, 1.5899, 1.5526, -0.9411],
[first_slot+3*slot_distance, -0.3426, slot_height, 1.5899, 1.5526, -0.9411],
]
rob.movel(slot_position[slot],vel=0.2, acc=1)
# Place/Grab the tube
if pick_up:
close_gripper()
else:
open_gripper()
# Move back
tilt = 0.3
curr_pos = rob.getl()
new_pos = curr_pos
if slot==3:
new_pos[0] -= 0.05 #x
new_pos[1] += 0.15 #y
new_pos[2] = 0.09 #z
new_pos[3] += tilt
new_pos[4] += tilt
new_pos[5] += tilt
rob.movel(new_pos, vel=0.2, acc=1)
# Go home to safe position
move_to_home(robot, speed=1, keep_flip=True)
def pick_up_tray(robot, slot=0):
tray_routine(robot, slot, True)
def drop_off_tray(robot, slot=0):
tray_routine(robot, slot, False)
def return_routine(robot, slot, holder_index=None, verbose=False):
robot = connect(robot)
rob = robot.robot
open_gripper()
was_flipped = is_flipped(robot)
if slot is None:
rob.movej(offset_gripper_angle(robot, -0.15, -0.15, 0.3, flip=was_flipped, use_closest_path=False), vel=4, acc=3)
rob.movej(get_joints_from_xyz_abs(robot, -0.35, -0.15, 0.0, math.pi/2, 0.1), vel=4, acc=3)
close_gripper()
else:
xoffset = 0.051 * slot
rob.movej(offset_gripper_angle(robot, -0.15, -0.15, 0.3, flip=was_flipped, use_closest_path=False), vel=4, acc=3)
rob.movej(get_joints_from_xyz_abs(robot, -0.35+xoffset, -0.15, 0.0, math.pi/2, 0.1), vel=4, acc=3)
close_gripper()
if holder_index is not None:
goto_holder_index(robot, holder_index, 0.2, use_closest_path=False)
curr_pos = rob.getl()
new_pos = curr_pos
new_pos[2] = 0.015
rob.movel(new_pos, vel=0.1, acc=1)
open_gripper()
new_pos[2] = 0.1
rob.movel(new_pos, vel=2, acc=1)
return True
else:
# go to camera
rob.movej(offset_gripper_angle(robot, 0.35, -0.35, 0.3, flip=was_flipped, use_closest_path=False), vel=2, acc=2)
return True
def goto_camera(robot):
robot = connect(robot)
goto_holder_index(robot, 49, 0.2)
def tray_to_camera(robot, slot):
pick_up_tray(robot, slot)
goto_camera(robot)
def holder_to_tray(robot, holder_index, slot):
pick_up_holder(robot, holder_index)
drop_off_tray(robot, slot)
def holder_to_camera(robot, holder_index, verbose=False):
robot = connect(robot)
fprint("Bringing tube at " + str(holder_index) + " to camera")
rob = robot.robot
pick_up_holder(robot, holder_index)
goto_camera(robot)
def camera_to_holder(robot, holder_index, verbose=False):
robot = connect(robot)
rob = robot.robot
drop_off_holder(robot, holder_index)
def open_gripper():
fprint("Opening gripper")
c = ModbusClient(host="192.168.1.21", port=502, auto_open=True, auto_close=False)
c.write_single_register(112, 0b0)
c.write_single_register(435, 0b10000000)
c.write_single_register(112, 0b0)
c.write_single_register(435, 0b10000000)
time.sleep(0.5)
c.close()
#c.close()
def close_gripper():
fprint("Closing gripper")
c = ModbusClient(host="192.168.1.21", port=502, auto_open=True, auto_close=False)
c.write_single_register(435, 0b00000000)
c.write_single_register(112, 0b1)
c.write_single_register(435, 0b00000000)
c.write_single_register(112, 0b1)
time.sleep(0.5)
c.close()
#
if __name__ == "__main__": if __name__ == "__main__":
#rob.movej((0, 0, 0, 0, 0, 0), 0.1, 0.2) #init("192.168.1.145")
#rob.movel((x, y, z, rx, ry, rz), a, v) with open('config.yml', 'r') as fileread:
init("192.168.1.145") #global config
config = yaml.safe_load(fileread)
robot = Rob(config) # robot of type Rob is the custom class above
#powerup_arm(robot)
robot = connect(robot)
init_arm(robot)
rob = robot.robot # rob is robot.robot is the urx robot class, what we've been using previously
#move_to_packup(robot)
# for i in range(3):
# pick_up_holder(robot, i)
# print('Drop off', i+1)
# drop_off_holder(robot, i+1)
holder_to_camera(robot, 0)
camera_to_holder(robot, 0)
print("Current tool pose is: ", rob.getl()) print("Current tool pose is: ", rob.getl())
move_to_home()
home_pose = [-0.4999999077032916,
-0.2000072960336574,
0.40002172976662786,
0,
-3.14152741295329,
math.radians(62)]
# time.sleep(.5)
p1 = [0,
0.6,
.4,
0.2226,
3.1126,
0.0510]
p2 = [0.171,
-0.115,
0.2,
0.2226,
3.1126,
0.0510]
curr_pos = rob.getl() curr_pos = rob.getl()
# up/down, config = None
# tool rotation
# tool angle (shouldn't need)
# rob.set_pos(p1[0:3], acc=0.5, vel=0.5)
# set_pos_abs(*home_pose)
angles = get_joints_from_xyz_abs(-0.7, 0, 0)
rob.movej(angles, acc=2, vel=2)
# joints = []
# for i in np.linspace(-0.3, -0.7, 50):
# joints.append(get_joints_from_xyz_abs(i, 0, 0))
# rob.movejs(joints, acc=2, vel=2)
# time.sleep(5)
# angles = get_joints_from_xyz_abs(0, -0.6, 0)
# rob.movej(angles, acc=2, vel=2)
# set_pos_abs(*p1)
# move = move_to_polar(p1, p2)
# for p in move:
# print(math.degrees(p))
# print("Safe? :", is_safe_move(p1, p2))
# #set_pos_rel_rot_abs(0, 0, -0.2, math.pi, 0, -math.pi)
# set_pos_abs(0.3, -0.2, 0.5, math.pi, 0, -math.pi)
# set_pos_abs(0, 0.2, 0.6, math.pi, 0, -math.pi)
# set_pos_abs(-0.5, -0.2, 0.4, math.pi, 0, -math.pi)
# #set_pos_rel_rot_abs(0, 0, 0, math.pi, 0, -math.pi)
# print("Current tool pose is: ", rob.getl())
# print("getj(): ", rob.getj())
# move_to_home()
rob.stop() rob.stop()
os.kill(os.getpid(), 9) # dirty kill of self os.kill(os.getpid(), 9) # dirty kill of self

View File

@ -81,7 +81,7 @@
socket.send(message); socket.send(message);
console.log('Message sent', message); console.log('Message sent', message);
} }
setInterval(ping, 1500); //setInterval(ping, 1500);
// setInterval(() => { // setInterval(() => {
// updateServiceStatus('serviceA', 'down'); // updateServiceStatus('serviceA', 'down');