Compare commits
28
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
069d2175d9 | ||
|
|
9b1b92e21d | ||
|
|
ee0f8f4250 | ||
|
|
9c9435570b | ||
|
|
1bf10f7349 | ||
|
|
3c8d6c7ad3 | ||
|
|
cbe7225fc9 | ||
|
|
44efc4006e | ||
|
|
218303e92b | ||
|
|
e5d3f87b5c | ||
|
|
2ab1d0dbb3 | ||
|
|
1338c3f440 | ||
|
|
83b077b4df | ||
|
|
f16242f5be | ||
|
|
2f28a01b7c | ||
|
|
fb85a56d47 | ||
|
|
bec0c63763 | ||
|
|
4ae30b82a0 | ||
|
|
4bc3e30116 | ||
|
|
6053d1b4ec | ||
|
|
f43f9cda2f | ||
|
|
992040e812 | ||
|
|
5502a5069d | ||
|
|
fc2af34450 | ||
|
|
39723ec442 | ||
|
|
25ceb6c133 | ||
|
|
56451d3e5c | ||
|
|
53638f72e1
|
No files matched your search
+5
-1
@@ -15,4 +15,8 @@ output.mp4
|
||||
# log files
|
||||
output.log
|
||||
# images
|
||||
*.png
|
||||
map*.png
|
||||
# Built app
|
||||
build
|
||||
# Generated label images
|
||||
labels
|
||||
+5
-3
@@ -1,7 +1,9 @@
|
||||
FROM python:latest
|
||||
FROM python:3.11-slim
|
||||
|
||||
RUN apt-get update && apt-get install -y libgl1-mesa-glx ghostscript && apt-get clean && rm -rf /var/lib/apt/lists
|
||||
COPY . .
|
||||
# Get runtime dependencies
|
||||
# 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
|
||||
COPY *.py *.yml *.sh *.txt *.html static templates ./
|
||||
#COPY config-server.yml config.yml
|
||||
RUN pip3 install -r requirements.txt
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 448 KiB |
@@ -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 |
+81
-40
@@ -27,6 +27,7 @@ def check_internet(url='https://belden.com', timeout=5):
|
||||
|
||||
|
||||
def query_search(partnum, source):
|
||||
fprint("Searching for " + partnum)
|
||||
if source == "Belden":
|
||||
token_url = "https://www.belden.com/coveo/rest/token?t=" + str(int(time.time()))
|
||||
with requests.get(token_url) as r:
|
||||
@@ -52,15 +53,15 @@ def query_search(partnum, source):
|
||||
a = json.loads(a)
|
||||
idx = -1
|
||||
name = ""
|
||||
for partid in range(len(a["results"])):
|
||||
for partid in range(len(a["results"])-1, -1, -1):
|
||||
name = a["results"][partid]["title"]
|
||||
if name != partnum:
|
||||
if name.find(partnum) >= 0:
|
||||
idx = partid
|
||||
break
|
||||
#break
|
||||
elif partnum.find(name) >= 0:
|
||||
idx = partid
|
||||
break
|
||||
#break
|
||||
|
||||
else:
|
||||
idx = partid
|
||||
@@ -69,7 +70,9 @@ def query_search(partnum, source):
|
||||
if idx < 0:
|
||||
fprint("Could not find part in API: " + partnum)
|
||||
return False
|
||||
fprint("Search result found: result " + str(idx) + ", for ID " + name)
|
||||
|
||||
name = a["results"][idx]["title"]
|
||||
#fprint("Search result found: result " + str(idx) + ", for ID " + name)
|
||||
#urlname = a["results"][0]["raw"]["catalogitemurlname"]
|
||||
img = a["results"][idx]["raw"]["catalogitemimageurl"]
|
||||
img = img[0:img.index("?")]
|
||||
@@ -92,7 +95,7 @@ def query_search(partnum, source):
|
||||
#print(out)
|
||||
return out
|
||||
except:
|
||||
print("falied to search with API. Falling back to datasheet lookup.")
|
||||
print("Failed to search with API. Falling back to datasheet lookup.")
|
||||
return False
|
||||
|
||||
|
||||
@@ -112,12 +115,14 @@ def query_search(partnum, source):
|
||||
r = requests.get(url=alphaurl)
|
||||
data = r.json()
|
||||
output = dict()
|
||||
#print(data)
|
||||
#print(data["Results"])
|
||||
|
||||
try:
|
||||
if data["Count"] > 0:
|
||||
#print(data["Results"][0]["Url"])
|
||||
for result in data["Results"]:
|
||||
if result["Url"].split("/")[-1] == partnum:
|
||||
#print(result["Url"])
|
||||
if result["Url"].split("/")[-1] == partnum.replace("-", "").replace("/", "_"):
|
||||
#print(partnum)
|
||||
#print(result["Html"])
|
||||
try:
|
||||
@@ -133,14 +138,18 @@ def query_search(partnum, source):
|
||||
dsidx = result["Html"].index("<a href=\"/disteAPI/") + 9
|
||||
dsidx2 = result["Html"].index(partnum, dsidx) + len(partnum)
|
||||
output["datasheet"] = "https://www.alphawire.com" + result["Html"][dsidx:dsidx2]
|
||||
output["partnum"] = partnum
|
||||
output["partnum"] = partnum.replace("/", "_") #.replace("-", "").replace("/", "_")
|
||||
#
|
||||
# "test".index()
|
||||
#print(output)
|
||||
return output
|
||||
|
||||
|
||||
except:
|
||||
print("Failed to search with API. Falling back to datasheet lookup.")
|
||||
return False
|
||||
|
||||
print("Failed to search with API. Falling back to datasheet lookup.")
|
||||
return False
|
||||
|
||||
|
||||
@@ -150,14 +159,19 @@ def touch(path):
|
||||
|
||||
|
||||
|
||||
def get_multi(partnums, delay=0.25):
|
||||
def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
|
||||
with alive_bar(len(partnums) * 2, dual_line=True, calibrate=30, bar="classic2", spinner="classic") as bar:
|
||||
|
||||
def _try_download_datasheet(partnum, output_dir): # Guess datasheet URL
|
||||
failed = list()
|
||||
actualpartnums = list()
|
||||
def _try_download_datasheet(partnum, output_dir, dstype): # Guess datasheet URL
|
||||
global bartext
|
||||
|
||||
if dstype == "Belden":
|
||||
sanitized_name = partnum.replace(" ", "")
|
||||
url = "https://catalog.belden.com/techdata/EN/" + sanitized_name + "_techdata.pdf"
|
||||
elif dstype == "Alphawire":
|
||||
# Alphawire Datasheet URLs do not use a sanitized part number (but product pages do)
|
||||
url = "https://www.alphawire.com/disteAPI/SpecPDF/DownloadProductSpecPdf?productPartNumber=" + partnum
|
||||
#fprint(url)
|
||||
try:
|
||||
with requests.get(url, stream=True) as r:
|
||||
@@ -167,8 +181,9 @@ def get_multi(partnums, delay=0.25):
|
||||
if r.status_code == 404:
|
||||
return False
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
bartext = ""
|
||||
with open(output_dir + "/datasheet.pdf", 'wb') as f:
|
||||
for chunk in r.iter_content(chunk_size=131072):
|
||||
for chunk in r.iter_content(chunk_size=65536):
|
||||
# If you have chunk encoded response uncomment if
|
||||
# and set chunk_size parameter to None.
|
||||
#if chunk:
|
||||
@@ -195,8 +210,9 @@ def get_multi(partnums, delay=0.25):
|
||||
if r.status_code == 404:
|
||||
return False
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
bartext = ""
|
||||
with open(output_dir + "/datasheet.pdf", 'wb') as f:
|
||||
for chunk in r.iter_content(chunk_size=131072):
|
||||
for chunk in r.iter_content(chunk_size=65536):
|
||||
# If you have chunk encoded response uncomment if
|
||||
# and set chunk_size parameter to None.
|
||||
#if chunk:
|
||||
@@ -221,8 +237,9 @@ def get_multi(partnums, delay=0.25):
|
||||
if r.status_code == 404:
|
||||
return False
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
bartext = ""
|
||||
with open(output_dir + "/part-hires." + url.split(".")[-1], 'wb') as f:
|
||||
for chunk in r.iter_content(chunk_size=131072):
|
||||
for chunk in r.iter_content(chunk_size=65536):
|
||||
# If you have chunk encoded response uncomment if
|
||||
# and set chunk_size parameter to None.
|
||||
#if chunk:
|
||||
@@ -245,8 +262,9 @@ def get_multi(partnums, delay=0.25):
|
||||
fprint("Parsing Datasheet contents of " + partnum)
|
||||
bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..."
|
||||
|
||||
read_datasheet.parse(path, output_dir, partnum, dstype)
|
||||
out = read_datasheet.parse(path, output_dir, partnum, dstype)
|
||||
bar(skipped=False)
|
||||
return out
|
||||
else:
|
||||
fprint("Datasheet already parsed for " + partnum)
|
||||
bar.text = "Datasheet already parsed for " + partnum + ".pdf"
|
||||
@@ -258,57 +276,74 @@ def get_multi(partnums, delay=0.25):
|
||||
bar(skipped=False)
|
||||
fprint("Parsing Datasheet contents of " + partnum)
|
||||
bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..."
|
||||
read_datasheet.parse(path, output_dir, partnum, dstype)
|
||||
out = read_datasheet.parse(path, output_dir, partnum, dstype)
|
||||
bar(skipped=False)
|
||||
return out
|
||||
|
||||
def run_search(partnum):
|
||||
output_dir = "cables/" + partnum
|
||||
partnum = partnum.replace("%20", " ") # undo URL encoding
|
||||
oldpartnum = partnum
|
||||
if dstype == "Alphawire":
|
||||
# For alphawire, sanitize the part number for only the final result check, because their API is very wierd
|
||||
# For the actual search, it must be un-sanitized
|
||||
partnum = partnum.replace("/","_")
|
||||
output_dir = dir + partnum
|
||||
path = output_dir + "/datasheet.pdf"
|
||||
bartext = "Downloading files for part " + partnum
|
||||
bar.text = bartext
|
||||
#
|
||||
if (not os.path.exists(output_dir + "/found_part_hires")) or not (os.path.exists(path) and os.path.getsize(path) > 1):
|
||||
partnum = oldpartnum.replace("_","/")
|
||||
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:
|
||||
# Use query
|
||||
search_result = query_search(partnum, dstype)
|
||||
# Try to use belden.com search
|
||||
if search_result is not False:
|
||||
# Download high resolution part image if available and needed
|
||||
#oldpartnum = partnum
|
||||
partnum = search_result["partnum"]
|
||||
output_dir = "cables/" + partnum
|
||||
returnval = [partnum, dstype, False, False]
|
||||
output_dir = dir + partnum
|
||||
path = output_dir + "/datasheet.pdf"
|
||||
bartext = "Downloading files for part " + partnum
|
||||
bar.text = bartext
|
||||
|
||||
if not os.path.exists(output_dir + "/found_part_hires"):
|
||||
if not os.path.exists(output_dir + "/found_part_hires") or not cache:
|
||||
if _download_image(search_result["image"], output_dir):
|
||||
fprint("Downloaded hi-res part image for " + partnum)
|
||||
returnval = [partnum, dstype, True, False]
|
||||
touch(output_dir + "/found_part_hires")
|
||||
else:
|
||||
fprint("Using cached hi-res part image for " + partnum)
|
||||
|
||||
# Download datasheet from provided URL if needed
|
||||
if os.path.exists(path) and os.path.getsize(path) > 1:
|
||||
__use_cached_datasheet(partnum, path, output_dir, dstype)
|
||||
if os.path.exists(path) and os.path.getsize(path) > 1 and cache:
|
||||
out = __use_cached_datasheet(partnum, path, output_dir, dstype)
|
||||
returnval = [partnum, dstype, True, out]
|
||||
|
||||
elif _download_datasheet(search_result["datasheet"], output_dir) is not False:
|
||||
__downloaded_datasheet(partnum, path, output_dir, dstype)
|
||||
out = __downloaded_datasheet(partnum, path, output_dir, dstype)
|
||||
returnval = [partnum, dstype, True, out]
|
||||
|
||||
elif os.path.exists(path) and os.path.getsize(path) > 1:
|
||||
__use_cached_datasheet(partnum, path, output_dir, dstype)
|
||||
elif os.path.exists(path) and os.path.getsize(path) > 1 and cache:
|
||||
out = __use_cached_datasheet(partnum, path, output_dir, dstype)
|
||||
returnval = [partnum, dstype, True, out]
|
||||
|
||||
# If search fails, and we don't already have the datasheet, guess datasheet URL and skip the hires image download
|
||||
elif _try_download_datasheet(partnum, output_dir) is not False:
|
||||
__downloaded_datasheet(partnum, path, output_dir, dstype)
|
||||
elif _try_download_datasheet(partnum, output_dir, dstype) is not False:
|
||||
out = __downloaded_datasheet(partnum, path, output_dir, dstype)
|
||||
returnval = [partnum, dstype, False, out]
|
||||
|
||||
# Failed to download with search or guess :(
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
actualpartnums.append(returnval)
|
||||
return returnval
|
||||
|
||||
# We already have a hi-res image and the datasheet - perfect!
|
||||
else:
|
||||
fprint("Using cached hi-res part image for " + partnum)
|
||||
__use_cached_datasheet(partnum, path, output_dir, dstype)
|
||||
out = __use_cached_datasheet(partnum, path, output_dir, dstype)
|
||||
returnval = [partnum, dstype, False, out]
|
||||
return True
|
||||
|
||||
for fullpartnum in partnums:
|
||||
@@ -339,7 +374,7 @@ def get_multi(partnums, delay=0.25):
|
||||
if not success:
|
||||
fprint("Failed to download datasheet for part " + partnum)
|
||||
bar.text = "Failed to download datasheet for part " + partnum
|
||||
failed.append(partnum)
|
||||
failed.append((partnum, dstype))
|
||||
bar(skipped=True)
|
||||
bar(skipped=True)
|
||||
time.sleep(delay)
|
||||
@@ -347,10 +382,10 @@ def get_multi(partnums, delay=0.25):
|
||||
if len(failed) > 0:
|
||||
fprint("Failed to download:")
|
||||
for partnum in failed:
|
||||
fprint(partnum)
|
||||
return False # Go to manual review upload page
|
||||
fprint(partnum[1] + " " + partnum[0])
|
||||
return False, actualpartnums # Go to manual review upload page
|
||||
else:
|
||||
return True # All cables downloaded; we are good to go
|
||||
return True, actualpartnums # All cables downloaded; we are good to go
|
||||
|
||||
|
||||
|
||||
@@ -373,11 +408,12 @@ if __name__ == "__main__":
|
||||
# ]
|
||||
partnums = [
|
||||
# Actual cables in Jukebox
|
||||
|
||||
"AW86104CY",
|
||||
"AW3050",
|
||||
"AW6714",
|
||||
"AW1172C",
|
||||
"AW2211/4",
|
||||
"AWFIT-221-1/4",
|
||||
|
||||
"BLTF-1LF-006-RS5N",
|
||||
"BLTF-SD9-006-RI5N",
|
||||
@@ -405,7 +441,7 @@ if __name__ == "__main__":
|
||||
|
||||
# Some ones I picked, including some invalid ones
|
||||
"BL10GXS12",
|
||||
"BLRST 5L-RKT 5L-949",
|
||||
"BLRST%205L-RKT%205L-949",
|
||||
"BL10GXS13",
|
||||
"BL10GXW12",
|
||||
"BL10GXW13",
|
||||
@@ -416,12 +452,17 @@ if __name__ == "__main__":
|
||||
"BLFISD012R9",
|
||||
"BLFDSD012A9",
|
||||
"BLFSSL024NG",
|
||||
"BLFISX006W0",
|
||||
"BLFISX00103",
|
||||
"BLC6D1100007"
|
||||
"BLFISX006W0", # datasheet only
|
||||
"BLFISX00103", # invalid
|
||||
"BLC6D1100007" # invalid
|
||||
|
||||
]
|
||||
#query_search("86104CY", "Alphawire")
|
||||
#print(query_search("TT-SLG-024-HTNN", "Belden"))
|
||||
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")
|
||||
|
||||
|
||||
Binary file not shown.
@@ -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>
|
||||
+224
-181
@@ -9,7 +9,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"execution_count": 81,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -28,7 +28,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"execution_count": 82,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -52,16 +52,23 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 157,
|
||||
"execution_count": 83,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[45.0, 90.70951422006029, 110.71500355039022, -20.005489330329944]\n",
|
||||
"[45.0, -90.70951422006029, 110.71500355039022, -110.00548933032994]\n"
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[-243.619306486927,\n",
|
||||
" -123.2097721836616,\n",
|
||||
" 140.34764917140853,\n",
|
||||
" -107.13787698774695,\n",
|
||||
" -90.0,\n",
|
||||
" 90.0]"
|
||||
]
|
||||
},
|
||||
"execution_count": 83,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
@@ -77,88 +84,99 @@
|
||||
" # Return angle\n",
|
||||
" return normalized_theta\n",
|
||||
"\n",
|
||||
"def get_joints_from_xyz_rel(x, y, z, initial_guess = (math.pi/2, math.pi/2, 0), limbs=(.422864, .359041, .092124)):\n",
|
||||
" # Get polar coordinates of x,y pair\n",
|
||||
" r, theta = cartesian_to_polar(x, y)\n",
|
||||
"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)):\n",
|
||||
" # Get limbs and offsets\n",
|
||||
" offset_x, offset_y, offset_z = (0, 0, 0.14) # Tool offset\n",
|
||||
" l_bs, l1, l2, l3, l_wt = (0.1333, .425, .39225, .1267, .0997) # Limb lengths\n",
|
||||
" \n",
|
||||
" # Calculate base angle and r relative to shoulder joint\n",
|
||||
" def calculate_theta(x, y, a):\n",
|
||||
" # Calculate if we need the + or - in our equations\n",
|
||||
" if (x>a and y>=0) or (x>-a and y<0):\n",
|
||||
" flip = 1\n",
|
||||
" elif (x<a and y>=0) or (x<-a and y<0):\n",
|
||||
" flip = -1\n",
|
||||
" else: \n",
|
||||
" # Critical section (x=a, or x=-a). Infinite slope\n",
|
||||
" # Return 0 or 180 depending on sign\n",
|
||||
" return math.atan2(y, 0) - math.pi/2\n",
|
||||
" \n",
|
||||
" # Calculate tangent line y = mx + b\n",
|
||||
" if abs(a) != abs(x): # If there is no division by 0\n",
|
||||
" m = (x*y + math.sqrt(x*x*y*y-(x*x-a*a)*(y*y-a*a)))/(x*x-a*a)\n",
|
||||
" else: # Deal with edge case when x^2=a^2\n",
|
||||
" m = flip*(-a*a+y*y)/(a*y-flip*abs(a*y))\n",
|
||||
" b = flip * a * math.sqrt(1+m*m)\n",
|
||||
"\n",
|
||||
" # Calculate equivalent tangent point on circle\n",
|
||||
" cx = (-flip*m*b)/(1+m*m)\n",
|
||||
" cy = m*cx + flip*b\n",
|
||||
"\n",
|
||||
" # Calculate base angle, make angle negative if flip=1\n",
|
||||
" theta = math.atan2(cy, cx) + (-math.pi if flip==1 else 0)\n",
|
||||
"\n",
|
||||
" return theta \n",
|
||||
" \n",
|
||||
" base_theta = calculate_theta(x, y, l_bs)\n",
|
||||
" cx, cy = l_bs*math.cos(base_theta), l_bs*math.sin(base_theta)\n",
|
||||
" r = math.sqrt((x-cx)**2 + (y-cy)**2) \n",
|
||||
"\n",
|
||||
" # Get length of each limb\n",
|
||||
" l1, l2, l3 = limbs\n",
|
||||
"\n",
|
||||
" # Formulas to find out joint positions for (r, z)\n",
|
||||
" def inv_kin_r_z(p):\n",
|
||||
" a, b, c = p \n",
|
||||
"\n",
|
||||
" return (l1*math.cos(a) + l2*math.cos(a-b) + l3*math.cos(a-b-c) - r, # r\n",
|
||||
" l1*math.sin(a) + l2*math.sin(a-b) - l3*math.sin(a-b-c) - z, # z\n",
|
||||
" l1*math.sin(a) + l2*math.sin(a-b) - l3*math.sin(a-b-c) - (l3*math.sin(a-b-c)) - (z + offset_z), # z\n",
|
||||
" a-b-c) # wrist angle\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" # Normalize angles\n",
|
||||
" base, shoulder, elbow, wrist = [normalize_degree(deg) for deg in [theta, *fsolve(inv_kin_r_z, initial_guess)]]\n",
|
||||
" base, shoulder, elbow, wrist1 = [normalize_degree(deg) for deg in [base_theta, *fsolve(inv_kin_r_z, initial_guess)]]\n",
|
||||
"\n",
|
||||
" # Return result\n",
|
||||
" return base, shoulder, elbow, wrist\n",
|
||||
" return base, shoulder, elbow, wrist1, ry, rz\n",
|
||||
"\n",
|
||||
"def get_joints_from_xyz_abs(x, y, z):\n",
|
||||
" joints = get_joints_from_xyz_rel(x, y, z)\n",
|
||||
"def get_joints_from_xyz_abs(x, y, z, rx=0, ry=-math.pi/2, rz=math.pi/2):\n",
|
||||
" joints = get_joints_from_xyz_rel(x, y, z, rx, ry, rz)\n",
|
||||
"\n",
|
||||
" # Joint offsets\n",
|
||||
" # Base, Shoulder, Elbow, Wrist\n",
|
||||
" inverse = [1, -1, 1, 1]\n",
|
||||
" offsets = [0, 0, 0, -math.pi/2]\n",
|
||||
" inverse = [1, -1, 1, 1, 1, 1]\n",
|
||||
" offsets = [-math.pi/2, 0, 0, -math.pi/2, 0, 0]\n",
|
||||
"\n",
|
||||
" # Return adjusted joint positions\n",
|
||||
" return [o+j*i for j, o, i in zip(joints, offsets, inverse)]\n",
|
||||
"\n",
|
||||
"print([math.degrees(deg) for deg in get_joints_from_xyz_rel(0.3, 0.3, 0.3)])\n",
|
||||
"print([math.degrees(deg) for deg in get_joints_from_xyz_abs(0.3, 0.3, 0.3)])"
|
||||
"# Print degree rotation for each joint (robot angles)\n",
|
||||
"[math.degrees(deg) for deg in get_joints_from_xyz_abs(0, -0.3, 0.1)]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Simulate arm and joint angles"
|
||||
"### Simulate Arm and Joint Angles"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 164,
|
||||
"execution_count": 84,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Target position (x,y,z): 0.3 0.3 0.3\n",
|
||||
"Angles (base, shoulder, elbow, wrist): [45.0, 90.7095, 110.715, -20.0055]\n",
|
||||
"Robot Angles: [45.0, -90.7095, 110.715, -110.0055]\n",
|
||||
"elbow (x,y): -0.005 0.423\n",
|
||||
"wrist (x,y): 0.332 0.3\n",
|
||||
"tool (x,y): 0.424 0.3\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 640x480 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def draw_arm(x, y, z):\n",
|
||||
"def draw_arm_side_view(x, y, z, details=False):\n",
|
||||
"\n",
|
||||
" # Get joint angles\n",
|
||||
" l1, l2, l3 = (.422864, .359041, .092124)\n",
|
||||
" l1, l2, l3 = .425, .39225, .1267\n",
|
||||
" offset_x, offset_y, offset_z = (0, 0, 0.14)\n",
|
||||
" r, theta = cartesian_to_polar(x, y)\n",
|
||||
" base, shoulder, elbow, wrist = get_joints_from_xyz_rel(x, y, z)\n",
|
||||
" base, shoulder, elbow, wrist, _, _ = get_joints_from_xyz_rel(x, y, z)\n",
|
||||
"\n",
|
||||
" # Print angles\n",
|
||||
" if details:\n",
|
||||
" print('Target position (x,y,z):', x, y, z)\n",
|
||||
" print('R: ', round(math.sqrt(x**2+y**2),4))\n",
|
||||
" print('Angles (base, shoulder, elbow, wrist):', [round(math.degrees(i), 4) for i in [base, shoulder, elbow, wrist]])\n",
|
||||
" print('Robot Angles:', [round(math.degrees(i), 4) for i in get_joints_from_xyz_abs(x, y, z)])\n",
|
||||
"\n",
|
||||
@@ -171,7 +189,11 @@
|
||||
" x3 += x2\n",
|
||||
" y3 += y2 \n",
|
||||
" \n",
|
||||
" tx = x3\n",
|
||||
" ty = y3 - offset_z\n",
|
||||
"\n",
|
||||
" # Print each joint's endpoint position\n",
|
||||
" if details:\n",
|
||||
" print('elbow (x,y):', round(x1,3), round(y1,3))\n",
|
||||
" print('wrist (x,y):', round(x2,3), round(y2,3))\n",
|
||||
" print('tool (x,y):', round(x3,3), round(y3,3))\n",
|
||||
@@ -180,6 +202,10 @@
|
||||
" plt.plot([0, x1], [0, y1], color='cyan', linewidth=7)\n",
|
||||
" plt.plot([x1, x2], [y1, y2], color='orange', linewidth=7)\n",
|
||||
" plt.plot([x2, x2+l3], [y2, y2], color='red', linewidth=7)\n",
|
||||
" plt.plot()\n",
|
||||
"\n",
|
||||
" # Draw toolpoint\n",
|
||||
" plt.plot([x3, tx], [y3, ty], color='black', linewidth=7)\n",
|
||||
"\n",
|
||||
" # Display angles\n",
|
||||
" plt.text(0, 0.02, f'{round(math.degrees(shoulder), 2)}°')\n",
|
||||
@@ -191,140 +217,14 @@
|
||||
" plt.annotate(f'r={round(r,4)}', xy=(x2/2, 0.01), xycoords='data', xytext=(x2/2, 0), textcoords='offset points')\n",
|
||||
"\n",
|
||||
" # Display z arrow\n",
|
||||
" plt.annotate(f'', xy=(x3, 0), xycoords='data', xytext=(x3, y3), textcoords='data', arrowprops={'arrowstyle': '<->'})\n",
|
||||
" plt.annotate(f'z={round(y2,4)}', xy=(x3+0.01, y2/2), xycoords='data', xytext=(x3/2, 0), textcoords='offset points')\n",
|
||||
" plt.annotate(f'', xy=(x3, 0), xycoords='data', xytext=(tx, ty), textcoords='data', arrowprops={'arrowstyle': '<->'})\n",
|
||||
" plt.annotate(f'z={round(ty,4)}', xy=(tx+0.01, ty/2), xycoords='data', xytext=(x3/2, 0), textcoords='offset points')\n",
|
||||
" \n",
|
||||
" # Display plot\n",
|
||||
" ax = plt.subplot(111)\n",
|
||||
" ax.spines[['right', 'top']].set_visible(False)\n",
|
||||
" plt.axis('equal')\n",
|
||||
" plt.show()\n",
|
||||
"\n",
|
||||
"draw_arm(0.3, 0.3, 0.3)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 165,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Target position (x,y,z): 0.3 0.3 0.3\n",
|
||||
"Angles (base, shoulder, elbow, wrist): [45.0, 90.7095, 110.715, -20.0055]\n",
|
||||
"Robot Angles: [45.0, -90.7095, 110.715, -110.0055]\n",
|
||||
"elbow (x,y): -0.005 0.423\n",
|
||||
"wrist (x,y): 0.332 0.3\n",
|
||||
"tool (x,y): 0.424 0.3\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 640x480 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Target position (x,y,z): -0.3 -0.3 0.7\n",
|
||||
"Angles (base, shoulder, elbow, wrist): [-135.0, 71.7346, 15.5104, 56.2242]\n",
|
||||
"Robot Angles: [-135.0, -71.7346, 15.5104, -33.7758]\n",
|
||||
"elbow (x,y): 0.133 0.402\n",
|
||||
"wrist (x,y): 0.332 0.7\n",
|
||||
"tool (x,y): 0.424 0.7\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 640x480 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Target position (x,y,z): -0.3 0.4 0.2\n",
|
||||
"Angles (base, shoulder, elbow, wrist): [126.8699, 74.2826, 109.5002, -35.2176]\n",
|
||||
"Robot Angles: [126.8699, -74.2826, 109.5002, -125.2176]\n",
|
||||
"elbow (x,y): 0.115 0.407\n",
|
||||
"wrist (x,y): 0.408 0.2\n",
|
||||
"tool (x,y): 0.5 0.2\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 640x480 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"draw_arm(0.3, 0.3, 0.3)\n",
|
||||
"draw_arm(-0.3, -0.3, 0.7)\n",
|
||||
"draw_arm(-0.3, 0.4, 0.2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Interactive Arm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 160,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "5617bc9f737949c4bc84c787ff88ce16",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"interactive(children=(FloatSlider(value=0.3, description='x', max=1.0, step=0.01), FloatSlider(value=0.3, desc…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"<function __main__.draw_arm(x, y, z)>"
|
||||
]
|
||||
},
|
||||
"execution_count": 160,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from ipywidgets import interact, FloatSlider\n",
|
||||
"\n",
|
||||
"# Interactive slider for z coordinate\n",
|
||||
"interact(draw_arm, x=FloatSlider(min=0, max=1, step=0.01, value=0.3),\n",
|
||||
" y=FloatSlider(min=0, max=1, step=0.01, value=0.3),\n",
|
||||
" z=FloatSlider(min=0, max=1, step=0.01, value=0.3))\n"
|
||||
" plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -332,7 +232,150 @@
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
"source": [
|
||||
"def draw_arm_top_view(x, y, z, details=False):\n",
|
||||
" # Get joint and position information\n",
|
||||
" angles = get_joints_from_xyz_rel(x, y, z)\n",
|
||||
" offset_x, offset_y, offset_z = (0, 0, 0.14) # Tool offset\n",
|
||||
" l_bs, l1, l2, l3, l_wt = (0.1333, .425, .39225, .1267, .0997) # Limb lengths\n",
|
||||
" cx, cy = l_bs*math.cos(angles[0]), l_bs*math.sin(angles[0]) # Base tangent point\n",
|
||||
" line_angle = math.pi/2+angles[0]\n",
|
||||
"\n",
|
||||
" if details:\n",
|
||||
" print('Angles:', [round(math.degrees(angle),3) for angle in angles])\n",
|
||||
" print(f'Circle position (cx, cy): ({round(cx, 3)}, {round(cy, 3)})')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" # Plot coordinate system\n",
|
||||
" fig = plt.figure()\n",
|
||||
" ax = fig.add_subplot(1, 1, 1)\n",
|
||||
" ax.spines['left'].set_position('center')\n",
|
||||
" ax.spines['bottom'].set_position('center')\n",
|
||||
" ax.spines['right'].set_color('none')\n",
|
||||
" ax.spines['top'].set_color('none')\n",
|
||||
" ax.set_yticklabels([])\n",
|
||||
" ax.set_xticklabels([])\n",
|
||||
" ax.set_xticks([])\n",
|
||||
" ax.set_yticks([])\n",
|
||||
"\n",
|
||||
" # Target point\n",
|
||||
" # plt.plot(x, y, 'go')\n",
|
||||
"\n",
|
||||
" # Circle\n",
|
||||
" circle = plt.Circle((0, 0), l_bs, color='b', fill=False, linewidth=1)\n",
|
||||
" plt.plot([0, cx], [0, cy], color='b', linewidth=1)\n",
|
||||
" ax.add_patch(circle)\n",
|
||||
"\n",
|
||||
" # Draw limbs\n",
|
||||
" # Shoulder\n",
|
||||
" x1, y1 = polar_to_cartesian(l1*math.cos(angles[1]), line_angle)\n",
|
||||
" x1, y1 = cx+x1, cy+y1\n",
|
||||
" z1 = l1*math.sin(angles[1])\n",
|
||||
" plt.plot([cx, x1], [cy, y1], color='cyan', linewidth=3)\n",
|
||||
"\n",
|
||||
" # Elbow\n",
|
||||
" x2, y2 = polar_to_cartesian(l2*math.cos(angles[1]-angles[2]), line_angle)\n",
|
||||
" x2 += x1\n",
|
||||
" y2 += y1\n",
|
||||
" z2 = z1 + l2*math.sin(angles[1]-angles[2])\n",
|
||||
" plt.plot([x1, x2], [y1, y2], color='orange', linewidth=2)\n",
|
||||
"\n",
|
||||
" # Wrist\n",
|
||||
" x3, y3 = polar_to_cartesian(l3*math.cos(angles[1]-angles[2]-angles[3]), line_angle)\n",
|
||||
" x3 += x2\n",
|
||||
" y3 += y2\n",
|
||||
" z3 = z2 + l3*math.sin(angles[1]-angles[2]-angles[3]) \n",
|
||||
" plt.plot([x2, x3], [y2, y3], color='red', linewidth=2)\n",
|
||||
"\n",
|
||||
" # Print joint positions\n",
|
||||
" if details:\n",
|
||||
" print(f'Shoulder (x, y, z): ({round(x1,3)}, {round(y1,3)}, {round(z1,3)})')\n",
|
||||
" print(f'Elbow (x, y, z): ({round(x2,3)}, {round(y2,3)}, {round(z2,3)})')\n",
|
||||
" print(f'Wrist (x, y, z): ({round(x3,3)}, {round(y3,3)}, {round(z3,3)})')\n",
|
||||
"\n",
|
||||
" # Display angle\n",
|
||||
" plt.text(0.01, -0.01-cy/abs(cy+0.00001)*0.02, f'{round(math.degrees(angles[0]), 2)}°', fontsize=7)\n",
|
||||
"\n",
|
||||
" # Display x arrow\n",
|
||||
" sign = x3/abs(x3)\n",
|
||||
" plt.annotate(f'', xy=(0, y3), xycoords='data', xytext=(x3, y3), textcoords='data', arrowprops={'arrowstyle': '<->'})\n",
|
||||
" plt.annotate(f'x={round(x3,3)}', xy=(-0.1-sign*0.13, y3-0.015), xycoords='data', xytext=(x2/2, 0), textcoords='offset points')\n",
|
||||
"\n",
|
||||
" # Display y arrow\n",
|
||||
" sign = y3/abs(y3)\n",
|
||||
" plt.annotate(f'', xy=(x3, 0), xycoords='data', xytext=(x3, y3), textcoords='data', arrowprops={'arrowstyle': '<->'})\n",
|
||||
" plt.annotate(f'y={round(y3,3)}', xy=((x3-0.1), -0.015-sign*0.03), xycoords='data', xytext=(x3/2, 0), textcoords='offset points')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" # Set axis limits and labels\n",
|
||||
" axis_limit = math.hypot(x, y)+.1\n",
|
||||
" plt.axis('square')\n",
|
||||
" plt.xlim(-axis_limit, axis_limit)\n",
|
||||
" plt.ylim(-axis_limit, axis_limit)\n",
|
||||
"\n",
|
||||
" # Adjust the position of axis labels\n",
|
||||
" plt.xlabel('+x', horizontalalignment='right', x=1.05)\n",
|
||||
" plt.ylabel('+y', verticalalignment='top', rotation=0, y=1.05)\n",
|
||||
" plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 89,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Target position (x,y,z): 0.5 0.5 0.3\n",
|
||||
"R: 0.7071\n",
|
||||
"Angles (base, shoulder, elbow, wrist): [-34.1339, 65.0453, 57.0325, 8.0128]\n",
|
||||
"Robot Angles: [-124.1339, -65.0453, 57.0325, -81.9872, -90.0, 90.0]\n",
|
||||
"elbow (x,y): 0.179 0.385\n",
|
||||
"wrist (x,y): 0.568 0.44\n",
|
||||
"tool (x,y): 0.694 0.44\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAj0AAAGfCAYAAAC0rWN5AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAA9hAAAPYQGoP6dpAABCx0lEQVR4nO3de1xUdf7H8RcMAiIXNZKLoSiYlqmUJGGm9osi10p3t12r3TAq223VX8WvvJRKFwtvmbvqapqXLutq7c+t3S5Ysflr3ShbL128bZiGmqBWgoCBMuf3BzVGgJyBOTPMzPv5eJxHcOZzznzmRPDunO/5ngDDMAxEREREfFygpxsQERERcQeFHhEREfELCj0iIiLiFxR6RERExC8o9IiIiIhfUOgRERERv6DQIyIiIn5BoUdERET8gkKPiIiI+AWFHhEREfELLQo9ixcvJjExkdDQUNLS0ti8eXOTtatXryYgIKDeEhoa6tT7GYZBeXk5emKGiIiItJTToWfdunXk5OSQm5vL1q1bGTBgAJmZmRw5cqTJbSIjIzl8+LBj+eKLL5x6zxMnThAVFcWJEyecbVdEREQEaEHomT9/PuPGjSM7O5sLL7yQpUuXEhYWxsqVK5vcJiAggNjYWMcSExPTqqZFREREnOVU6KmpqWHLli1kZGSc2UFgIBkZGRQWFja5XUVFBd27dychIYFRo0axY8eOs75PdXU15eXl9RYRERGR1nAq9Bw7doza2toGZ2piYmIoKSlpdJvevXuzcuVKXnnlFV544QXsdjuDBw/m4MGDTb5PXl4eUVFRjiUhIcGZNkVEREQasPzurfT0dLKyskhJSWHYsGGsX7+ec889l6effrrJbaZOnUpZWZljOXDggNVtioiIiI8LcqY4Ojoam81GaWlpvfWlpaXExsaa2ke7du24+OKLKSoqarImJCSEkJAQZ1oTEREROSunzvQEBwczcOBACgoKHOvsdjsFBQWkp6eb2kdtbS2ffPIJcXFxznUqIiIi0gpOnekByMnJYezYsaSmpjJo0CAWLFhAZWUl2dnZAGRlZdG1a1fy8vIAePTRR7nssstITk7m+PHjzJ07ly+++II777zTtZ9ERERE5CycDj1jxozh6NGjzJgxg5KSElJSUsjPz3cMbi4uLiYw8MwJpG+++YZx48ZRUlJCp06dGDhwIO+99x4XXnih6z6FiIiISDMCDC+Y5ri8vJyoqCjKysqIjIz0dDsiIiLihfTsLREREfELCj0iIiLiFxR6RERExC8o9IiIiIhfUOgRERERv6DQIyIiIn5BoUdERET8gkKPiIiI+AWFHhEREfELCj0iIuLVamtrmT59Oj169KB9+/YkJSXx2GOP0dwDBzZu3Mgll1xCSEgIycnJrF69ut7r7777Ltdffz3x8fEEBATw8ssvN9hHSUkJI0aMID4+ngkTJmC32134ycTVFHpERMSrzZ49myVLlrBo0SJ27drF7NmzmTNnDgsXLmxym3379jFy5EiuvPJKtm/fzr333sudd97Jhg0bHDWVlZUMGDCAxYsXN7mf6dOnk5qayhtvvMHnn3/O2rVrXfrZxLWcfuCoiIhIW/Lee+8xatQoRo4cCUBiYiJ//vOf2bx5c5PbLF26lB49evDkk08CcMEFF7Bp0yaeeuopMjMzARgxYgQjRow463t/8803XH311fTr14+ePXty/Phx13wosYTO9IiIiFcbPHgwBQUF/Oc//wHgo48+YtOmTWcNLIWFhWRkZNRbl5mZSWFhoVPvPWXKFCZOnEhISAhbt24lKyvL+Q8gbqMzPSIi4tWmTJlCeXk5ffr0wWazUVtby+OPP86vfvWrJrcpKSkhJiam3rqYmBjKy8s5efIk7du3N/XeqampHDp0iGPHjhEbG9uqzyHWU+gRERGv9uKLL/KnP/2JNWvW0LdvX8cYnfj4eMaOHWv5+wcFBSnweAmFHhER8WoPPPAAU6ZM4aabbgKgX79+fPHFF+Tl5TUZemJjYyktLa23rrS0lMjISNNnecT7aEyPiIh4taqqKgID6/85s9lsZ719PD09nYKCgnrr3nrrLdLT0y3pUdoGnekRERGvdv311/P444/TrVs3+vbty7Zt25g/fz633367o2bq1KkcOnSI5557DoDf/va3LFq0iEmTJnH77bfzj3/8gxdffJHXXnvNsU1FRQVFRUWO7/ft28f27dvp3Lkz3bp1c98HFJcJMJqbvakNKC8vJyoqirKyMiIjIz3djoiItCEnTpxg+vTp/PWvf+XIkSPEx8dz8803M2PGDIKDgwG47bbb2L9/Pxs3bnRst3HjRu677z527tzJeeedx/Tp07ntttvqvX7llVc2eL+xY8c2mMhQvINCj4iIiPgFjekRERERv6DQIyIi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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 640x480 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Angles: [-34.134, 65.045, 57.033, 8.013, -90.0, 0.0]\n",
|
||||
"Circle position (cx, cy): (0.11, -0.075)\n",
|
||||
"Shoulder (x, y, z): (0.211, 0.074, 0.385)\n",
|
||||
"Elbow (x, y, z): (0.429, 0.395, 0.44)\n",
|
||||
"Wrist (x, y, z): (0.5, 0.5, 0.44)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 640x480 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def draw_arm(x, y, z, details=False):\n",
|
||||
" draw_arm_side_view(x,y,z, details=details)\n",
|
||||
" draw_arm_top_view(x,y,z, details=details)\n",
|
||||
"\n",
|
||||
"draw_arm(0.5,0.5,0.3, details=True)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
Executable
+106
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
|
||||
from get_specs import get_multi
|
||||
import sys
|
||||
import uuid
|
||||
import os
|
||||
import signal
|
||||
from PIL import Image
|
||||
from label_image import generate_code
|
||||
|
||||
|
||||
def input_cable():
|
||||
print("")
|
||||
print("Use the full part number. Spaces, special characters are allowed. Do not specify the brand.")
|
||||
print("")
|
||||
print("Please enter a part number and press enter:")
|
||||
inputnum = input("").strip()
|
||||
if len(inputnum) < 2:
|
||||
killall_signal(0, 0)
|
||||
print("Input part number:", inputnum)
|
||||
print("Searching databases for cables...")
|
||||
# Search both AW and BL sites
|
||||
status, output = get_multi(["BL"+inputnum, "AW"+inputnum], delay=0.1, dir="temp/" + str(uuid.uuid4()) + "/", cache=False)
|
||||
print("")
|
||||
if len(output) > 1:
|
||||
for i in output:
|
||||
print(i[1], i[0])
|
||||
print("Multiple brands with the same part number! Please type \"b\" for the Belden part number or \"a\" for the Alphawire cable")
|
||||
inputbrand = input()
|
||||
if inputbrand == "b":
|
||||
output = [output[0]]
|
||||
elif inputbrand == "a":
|
||||
output = [output[1]]
|
||||
elif len(output) == 0:
|
||||
print("No results found for part number", inputnum + ". Please try again with a different part number.")
|
||||
return
|
||||
|
||||
output = output[0]
|
||||
print("")
|
||||
if output[2] and output[3]:
|
||||
print("Cable result found -",output[1], output[0], "with high-quality image and full specs")
|
||||
elif output[2]:
|
||||
print("Cable result found -",output[1], output[0], "with high-quality image and no specs")
|
||||
elif output[3]:
|
||||
print("Cable result found -",output[1], output[0], "with no/low quality image and full specs")
|
||||
else:
|
||||
print("Cable result found -",output[1], output[0], "with no/low quality image and no specs")
|
||||
print("")
|
||||
if not output[3]:
|
||||
print("Unable to decode cable specs. Please try again with a different part number.")
|
||||
return False
|
||||
else:
|
||||
print("")
|
||||
print("*** Cable details confirmed. Creating label...")
|
||||
print("")
|
||||
img = None
|
||||
imgstr = ""
|
||||
if output[1] == "Belden":
|
||||
imgstr = "BL"
|
||||
elif output[1] == "Alphawire":
|
||||
imgstr = "AW"
|
||||
gen_label(imgstr + output[0])
|
||||
#img = generate_code(imgstr + output[0])
|
||||
#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):
|
||||
# Check if the path is a directory
|
||||
if not os.path.isdir(path):
|
||||
return
|
||||
|
||||
# List all files and directories in the path
|
||||
for filename in os.listdir(path):
|
||||
file_path = os.path.join(path, filename)
|
||||
# If it's a directory, recursively call this function
|
||||
if os.path.isdir(file_path):
|
||||
delete_folder(file_path)
|
||||
else:
|
||||
# If it's a file, remove it
|
||||
os.remove(file_path)
|
||||
|
||||
# After removing all contents, remove the directory itself
|
||||
os.rmdir(path)
|
||||
|
||||
def killall_signal(a,b):
|
||||
delete_folder("temp")
|
||||
os.kill(os.getpid(), 9) # dirty kill of self
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
signal.signal(signal.SIGINT, killall_signal)
|
||||
signal.signal(signal.SIGTERM, killall_signal)
|
||||
print("Welcome to the Jukebox cable utility. This tool will allow you to verify Belden & Alphawire cable part numbers and create labels for samples in the Jukebox.")
|
||||
print("This tool requires internet access to download cable specifications and verify part numbers.")
|
||||
#print("Use Ctrl+C to exit.")
|
||||
while True:
|
||||
delete_folder("temp")
|
||||
input_cable()
|
||||
|
||||
Executable
+319
@@ -0,0 +1,319 @@
|
||||
#!/usr/bin/env python3
|
||||
from util import fprint
|
||||
|
||||
from PIL import Image
|
||||
from PIL import ImageDraw
|
||||
from PIL import ImageFont
|
||||
#import cv2
|
||||
import numpy as np
|
||||
from util import find_data_file
|
||||
import segno
|
||||
import io
|
||||
#import cairosvg
|
||||
#import math
|
||||
|
||||
|
||||
|
||||
# Copied from http://en.wikipedia.org/wiki/Code_128
|
||||
# Value Weights 128A 128B 128C
|
||||
CODE128_CHART = """
|
||||
0 212222 space space 00
|
||||
1 222122 ! ! 01
|
||||
2 222221 " " 02
|
||||
3 121223 # # 03
|
||||
4 121322 $ $ 04
|
||||
5 131222 % % 05
|
||||
6 122213 & & 06
|
||||
7 122312 ' ' 07
|
||||
8 132212 ( ( 08
|
||||
9 221213 ) ) 09
|
||||
10 221312 * * 10
|
||||
11 231212 + + 11
|
||||
12 112232 , , 12
|
||||
13 122132 - - 13
|
||||
14 122231 . . 14
|
||||
15 113222 / / 15
|
||||
16 123122 0 0 16
|
||||
17 123221 1 1 17
|
||||
18 223211 2 2 18
|
||||
19 221132 3 3 19
|
||||
20 221231 4 4 20
|
||||
21 213212 5 5 21
|
||||
22 223112 6 6 22
|
||||
23 312131 7 7 23
|
||||
24 311222 8 8 24
|
||||
25 321122 9 9 25
|
||||
26 321221 : : 26
|
||||
27 312212 ; ; 27
|
||||
28 322112 < < 28
|
||||
29 322211 = = 29
|
||||
30 212123 > > 30
|
||||
31 212321 ? ? 31
|
||||
32 232121 @ @ 32
|
||||
33 111323 A A 33
|
||||
34 131123 B B 34
|
||||
35 131321 C C 35
|
||||
36 112313 D D 36
|
||||
37 132113 E E 37
|
||||
38 132311 F F 38
|
||||
39 211313 G G 39
|
||||
40 231113 H H 40
|
||||
41 231311 I I 41
|
||||
42 112133 J J 42
|
||||
43 112331 K K 43
|
||||
44 132131 L L 44
|
||||
45 113123 M M 45
|
||||
46 113321 N N 46
|
||||
47 133121 O O 47
|
||||
48 313121 P P 48
|
||||
49 211331 Q Q 49
|
||||
50 231131 R R 50
|
||||
51 213113 S S 51
|
||||
52 213311 T T 52
|
||||
53 213131 U U 53
|
||||
54 311123 V V 54
|
||||
55 311321 W W 55
|
||||
56 331121 X X 56
|
||||
57 312113 Y Y 57
|
||||
58 312311 Z Z 58
|
||||
59 332111 [ [ 59
|
||||
60 314111 \ \ 60
|
||||
61 221411 ] ] 61
|
||||
62 431111 ^ ^ 62
|
||||
63 111224 _ _ 63
|
||||
64 111422 NUL ` 64
|
||||
65 121124 SOH a 65
|
||||
66 121421 STX b 66
|
||||
67 141122 ETX c 67
|
||||
68 141221 EOT d 68
|
||||
69 112214 ENQ e 69
|
||||
70 112412 ACK f 70
|
||||
71 122114 BEL g 71
|
||||
72 122411 BS h 72
|
||||
73 142112 HT i 73
|
||||
74 142211 LF j 74
|
||||
75 241211 VT k 75
|
||||
76 221114 FF l 76
|
||||
77 413111 CR m 77
|
||||
78 241112 SO n 78
|
||||
79 134111 SI o 79
|
||||
80 111242 DLE p 80
|
||||
81 121142 DC1 q 81
|
||||
82 121241 DC2 r 82
|
||||
83 114212 DC3 s 83
|
||||
84 124112 DC4 t 84
|
||||
85 124211 NAK u 85
|
||||
86 411212 SYN v 86
|
||||
87 421112 ETB w 87
|
||||
88 421211 CAN x 88
|
||||
89 212141 EM y 89
|
||||
90 214121 SUB z 90
|
||||
91 412121 ESC { 91
|
||||
92 111143 FS | 92
|
||||
93 111341 GS } 93
|
||||
94 131141 RS ~ 94
|
||||
95 114113 US DEL 95
|
||||
96 114311 FNC3 FNC3 96
|
||||
97 411113 FNC2 FNC2 97
|
||||
98 411311 ShiftB ShiftA 98
|
||||
99 113141 CodeC CodeC 99
|
||||
100 114131 CodeB FNC4 CodeB
|
||||
101 311141 FNC4 CodeA CodeA
|
||||
102 411131 FNC1 FNC1 FNC1
|
||||
103 211412 StartA StartA StartA
|
||||
104 211214 StartB StartB StartB
|
||||
105 211232 StartC StartC StartC
|
||||
106 2331112 Stop Stop Stop
|
||||
""".split()
|
||||
|
||||
VALUES = [int(value) for value in CODE128_CHART[0::5]]
|
||||
WEIGHTS = dict(zip(VALUES, CODE128_CHART[1::5]))
|
||||
CODE128A = dict(zip(CODE128_CHART[2::5], VALUES))
|
||||
CODE128B = dict(zip(CODE128_CHART[3::5], VALUES))
|
||||
CODE128C = dict(zip(CODE128_CHART[4::5], VALUES))
|
||||
|
||||
for charset in (CODE128A, CODE128B):
|
||||
charset[' '] = charset.pop('space')
|
||||
|
||||
|
||||
|
||||
def generate_code(data, show=False, check=False):
|
||||
|
||||
#img = code128_image(data)
|
||||
img = qr_image(data)
|
||||
if show:
|
||||
img.show()
|
||||
#img.show()
|
||||
#print(data)
|
||||
|
||||
if(check):
|
||||
from pyzbar.pyzbar import decode
|
||||
from pyzbar.pyzbar import ZBarSymbol
|
||||
print(decode(img, symbols=[ZBarSymbol.CODE128])[0].data.decode('ascii'))
|
||||
|
||||
#if(decode(img, symbols=[ZBarSymbol.CODE128])[0].data.decode('ascii') == data):
|
||||
# return True
|
||||
#else:
|
||||
# return False
|
||||
return img
|
||||
|
||||
def code128_format(data):
|
||||
"""
|
||||
Generate an optimal barcode from ASCII text
|
||||
"""
|
||||
text = str(data)
|
||||
pos = 0
|
||||
length = len(text)
|
||||
|
||||
# Start Code
|
||||
if text[:2].isdigit():
|
||||
charset = CODE128C
|
||||
codes = [charset['StartC']]
|
||||
else:
|
||||
charset = CODE128B
|
||||
codes = [charset['StartB']]
|
||||
|
||||
# Data
|
||||
while pos < length:
|
||||
if charset is CODE128C:
|
||||
if text[pos:pos+2].isdigit() and length - pos > 1:
|
||||
# Encode Code C two characters at a time
|
||||
codes.append(int(text[pos:pos+2]))
|
||||
pos += 2
|
||||
else:
|
||||
# Switch to Code B
|
||||
codes.append(charset['CodeB'])
|
||||
charset = CODE128B
|
||||
elif text[pos:pos+4].isdigit() and length - pos >= 4:
|
||||
# Switch to Code C
|
||||
codes.append(charset['CodeC'])
|
||||
charset = CODE128C
|
||||
else:
|
||||
# Encode Code B one character at a time
|
||||
codes.append(charset[text[pos]])
|
||||
pos += 1
|
||||
|
||||
# Checksum
|
||||
checksum = 0
|
||||
for weight, code in enumerate(codes):
|
||||
checksum += max(weight, 1) * code
|
||||
codes.append(checksum % 103)
|
||||
|
||||
# Stop Code
|
||||
codes.append(charset['Stop'])
|
||||
return codes
|
||||
|
||||
def code128_image(data, height=100, thickness=3, quiet_zone=False):
|
||||
partnum = data
|
||||
if not data[-1] == CODE128B['Stop']:
|
||||
data = code128_format(data)
|
||||
|
||||
|
||||
barcode_widths = []
|
||||
for code in data:
|
||||
for weight in WEIGHTS[code]:
|
||||
barcode_widths.append(int(weight) * thickness)
|
||||
width = sum(barcode_widths)
|
||||
x = 0
|
||||
|
||||
|
||||
if quiet_zone:
|
||||
width += 20 * thickness
|
||||
x = 10 * thickness
|
||||
|
||||
# Monochrome Image
|
||||
img = Image.new('RGB', (int(width * 10), int(width * 10)), 'white')
|
||||
draw = ImageDraw.Draw(img)
|
||||
draw_bar = True
|
||||
for bwidth in barcode_widths:
|
||||
bwidth *= 4
|
||||
if draw_bar:
|
||||
draw.rectangle(((x + int(width * 3), width*6.25), (x + int(width * 3) + bwidth - 1, width*7)), fill='black')
|
||||
draw_bar = not draw_bar
|
||||
x += bwidth
|
||||
|
||||
#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))
|
||||
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
|
||||
|
||||
if __name__ == "__main__":
|
||||
#print(generate_code("BL10GXS13"))
|
||||
#print(generate_code("BL10GXgd35j35S13"))
|
||||
#print(generate_code("BL10GX54hS13"))
|
||||
#print(generate_code("BL10Gj34qXS13", False, False))
|
||||
#print(generate_code("BL104w5545dp7bfwp43643534/4563G-XS13"))
|
||||
#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")
|
||||
+267
-279
@@ -14,6 +14,9 @@ import cv2
|
||||
import numpy as np
|
||||
from uptime import uptime
|
||||
|
||||
|
||||
|
||||
class LEDSystem():
|
||||
sender = None
|
||||
debug = True
|
||||
config = None
|
||||
@@ -31,7 +34,12 @@ changecount = 0
|
||||
animation_time = 0
|
||||
start = uptime()
|
||||
|
||||
def ping(host):
|
||||
def __init__(self):
|
||||
self.start = uptime()
|
||||
#self.init()
|
||||
#return self
|
||||
|
||||
def ping(self, host):
|
||||
#Returns True if host (str) responds to a ping request.
|
||||
|
||||
# Option for the number of packets as a function of
|
||||
@@ -49,32 +57,23 @@ def ping(host):
|
||||
|
||||
return subprocess.call(command, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) == 0
|
||||
|
||||
def map():
|
||||
global config
|
||||
global leds
|
||||
global leds_size
|
||||
global leds_normalized
|
||||
global controllers
|
||||
global rings
|
||||
global ringstatus
|
||||
global animation_time
|
||||
|
||||
def map(self):
|
||||
|
||||
with open('config.yml', 'r') as fileread:
|
||||
#global config
|
||||
config = yaml.safe_load(fileread)
|
||||
self.config = yaml.safe_load(fileread)
|
||||
|
||||
animation_time = config["animation_time"]
|
||||
leds = list()
|
||||
leds_size = list()
|
||||
controllers = list()
|
||||
rings = list(range(len(config["position_map"])))
|
||||
ringstatus = list(range(len(config["position_map"])))
|
||||
self.animation_time = self.config["animation_time"]
|
||||
self.leds = list()
|
||||
self.leds_size = list()
|
||||
self.controllers = list()
|
||||
self.rings = list(range(len(self.config["position_map"])))
|
||||
self.ringstatus = list(range(len(self.config["position_map"])))
|
||||
#print(rings)
|
||||
#fprint(config["led"]["map"])
|
||||
generate_map = False
|
||||
map = list()
|
||||
for shape in config["led"]["map"]:
|
||||
for shape in self.config["led"]["map"]:
|
||||
if shape["type"] == "circle":
|
||||
|
||||
if generate_map:
|
||||
@@ -84,22 +83,22 @@ def map():
|
||||
angle = 0
|
||||
radius = shape["diameter"] / 2
|
||||
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
|
||||
#print(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
|
||||
ringstatus[item["index"]] = [None, None]
|
||||
self.rings[item["index"]] = (shape["pos"][1],shape["pos"][0],lednum,lednum+shape["size"]) # rings[index] = x, y, startpos, endpos
|
||||
self.ringstatus[item["index"]] = [None, None]
|
||||
break
|
||||
if len(leds) < lednum + shape["size"]:
|
||||
for x in range(lednum + shape["size"] - len(leds)):
|
||||
leds.append(None)
|
||||
leds_size.append(None)
|
||||
if len(self.leds) < lednum + shape["size"]:
|
||||
for x in range(lednum + shape["size"] - len(self.leds)):
|
||||
self.leds.append(None)
|
||||
self.leds_size.append(None)
|
||||
while angle < 359.999:
|
||||
tmpangle = angle + shape["angle"]
|
||||
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]
|
||||
leds[lednum] = (x,y)
|
||||
self.leds[lednum] = (x,y)
|
||||
lednum = lednum + 1
|
||||
angle = angle + anglediv
|
||||
|
||||
@@ -112,13 +111,13 @@ def map():
|
||||
xmov = math.cos(angle * (math.pi / 180.0)) * distdiv
|
||||
ymov = math.sin(angle * (math.pi / 180.0)) * distdiv
|
||||
pos = shape["pos"]
|
||||
if len(leds) < lednum + shape["size"]:
|
||||
for x in range(lednum + shape["size"] - len(leds)):
|
||||
leds.append(None)
|
||||
leds_size.append(None)
|
||||
if len(self.leds) < lednum + shape["size"]:
|
||||
for x in range(lednum + shape["size"] - len(self.leds)):
|
||||
self.leds.append(None)
|
||||
self.leds_size.append(None)
|
||||
|
||||
while dist < length:
|
||||
leds[lednum] = (pos[0], pos[1])
|
||||
self.leds[lednum] = (pos[0], pos[1])
|
||||
pos[0] += xmov
|
||||
pos[1] += ymov
|
||||
dist += distdiv
|
||||
@@ -140,276 +139,262 @@ def map():
|
||||
yaml_str = yaml.dump(data, default_flow_style=False)
|
||||
print(yaml_str)
|
||||
|
||||
print(rings)
|
||||
print(self.rings)
|
||||
flag = 0
|
||||
for x in leds:
|
||||
for x in self.leds:
|
||||
if x is None:
|
||||
flag = flag + 1
|
||||
if flag > 0:
|
||||
fprint("Warning: Imperfect LED map ordering. Hiding undefined lights.")
|
||||
for x in range(len(leds)):
|
||||
if leds[x] is None:
|
||||
leds[x] = (0, 0)
|
||||
for x in range(len(self.leds)):
|
||||
if self.leds[x] is None:
|
||||
self.leds[x] = (0, 0)
|
||||
|
||||
|
||||
#leds = tmpleds.reverse()
|
||||
#fprint(leds)
|
||||
|
||||
# controller mapping
|
||||
for ctrl in config["led"]["controllers"]:
|
||||
if len(controllers) < ctrl["universe"]+1:
|
||||
for x in range(ctrl["universe"]+1 - len(controllers)):
|
||||
controllers.append(None)
|
||||
for ctrl in self.config["led"]["controllers"]:
|
||||
if len(self.controllers) < ctrl["universe"]+1:
|
||||
for x in range(ctrl["universe"]+1 - len(self.controllers)):
|
||||
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):
|
||||
leds_size[x] = len(ctrl["mode"])
|
||||
self.leds_size[x] = len(ctrl["mode"])
|
||||
#fprint(controllers)
|
||||
|
||||
if(debug):
|
||||
if(self.debug):
|
||||
import matplotlib.pyplot as plt
|
||||
plt.axis('equal')
|
||||
for ctrl in controllers:
|
||||
plt.scatter(*zip(*leds[ctrl[0]:ctrl[1]]), s=2)
|
||||
for ctrl in self.controllers:
|
||||
plt.scatter(*zip(*self.leds[ctrl[0]:ctrl[1]]), s=2)
|
||||
#plt.scatter(*zip(*leds), s=3)
|
||||
plt.savefig("map.png", dpi=600, bbox_inches="tight")
|
||||
|
||||
leds_adj = [(x-min([led[0] for led in leds]), # push to zero start
|
||||
y-min([led[1] for led in leds]) )
|
||||
for x, y in leds]
|
||||
leds_adj = [(x-min([led[0] for led in self.leds]), # push to zero start
|
||||
y-min([led[1] for led in self.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]))
|
||||
for x, y in leds_adj]
|
||||
#return leds, controllers
|
||||
|
||||
def init():
|
||||
map()
|
||||
global sender
|
||||
global config
|
||||
global leds
|
||||
global leds_size
|
||||
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="")
|
||||
def init(self):
|
||||
self.map()
|
||||
self.sender = sacn.sACNsender(fps=self.config["led"]["fps"], universeDiscovery=False)
|
||||
self.sender.start() # start the sending thread
|
||||
"""for x in range(len(self.controllers)):
|
||||
print("Waiting for the controller at", self.controllers[x][2], "to be online...", end="")
|
||||
count = 0
|
||||
while not ping(controllers[x][2]):
|
||||
while not ping(self.controllers[x][2]):
|
||||
count = count + 1
|
||||
if count >= config["led"]["timeout"]:
|
||||
if count >= self.config["led"]["timeout"]:
|
||||
fprint(" ERROR: controller still offline after " + str(count) + " seconds, continuing...")
|
||||
break
|
||||
if count < config["led"]["timeout"]:
|
||||
if count < self.config["led"]["timeout"]:
|
||||
fprint(" done")"""
|
||||
for x in range(len(controllers)):
|
||||
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
|
||||
sender[x+1].destination = controllers[x][2]
|
||||
sender.manual_flush = True
|
||||
for x in range(len(self.controllers)):
|
||||
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
|
||||
data = list()
|
||||
exactdata = list()
|
||||
for x in range(len(leds)):
|
||||
if leds_size[x] == 3:
|
||||
exactdata.append(None)
|
||||
data.append((20,20,127))
|
||||
elif leds_size[x] == 4:
|
||||
exactdata.append(None)
|
||||
data.append((50,50,255,0))
|
||||
self.data = list()
|
||||
self.exactdata = list()
|
||||
for x in range(len(self.leds)):
|
||||
if self.leds_size[x] == 3:
|
||||
self.exactdata.append(None)
|
||||
self.data.append((20,20,127))
|
||||
elif self.leds_size[x] == 4:
|
||||
self.exactdata.append(None)
|
||||
self.data.append((50,50,255,0))
|
||||
else:
|
||||
exactdata.append(None)
|
||||
data.append((0,0,0))
|
||||
sendall(data)
|
||||
self.exactdata.append(None)
|
||||
self.data.append((0,0,0))
|
||||
self.sendall(self.data)
|
||||
#time.sleep(50000)
|
||||
fprint("Running start-up test sequence...")
|
||||
for y in range(1):
|
||||
for x in range(len(leds)):
|
||||
setpixel(0,60,144,x)
|
||||
sendall(data)
|
||||
for x in range(len(self.leds)):
|
||||
self.setpixel(0,60,144,x)
|
||||
self.sendall(self.data)
|
||||
#time.sleep(2)
|
||||
alloffsmooth()
|
||||
self.alloffsmooth()
|
||||
|
||||
def sendall(datain):
|
||||
def sendall(self, datain):
|
||||
# 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
|
||||
global controllers
|
||||
global sender
|
||||
sender.manual_flush = True
|
||||
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
|
||||
self.sender.manual_flush = True
|
||||
for x in range(len(self.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
|
||||
|
||||
sender.flush()
|
||||
self.sender.flush()
|
||||
time.sleep(0.002)
|
||||
#sender.flush() # 100% reliable with 2 flushes, often fails with 1
|
||||
#time.sleep(0.002)
|
||||
#sender.flush()
|
||||
|
||||
def fastsendall(datain):
|
||||
def fastsendall(self, datain):
|
||||
# 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
|
||||
global controllers
|
||||
global sender
|
||||
sender.manual_flush = False
|
||||
print(datain[controllers[0][0]:controllers[0][1]])
|
||||
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
|
||||
self.sender.manual_flush = False
|
||||
print(datain[self.controllers[0][0]:self.controllers[0][1]])
|
||||
for x in range(len(self.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
|
||||
|
||||
sender.flush()
|
||||
self.sender.flush()
|
||||
|
||||
def senduniverse(datain, lednum):
|
||||
def senduniverse(self, datain, lednum):
|
||||
# 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
|
||||
global controllers
|
||||
global sender
|
||||
for x in range(len(controllers)):
|
||||
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
|
||||
for x in range(len(self.controllers)):
|
||||
if lednum >= self.controllers[x][0] and lednum < self.controllers[x][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
|
||||
|
||||
sender.flush()
|
||||
self.sender.flush()
|
||||
time.sleep(0.004)
|
||||
#sender.flush() # 100% reliable with 2 flushes, often fails with 1
|
||||
#time.sleep(0.002)
|
||||
#sender.flush()
|
||||
|
||||
def alloff():
|
||||
def alloff(self):
|
||||
tmpdata = list()
|
||||
for x in range(len(leds)):
|
||||
if leds_size[x] == 3:
|
||||
for x in range(len(self.leds)):
|
||||
if self.leds_size[x] == 3:
|
||||
tmpdata.append((0,0,0))
|
||||
elif leds_size[x] == 4:
|
||||
elif self.leds_size[x] == 4:
|
||||
tmpdata.append((0,0,0,0))
|
||||
else:
|
||||
tmpdata.append((0,0,0))
|
||||
sendall(tmpdata)
|
||||
self.sendall(tmpdata)
|
||||
#sendall(tmpdata)
|
||||
#sendall(tmpdata) #definitely make sure it's off
|
||||
return self
|
||||
|
||||
def allon():
|
||||
global data
|
||||
sendall(data)
|
||||
def allon(self):
|
||||
self.sendall(self.data)
|
||||
return self
|
||||
|
||||
def alloffsmooth():
|
||||
tmpdata = data
|
||||
def alloffsmooth(self):
|
||||
tmpdata = self.data
|
||||
for x in range(256):
|
||||
for x in range(len(data)):
|
||||
setpixel(tmpdata[x][0]-1,tmpdata[x][1]-1,tmpdata[x][2]-1, x)
|
||||
sendall(tmpdata)
|
||||
for x in range(len(self.data)):
|
||||
self.setpixel(tmpdata[x][0]-1,tmpdata[x][1]-1,tmpdata[x][2]-1, x)
|
||||
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
|
||||
# unfortunately no way to manual flush data packets to only 1 controller with this sACN library
|
||||
global data
|
||||
setpixel(r,g,b,num)
|
||||
senduniverse(data, num)
|
||||
self.setpixel(r,g,b,num)
|
||||
self.senduniverse(self.data, num)
|
||||
return self
|
||||
|
||||
def setmode(stmode, r=0,g=0,b=0):
|
||||
global mode
|
||||
global firstrun
|
||||
def setmode(self, stmode, r=0,g=0,b=0):
|
||||
if stmode is not None:
|
||||
if mode != stmode:
|
||||
firstrun = True
|
||||
if self.mode != stmode:
|
||||
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]):
|
||||
setpixel(r,g,b,pixel)
|
||||
self.setpixel(r,g,b,pixel)
|
||||
#global data
|
||||
#senduniverse(data, ring[2])
|
||||
return self
|
||||
|
||||
def runmodes(ring = -1, speed = 1):
|
||||
global mode
|
||||
global firstrun
|
||||
global changecount
|
||||
fprint("Mode: " + str(mode))
|
||||
if mode == "Startup":
|
||||
def runmodes(self, ring = -1, speed = 1):
|
||||
fprint("Mode: " + str(self.mode))
|
||||
if self.mode == "Startup":
|
||||
# loading animation. cable check
|
||||
if firstrun:
|
||||
changecount = animation_time * 3
|
||||
if self.firstrun:
|
||||
self.changecount = self.animation_time * 3
|
||||
firstrun = False
|
||||
for x in range(len(ringstatus)):
|
||||
ringstatus[x] = [True, animation_time]
|
||||
for x in range(len(self.ringstatus)):
|
||||
self.ringstatus[x] = [True, self.animation_time]
|
||||
|
||||
if changecount > 0:
|
||||
fprint(changecount)
|
||||
changecount = fadeorder(0,len(leds), changecount, 0,50,100)
|
||||
if self.changecount > 0:
|
||||
fprint(self.changecount)
|
||||
self.changecount = self.fadeorder(0,len(self.leds), self.changecount, 0,50,100)
|
||||
else:
|
||||
setmode("Startup2")
|
||||
self.setmode("Startup2")
|
||||
|
||||
|
||||
elif mode == "Startup2":
|
||||
if firstrun:
|
||||
firstrun = False
|
||||
elif self.mode == "Startup2":
|
||||
if self.firstrun:
|
||||
self.firstrun = False
|
||||
|
||||
else:
|
||||
for x in range(len(ringstatus)):
|
||||
if ringstatus[x][0]:
|
||||
setring(0, 50, 100, x)
|
||||
for x in range(len(self.ringstatus)):
|
||||
if self.ringstatus[x][0]:
|
||||
self.setring(0, 50, 100, x)
|
||||
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":
|
||||
if firstrun:
|
||||
firstrun = False
|
||||
for x in range(len(ringstatus)):
|
||||
ringstatus[x] = [False, animation_time]
|
||||
elif self.mode == "StartupCheck":
|
||||
if self.firstrun:
|
||||
self.firstrun = False
|
||||
for x in range(len(self.ringstatus)):
|
||||
self.ringstatus[x] = [False, self.animation_time]
|
||||
else:
|
||||
for x in range(len(ringstatus)):
|
||||
if ringstatus[x][0]:
|
||||
ringstatus[x][1] = fadeall(rings[x][2],rings[x][3], ringstatus[x][1], 0,50,100) # ready
|
||||
for x in range(len(self.ringstatus)):
|
||||
if self.ringstatus[x][0]:
|
||||
self.ringstatus[x][1] = self.fadeall(self.rings[x][2],self.rings[x][3], self.ringstatus[x][1], 0,50,100) # ready
|
||||
else:
|
||||
setring(100, 0, 0, x)
|
||||
self.setring(100, 0, 0, x)
|
||||
|
||||
elif mode == "GrabA":
|
||||
if firstrun:
|
||||
firstrun = False
|
||||
changecount = animation_time # 100hz
|
||||
if changecount > 0:
|
||||
changecount = fadeall(rings[ring][2],rings[ring][3], changecount, 100,0,0)
|
||||
elif self.mode == "GrabA":
|
||||
if self.firstrun:
|
||||
self.firstrun = False
|
||||
self.changecount = self.animation_time # 100hz
|
||||
if self.changecount > 0:
|
||||
self.changecount = self.fadeall(self.rings[ring][2],self.rings[ring][3], self.changecount, 100,0,0)
|
||||
else:
|
||||
setring(100,0,0,ring)
|
||||
setmode("GrabB")
|
||||
elif mode == "GrabB":
|
||||
if firstrun:
|
||||
firstrun = False
|
||||
changecount = animation_time # 100hz
|
||||
if changecount > 0:
|
||||
changecount = fadeorder(rings[ring][2],rings[ring][3], changecount, 0,100,0)
|
||||
self.setring(100,0,0,ring)
|
||||
self.setmode("GrabB")
|
||||
elif self.mode == "GrabB":
|
||||
if self.firstrun:
|
||||
self.firstrun = False
|
||||
self.changecount = self.animation_time # 100hz
|
||||
if self.changecount > 0:
|
||||
self.changecount = self.fadeorder(self.rings[ring][2],self.rings[ring][3], self.changecount, 0,100,0)
|
||||
else:
|
||||
setring(0,100,0,ring)
|
||||
setmode("idle")
|
||||
elif mode == "GrabC":
|
||||
if firstrun:
|
||||
firstrun = False
|
||||
changecount = animation_time # 100hz
|
||||
if changecount > 0:
|
||||
changecount = fadeall(rings[ring][2],rings[ring][3], changecount, 0,50,100)
|
||||
self.setring(0,100,0,ring)
|
||||
self.setmode("idle")
|
||||
elif self.mode == "GrabC":
|
||||
if self.firstrun:
|
||||
self.firstrun = False
|
||||
self.changecount = self.animation_time # 100hz
|
||||
if self.changecount > 0:
|
||||
self.changecount = self.fadeall(self.rings[ring][2],self.rings[ring][3], self.changecount, 0,50,100)
|
||||
else:
|
||||
setring(0,50,100,ring)
|
||||
setmode("idle")
|
||||
elif mode == "idle":
|
||||
self.setring(0,50,100,ring)
|
||||
self.setmode("idle")
|
||||
elif self.mode == "idle":
|
||||
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:
|
||||
return 0
|
||||
global exactdata
|
||||
sum = 0
|
||||
for x in range(idxa,idxb):
|
||||
if exactdata[x] is None:
|
||||
exactdata[x] = data[x]
|
||||
old = exactdata[x]
|
||||
if self.exactdata[x] is None:
|
||||
self.exactdata[x] = self.data[x]
|
||||
old = self.exactdata[x]
|
||||
dr = (r - old[0])/sizerem
|
||||
sum += abs(dr)
|
||||
dr += old[0]
|
||||
@@ -419,27 +404,26 @@ def fadeall(idxa,idxb,sizerem,r,g,b):
|
||||
db = (b - old[2])/sizerem
|
||||
db += old[2]
|
||||
sum += abs(db)
|
||||
exactdata[x] = (dr, dg, db)
|
||||
self.exactdata[x] = (dr, dg, db)
|
||||
#print(new)
|
||||
setpixel(dr, dg, db, x)
|
||||
self.setpixel(dr, dg, db, x)
|
||||
if sizerem == 1:
|
||||
exactdata[x] = None
|
||||
self.exactdata[x] = None
|
||||
if sum == 0 and sizerem > 2:
|
||||
sizerem = 2
|
||||
return sizerem - 1
|
||||
|
||||
def fadeorder(idxa,idxb,sizerem,r,g,b):
|
||||
def fadeorder(self, idxa,idxb,sizerem,r,g,b):
|
||||
if sizerem < 1:
|
||||
return 0
|
||||
global exactdata
|
||||
drs = 0
|
||||
dgs = 0
|
||||
dbs = 0
|
||||
sum = 0
|
||||
for x in range(idxa,idxb):
|
||||
if exactdata[x] is None:
|
||||
exactdata[x] = data[x]
|
||||
old = exactdata[x]
|
||||
if self.exactdata[x] is None:
|
||||
self.exactdata[x] = self.data[x]
|
||||
old = self.exactdata[x]
|
||||
dr = (r - old[0])
|
||||
dg = (g - old[1])
|
||||
db = (b - old[2])
|
||||
@@ -453,7 +437,7 @@ def fadeorder(idxa,idxb,sizerem,r,g,b):
|
||||
sum += abs(drs) + abs(dgs) + abs(dbs)
|
||||
print(drs,dgs,dbs)
|
||||
for x in range(idxa,idxb):
|
||||
old = exactdata[x]
|
||||
old = self.exactdata[x]
|
||||
new = list(old)
|
||||
if drs > 0:
|
||||
if old[0] + drs > r:
|
||||
@@ -500,20 +484,18 @@ def fadeorder(idxa,idxb,sizerem,r,g,b):
|
||||
dbs = 0
|
||||
|
||||
if drs != 0 or dgs != 0 or dbs != 0:
|
||||
exactdata[x] = new
|
||||
setpixel(new[0],new[1],new[2],x)
|
||||
self.exactdata[x] = new
|
||||
self.setpixel(new[0],new[1],new[2],x)
|
||||
|
||||
if sizerem == 1:
|
||||
exactdata[x] = None
|
||||
self.exactdata[x] = None
|
||||
|
||||
if sum == 0 and sizerem > 2:
|
||||
sizerem = 2
|
||||
return sizerem - 1
|
||||
|
||||
|
||||
def setpixel(r, g, b, num):
|
||||
global data
|
||||
global leds_size
|
||||
def setpixel(self, r, g, b, num):
|
||||
# constrain values
|
||||
if r < 0:
|
||||
r = 0
|
||||
@@ -528,29 +510,28 @@ def setpixel(r, g, b, num):
|
||||
elif b > 255:
|
||||
b = 255
|
||||
|
||||
if leds_size[num] == 3:
|
||||
data[num] = (int(r), int(g), int(b))
|
||||
elif 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))) )
|
||||
if self.leds_size[num] == 3:
|
||||
self.data[num] = (int(r), int(g), int(b))
|
||||
elif self.leds_size[num] == 4: # cut out matching white and turn on white pixel instead
|
||||
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:
|
||||
data[num] = (int(r), int(g), int(b))
|
||||
self.data[num] = (int(r), int(g), int(b))
|
||||
return self
|
||||
|
||||
|
||||
def close():
|
||||
global sender
|
||||
def close(self):
|
||||
time.sleep(0.5)
|
||||
sender.stop()
|
||||
self.sender.stop()
|
||||
return self
|
||||
|
||||
def mapimage(image, fps=90):
|
||||
global start
|
||||
while uptime() - start < 1/fps:
|
||||
def mapimage(self, image, fps=90):
|
||||
while uptime() - self.start < 1/fps:
|
||||
time.sleep(0.00001)
|
||||
fprint(1 / (uptime() - start))
|
||||
start = uptime()
|
||||
fprint(1 / (uptime() - self.start))
|
||||
self.start = uptime()
|
||||
minsize = min(image.shape[0:2])
|
||||
leds_normalized2 = [(x * minsize,
|
||||
y * minsize)
|
||||
for x, y in leds_normalized]
|
||||
for x, y in self.leds_normalized]
|
||||
|
||||
cv2.imshow("video", image)
|
||||
cv2.waitKey(1)
|
||||
@@ -567,39 +548,39 @@ def mapimage(image, fps=90):
|
||||
#avgx += x
|
||||
#avgy += y
|
||||
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)
|
||||
else:
|
||||
#avgx += x
|
||||
#avgy += y
|
||||
setpixel(0,0,0,xx)
|
||||
self.setpixel(0,0,0,xx)
|
||||
#avgx /= 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]) ))
|
||||
global data
|
||||
fastsendall(data)
|
||||
self.fastsendall(self.data)
|
||||
return self
|
||||
|
||||
def mainloop(stmode, ring = -1, fps = 100, preview = False):
|
||||
global start
|
||||
while uptime() - start < 1/fps:
|
||||
def mainloop(self, stmode, ring = -1, fps = 100, preview = False):
|
||||
while uptime() - self.start < 1/fps:
|
||||
time.sleep(0.00001)
|
||||
fprint(1 / (uptime() - start))
|
||||
start = uptime()
|
||||
if mode is not None:
|
||||
setmode(stmode)
|
||||
runmodes(ring)
|
||||
fprint(1 / (uptime() - self.start))
|
||||
self.start = uptime()
|
||||
if self.mode is not None:
|
||||
self.setmode(stmode)
|
||||
self.runmodes(ring)
|
||||
if preview:
|
||||
drawdata()
|
||||
self.drawdata()
|
||||
return self
|
||||
|
||||
def drawdata():
|
||||
def drawdata(self):
|
||||
#tmp = list()
|
||||
#for x in len(leds):
|
||||
# led = leds[x]
|
||||
# tmp.append((led[0], led[1], data[x]))
|
||||
|
||||
x = [led[0] for led in leds]
|
||||
y = [led[1] for led in leds]
|
||||
colors = data
|
||||
x = [led[0] for led in self.leds]
|
||||
y = [led[1] for led in self.leds]
|
||||
colors = self.data
|
||||
colors_normalized = [(x[0]/255, x[1]/255, x[2]/255) for x in colors]
|
||||
# Plot the points
|
||||
plt.scatter(x, y, c=colors_normalized)
|
||||
@@ -612,42 +593,48 @@ def drawdata():
|
||||
plt.show()
|
||||
plt.savefig("map3.png", dpi=50, bbox_inches="tight")
|
||||
plt.clf()
|
||||
return self
|
||||
|
||||
def startup_animation(show):
|
||||
def startup_animation(self, show):
|
||||
|
||||
|
||||
stmode = "Startup"
|
||||
mainloop(stmode, preview=show)
|
||||
while mode == "Startup":
|
||||
mainloop(None, preview=show)
|
||||
self.mainloop(stmode, preview=show)
|
||||
while self.mode == "Startup":
|
||||
self.mainloop(None, preview=show)
|
||||
for x in range(54):
|
||||
ringstatus[x][0] = False
|
||||
mainloop(None, preview=show)
|
||||
self.ringstatus[x][0] = False
|
||||
self.mainloop(None, preview=show)
|
||||
|
||||
for x in range(animation_time):
|
||||
mainloop(None, preview=show)
|
||||
clear_animations()
|
||||
for x in range(self.animation_time):
|
||||
self.mainloop(None, preview=show)
|
||||
self.clear_animations()
|
||||
stmode = "StartupCheck"
|
||||
mainloop(stmode, preview=show)
|
||||
clear_animations()
|
||||
self.mainloop(stmode, preview=show)
|
||||
self.clear_animations()
|
||||
return self
|
||||
|
||||
def clear_animations():
|
||||
for x in range(len(leds)):
|
||||
exactdata[x] = None
|
||||
def clear_animations(self):
|
||||
for x in range(len(self.leds)):
|
||||
self.exactdata[x] = None
|
||||
return self
|
||||
|
||||
def do_animation(stmode, ring=-1):
|
||||
mainloop(stmode, ring, preview=show)
|
||||
wait_for_animation(ring)
|
||||
def do_animation(self, stmode, ring=-1):
|
||||
self.mainloop(stmode, ring, preview=show)
|
||||
self.wait_for_animation(ring)
|
||||
return self
|
||||
|
||||
def start_animation(stmode, ring=-1):
|
||||
mainloop(stmode, ring, preview=show)
|
||||
def start_animation(self, stmode, ring=-1):
|
||||
self.mainloop(stmode, ring, preview=show)
|
||||
return self
|
||||
|
||||
def wait_for_animation(ring=-1):
|
||||
while mode != "idle":
|
||||
mainloop(None, ring, preview=show)
|
||||
def wait_for_animation(self, ring=-1):
|
||||
while self.mode != "idle":
|
||||
self.mainloop(None, ring, preview=show)
|
||||
return self
|
||||
|
||||
if __name__ == "__main__":
|
||||
init()
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
"""cap = cv2.VideoCapture('badapple.mp4')
|
||||
while cap.isOpened():
|
||||
@@ -655,24 +642,25 @@ if __name__ == "__main__":
|
||||
if not ret:
|
||||
break
|
||||
mapimage(frame, fps=30)"""
|
||||
show = True
|
||||
show = False
|
||||
ring = 1
|
||||
startup_animation(show)
|
||||
ledsys = LEDSystem()
|
||||
ledsys.startup_animation(show)
|
||||
for x in range(54):
|
||||
ringstatus[x][0] = True
|
||||
mainloop(None, preview=show)
|
||||
for x in range(animation_time):
|
||||
mainloop(None, preview=show)
|
||||
ledsys.ringstatus[x][0] = True
|
||||
ledsys.mainloop(None, preview=show)
|
||||
for x in range(ledsys.animation_time):
|
||||
ledsys.mainloop(None, preview=show)
|
||||
|
||||
do_animation("GrabA", 1)
|
||||
ledsys.do_animation("GrabA", 1)
|
||||
|
||||
do_animation("GrabA", 5)
|
||||
start_animation("GrabC", 1)
|
||||
ledsys.do_animation("GrabA", 5)
|
||||
ledsys.start_animation("GrabC", 1)
|
||||
|
||||
wait_for_animation(1)
|
||||
do_animation("GrabC", 5)
|
||||
ledsys.wait_for_animation(1)
|
||||
ledsys.do_animation("GrabC", 5)
|
||||
|
||||
close()
|
||||
ledsys.close()
|
||||
#sys.exit(0)
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 41 KiB |
+140
-36
@@ -1,9 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Parse Belden catalog techdata datasheets
|
||||
# Parse Belden (100%) & Alphawire (75%) catalog techdata datasheets
|
||||
|
||||
import pandas as pd
|
||||
pd.set_option('future.no_silent_downcasting', True)
|
||||
from PyPDF2 import PdfReader
|
||||
import camelot
|
||||
import numpy as np
|
||||
@@ -13,55 +12,94 @@ import json
|
||||
from util import fprint
|
||||
import uuid
|
||||
from util import run_cmd
|
||||
from util import win32
|
||||
import os
|
||||
import glob
|
||||
import sys
|
||||
|
||||
def touch(path):
|
||||
with open(path, 'a'):
|
||||
os.utime(path, None)
|
||||
|
||||
def find_data_file(filename):
|
||||
if getattr(sys, "frozen", False):
|
||||
# The application is frozen
|
||||
datadir = os.path.dirname(sys.executable)
|
||||
else:
|
||||
# The application is not frozen
|
||||
# Change this bit to match where you store your data files:
|
||||
datadir = os.path.dirname(__file__)
|
||||
return os.path.join(datadir, filename)
|
||||
|
||||
def extract_table_name(table_start, searchpage, reader, dstype, fallbackname):
|
||||
if dstype == "Belden":
|
||||
ymin = table_start
|
||||
ymax = table_start + 10
|
||||
elif dstype == "Alphawire":
|
||||
ymin = table_start - 5
|
||||
ymax = table_start + 10
|
||||
page = reader.pages[searchpage - 1]
|
||||
parts = []
|
||||
def visitor_body(text, cm, tm, fontDict, fontSize):
|
||||
y = tm[5]
|
||||
if y > ymin and y < ymax:
|
||||
parts.append(text)
|
||||
page.extract_text(visitor_text=visitor_body)
|
||||
text_body = "".join(parts).strip('\n')
|
||||
if len(text_body) == 0:
|
||||
text_body = str(fallbackname)
|
||||
|
||||
return text_body
|
||||
#fprint(text_body)
|
||||
|
||||
def parse(filename, output_dir, partnum, dstype):
|
||||
|
||||
tables = []
|
||||
# Extract table data
|
||||
|
||||
tables = camelot.read_pdf(filename, pages="1-end", flavor='lattice', backend="poppler", split_text=False, line_scale=100, process_background=True, resolution=600, interations=1, layout_kwargs={'detect_vertical': False, 'char_margin': 0.5}, shift_text=['r', 't'])
|
||||
try:
|
||||
if dstype == "Belden":
|
||||
tables = camelot.read_pdf(filename, pages="1-end", flavor='lattice', backend="ghostscript", split_text=False, line_scale=100, process_background=True, resolution=600, interations=1, layout_kwargs={'detect_vertical': False, 'char_margin': 0.5}, shift_text=['r', 't'])
|
||||
elif dstype == "Alphawire":
|
||||
tables = camelot.read_pdf(filename, pages="1-end", flavor='lattice', backend="ghostscript", split_text=False, line_scale=50, process_background=True, resolution=600, interations=1, layout_kwargs={'detect_vertical': True, 'char_margin': 0.5}, shift_text=['l', 't'])
|
||||
except (OSError, RuntimeError) as e:
|
||||
print(e)
|
||||
if win32:
|
||||
print("Ghostscript is not installed! Launching installer...")
|
||||
#subprocess.run([r".\\gs10030w64.exe"])
|
||||
os.system(r'''Powershell -Command "& { Start-Process \"''' + find_data_file("gs10030w64.exe") + r'''\" -Verb RunAs } " ''')
|
||||
# Will return once file launched...
|
||||
print("Once the install is completed, try again.")
|
||||
return False
|
||||
else:
|
||||
print("Ghostscript is not installed. You can install it with e.g. apt install ghostscript for Debian-based systems.")
|
||||
return False
|
||||
#fprint("Total tables extracted:", tables.n)
|
||||
n = 0
|
||||
pagenum = 0
|
||||
#pagenum = 0
|
||||
reader = PdfReader(filename)
|
||||
page = reader.pages[0]
|
||||
table_list = {}
|
||||
|
||||
table_list_raw = {}
|
||||
pd.set_option('future.no_silent_downcasting', True)
|
||||
for table in tables:
|
||||
#with pd.options.context("future.no_silent_downcasting", True):
|
||||
table.df.infer_objects(copy=False)
|
||||
table.df.replace('', np.nan, inplace=True)
|
||||
table.df = table.df.replace('', np.nan).infer_objects(copy=False)
|
||||
table.df.dropna(inplace=True, how="all")
|
||||
table.df.dropna(inplace=True, axis="columns", how="all")
|
||||
table.df.replace(np.nan, '', inplace=True)
|
||||
table.df = table.df.replace(np.nan, '').infer_objects(copy=False)
|
||||
|
||||
if not table.df.empty:
|
||||
#fprint("\nTable " + str(n))
|
||||
# Extract table names
|
||||
table_start = table.cells[0][0].lt[1] # Read top-left cell's top-left coordinate
|
||||
#fprint(table_start)
|
||||
ymin = table_start
|
||||
ymax = table_start + 10
|
||||
if pagenum != table.page - 1:
|
||||
pagenum = table.page - 1
|
||||
page = reader.pages[table.page - 1]
|
||||
parts = []
|
||||
def visitor_body(text, cm, tm, fontDict, fontSize):
|
||||
y = tm[5]
|
||||
if y > ymin and y < ymax:
|
||||
parts.append(text)
|
||||
|
||||
page.extract_text(visitor_text=visitor_body)
|
||||
text_body = "".join(parts).strip('\n')
|
||||
if len(text_body) == 0:
|
||||
text_body = str(n)
|
||||
#fprint(text_body)
|
||||
|
||||
text_body = extract_table_name(table_start, table.page, reader, dstype, n)
|
||||
|
||||
table_list[text_body] = table.df
|
||||
if dstype == "Alphawire":
|
||||
table_list_raw[text_body] = table
|
||||
|
||||
#table.to_html("table" + str(n) + ".html")
|
||||
|
||||
#fprint(table.df)
|
||||
@@ -100,24 +138,32 @@ def parse(filename, output_dir, partnum, dstype):
|
||||
tables = dict()
|
||||
torename = dict()
|
||||
previous_table = ""
|
||||
#print(table_list.keys())
|
||||
for table_name in table_list.keys():
|
||||
# determine shape: horizontal or vertical
|
||||
table = table_list[table_name]
|
||||
rows = table.shape[0]
|
||||
cols = table.shape[1]
|
||||
vertical = None
|
||||
#print(rows, cols, table_name)
|
||||
if rows > 2 and cols == 2:
|
||||
vertical = True
|
||||
elif cols == 1:
|
||||
elif cols == 1 and rows > 1:
|
||||
vertical = False
|
||||
elif rows == 1:
|
||||
vertical = True
|
||||
elif cols == 2: # and rows <= 2
|
||||
# inconsistent
|
||||
if dstype == "Belden":
|
||||
if table.iloc[0, 0].find(":") == len(table.iloc[0, 0]) - 1: # check if last character is ":" indicating a vertical table
|
||||
vertical = True
|
||||
else:
|
||||
vertical = False
|
||||
elif dstype == "Alphawire":
|
||||
if table.iloc[0, 0].find(")") == 1 or table.iloc[0, 0].find(")") == 2 or table.iloc[0, 0].find(":") == len(table.iloc[0, 0]) - 1: # check if last character is ":" indicating a vertical table
|
||||
vertical = True
|
||||
else:
|
||||
vertical = False
|
||||
|
||||
elif cols > 2: # and rows <= 2
|
||||
vertical = False
|
||||
@@ -125,9 +171,12 @@ def parse(filename, output_dir, partnum, dstype):
|
||||
vertical = False
|
||||
else: # 1 column, <= 2 rows
|
||||
vertical = False
|
||||
|
||||
#print(vertical)
|
||||
# missing name check
|
||||
for table_name_2 in table_list.keys():
|
||||
if dstype == "Alphawire" and table_name_2.find("\n") >= 0:
|
||||
torename[table_name_2] = table_name_2[0:table_name_2.find("\n")]
|
||||
|
||||
if table_name_2.find(table.iloc[-1, 0]) >= 0:
|
||||
# Name taken from table directly above - this table does not have a name
|
||||
torename[table_name_2] = "Specs " + str(len(tables))
|
||||
@@ -136,8 +185,12 @@ def parse(filename, output_dir, partnum, dstype):
|
||||
|
||||
if vertical:
|
||||
out = dict()
|
||||
if rows > 1:
|
||||
for row in table.itertuples(index=False, name=None):
|
||||
out[row[0].replace("\n", " ").replace(":", "")] = row[1]
|
||||
else:
|
||||
for row in table.itertuples(index=False, name=None):
|
||||
out[row[0].replace("\n", " ").replace(":", "")] = ""
|
||||
|
||||
else: # horizontal
|
||||
out = dict()
|
||||
@@ -147,9 +200,52 @@ def parse(filename, output_dir, partnum, dstype):
|
||||
|
||||
tables[table_name] = out
|
||||
|
||||
# multi-page table check, Alphawire
|
||||
if dstype == "Alphawire" and table_name.isdigit():
|
||||
# table continues from previous page or has name on previous page
|
||||
thistbl = table_list_raw[table_name]
|
||||
prevtbl = table_list_raw[previous_table]
|
||||
|
||||
if prevtbl.cells[-1][0].lb[1] < 50 and thistbl.cells[0][0].lt[1] > 600:
|
||||
# wraparound
|
||||
#print("WRAP")
|
||||
#print("PREV TABLE", prevtbl.df)
|
||||
#print("THIS TABLE", thistbl.df)
|
||||
#print("PREV TABLE CORNER", prevtbl.cells[-1][0].lb[1])
|
||||
#print("THIS TABLE CORNER", thistbl.cells[0][0].lt[1])
|
||||
main_key = previous_table
|
||||
cont_key = table_name
|
||||
#print(vertical)
|
||||
if vertical == False:
|
||||
main_keys = list(tables[main_key].keys())
|
||||
for i, (cont_key, cont_values) in enumerate(tables[cont_key].items()):
|
||||
if i < len(main_keys):
|
||||
#print(tables[main_key][main_keys[i]])
|
||||
tables[main_key][main_keys[i]] = (tuple(tables[main_key][main_keys[i]]) + (cont_key,) + cont_values)
|
||||
|
||||
del tables[table_name]
|
||||
|
||||
else:
|
||||
#print(tables[cont_key].keys())
|
||||
for key in tables[cont_key].keys():
|
||||
#print(main_key, key, cont_key, key)
|
||||
tables[main_key][key] = tables[cont_key][key]
|
||||
del tables[table_name]
|
||||
|
||||
elif thistbl.cells[0][0].lt[1] > 600:
|
||||
# name on previous page (grrrr)
|
||||
#print("NAMEABOVE")
|
||||
#print("PREV TABLE", prevtbl.df)
|
||||
#print("THIS TABLE", thistbl.df)
|
||||
#print("PREV TABLE CORNER", prevtbl.cells[-1][0].lb[1])
|
||||
#print("THIS TABLE CORNER", thistbl.cells[0][0].lt[1])
|
||||
name = extract_table_name(50, prevtbl.page,reader,dstype,table_name).strip("\n").strip()
|
||||
#print("FOUND NAME:", name)
|
||||
torename[table_name] = name
|
||||
|
||||
|
||||
# multi-page table check
|
||||
|
||||
# multi-page table check, Belden
|
||||
if dstype == "Belden":
|
||||
if table_name.isdigit() and len(tables) > 1:
|
||||
#fprint(table_name)
|
||||
@@ -177,7 +273,7 @@ def parse(filename, output_dir, partnum, dstype):
|
||||
|
||||
previous_table = table_name
|
||||
|
||||
# remove renamed tables
|
||||
# remove & rename tables
|
||||
for table_name in torename.keys():
|
||||
tables[torename[table_name]] = tables[table_name]
|
||||
del tables[table_name]
|
||||
@@ -211,11 +307,20 @@ def parse(filename, output_dir, partnum, dstype):
|
||||
|
||||
#print(output_table)
|
||||
|
||||
run_cmd("rm \"" + output_dir + "\"/*.json") # not reliable!
|
||||
with open(output_dir + "/" + output_table["searchspecs"]["id"] + ".json", 'w') as json_file:
|
||||
#run_cmd("rm \"" + output_dir + "\"/*.json") # not reliable!
|
||||
pattern = os.path.join(output_dir, '*.json')
|
||||
json_files = glob.glob(pattern)
|
||||
for file_path in json_files:
|
||||
os.remove(file_path)
|
||||
#print(f"Deleted {file_path}")
|
||||
with open(output_dir + "/search_" + output_table["searchspecs"]["id"] + ".json", 'w') as json_file:
|
||||
json.dump(output_table["searchspecs"], json_file)
|
||||
touch(output_dir + "/parsed")
|
||||
return output_table
|
||||
with open(output_dir + "/specs_" + output_table["partnum"] + ".json", 'w') as json_file:
|
||||
json.dump(output_table["fullspecs"], json_file)
|
||||
|
||||
#print(json.dumps(output_table, indent=2))
|
||||
touch(output_dir + "/parsed") # mark as parsed
|
||||
return True
|
||||
|
||||
|
||||
def flatten(tables):
|
||||
@@ -245,7 +350,6 @@ def flatten(tables):
|
||||
#print("\"" + keyname + "\":", "\"" + str(out[fullkeyname]) + "\",")
|
||||
elif len(tables[table][key]) == 1:
|
||||
out[fullkeyname] = convert_to_number(tables[table][key][0])
|
||||
|
||||
#print("\"" + keyname + "\":", "\"" + str(out[fullkeyname]) + "\",")
|
||||
|
||||
# if the item has at least two commas in it, split it
|
||||
@@ -256,7 +360,7 @@ def flatten(tables):
|
||||
# if the item has at least two commas in it, split it
|
||||
if tables[table][key].count(',') > 0:
|
||||
out[fullkeyname] = list(map(lambda x: x.strip(), tables[table][key].split(",")))
|
||||
print("\"" + keyname + "\":", "\"" + str(out[fullkeyname]) + "\",")
|
||||
#print("\"" + keyname + "\":", "\"" + str(out[fullkeyname]) + "\",")
|
||||
|
||||
|
||||
#print("}")
|
||||
@@ -265,4 +369,4 @@ def flatten(tables):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parse("test2.pdf", "cables/10GXS13", "10GXS13")
|
||||
print(parse("cables/3050/datasheet.pdf", "cables/3050", "3050", "Alphawire"))
|
||||
+8
-1
@@ -1,5 +1,5 @@
|
||||
# Runtime
|
||||
camelot-py[base]
|
||||
camelot-py
|
||||
opencv-python
|
||||
pypdf2==2.12.1
|
||||
alive-progress
|
||||
@@ -15,6 +15,13 @@ websockets
|
||||
numpy
|
||||
scipy
|
||||
ipywidgets
|
||||
pandas
|
||||
pyarrow
|
||||
ghostscript
|
||||
pyzbar
|
||||
segno
|
||||
|
||||
# Development
|
||||
matplotlib
|
||||
#cx_Freeze # uncomment if building label generator app
|
||||
# requires windows 10 SDK, visual C++, etc
|
||||
@@ -17,7 +17,7 @@ import signal
|
||||
import socket
|
||||
from flask import Flask, render_template, request
|
||||
import requests
|
||||
import led_control
|
||||
from led_control import LEDSystem
|
||||
import server
|
||||
import asyncio
|
||||
import json
|
||||
@@ -36,7 +36,7 @@ killme = None
|
||||
#pool = None
|
||||
serverproc = None
|
||||
camera = None
|
||||
|
||||
ledsys = None
|
||||
to_server_queue = Queue()
|
||||
from_server_queue = Queue()
|
||||
|
||||
@@ -47,6 +47,8 @@ def arm_start_callback(res):
|
||||
def led_start_callback(res):
|
||||
global led_ready
|
||||
led_ready = True
|
||||
global ledsys
|
||||
ledsys = res
|
||||
|
||||
def camera_start_callback(res):
|
||||
global camera_ready
|
||||
@@ -233,7 +235,9 @@ def setup_server(pool):
|
||||
global camera
|
||||
|
||||
pool.apply_async(ur5_control.init, (config["arm"]["ip"],), callback=arm_start_callback)
|
||||
pool.apply_async(led_control.init, callback=led_start_callback)
|
||||
global ledsys
|
||||
ledsys = LEDSystem()
|
||||
pool.apply_async(ledsys.init, callback=led_start_callback)
|
||||
#pool.apply_async(sensor_control.init, callback=sensor_start_callback)
|
||||
serverproc = Process(target=start_server_socket)
|
||||
serverproc.start()
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import sys
|
||||
from cx_Freeze import setup, Executable
|
||||
|
||||
debug = True
|
||||
debug = not debug
|
||||
# Dependencies are automatically detected, but it might need fine tuning.
|
||||
# "packages": ["os"] is used as example only
|
||||
|
||||
import opcode
|
||||
import os
|
||||
import distutils
|
||||
#distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'distutils')
|
||||
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 = "console"
|
||||
#if sys.platform == "win32" and not debug:
|
||||
# base = "Win32GUI"
|
||||
|
||||
if sys.platform == "linux" or sys.platform == "linux2" or sys.platform == "darwin":
|
||||
name = "jukebox-labelgen"
|
||||
else:
|
||||
name = "jukebox-labelgen.exe"
|
||||
|
||||
setup(
|
||||
name="IP Pigeon",
|
||||
version="0.2.4",
|
||||
description="IP Pigeon client application",
|
||||
options={"build_exe": build_exe_options},
|
||||
executables=[Executable("label_generator.py", base=base, uac_admin=False, target_name=name)],
|
||||
)
|
||||
+170
-22
@@ -14,7 +14,8 @@ from util import fprint
|
||||
|
||||
|
||||
rob = None
|
||||
|
||||
offset_x, offset_y, offset_z = (0, 0, 0.14) # Tool offset
|
||||
limb_base, limb1, limb2, limb3, limb_wrist = (0.105, .425, .39225, .1, .0997) # Limb lengths
|
||||
|
||||
def init(ip):
|
||||
global rob
|
||||
@@ -190,6 +191,11 @@ def move_to_polar(start_pos, end_pos):
|
||||
|
||||
return rx_intermediate
|
||||
|
||||
def degtorad(angle):
|
||||
return angle/180.0 * math.pi
|
||||
def radtodeg(angle):
|
||||
return angle*180.0 / math.pi
|
||||
|
||||
def move_to_home():
|
||||
global rob
|
||||
|
||||
@@ -216,39 +222,107 @@ def normalize_degree(theta):
|
||||
# Return angle
|
||||
return normalized_theta
|
||||
|
||||
def get_joints_from_xyz_rel(x, y, z, initial_guess = (math.pi/2, math.pi/2, 0), limbs=(.422864, .359041, .092124)):
|
||||
# Get polar coordinates of x,y pair
|
||||
r, theta = cartesian_to_polar(x, y)
|
||||
|
||||
# Get length of each limb
|
||||
l1, l2, l3 = limbs
|
||||
|
||||
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), l3offset=0):
|
||||
# Get limbs and offsets
|
||||
|
||||
#l3=0.15
|
||||
l_bs, l1, l2, l3, l_wt = (limb_base, limb1, limb2, limb3, limb_wrist) # Limb lengths
|
||||
l3 += l3offset # add wrist offset, used for gripper angle calculations
|
||||
|
||||
# Calculate base angle and r relative to shoulder joint
|
||||
def calculate_theta(x, y, a):
|
||||
# Calculate if we need the + or - in our equations
|
||||
if (x>-a and y>=0) or (x>a and y<0):
|
||||
flip = 1
|
||||
elif (x<-a and y>=0) or (x<a and y<0):
|
||||
flip = -1
|
||||
else:
|
||||
# Critical section (x=a, or x=-a). Infinite slope
|
||||
# Return 0 or 180 depending on sign
|
||||
return math.atan2(y, 0)
|
||||
|
||||
# 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)
|
||||
b = flip * a * math.sqrt(1+m*m)
|
||||
# Calculate equivalent tangent point on circle
|
||||
cx = (-flip*m*b)/(1+m*m)
|
||||
cy = m*cx + flip*b
|
||||
# Calculate base angle, make angle negative if flip=1
|
||||
theta = math.atan2(cy, cx) + (-math.pi if flip==1 else 0)
|
||||
return theta
|
||||
|
||||
base_theta = calculate_theta(x, y, l_bs)
|
||||
cx, cy = l_bs*math.cos(base_theta), l_bs*math.sin(base_theta)
|
||||
r = math.sqrt((x+offset_x+cx)**2 + (y+offset_y+cy)**2)
|
||||
|
||||
|
||||
# Formulas to find out joint positions for (r, z)
|
||||
def inv_kin_r_z(p):
|
||||
a, b, c = p
|
||||
|
||||
return (l1*math.cos(a) + l2*math.cos(a-b) + l3*math.cos(a-b-c) - r, # r
|
||||
l1*math.sin(a) + l2*math.sin(a-b) - l3*math.sin(a-b-c) - z, # z
|
||||
l1*math.sin(a) + l2*math.sin(a-b) - l3*math.sin(a-b-c) - (l3*math.sin(a-b-c)) - (z + offset_z), # z
|
||||
a-b-c) # wrist angle
|
||||
|
||||
|
||||
# Normalize angles
|
||||
base, shoulder, elbow, wrist = [normalize_degree(deg) for deg in [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 base, shoulder, elbow, wrist
|
||||
return base, shoulder, elbow, wrist1, ry, rz
|
||||
|
||||
def get_joints_from_xyz_abs(x, y, z):
|
||||
joints = get_joints_from_xyz_rel(x, y, z)
|
||||
def get_joints_from_xyz_abs(x, y, z, rx=0, ry=-math.pi/2, rz=math.pi/2, l3offset=0):
|
||||
joints = get_joints_from_xyz_rel(x, y, z, rx, ry, rz, l3offset=l3offset)
|
||||
|
||||
# Joint offsets
|
||||
# Base, Shoulder, Elbow, Wrist
|
||||
inverse = [1, -1, 1, 1]
|
||||
offsets = [0, 0, 0, -math.pi/2]
|
||||
|
||||
inverse = [1, -1, 1, 1, 1, 1]
|
||||
offsets = [-math.pi/2, 0, 0, -math.pi/2, 0, 0]
|
||||
if radtodeg(joints[1]) > 137:
|
||||
print("CRASH! Shoulder at", joints[1] * 180/math.pi)
|
||||
#else:
|
||||
#print("Shoulder at", joints[1] * 180/math.pi)
|
||||
# Return adjusted joint positions
|
||||
return [o+j*i for j, o, i in zip(joints, offsets, inverse)]
|
||||
|
||||
# gripper angle: from vertical
|
||||
# gripper length: from joint to start of grip
|
||||
# to flip, you can use flip=True or make gripper angle negative
|
||||
def offset_gripper_angle(x, y, z, gripperangle=35, gripperlength=0.20+0.018, flip=False):
|
||||
if gripperangle < 0:
|
||||
rz = - math.pi / 2
|
||||
else:
|
||||
rz = math.pi / 2
|
||||
|
||||
if flip:
|
||||
gripperangle = -degtorad(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(x, y, z-grippery, rx=gripperangle + degtorad(180), l3offset=-gripperx, ry=math.pi/2, rz=rz)
|
||||
else:
|
||||
gripperangle = degtorad(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(x, y, z-grippery, rx=gripperangle, l3offset=-gripperx, rz=rz)
|
||||
|
||||
|
||||
def goto_holder_index(idx, z=0.05, gripperangle=35, flip=False):
|
||||
joint = config["position_map"][idx]
|
||||
print("Going to cable holder index", joint["index"], "at position", joint["pos"])
|
||||
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, )
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
#rob.movej((0, 0, 0, 0, 0, 0), 0.1, 0.2)
|
||||
@@ -262,7 +336,7 @@ if __name__ == "__main__":
|
||||
0.40002172976662786,
|
||||
0,
|
||||
-3.14152741295329,
|
||||
0]
|
||||
math.radians(62)]
|
||||
|
||||
# time.sleep(.5)
|
||||
|
||||
@@ -290,14 +364,88 @@ if __name__ == "__main__":
|
||||
# set_pos_abs(*home_pose)
|
||||
|
||||
|
||||
angles = get_joints_from_xyz_abs(0.3, 0.3, 0.3)
|
||||
rob.movej([*angles, *rob.getj()[4:]], acc=1, vel=1)
|
||||
|
||||
angles = get_joints_from_xyz_abs(-0.3, -0.3, 0.7)
|
||||
rob.movej([*angles, *rob.getj()[4:]], acc=1, vel=1)
|
||||
# angles = get_joints_from_xyz_abs(-0.2, 0, 0)
|
||||
# rob.movej(angles, acc=2, vel=2)
|
||||
# angles = get_joints_from_xyz_abs(-0.2, -0.2, 0)
|
||||
# rob.movej(angles, acc=2, vel=2)
|
||||
# angles = get_joints_from_xyz_abs(0, -0.6, 0)
|
||||
# rob.movej(angles, acc=2, vel=2)
|
||||
# angles = get_joints_from_xyz_abs(0, -0.5, 0)
|
||||
# rob.movej(angles, acc=2, vel=2)
|
||||
# angles = get_joints_from_xyz_abs(0, -0.4, 0)
|
||||
# rob.movej(angles, acc=2, vel=2)
|
||||
# angles = get_joints_from_xyz_abs(0, -0.3, 0)
|
||||
# rob.movej(angles, acc=2, vel=2)
|
||||
# angles = get_joints_from_xyz_abs(0, -0.2, 0)
|
||||
# rob.movej(angles, acc=2, vel=2)
|
||||
# angles = get_joints_from_xyz_abs(0, -0.13, 0)
|
||||
# rob.movej(angles, acc=2, vel=2)
|
||||
config = None
|
||||
joints = []
|
||||
for i in np.linspace(-0.2, -0.7, 50):
|
||||
joints.append(get_joints_from_xyz_abs(i, 0, 0))
|
||||
#rob.movejs(joints, acc=2, vel=2)
|
||||
import yaml
|
||||
with open('config.yml', 'r') as fileread:
|
||||
#global config
|
||||
config = yaml.safe_load(fileread)
|
||||
|
||||
#rob.movej(goto_holder_index(24, 0.2, 0), acc=2, vel=2)
|
||||
#joints = []
|
||||
|
||||
#for i in np.linspace(0, 340, 340):
|
||||
# joints.append(goto_holder_index(24, 0.5, i))
|
||||
#rob.movejs(joints, acc=1, vel=3)
|
||||
angle = 30
|
||||
rob.movej(goto_holder_index(26, 0.1, angle), acc=2, vel=2)
|
||||
time.sleep(1)
|
||||
rob.movej(goto_holder_index(25, 0.1, angle), acc=2, vel=2)
|
||||
time.sleep(1)
|
||||
rob.movej(goto_holder_index(24, 0.1, angle, flip=True), acc=2, vel=2)
|
||||
#rob.movej(goto_holder_index(32, 0.2, angle), acc=2, vel=2)
|
||||
#rob.movej(goto_holder_index(38, 0.2, angle), acc=2, vel=2)
|
||||
#rob.movej(goto_holder_index(25, 0.1, angle, flip=True), acc=2, vel=2)
|
||||
|
||||
#rob.movej(goto_holder_index(25, 0.2, angle, flip=True), acc=2, vel=2)
|
||||
#rob.movej(goto_holder_index(24, 0.1, angle, flip=True), acc=2, vel=2)
|
||||
#time.sleep(1)
|
||||
#rob.movej(goto_holder_index(25, 0.1, angle, flip=True), acc=2, vel=2)
|
||||
#rob.movej(goto_holder_index(49, 0.1, angle), acc=2, vel=2)
|
||||
#rob.movej(goto_holder_index(49, 0.1, angle, flip=True), acc=2, vel=2)
|
||||
# rob.movej(goto_holder_index(50, 0.1, angle, flip=True), acc=2, vel=2)
|
||||
# rob.movej(goto_holder_index(51, 0.1, angle, flip=True), acc=2, vel=2)
|
||||
# rob.movej(goto_holder_index(52, 0.1, angle, flip=True), acc=2, vel=2)
|
||||
# rob.movej(goto_holder_index(53, 0.1, angle, flip=True), acc=2, vel=2)
|
||||
#time.sleep(2)
|
||||
#rob.movej(goto_holder_index(24, 0.15, 35, flip=True), acc=2, vel=2)
|
||||
#time.sleep(10)
|
||||
# time.sleep(4)
|
||||
# goto_holder_index(26, 0.1, 20)
|
||||
# time.sleep(4)
|
||||
# goto_holder_index(26, 0.1, 30)
|
||||
# time.sleep(4)
|
||||
# goto_holder_index(26, 0.1, 40)
|
||||
# for joint in config["position_map"]:
|
||||
#joint = config["position_map"][26]
|
||||
#print("Going to cable holder index", joint["index"], "at position", joint["pos"])
|
||||
#angles = get_joints_from_xyz_abs(joint["pos"][1]/1000, joint["pos"][0]/1000, 0.05, )# rx=math.pi / 5)
|
||||
#joints.append(angles)
|
||||
|
||||
#rob.movej(angles, acc=2, vel=2)
|
||||
#time.sleep(10)
|
||||
#rob.movejs(joints, 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)
|
||||
|
||||
angles = get_joints_from_xyz_abs(-0.3, 0.4, 0.2)
|
||||
rob.movej([*angles, *rob.getj()[4:]], acc=1, vel=1)
|
||||
|
||||
|
||||
# set_pos_abs(*p1)
|
||||
|
||||
Reference in new issue
Block a user