Compare commits
	
		
			26 Commits
		
	
	
		
			dthomas-db
			...
			b861a61f07
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | b861a61f07 | ||
|  | 925ceb4b5a | ||
|  | dd2559130d | ||
|  | 1fa7654da5 | ||
|  | 051cc1d003 | ||
|  | e1af00e1db | ||
| af6ffe451d | |||
| 50bf835d13 | |||
| fe5de4e54c | |||
| 523915feb0 | |||
| b5b2a936c1 | |||
| afd144bd32 | |||
| eb221a5206 | |||
| db7c8c4577 | |||
|  | 21b1bf7992 | ||
| d376dba67c | |||
| 95631dbdbe | |||
| 9aef296763 | |||
| 2b287492de | |||
| d2a4d93590 | |||
| 58605dbe85 | |||
| 7bf3276ce9 | |||
| 818688452b | |||
| 01526524d4 | |||
| 33671683ea | |||
| fad885c610 | 
							
								
								
									
										11
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | FROM python:latest | ||||||
|  |  | ||||||
|  | RUN apt-get update && apt-get install -y libgl1-mesa-glx ghostscript && apt-get clean && rm -rf /var/lib/apt/lists | ||||||
|  | COPY . . | ||||||
|  | #COPY config-server.yml config.yml | ||||||
|  | RUN pip3 install -r requirements.txt | ||||||
|  |  | ||||||
|  | CMD ["python3", "run.py"] | ||||||
|  | EXPOSE 5000 | ||||||
|  | EXPOSE 8000 | ||||||
|  | EXPOSE 9000 | ||||||
| @@ -32,13 +32,13 @@ led: | |||||||
|       ledstart: 288 |       ledstart: 288 | ||||||
|       ledend: 431 |       ledend: 431 | ||||||
|       mode: rgb |       mode: rgb | ||||||
|     - universe: 1 |     - universe: 4 | ||||||
|       ip: 192.168.68.130 |       ip: 192.168.5.40 | ||||||
|       ledstart: 432 |       ledstart: 432 | ||||||
|       ledend: 575 |       ledend: 575 | ||||||
|       mode: rgb |       mode: rgb | ||||||
|     - universe: 4 |     - universe: 1 | ||||||
|       ip: 192.168.68.131 |       ip: 192.168.5.4 | ||||||
|       ledstart: 576 |       ledstart: 576 | ||||||
|       ledend: 719 |       ledend: 719 | ||||||
|       mode: rgb |       mode: rgb | ||||||
|   | |||||||
							
								
								
									
										110
									
								
								get_specs.py
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								get_specs.py
									
									
									
									
									
								
							| @@ -26,7 +26,7 @@ def check_internet(url='https://belden.com', timeout=5): | |||||||
|      |      | ||||||
|  |  | ||||||
|  |  | ||||||
| def query_search(partnum): | def query_search(partnum, source): | ||||||
|     """token_url = "https://www.belden.com/coveo/rest/token?t=" + str(int(time.time())) |     """token_url = "https://www.belden.com/coveo/rest/token?t=" + str(int(time.time())) | ||||||
|     with requests.get(token_url) as r: |     with requests.get(token_url) as r: | ||||||
|         out = json.loads(r.content) |         out = json.loads(r.content) | ||||||
| @@ -49,15 +49,50 @@ def query_search(partnum): | |||||||
|     # Bash script uses some crazy json formatting that I could not figure out |     # Bash script uses some crazy json formatting that I could not figure out | ||||||
|     # Despite the fact that I wrote it |     # Despite the fact that I wrote it | ||||||
|     # So I'll just leave it, becuase it works. |     # So I'll just leave it, becuase it works. | ||||||
|  |     if source == "Belden": | ||||||
|  |         command = ["./query-search.sh", partnum] | ||||||
|  |         result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) | ||||||
|  |         if result.returncode != 0: # error | ||||||
|  |             fprint("No results found in search database for " + partnum + ". No hi-res part image available.", result.stderr) | ||||||
|  |             return False | ||||||
|  |         else: | ||||||
|  |             data_out = json.loads(result.stdout) | ||||||
|  |             return data_out | ||||||
|  |     elif source == "Alphawire": | ||||||
|  |         alphaurl = "https://www.alphawire.com//sxa/search/results/?l=en&s={4A774076-6068-460C-9CC6-A2D8E85E407F}&itemid={BF82F58C-EFD9-4D8B-AE3E-097DD12CF7DA}&sig=&autoFireSearch=true&productpartnumber=*" + partnum + "*&v={B22CD56D-AB95-4048-8AA1-5BBDF2F2D17F}&p=10&e=0&o=ProductPartNumber%2CAscending" | ||||||
|  |         r = requests.get(url=alphaurl) | ||||||
|  |         data = r.json() | ||||||
|  |         output = dict() | ||||||
|  |         #print(data) | ||||||
|  |         try: | ||||||
|  |             if data["Count"] > 0: | ||||||
|  |                 print(data["Results"][0]["Url"]) | ||||||
|  |                 result = data["Results"][0] | ||||||
|  |                 if result["Url"].split("/")[-1] == partnum: | ||||||
|  |                     #print(partnum) | ||||||
|  |                     print(result["Html"]) | ||||||
|  |                     try: | ||||||
|  |                         imgidx = result["Html"].index("<img src=") + 10 | ||||||
|  |                         imgidx2 = result["Html"].index("?", imgidx) | ||||||
|  |                         output["image"] = result["Html"][imgidx:imgidx2] | ||||||
|  |                         if output["image"].index("http") != 0: | ||||||
|  |                             output["image"] = "" | ||||||
|  |                             print("No cable image found.") | ||||||
|  |                     except: | ||||||
|  |                         print("No cable image found.") | ||||||
|  |  | ||||||
|     command = ["./query-search.sh", partnum] |                     dsidx = result["Html"].index("<a href=\"/disteAPI/") + 9 | ||||||
|     result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) |                     dsidx2 = result["Html"].index(partnum, dsidx) + len(partnum) | ||||||
|     if result.returncode != 0: # error |                     output["datasheet"] = "https://www.alphawire.com" + result["Html"][dsidx:dsidx2] | ||||||
|         fprint("No results found in search database for " + partnum + ". No hi-res part image available.", result.stderr) |                     #"test".index() | ||||||
|  |                     print(output) | ||||||
|  |                     return output | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         except: | ||||||
|  |             return False | ||||||
|         return False |         return False | ||||||
|     else: |  | ||||||
|         data_out = json.loads(result.stdout) |  | ||||||
|         return data_out |  | ||||||
|  |  | ||||||
| def touch(path): | def touch(path): | ||||||
|     with open(path, 'a'): |     with open(path, 'a'): | ||||||
| @@ -126,7 +161,7 @@ def get_multi(partnums): | |||||||
|                 sys.exit() |                 sys.exit() | ||||||
|  |  | ||||||
|  |  | ||||||
|         def _download_image(url, output_dir): # Download datasheet with known URL |         def _download_image(url, output_dir): # Download image with known URL | ||||||
|             global bartext |             global bartext | ||||||
|  |  | ||||||
|             #fprint(url) |             #fprint(url) | ||||||
| @@ -151,25 +186,31 @@ def get_multi(partnums): | |||||||
|                 os.remove(partnum + "/datasheet.pdf") |                 os.remove(partnum + "/datasheet.pdf") | ||||||
|                 sys.exit() |                 sys.exit() | ||||||
|  |  | ||||||
|         def __use_cached_datasheet(partnum, path, output_dir): |         def __use_cached_datasheet(partnum, path, output_dir, dstype): | ||||||
|             fprint("Using cached datasheet for " + partnum) |             fprint("Using cached datasheet for " + partnum) | ||||||
|             bar.text = "Using cached datasheet for " + partnum |             bar.text = "Using cached datasheet for " + partnum | ||||||
|             bar(skipped=True) |             bar(skipped=True) | ||||||
|             fprint("Parsing Datasheet contents of " + partnum) |             fprint("Parsing Datasheet contents of " + partnum) | ||||||
|             bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..." |             bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..." | ||||||
|             read_datasheet.parse(path, output_dir) |             read_datasheet.parse(path, output_dir, partnum, dstype) | ||||||
|             bar(skipped=False) |             bar(skipped=False) | ||||||
|  |  | ||||||
|         def __downloaded_datasheet(partnum, path, output_dir): |         def __downloaded_datasheet(partnum, path, output_dir, dstype): | ||||||
|             fprint("Downloaded " + path) |             fprint("Downloaded " + path) | ||||||
|             bar.text = "Downloaded " + path |             bar.text = "Downloaded " + path | ||||||
|             bar(skipped=False) |             bar(skipped=False) | ||||||
|             fprint("Parsing Datasheet contents of " + partnum) |             fprint("Parsing Datasheet contents of " + partnum) | ||||||
|             bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..." |             bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..." | ||||||
|             read_datasheet.parse(path, output_dir) |             read_datasheet.parse(path, output_dir, partnum, dstype) | ||||||
|             bar(skipped=False) |             bar(skipped=False) | ||||||
|  |  | ||||||
|         for partnum in partnums: |         for fullpartnum in partnums: | ||||||
|  |             if fullpartnum[0:2] == "BL": # catalog.belden.com entry\ | ||||||
|  |                 partnum = fullpartnum[2:] | ||||||
|  |                 dstype = "Belden" | ||||||
|  |             elif fullpartnum[0:2] == "AW": | ||||||
|  |                 partnum = fullpartnum[2:] | ||||||
|  |                 dstype = "Alphawire" | ||||||
|             output_dir = "cables/" + partnum |             output_dir = "cables/" + partnum | ||||||
|             path = output_dir + "/datasheet.pdf" |             path = output_dir + "/datasheet.pdf" | ||||||
|             bartext = "Downloading files for part " + partnum |             bartext = "Downloading files for part " + partnum | ||||||
| @@ -177,7 +218,7 @@ def get_multi(partnums): | |||||||
|             # |             # | ||||||
|             if (not os.path.exists(output_dir + "/found_part_hires")) or not (os.path.exists(path) and os.path.getsize(path) > 1): |             if (not os.path.exists(output_dir + "/found_part_hires")) or not (os.path.exists(path) and os.path.getsize(path) > 1): | ||||||
|                 # Use query |                 # Use query | ||||||
|                 search_result = query_search(partnum.replace(" ", "")) |                 search_result = query_search(partnum.replace(" ", ""), dstype) | ||||||
|                 # Try to use belden.com search |                 # Try to use belden.com search | ||||||
|                 if search_result is not False: |                 if search_result is not False: | ||||||
|                     # Download high resolution part image if available and needed |                     # Download high resolution part image if available and needed | ||||||
| @@ -190,17 +231,17 @@ def get_multi(partnums): | |||||||
|  |  | ||||||
|                     # Download datasheet from provided URL if needed |                     # Download datasheet from provided URL if needed | ||||||
|                     if os.path.exists(path) and os.path.getsize(path) > 1: |                     if os.path.exists(path) and os.path.getsize(path) > 1: | ||||||
|                         __use_cached_datasheet(partnum, path, output_dir) |                         __use_cached_datasheet(partnum, path, output_dir, dstype) | ||||||
|  |  | ||||||
|                     elif _download_datasheet(search_result["datasheet"], output_dir) is not False: |                     elif _download_datasheet(search_result["datasheet"], output_dir) is not False: | ||||||
|                         __downloaded_datasheet(partnum, path, output_dir) |                         __downloaded_datasheet(partnum, path, output_dir, dstype) | ||||||
|                  |                  | ||||||
|                 elif os.path.exists(path) and os.path.getsize(path) > 1: |                 elif os.path.exists(path) and os.path.getsize(path) > 1: | ||||||
|                     __use_cached_datasheet(partnum, path, output_dir) |                     __use_cached_datasheet(partnum, path, output_dir, dstype) | ||||||
|                  |                  | ||||||
|                 # If search fails, and we don't already have the datasheet, guess datasheet URL and skip the hires image download |                 # 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: |                 elif _try_download_datasheet(partnum, output_dir) is not False: | ||||||
|                     __downloaded_datasheet(partnum, path, output_dir) |                     __downloaded_datasheet(partnum, path, output_dir, dstype) | ||||||
|  |  | ||||||
|                 # Failed to download with search or guess :( |                 # Failed to download with search or guess :( | ||||||
|                 else:  |                 else:  | ||||||
| @@ -213,7 +254,7 @@ def get_multi(partnums): | |||||||
|             # We already have a hi-res image and the datasheet - perfect! |             # We already have a hi-res image and the datasheet - perfect! | ||||||
|             else: |             else: | ||||||
|                 fprint("Using cached hi-res part image for " + partnum) |                 fprint("Using cached hi-res part image for " + partnum) | ||||||
|                 __use_cached_datasheet(partnum, path, output_dir) |                 __use_cached_datasheet(partnum, path, output_dir, dstype) | ||||||
|      |      | ||||||
|     if len(failed) > 0: |     if len(failed) > 0: | ||||||
|         fprint("Failed to download:") |         fprint("Failed to download:") | ||||||
| @@ -227,21 +268,22 @@ def get_multi(partnums): | |||||||
|  |  | ||||||
|  |  | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     partnums = ["10GXS12", "RST 5L-RKT 5L-949",  |     partnums = ["BL7958A", "BL10GXS12", "BLRST 5L-RKT 5L-949",  | ||||||
| "10GXS13", | "BL10GXS13", | ||||||
| "10GXW12", | "BL10GXW12", | ||||||
| "10GXW13", | "BL10GXW13", | ||||||
| "2412", | "BL2412", | ||||||
| "2413", | "BL2413", | ||||||
| "OSP6AU", | "BLOSP6AU", | ||||||
| "FI4D024P9", | "BLFI4D024P9", | ||||||
| "FISD012R9", | "BLFISD012R9", | ||||||
| "FDSD012A9", | "BLFDSD012A9", | ||||||
| "FSSL024NG", | "BLFSSL024NG", | ||||||
| "FISX006W0", | "BLFISX006W0", | ||||||
| "FISX00103", | "BLFISX00103", | ||||||
| "C6D1100007" | "BLC6D1100007" | ||||||
|     ] |     ] | ||||||
|     get_multi(partnums) |     get_multi(partnums) | ||||||
|  |     #query_search("3248", "Alphawire") | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										359
									
								
								inv_kin_testing.ipynb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								inv_kin_testing.ipynb
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -178,9 +178,9 @@ def init(): | |||||||
|     sendall(data) |     sendall(data) | ||||||
|     #time.sleep(50000)     |     #time.sleep(50000)     | ||||||
|     fprint("Running start-up test sequence...") |     fprint("Running start-up test sequence...") | ||||||
|     for y in range(1): |     for y in range(100): | ||||||
|         for x in range(len(leds)): |         for x in range(len(leds)): | ||||||
|             setpixel(5,5,5,x) |             setpixel(0,0,150,x) | ||||||
|         sendall(data) |         sendall(data) | ||||||
|         #time.sleep(2) |         #time.sleep(2) | ||||||
|         #alloffsmooth() |         #alloffsmooth() | ||||||
| @@ -290,7 +290,7 @@ def close(): | |||||||
|     time.sleep(0.5) |     time.sleep(0.5) | ||||||
|     sender.stop() |     sender.stop() | ||||||
|  |  | ||||||
| def mapimage(image, fps=60): | def mapimage(image, fps=90): | ||||||
|     global start |     global start | ||||||
|     while uptime() - start < 1/fps: |     while uptime() - start < 1/fps: | ||||||
|         time.sleep(0.00001) |         time.sleep(0.00001) | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								map.png
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								map.png
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 381 KiB After Width: | Height: | Size: 381 KiB | 
| @@ -9,8 +9,10 @@ from PIL import Image | |||||||
| import io | import io | ||||||
| import json | import json | ||||||
| from util import fprint | from util import fprint | ||||||
|  | import uuid | ||||||
|  | from util import run_cmd | ||||||
|  |  | ||||||
| def parse(filename, output_dir): | def parse(filename, output_dir, partnum, dstype): | ||||||
|  |  | ||||||
|     # Extract table data |     # Extract table data | ||||||
|  |  | ||||||
| @@ -22,6 +24,7 @@ def parse(filename, output_dir): | |||||||
|     page = reader.pages[0] |     page = reader.pages[0] | ||||||
|     table_list = {} |     table_list = {} | ||||||
|     for table in tables: |     for table in tables: | ||||||
|  |         table.df.infer_objects(copy=False) | ||||||
|         table.df.replace('', np.nan, inplace=True) |         table.df.replace('', np.nan, inplace=True) | ||||||
|         table.df.dropna(inplace=True, how="all") |         table.df.dropna(inplace=True, how="all") | ||||||
|         table.df.dropna(inplace=True, axis="columns", how="all") |         table.df.dropna(inplace=True, axis="columns", how="all") | ||||||
| @@ -137,44 +140,104 @@ def parse(filename, output_dir): | |||||||
|  |  | ||||||
|  |  | ||||||
|         # multi-page table check |         # multi-page table check | ||||||
|         if table_name.isdigit() and len(tables) > 1: |         if dstype == "Belden": | ||||||
|             fprint(table_name) |             if table_name.isdigit() and len(tables) > 1: | ||||||
|             fprint(previous_table) |                 fprint(table_name) | ||||||
|              |                 fprint(previous_table) | ||||||
|              |                  | ||||||
|              |                  | ||||||
|              |                  | ||||||
|             main_key = previous_table |                  | ||||||
|             cont_key = table_name |                 main_key = previous_table | ||||||
|             fprint(tables) |                 cont_key = table_name | ||||||
|             if vertical == False: |                 fprint(tables) | ||||||
|                 main_keys = list(tables[main_key].keys()) |                 if vertical == False: | ||||||
|                 for i, (cont_key, cont_values) in enumerate(tables[cont_key].items()): |                     main_keys = list(tables[main_key].keys()) | ||||||
|                     if i < len(main_keys): |                     for i, (cont_key, cont_values) in enumerate(tables[cont_key].items()): | ||||||
|                         fprint(tables[main_key][main_keys[i]]) |                         if i < len(main_keys): | ||||||
|                         tables[main_key][main_keys[i]] = (tables[main_key][main_keys[i]] + (cont_key,) + cont_values) |                             fprint(tables[main_key][main_keys[i]]) | ||||||
|  |                             tables[main_key][main_keys[i]] = (tables[main_key][main_keys[i]] + (cont_key,) + cont_values) | ||||||
|                 del tables[table_name] |      | ||||||
|  |                     del tables[table_name] | ||||||
|             else: |      | ||||||
|                 for key in tables[cont_key].keys(): |                 else: | ||||||
|                     tables[main_key][key] = tables[cont_key][key] |                     for key in tables[cont_key].keys(): | ||||||
|                 del tables[table_name] |                         tables[main_key][key] = tables[cont_key][key] | ||||||
|  |                     del tables[table_name] | ||||||
|  |  | ||||||
|         previous_table = table_name |         previous_table = table_name | ||||||
|      |      | ||||||
|  |     # remove multi-line values that occasionally squeak through | ||||||
|  |     def replace_newlines_in_dict(d): | ||||||
|  |         for key, value in d.items(): | ||||||
|  |             if isinstance(value, str): | ||||||
|  |                 # Replace \n with " " if the value is a string | ||||||
|  |                 d[key] = value.replace('\n', ' ') | ||||||
|  |             elif isinstance(value, dict): | ||||||
|  |                 # Recursively call the function if the value is another dictionary | ||||||
|  |                 replace_newlines_in_dict(value) | ||||||
|  |         return d | ||||||
|  |      | ||||||
|  |     tables = replace_newlines_in_dict(tables) | ||||||
|  |  | ||||||
|     fprint(tables) |     # summary | ||||||
|     with open(output_dir + "/tables.json", 'w') as json_file: |  | ||||||
|         json.dump(tables, json_file) |     output_table = dict() | ||||||
|  |     output_table["partnum"] = partnum | ||||||
|  |     id = str(uuid.uuid4()) | ||||||
|  |     output_table["id"] = id | ||||||
|  |     #output_table["position"] = id | ||||||
|  |     #output_table["brand"] = brand | ||||||
|  |     output_table["fullspecs"] = tables | ||||||
|  |     output_table["searchspecs"] = {"partnum": partnum, **flatten(tables)} | ||||||
|  |      | ||||||
|  |     output_table["searchspecs"]["id"] = id | ||||||
|  |      | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     print(output_table) | ||||||
|  |  | ||||||
|  |     run_cmd("rm " + output_dir + "/*.json") # not reliable! | ||||||
|  |     with open(output_dir + "/" + output_table["searchspecs"]["id"] + ".json", 'w') as json_file: | ||||||
|  |         json.dump(output_table["searchspecs"], json_file) | ||||||
|  |  | ||||||
|  |     return output_table | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def flatten(tables): | ||||||
|  |     def convert_to_number(s): | ||||||
|  |         try: | ||||||
|  |             # First, try converting to an integer. | ||||||
|  |             return int(s) | ||||||
|  |         except ValueError: | ||||||
|  |             # If that fails, try converting to a float. | ||||||
|  |             try: | ||||||
|  |                 return float(s) | ||||||
|  |             except ValueError: | ||||||
|  |                 # If it fails again, return the original string. | ||||||
|  |                 return s | ||||||
|  |     out = dict() | ||||||
|  |     print("{") | ||||||
|  |     for table in tables.keys(): | ||||||
|  |         for key in tables[table].keys(): | ||||||
|  |             if len(key) < 64: | ||||||
|  |                 keyname = key | ||||||
|  |             else: | ||||||
|  |                 keyname = key[0:64] | ||||||
|  |  | ||||||
|     return tables |             fullkeyname = (table + ": " + keyname).replace(".","") | ||||||
|  |             if type(tables[table][key]) is not tuple: | ||||||
|  |                 out[fullkeyname] = convert_to_number(tables[table][key]) | ||||||
|  |                 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]) + "\",") | ||||||
|  |  | ||||||
|  |     print("}") | ||||||
|  |     return out | ||||||
|  |  | ||||||
|      |      | ||||||
|  |  | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     parse("test2.pdf", "10GXS13") |     parse("test2.pdf", "cables/10GXS13", "10GXS13") | ||||||
| @@ -5,13 +5,15 @@ pypdf2==2.12.1 | |||||||
| alive-progress | alive-progress | ||||||
| requests | requests | ||||||
| git+https://github.com/Byeongdulee/python-urx.git | git+https://github.com/Byeongdulee/python-urx.git | ||||||
| psycopg2 | psycopg2-binary | ||||||
| pyyaml | pyyaml | ||||||
| Flask | Flask | ||||||
| selenium | selenium | ||||||
| sacn | sacn | ||||||
| uptime | uptime | ||||||
| websockets | websockets | ||||||
|  | numpy | ||||||
|  | scipy | ||||||
|  |  | ||||||
| # Development | # Development | ||||||
| matplotlib | matplotlib | ||||||
|   | |||||||
							
								
								
									
										243
									
								
								ur5_control.py
									
									
									
									
									
								
							
							
						
						
									
										243
									
								
								ur5_control.py
									
									
									
									
									
								
							| @@ -1,6 +1,8 @@ | |||||||
| import urx | import urx | ||||||
| import math3d as m3d | import math3d as m3d | ||||||
|  | from scipy.optimize import fsolve | ||||||
| import math | import math | ||||||
|  | import numpy as np | ||||||
| import time | import time | ||||||
| import os | import os | ||||||
| import logging | import logging | ||||||
| @@ -8,6 +10,9 @@ from urx.robotiq_two_finger_gripper import Robotiq_Two_Finger_Gripper | |||||||
| import sys | import sys | ||||||
| from util import fprint | from util import fprint | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| rob = None | rob = None | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -45,7 +50,7 @@ def init(ip): | |||||||
|     time.sleep(0.2) |     time.sleep(0.2) | ||||||
|     fprint("UR5 ready.") |     fprint("UR5 ready.") | ||||||
|  |  | ||||||
| def set_pos_abs(x, y, z, xb, yb, zb): | def set_pos_abs(x, y, z, xb, yb, zb, threshold=None): | ||||||
|     global rob |     global rob | ||||||
|     new_orientation = m3d.Transform() |     new_orientation = m3d.Transform() | ||||||
|     new_orientation.orient.rotate_xb(xb)  # Replace rx with the desired rotation around X-axis |     new_orientation.orient.rotate_xb(xb)  # Replace rx with the desired rotation around X-axis | ||||||
| @@ -60,7 +65,7 @@ def set_pos_abs(x, y, z, xb, yb, zb): | |||||||
|     new_trans.pos.y = y |     new_trans.pos.y = y | ||||||
|     new_trans.pos.z = z |     new_trans.pos.z = z | ||||||
|     #rob.speedj(0.2, 0.5, 99999) |     #rob.speedj(0.2, 0.5, 99999) | ||||||
|     rob.set_pose(new_trans, acc=2, vel=2, command="movej")  # apply the new pose |     rob.set_pose(new_trans, acc=2, vel=2, command="movej", threshold=threshold)  # apply the new pose | ||||||
|  |  | ||||||
| def set_pos_rel_rot_abs(x, y, z, xb, yb, zb): | def set_pos_rel_rot_abs(x, y, z, xb, yb, zb): | ||||||
|     global rob |     global rob | ||||||
| @@ -80,21 +85,241 @@ def set_pos_rel_rot_abs(x, y, z, xb, yb, zb): | |||||||
|     #rob.speedj(0.2, 0.5, 99999) |     #rob.speedj(0.2, 0.5, 99999) | ||||||
|     rob.set_pose(new_trans, acc=0.1, vel=0.4, command="movej")  # apply the new pose |     rob.set_pose(new_trans, acc=0.1, vel=0.4, command="movej")  # apply the new pose | ||||||
|  |  | ||||||
|  | def set_pos_abs_rot_rel(x, y, z, xb, yb, zb): | ||||||
|  |     global rob | ||||||
|  |     new_orientation = m3d.Transform() | ||||||
|  |     new_orientation.orient.rotate_xb(xb)  # Replace rx with the desired rotation around X-axis | ||||||
|  |     new_orientation.orient.rotate_yb(yb)  # Replace ry with the desired rotation around Y-axis | ||||||
|  |     new_orientation.orient.rotate_zb(zb)  # Replace rz with the desired rotation around Z-axis | ||||||
|  |  | ||||||
|  |     # Get the current pose | ||||||
|  |     trans = rob.getl() | ||||||
|  |      | ||||||
|  |     # Apply the new orientation while keeping the current position | ||||||
|  |     new_trans = m3d.Transform(new_orientation.orient, m3d.Vector(trans[0:3])) | ||||||
|  |     new_trans.pos.x = x | ||||||
|  |     new_trans.pos.y = y | ||||||
|  |     new_trans.pos.z = z | ||||||
|  |     #rob.speedj(0.2, 0.5, 99999) | ||||||
|  |     rob.set_pose(new_trans, acc=0.1, vel=0.4, command="movej")  # apply the new pose | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def is_safe_move(start_pose, end_pose, r=0.25): | ||||||
|  |     start_x, start_y = (start_pose[0], start_pose[1]) | ||||||
|  |     end_x, end_y = (end_pose[0], end_pose[1]) | ||||||
|  |  | ||||||
|  |     try: | ||||||
|  |         m = (end_y-start_y)/(end_x-start_x) | ||||||
|  |         b = start_y - m*start_x | ||||||
|  |         # print('m = y/x =', m) | ||||||
|  |         # print('b =', b) | ||||||
|  |     except: | ||||||
|  |         m = (end_x-start_x)/(end_y-start_y) | ||||||
|  |         b = start_x - m*start_y | ||||||
|  |         # print('m = x/y =', m) | ||||||
|  |         # print('b =', b) | ||||||
|  |      | ||||||
|  |     return r**2 - b**2 + m**2 * r**2 < 0 | ||||||
|  |  | ||||||
|  | def cartesian_to_polar(x, y): | ||||||
|  |     r = np.sqrt(x**2 + y**2) | ||||||
|  |     theta = np.arctan2(y, x) | ||||||
|  |     return r, theta | ||||||
|  |  | ||||||
|  | def polar_to_cartesian(r, theta): | ||||||
|  |     x = r * np.cos(theta) | ||||||
|  |     y = r * np.sin(theta) | ||||||
|  |     return x, y | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def move_to_polar(start_pos, end_pos): | ||||||
|  |     global rob | ||||||
|  |  | ||||||
|  |     # Convert to polar coordinates | ||||||
|  |     start_r, start_theta = cartesian_to_polar(start_pos[0], start_pos[1]) | ||||||
|  |     end_r, end_theta = cartesian_to_polar(end_pos[0], end_pos[1]) | ||||||
|  |  | ||||||
|  |     # Interpolate for xy (spiral arc) | ||||||
|  |     n_points = 30 | ||||||
|  |     r_intermediate = np.linspace(start_r, end_r, n_points) | ||||||
|  |     theta_intermediate = np.linspace(start_theta, end_theta, n_points) | ||||||
|  |  | ||||||
|  |     # Interpolate for z (height) | ||||||
|  |     start_z = start_pos[2] | ||||||
|  |     end_z = end_pos[2] | ||||||
|  |  | ||||||
|  |     z_intermediate = np.linspace(start_z, end_z, n_points) | ||||||
|  |  | ||||||
|  |     # Interpolate for rz (keep tool rotation fixed relative to robot) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     curr_rot = rob.getl() | ||||||
|  |  | ||||||
|  |     theta_delta = theta_intermediate[1]-theta_intermediate[0] | ||||||
|  |      | ||||||
|  |     rx_intermediate = [curr_rot[5] + theta_delta*i for i in range(n_points)] | ||||||
|  |  | ||||||
|  |     # curr_rot = rob.getj() | ||||||
|  |     # start_rz = curr_rot[5] | ||||||
|  |     # rot = end_theta - start_theta | ||||||
|  |     # end_base_joint = curr_rot[0]-start_theta + rot | ||||||
|  |  | ||||||
|  |     # end_rz = curr_rot[0] + rot | ||||||
|  |     # # rob.movel([*polar_to_cartesian(end_r, end_theta), *rob.getl()[2:]], acc=2, vel=2) | ||||||
|  |  | ||||||
|  |     # print('start_theta = ', math.degrees(start_theta)) | ||||||
|  |     # print('end_theta = ', math.degrees(curr_rot[0]-start_theta+rot)) | ||||||
|  |     # print('start_rz =', math.degrees(start_rz)) | ||||||
|  |     # print('rot =', math.degrees(rot)) | ||||||
|  |     # print('end_rz =', math.degrees(end_rz)) | ||||||
|  |  | ||||||
|  |     # rz_intermediate = np.linspace(start_rz, end_rz, n_points) | ||||||
|  |  | ||||||
|  |     # Convert back to cartesian coordinates | ||||||
|  |     curr_pos = rob.getl() | ||||||
|  |  | ||||||
|  |     intermediate_points = [[*polar_to_cartesian(r, theta), z, *curr_pos[3:]] | ||||||
|  |                             for r, theta, z, rx in zip(r_intermediate,  | ||||||
|  |                                                        theta_intermediate,  | ||||||
|  |                                                        z_intermediate,  | ||||||
|  |                                                        rx_intermediate)] | ||||||
|  |  | ||||||
|  |     # Move robot | ||||||
|  |     rob.movels(intermediate_points, acc=2, vel=2, radius=0.1) | ||||||
|  |      | ||||||
|  |  | ||||||
|  |     return rx_intermediate | ||||||
|  |  | ||||||
|  | def move_to_home(): | ||||||
|  |     global rob | ||||||
|  |  | ||||||
|  |     # Home position in degrees | ||||||
|  |     home_pos = [0.10421807948612624,  | ||||||
|  |                 -2.206111555015423,  | ||||||
|  |                 1.710679229503537,  | ||||||
|  |                 -1.075834511928354,  | ||||||
|  |                 -1.569301366430687,  | ||||||
|  |                 1.675098295930943] | ||||||
|  |  | ||||||
|  |     # Move robot | ||||||
|  |     rob.movej(home_pos, acc=2, vel=2) | ||||||
|  |  | ||||||
|  | def normalize_degree(theta): | ||||||
|  |     # Normalizes degree theta from -1.5pi to 1.5pi | ||||||
|  |     multiplier = 1 | ||||||
|  |     normalized_theta = theta % (math.pi * multiplier) | ||||||
|  |      | ||||||
|  |     # Maintain the negative sign if the original angle is negative | ||||||
|  |     if theta < 0: | ||||||
|  |         normalized_theta -= math.pi * multiplier | ||||||
|  |  | ||||||
|  |     # 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 | ||||||
|  |      | ||||||
|  |     # 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 | ||||||
|  |                 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)]] | ||||||
|  |  | ||||||
|  |     # Return result | ||||||
|  |     return base, shoulder, elbow, wrist | ||||||
|  |  | ||||||
|  | def get_joints_from_xyz_abs(x, y, z): | ||||||
|  |     joints = get_joints_from_xyz_rel(x, y, z) | ||||||
|  |  | ||||||
|  |     # Joint offsets | ||||||
|  |     # Base, Shoulder, Elbow, Wrist | ||||||
|  |     inverse = [1, -1, 1, 1] | ||||||
|  |     offsets = [0, 0, 0, -math.pi/2] | ||||||
|  |  | ||||||
|  |     # Return adjusted joint positions | ||||||
|  |     return [o+j*i for j, o, i in zip(joints, offsets, inverse)] | ||||||
|  |  | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|      |      | ||||||
|     #rob.movej((0, 0, 0, 0, 0, 0), 0.1, 0.2) |     #rob.movej((0, 0, 0, 0, 0, 0), 0.1, 0.2) | ||||||
|     #rob.movel((x, y, z, rx, ry, rz), a, v) |     #rob.movel((x, y, z, rx, ry, rz), a, v) | ||||||
|     init("192.168.1.145") |     init("192.168.1.145") | ||||||
|     fprint("Current tool pose is: ",  rob.getl()) |     print("Current tool pose is: ",  rob.getl()) | ||||||
|     #set_pos_rel_rot_abs(0, 0, -0.2, math.pi, 0, -math.pi) |     move_to_home() | ||||||
|     set_pos_abs(0.3, -0.2, 0.5, math.pi, 0, -math.pi) |  | ||||||
|     set_pos_abs(0, 0.2, 0.6, math.pi, 0, -math.pi) |     home_pose = [-0.4999999077032916,  | ||||||
|     set_pos_abs(-0.5, -0.2, 0.4, math.pi, 0, -math.pi) |                -0.2000072960336574,  | ||||||
|     #set_pos_rel_rot_abs(0, 0, 0, math.pi, 0, -math.pi) |                0.40002172976662786,  | ||||||
|     fprint("Current tool pose is: ",  rob.getl()) |                0,  | ||||||
|  |                -3.14152741295329,  | ||||||
|  |                0] | ||||||
|  |  | ||||||
|  |     # time.sleep(.5) | ||||||
|  |  | ||||||
|  |     p1 = [0, | ||||||
|  |  | ||||||
|  |         0.6, | ||||||
|  |         .4, | ||||||
|  |         0.2226, | ||||||
|  |         3.1126, | ||||||
|  |         0.0510] | ||||||
|  |      | ||||||
|  |     p2 = [0.171, | ||||||
|  |         -0.115, | ||||||
|  |         0.2, | ||||||
|  |         0.2226, | ||||||
|  |         3.1126, | ||||||
|  |         0.0510] | ||||||
|  |  | ||||||
|  |     curr_pos = rob.getl() | ||||||
|  |     # up/down,  | ||||||
|  |     # tool rotation | ||||||
|  |     # tool angle (shouldn't need) | ||||||
|  |     # rob.set_pos(p1[0:3], acc=0.5, vel=0.5) | ||||||
|  |  | ||||||
|  |     # set_pos_abs(*home_pose) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     angles = get_joints_from_xyz_abs(0.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.3, 0.4, 0.2) | ||||||
|  |     rob.movej([*angles, *rob.getj()[4:]], acc=1, vel=1) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     # set_pos_abs(*p1) | ||||||
|  |     # move = move_to_polar(p1, p2) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     # for p in move: | ||||||
|  |     #     print(math.degrees(p)) | ||||||
|  |     # print("Safe? :", is_safe_move(p1, p2)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     # #set_pos_rel_rot_abs(0, 0, -0.2, math.pi, 0, -math.pi) | ||||||
|  |     # set_pos_abs(0.3, -0.2, 0.5, math.pi, 0, -math.pi) | ||||||
|  |     # set_pos_abs(0, 0.2, 0.6, math.pi, 0, -math.pi) | ||||||
|  |     # set_pos_abs(-0.5, -0.2, 0.4, math.pi, 0, -math.pi) | ||||||
|  |     # #set_pos_rel_rot_abs(0, 0, 0, math.pi, 0, -math.pi) | ||||||
|  |  | ||||||
|  |     # print("Current tool pose is: ",  rob.getl()) | ||||||
|  |     # print("getj(): ",  rob.getj()) | ||||||
|  |  | ||||||
|  |     # move_to_home() | ||||||
|  |  | ||||||
|     rob.stop() |     rob.stop() | ||||||
|     os.kill(os.getpid(), 9) # dirty kill of self |     os.kill(os.getpid(), 9) # dirty kill of self | ||||||
|     sys.exit(0) |     sys.exit(0) | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								util.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								util.py
									
									
									
									
									
								
							| @@ -123,7 +123,7 @@ class Logger(object): | |||||||
|         self.terminal = sys.stdout |         self.terminal = sys.stdout | ||||||
|  |  | ||||||
|     def write(self, message): |     def write(self, message): | ||||||
|         self.log.write(message) |         #self.log.write(message) | ||||||
|         #close(filename) |         #close(filename) | ||||||
|         #self.log = open(filename, "a") |         #self.log = open(filename, "a") | ||||||
|         try: |         try: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user