8 Commits

8 changed files with 1183 additions and 854 deletions

View File

@ -6,6 +6,17 @@ core:
arm: arm:
ip: 192.168.1.145 ip: 192.168.1.145
tool:
offset_x: 0
offset_y: 0
offset_z: 0.14
limbs:
limb_base: 0.105
limb1: 0.425
limb2: 0.39225
limb3: 0.1
limb_wrist: 0.0997
#cable_map: #cable_map:
cameras: cameras:

View File

@ -159,8 +159,8 @@ def touch(path):
def get_multi(partnums, delay=0.25, dir="cables/", cache=True): def get_multi(partnums, delay=0.25, dir="cables/", cache=True, bar=None):
with alive_bar(len(partnums) * 2, dual_line=True, calibrate=30, bar="classic2", spinner="classic") as bar: #with alive_bar(len(partnums) * 2, dual_line=True, calibrate=30, bar="classic2", spinner="classic", disable=True, file=sys.stdout) as bar:
failed = list() failed = list()
actualpartnums = list() actualpartnums = list()
def _try_download_datasheet(partnum, output_dir, dstype): # Guess datasheet URL def _try_download_datasheet(partnum, output_dir, dstype): # Guess datasheet URL
@ -188,7 +188,7 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
# and set chunk_size parameter to None. # and set chunk_size parameter to None.
#if chunk: #if chunk:
bartext = bartext + "." bartext = bartext + "."
bar.text = bartext # bar.text = bartext
f.write(chunk) f.write(chunk)
#fprint("") #fprint("")
return output_dir + "/datasheet.pdf" return output_dir + "/datasheet.pdf"
@ -217,7 +217,7 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
# and set chunk_size parameter to None. # and set chunk_size parameter to None.
#if chunk: #if chunk:
bartext = bartext + "." bartext = bartext + "."
bar.text = bartext # bar.text = bartext
f.write(chunk) f.write(chunk)
#fprint("") #fprint("")
return output_dir + "/datasheet.pdf" return output_dir + "/datasheet.pdf"
@ -244,7 +244,7 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
# and set chunk_size parameter to None. # and set chunk_size parameter to None.
#if chunk: #if chunk:
bartext = bartext + "." bartext = bartext + "."
bar.text = bartext # bar.text = bartext
f.write(chunk) f.write(chunk)
#fprint("") #fprint("")
return output_dir + "/part-hires." + url.split(".")[-1] return output_dir + "/part-hires." + url.split(".")[-1]
@ -255,29 +255,29 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
def __use_cached_datasheet(partnum, path, output_dir, dstype): def __use_cached_datasheet(partnum, path, output_dir, dstype):
fprint("Using cached datasheet for " + partnum) fprint("Using cached datasheet for " + partnum)
bar.text = "Using cached datasheet for " + partnum # bar.text = "Using cached datasheet for " + partnum
bar(skipped=True) # bar(skipped=True)
if not os.path.exists(output_dir + "/parsed"): if not os.path.exists(output_dir + "/parsed"):
fprint("Parsing Datasheet contents of " + partnum) fprint("Parsing Datasheet contents of " + partnum)
bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..." # bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..."
out = read_datasheet.parse(path, output_dir, partnum, dstype) out = read_datasheet.parse(path, output_dir, partnum, dstype)
bar(skipped=False) # bar(skipped=False)
return out return out
else: else:
fprint("Datasheet already parsed for " + partnum) fprint("Datasheet already parsed for " + partnum)
bar.text = "Datasheet already parsed for " + partnum + ".pdf" # bar.text = "Datasheet already parsed for " + partnum + ".pdf"
bar(skipped=True) # bar(skipped=True)
def __downloaded_datasheet(partnum, path, output_dir, dstype): def __downloaded_datasheet(partnum, path, output_dir, dstype):
fprint("Downloaded " + path) fprint("Downloaded " + path)
bar.text = "Downloaded " + path # bar.text = "Downloaded " + path
bar(skipped=False) # bar(skipped=False)
fprint("Parsing Datasheet contents of " + partnum) fprint("Parsing Datasheet contents of " + partnum)
bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..." # bar.text = "Parsing Datasheet contents of " + partnum + ".pdf..."
out = read_datasheet.parse(path, output_dir, partnum, dstype) out = read_datasheet.parse(path, output_dir, partnum, dstype)
bar(skipped=False) # bar(skipped=False)
return out return out
def run_search(partnum): def run_search(partnum):
@ -290,7 +290,7 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
output_dir = dir + partnum output_dir = dir + partnum
path = output_dir + "/datasheet.pdf" path = output_dir + "/datasheet.pdf"
bartext = "Downloading files for part " + partnum bartext = "Downloading files for part " + partnum
bar.text = bartext # bar.text = bartext
partnum = oldpartnum.replace("_","/") partnum = oldpartnum.replace("_","/")
returnval = [partnum, dstype, False, False] returnval = [partnum, dstype, False, False]
if (not os.path.exists(output_dir + "/found_part_hires")) or not (os.path.exists(path) and os.path.getsize(path) > 1) or not cache: if (not os.path.exists(output_dir + "/found_part_hires")) or not (os.path.exists(path) and os.path.getsize(path) > 1) or not cache:
@ -305,7 +305,7 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
output_dir = dir + partnum output_dir = dir + partnum
path = output_dir + "/datasheet.pdf" path = output_dir + "/datasheet.pdf"
bartext = "Downloading files for part " + partnum bartext = "Downloading files for part " + partnum
bar.text = bartext # bar.text = bartext
if not os.path.exists(output_dir + "/found_part_hires") or not cache: if not os.path.exists(output_dir + "/found_part_hires") or not cache:
if _download_image(search_result["image"], output_dir): if _download_image(search_result["image"], output_dir):
@ -373,19 +373,19 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True):
time.sleep(delay) time.sleep(delay)
if not success: if not success:
fprint("Failed to download datasheet for part " + partnum) fprint("Failed to download datasheet for part " + partnum)
bar.text = "Failed to download datasheet for part " + partnum # bar.text = "Failed to download datasheet for part " + partnum
failed.append((partnum, dstype)) failed.append((partnum, dstype))
bar(skipped=True) # bar(skipped=True)
bar(skipped=True) # bar(skipped=True)
time.sleep(delay) time.sleep(delay)
if len(failed) > 0: if len(failed) > 0:
fprint("Failed to download:") fprint("Failed to download:")
for partnum in failed: for partnum in failed:
fprint(partnum[1] + " " + partnum[0]) fprint(partnum[1] + " " + partnum[0])
return False, actualpartnums # Go to manual review upload page return False, actualpartnums # Go to manual review upload page
else: else:
return True, actualpartnums # All cables downloaded; we are good to go return True, actualpartnums # All cables downloaded; we are good to go
@ -408,7 +408,7 @@ if __name__ == "__main__":
# ] # ]
partnums = [ partnums = [
# Actual cables in Jukebox # Actual cables in Jukebox
"BL3092A",
"AW86104CY", "AW86104CY",
"AW3050", "AW3050",
"AW6714", "AW6714",
@ -438,8 +438,9 @@ if __name__ == "__main__":
"BL6300FE 009Q", "BL6300FE 009Q",
"BLRA500P 006Q", "BLRA500P 006Q",
]
# Some ones I picked, including some invalid ones # Some ones I picked, including some invalid ones
a = [
"BL10GXS12", "BL10GXS12",
"BLRST%205L-RKT%205L-949", "BLRST%205L-RKT%205L-949",
"BL10GXS13", "BL10GXS13",
@ -455,7 +456,7 @@ if __name__ == "__main__":
"BLFISX006W0", # datasheet only "BLFISX006W0", # datasheet only
"BLFISX00103", # invalid "BLFISX00103", # invalid
"BLC6D1100007" # invalid "BLC6D1100007" # invalid
] ]
#print(query_search("TT-SLG-024-HTNN", "Belden")) #print(query_search("TT-SLG-024-HTNN", "Belden"))
from label_generator import gen_label from label_generator import gen_label

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

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

189
run.py
View File

@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from alive_progress import alive_bar
import get_specs import get_specs
import traceback import traceback
#import logging #import logging
@ -12,16 +13,19 @@ from util import fprint
from util import run_cmd from util import run_cmd
import sys import sys
import ur5_control import ur5_control
from ur5_control import Rob
import os import os
import signal import signal
import socket import socket
from flask import Flask, render_template, request from flask import Flask, render_template, request
import requests import requests
import led_control from led_control import LEDSystem
import server import server
import asyncio import asyncio
import json import json
import process_video import process_video
import search
from search import JukeboxSearch
@ -32,13 +36,22 @@ led_ready = False
camera_ready = False camera_ready = False
sensor_ready = False sensor_ready = False
vm_ready = False vm_ready = False
cable_search_ready = False
killme = None killme = None
#pool = None #pool = None
serverproc = None serverproc = None
camera = None camera = None
ledsys = None
arm = None
to_server_queue = Queue() to_server_queue = Queue()
from_server_queue = Queue() from_server_queue = Queue()
mode = "Startup"
counter = 0
jbs = None
scan_value = None
arm_state = None
cable_list = list()
parse_res = None
def arm_start_callback(res): def arm_start_callback(res):
global arm_ready global arm_ready
@ -47,10 +60,14 @@ def arm_start_callback(res):
def led_start_callback(res): def led_start_callback(res):
global led_ready global led_ready
led_ready = True led_ready = True
global ledsys
ledsys = res
def camera_start_callback(res): def camera_start_callback(res):
global camera_ready global camera_ready
camera_ready = True camera_ready = True
global scan_value
scan_value = res
def sensor_start_callback(res): def sensor_start_callback(res):
global sensor_ready global sensor_ready
@ -60,6 +77,12 @@ def vm_start_callback(res):
global vm_ready global vm_ready
vm_ready = True vm_ready = True
def cable_search_callback(res):
global cable_search_ready
cable_search_ready = True
global parse_res
parse_res = res
def wait_for(val, name): def wait_for(val, name):
#global val #global val
if val is False: if val is False:
@ -231,13 +254,18 @@ def setup_server(pool):
global arm_ready global arm_ready
global serverproc global serverproc
global camera global camera
global arm
pool.apply_async(ur5_control.init, (config["arm"]["ip"],), callback=arm_start_callback) global jbs
pool.apply_async(led_control.init, callback=led_start_callback) arm = Rob(config)
pool.apply_async(arm.init_arm, callback=arm_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) #pool.apply_async(sensor_control.init, callback=sensor_start_callback)
serverproc = Process(target=start_server_socket) serverproc = Process(target=start_server_socket)
serverproc.start() serverproc.start()
if led_ready is False: if led_ready is False:
fprint("waiting for " + "LED controller initialization" + " to complete...", sendqueue=to_server_queue) fprint("waiting for " + "LED controller initialization" + " to complete...", sendqueue=to_server_queue)
while led_ready is False: while led_ready is False:
@ -253,7 +281,7 @@ def setup_server(pool):
if camera_ready is False: if camera_ready is False:
fprint("waiting for " + "Camera initilization" + " to complete...", sendqueue=to_server_queue) fprint("waiting for " + "Camera initilization" + " to complete...", sendqueue=to_server_queue)
# camera = process_video.qr_reader(config["cameras"]["banner"]["ip"], config["cameras"]["banner"]["port"]) camera = process_video.qr_reader(config["cameras"]["banner"]["ip"], config["cameras"]["banner"]["port"])
fprint("Camera initialized.", sendqueue=to_server_queue) fprint("Camera initialized.", sendqueue=to_server_queue)
@ -263,25 +291,158 @@ def setup_server(pool):
while arm_ready is False: while arm_ready is False:
sleep(0.1) sleep(0.1)
fprint("Arm initialized.", sendqueue=to_server_queue) fprint("Arm initialized.", sendqueue=to_server_queue)
jbs = JukeboxSearch()
return True return True
def mainloop_server(pool): def mainloop_server(pool):
# NON-blocking loop
global config global config
global counter global counter
global killme global killme
global mode
global jbs
global arm
global ledsys
global camera
global arm_ready
global arm_state
global camera_ready
global cable_search_ready
global cable_list
if killme.value > 0: if killme.value > 0:
killall() killall()
counter = counter + 1
# fprint("Looking for QR code...") if mode == "Startup":
# print(camera.read_qr(30)) counter = 54
if counter < 54:
# scanning cables
if arm_state is None:
#pool.apply_async(arm.get cable to camera, callback=arm_start_callback)
#ur5_control.goto_holder_index(arm)
#ur5 get item
# ur5 bring to camera
fprint("Getting cable index " + str(counter) + " and scanning...")
arm_state = "GET"
elif arm_ready and arm_state == "GET":
fprint("Looking for QR code...")
pool.apply_async(camera.read_qr, (30,), callback=camera_start_callback)
arm_ready = False
elif camera_ready:
fprint("Adding cable to list...")
global scan_value
if scan_value.find("bldn.app/") > -1:
scan_value = scan_value[scan_value.find("bldn.app/")+9:]
cable_list.append((counter, scan_value))
fprint(scan_value)
#pool.apply_async(arm.return cable, callback=arm_start_callback)
arm_state = "RETURN"
camera_ready = False
elif arm_ready and arm_state == "RETURN":
counter += 1
arm_state = None
else:
# just wait til arm/camera is ready
pass
else:
# scanned everything
tmp = list()
for cable in cable_list:
tmp.append(cable[1])
tmp = [
# Actual cables in Jukebox
"AW86104CY",
"AW3050",
"AW6714",
"AW1172C",
"AWFIT-221-1_4",
"BLTF-1LF-006-RS5",
"BLTF-SD9-006-RI5",
"BLTT-SLG-024-HTN",
"BLFISX012W0",
"BLFI4X012W0",
"BLSPE101",
"BLSPE102",
"BL7922A",
"BL7958A",
"BLIOP6U",
"BL10GXW13",
"BL10GXW53",
"BL29501F",
"BL29512",
"BL3106A",
"BL9841",
"BL3105A",
"BL3092A",
"BL8760",
"BL6300UE",
"BL6300FE",
"BLRA500P"
]
cable_list = tmp
pool.apply_async(get_specs.get_multi, (tmp, 0.5), callback=cable_search_callback)
mode = "Parsing"
fprint("All cables scanned. Finding & parsing datasheets...")
if mode == "Parsing":
# waiting for search & parse to complete
#cable_search_ready = True
if cable_search_ready is False:
pass
else:
# done
global parse_res
success, partnums = parse_res
#partnums = list()
# debug
#success = True
#cable_list = list(range(len(partnums)))
if success:
# easy mode
fprint("All cables inventoried and parsed.")
for x in range(len(cable_list)):
#cable_list[x] = (cable_list[x][0], partnums[x])
cable_list[x] = (x, cable_list[x])
fprint("Adding to database...")
for idx,partnum in cable_list:
with open("cables/" + partnum[2:] + "/search.json", "rb") as f:
searchdata = json.load(f)
searchdata["position"] = idx
with open("cables/" + partnum[2:] + "/specs.json", "rb") as f:
specs = json.load(f)
searchdata["fullspecs"] = specs
jbs.add_document(searchdata)
fprint("All cables added to database.")
mode = "Idle"
else:
# TODO: manual input
pass
if mode == "Idle":
# do nothing
if arm_ready is False:
pool.apply_async(ur5_control.move_to_home, (arm,), callback=arm_start_callback)
arm_ready = True
else:
# LED idle anim
pass
def run_loading_app(): def run_loading_app():

View File

@ -1,8 +1,10 @@
#!/usr/bin/env python3
"""Interactions with the Meilisearch API for adding and searching cables.""" """Interactions with the Meilisearch API for adding and searching cables."""
from meilisearch import Client from meilisearch import Client
from meilisearch.task import TaskInfo from meilisearch.task import TaskInfo
from meilisearch.errors import MeilisearchApiError from meilisearch.errors import MeilisearchApiError
import json import time
DEFAULT_URL = "http://localhost:7700" DEFAULT_URL = "http://localhost:7700"
DEFAULT_APIKEY = "fluffybunnyrabbit" # I WOULD RECOMMEND SOMETHING MORE SECURE DEFAULT_APIKEY = "fluffybunnyrabbit" # I WOULD RECOMMEND SOMETHING MORE SECURE
@ -34,12 +36,15 @@ class JukeboxSearch:
# create the index if it does not exist already # create the index if it does not exist already
try: try:
self.client.get_index(self.index) self.client.get_index(self.index)
self.client.delete_index(self.index)
self.client.create_index(self.index)
except MeilisearchApiError as _: except MeilisearchApiError as _:
self.client.create_index(self.index) self.client.create_index(self.index)
# make a variable to easily reference the index # make a variable to easily reference the index
self.idxref = self.client.index(self.index) self.idxref = self.client.index(self.index)
time.sleep(0.05)
# update filterable attributes if needed # update filterable attributes if needed
self.idxref.update_distinct_attribute('partnum')
self.update_filterables(filterable_attrs) self.update_filterables(filterable_attrs)
def add_document(self, document: dict) -> TaskInfo: def add_document(self, document: dict) -> TaskInfo:
@ -114,4 +119,4 @@ class JukeboxSearch:
# entrypoint # entrypoint
if __name__ == "__main__": if __name__ == "__main__":
jbs = JukeboxSearch() jbs = JukeboxSearch()

View File

@ -6,6 +6,7 @@ import numpy as np
import time import time
import os import os
import logging import logging
import yaml
from urx.robotiq_two_finger_gripper import Robotiq_Two_Finger_Gripper from urx.robotiq_two_finger_gripper import Robotiq_Two_Finger_Gripper
import sys import sys
from util import fprint from util import fprint
@ -13,46 +14,59 @@ 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): class Rob():
global rob robot = None
#sys.stdout = Logger() #offset_x, offset_y, offset_z = (0, 0, 0.14) # Tool offset
fprint("Starting UR5 power up...") #
def __init__(self, config):
# power up robot here self.config = config
armc = config["arm"]
self.ip = armc["ip"]
tool = armc["tool"]
limbs = armc["limbs"]
self.offset_x, self.offset_y, self.offset_z = (tool["offset_x"], tool["offset_y"], tool["offset_z"])
self.limb_base = limbs["limb_base"]
self.limb1 = limbs["limb1"]
self.limb2 = limbs["limb2"]
self.limb3 = limbs["limb3"]
self.limb_wrist = limbs["limb_wrist"]
#self.init_arm()
# wait for power up (this function runs async) def init_arm(self):
#sys.stdout = Logger()
fprint("Starting UR5 power up...")
# power up robot here
# wait for power up (this function runs async)
# trigger auto-initialize # trigger auto-initialize
# wait for auto-initialize # wait for auto-initialize
ip = self.ip
# init urx
fprint("Connecting to arm at " + ip)
trying = True
while trying:
try:
self.robot = urx.Robot(ip)
trying = False
except:
time.sleep(1)
# init urx # Sets robot arm endpoint offset (x,y,z,rx,ry,rz)
fprint("Connecting to arm at " + ip) self.robot.set_tcp((self.offset_x, self.offset_y, self.offset_z, 0, 0, 0))
trying = True
while trying:
try:
rob = urx.Robot(ip)
trying = False
except:
time.sleep(1)
robotiqgrip = Robotiq_Two_Finger_Gripper(rob)
# Sets robot arm endpoint offset (x,y,z,rx,ry,rz) # Set weight
rob.set_tcp((0, 0, 0.15, 0, 0, 0)) self.robot.set_payload(2, (0, 0, 0.1))
#rob.set_payload(2, (0, 0, 0.1))
time.sleep(0.2)
fprint("UR5 ready.")
# Set weight def set_pos_abs(robot, x, y, z, xb, yb, zb, threshold=None):
rob.set_payload(2, (0, 0, 0.1)) rob = robot.robot
#rob.set_payload(2, (0, 0, 0.1))
time.sleep(0.2)
fprint("UR5 ready.")
def set_pos_abs(x, y, z, xb, yb, zb, threshold=None):
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
new_orientation.orient.rotate_yb(yb) # Replace ry with the desired rotation around Y-axis new_orientation.orient.rotate_yb(yb) # Replace ry with the desired rotation around Y-axis
@ -68,8 +82,8 @@ def set_pos_abs(x, y, z, xb, yb, zb, threshold=None):
#rob.speedj(0.2, 0.5, 99999) #rob.speedj(0.2, 0.5, 99999)
rob.set_pose(new_trans, acc=2, vel=2, command="movej", threshold=threshold) # apply the new pose rob.set_pose(new_trans, acc=2, vel=2, command="movej", threshold=threshold) # apply the new pose
def set_pos_rel_rot_abs(x, y, z, xb, yb, zb): def set_pos_rel_rot_abs(robot, x, y, z, xb, yb, zb):
global rob rob = robot.robot
new_orientation = m3d.Transform() new_orientation = m3d.Transform()
new_orientation.orient.rotate_xb(xb) # Replace rx with the desired rotation around X-axis new_orientation.orient.rotate_xb(xb) # Replace rx with the desired rotation around X-axis
new_orientation.orient.rotate_yb(yb) # Replace ry with the desired rotation around Y-axis new_orientation.orient.rotate_yb(yb) # Replace ry with the desired rotation around Y-axis
@ -86,8 +100,8 @@ def set_pos_rel_rot_abs(x, y, z, xb, yb, zb):
#rob.speedj(0.2, 0.5, 99999) #rob.speedj(0.2, 0.5, 99999)
rob.set_pose(new_trans, acc=0.1, vel=0.4, command="movej") # apply the new pose rob.set_pose(new_trans, acc=0.1, vel=0.4, command="movej") # apply the new pose
def set_pos_abs_rot_rel(x, y, z, xb, yb, zb): def set_pos_abs_rot_rel(robot, x, y, z, xb, yb, zb):
global rob rob = robot.robot
new_orientation = m3d.Transform() new_orientation = m3d.Transform()
new_orientation.orient.rotate_xb(xb) # Replace rx with the desired rotation around X-axis new_orientation.orient.rotate_xb(xb) # Replace rx with the desired rotation around X-axis
new_orientation.orient.rotate_yb(yb) # Replace ry with the desired rotation around Y-axis new_orientation.orient.rotate_yb(yb) # Replace ry with the desired rotation around Y-axis
@ -133,8 +147,8 @@ def polar_to_cartesian(r, theta):
return x, y return x, y
def move_to_polar(start_pos, end_pos): def move_to_polar(robot, start_pos, end_pos):
global rob rob = robot.robot
# Convert to polar coordinates # Convert to polar coordinates
start_r, start_theta = cartesian_to_polar(start_pos[0], start_pos[1]) start_r, start_theta = cartesian_to_polar(start_pos[0], start_pos[1])
@ -191,13 +205,8 @@ def move_to_polar(start_pos, end_pos):
return rx_intermediate return rx_intermediate
def degtorad(angle): def move_to_home(robot):
return angle/180.0 * math.pi rob = robot.robot
def radtodeg(angle):
return angle*180.0 / math.pi
def move_to_home():
global rob
# Home position in degrees # Home position in degrees
home_pos = [0.10421807948612624, home_pos = [0.10421807948612624,
@ -222,15 +231,14 @@ def normalize_degree(theta):
# Return angle # Return angle
return normalized_theta return normalized_theta
def get_joints_from_xyz_rel(robot, x, y, z, rx=0, ry=-math.pi/2, rz=0, initial_guess = (math.pi/2, math.pi/2, 0), l3offset=0):
def get_joints_from_xyz_rel(x, y, z, rx=0, ry=-math.pi/2, rz=0, initial_guess = (math.pi/2, math.pi/2, 0), l3offset=0):
# Get limbs and offsets # Get limbs and offsets
#l3=0.15 #l3=0.15
l_bs, l1, l2, l3, l_wt = (limb_base, limb1, limb2, limb3, limb_wrist) # Limb lengths l_bs, l1, l2, l3, l_wt = (robot.limb_base, robot.limb1, robot.limb2, robot.limb3, robot.limb_wrist) # Limb lengths
l3 += l3offset # add wrist offset, used for gripper angle calculations l3 += l3offset # add wrist offset, used for gripper angle calculations
offset_x = robot.offset_x
offset_y = robot.offset_y
offset_z = robot.offset_z
# Calculate base angle and r relative to shoulder joint # Calculate base angle and r relative to shoulder joint
def calculate_theta(x, y, a): def calculate_theta(x, y, a):
# Calculate if we need the + or - in our equations # Calculate if we need the + or - in our equations
@ -273,63 +281,197 @@ def get_joints_from_xyz_rel(x, y, z, rx=0, ry=-math.pi/2, rz=0, initial_guess =
# Return result # Return result
return base, shoulder, elbow, wrist1, ry, rz return base, shoulder, elbow, wrist1, ry, rz
def get_joints_from_xyz_abs(x, y, z, rx=0, ry=-math.pi/2, rz=math.pi/2, l3offset=0): def get_joints_from_xyz_abs(robot, x, y, z, rx=0, ry=-math.pi/2, rz=math.pi/2, l3offset=0, use_closest_path=True):
joints = get_joints_from_xyz_rel(x, y, z, rx, ry, rz, l3offset=l3offset) rob = robot.robot
joints = get_joints_from_xyz_rel(robot, x, y, z, rx, ry, rz, l3offset=l3offset)
# Return current positions if coordinates don't make sense
if z<0:
return rob.getj()
# Joint offsets # Joint offsets
# Base, Shoulder, Elbow, Wrist # Base, Shoulder, Elbow, Wrist
inverse = [1, -1, 1, 1, 1, 1] inverse = [1, -1, 1, 1, 1, 1]
offsets = [-math.pi/2, 0, 0, -math.pi/2, 0, 0] offsets = [-math.pi/2, 0, 0, -math.pi/2, 0, 0]
if radtodeg(joints[1]) > 137:
if math.degrees(joints[1]) > 137:
print("CRASH! Shoulder at", joints[1] * 180/math.pi) print("CRASH! Shoulder at", joints[1] * 180/math.pi)
#else: #else:
#print("Shoulder at", joints[1] * 180/math.pi) #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 # Get adjusted joint positions
# gripper length: from joint to start of grip adjusted_joints = [o+j*i for j, o, i in zip(joints, offsets, inverse)]
# 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): curr_joints = rob.getj()
def get_complimentary_angle(joint_angle):
if joint_angle<0:
new_angle = joint_angle + 2*math.pi
else:
new_angle = joint_angle - 2*math.pi
if abs(new_angle) > math.radians(350):
return joint_angle
else:
return new_angle
# Use closest path (potentially going beyond 180 degrees)
if use_closest_path:
if abs(get_complimentary_angle(adjusted_joints[0])-curr_joints[0]) < abs(adjusted_joints[0]-curr_joints[0]):
adjusted_joints[0] = get_complimentary_angle(adjusted_joints[0])
# final_joint_positions = []
# for curr_joint, adjusted_joint in zip(curr_joints, adjusted_joints):
# if abs(curr_joint - adjusted_joint) < abs(curr_joint - get_complimentary_angle(adjusted_joint)):
# final_joint_positions.append(adjusted_joint)
# else:
# final_joint_positions.append(get_complimentary_angle(adjusted_joint))
# return final_joint_positions
return adjusted_joints
def move_arc(robot, x, y, z, rx=0, ry=-math.pi/2, rz=math.pi/2):
rob = robot.robot
start_joints = rob.getj()
end_joint = get_joints_from_xyz_abs(robot, x, y, z, rx, ry, rz)
n_points = 50
intermediate_joints = []
for i in range(0, 6):
intermediate_joints.append(np.linspace(start_joints[i], end_joint[i], n_points))
joints = [joint_position for joint_position in zip(*intermediate_joints)]
rob.movejs(joints, acc=2, vel=2, radius=0.1)
def offset_gripper_angle(robot, x, y, z, gripperangle=30, gripperlength=0.20+0.018, flip=False, use_closest_path=True):
# gripper angle: from vertical
# gripper length: from joint to start of grip
# to flip, you can use flip=True or make gripper angle negative
limb3 = robot.limb3
# Determine tool rotation depending on gripper angle
if gripperangle < 0: if gripperangle < 0:
rz = - math.pi / 2 rz = - math.pi / 2
else: else:
rz = math.pi / 2 rz = math.pi / 2
if flip: if flip:
gripperangle = -degtorad(gripperangle) gripperangle = -math.radians(gripperangle)
grippery = gripperlength - math.cos(gripperangle) * gripperlength grippery = gripperlength - math.cos(gripperangle) * gripperlength
grippery += math.sin(gripperangle) * limb3 grippery += math.sin(gripperangle) * limb3
gripperx = math.sin(gripperangle) * gripperlength + limb3 * 2 gripperx = math.sin(gripperangle) * gripperlength + limb3 * 2
gripperx -= (1-math.cos(gripperangle)) * limb3 gripperx -= (1-math.cos(gripperangle)) * limb3
rz = math.pi / 2 rz = math.pi / 2
# flip the whole wrist # 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) return get_joints_from_xyz_abs(robot, x, y, z-grippery, rx=gripperangle + math.radians(180), l3offset=-gripperx, ry=math.pi/2, rz=rz, use_closest_path=use_closest_path)
else: else:
gripperangle = degtorad(gripperangle) gripperangle = math.radians(gripperangle)
grippery = gripperlength - math.cos(gripperangle) * gripperlength grippery = gripperlength - math.cos(gripperangle) * gripperlength
grippery -= math.sin(gripperangle) * limb3 grippery -= math.sin(gripperangle) * limb3
gripperx = math.sin(gripperangle) * gripperlength gripperx = math.sin(gripperangle) * gripperlength
gripperx += (1-math.cos(gripperangle)) * limb3 gripperx += (1-math.cos(gripperangle)) * limb3
return get_joints_from_xyz_abs(x, y, z-grippery, rx=gripperangle, l3offset=-gripperx, rz=rz) return get_joints_from_xyz_abs(robot, x, y, z-grippery, rx=gripperangle, l3offset=-gripperx, rz=rz, use_closest_path=use_closest_path)
def goto_holder_index(robot, idx, z=0.05, gripperangle=30, flip=False, verbose=False):
def goto_holder_index(idx, z=0.05, gripperangle=35, flip=False): joint = robot.config["position_map"][idx]
joint = config["position_map"][idx]
print("Going to cable holder index", joint["index"], "at position", joint["pos"]) if verbose:
angles = offset_gripper_angle(joint["pos"][1]/1000, joint["pos"][0]/1000, z, gripperangle=gripperangle, flip=flip) print("Going to cable holder index", joint["index"], "at position", joint["pos"])
safe_move(robot, joint["pos"][1]/1000, joint["pos"][0]/1000, z)
#angles = offset_gripper_angle(joint["pos"][1]/1000, joint["pos"][0]/1000, z, gripperangle=gripperangle, flip=flip)
#rob.movej(angles, acc=2, vel=2) #rob.movej(angles, acc=2, vel=2)
return angles #return angles
#angles = get_joints_from_xyz_abs(joint["pos"][1]/1000, joint["pos"][0]/1000, 0.05, ) #angles = get_joints_from_xyz_abs(joint["pos"][1]/1000, joint["pos"][0]/1000, 0.05, )
def is_flipped(robot):
rob = robot.robot
wrist2 = rob.getj()[4]
if wrist2>0:
return True
else:
return False
def flip(robot):
rob = robot.robot
# A list of safe positions to flip
safe_positions = [(-0.18, -0.108, 0.35),
(0.18, -0.108, 0.35)]
# Find the closest safe position
curr_pos = rob.getl()[:3]
def dist_from_robot(pos):
x, y, z = pos
rx, ry, rz = curr_pos
return math.sqrt((rx-x)**2+(ry-y)**2+(rz-z)**2)
pos_dist_pairs = zip(safe_positions, [dist_from_robot(pos) for pos in safe_positions])
safe_pos = min(pos_dist_pairs, key=lambda x:x[1])[0]
# Flip at safe position
rob.movej(offset_gripper_angle(robot, *safe_pos, flip=is_flipped(robot)), vel=2, acc=2) # Move to safe position
rob.movej(offset_gripper_angle(robot, *safe_pos, flip=(not is_flipped(robot))), vel=2, acc=2) # Flip gripper
def safe_move(robot, x, y, z):
rob = robot.robot
flip_radius = 0.22 # Min radius on which to flip
r = math.sqrt(x**2 + y**2) # Get position radius
# Flip gripper if needed
if (r <= flip_radius and is_flipped(robot)) or (r > flip_radius and not is_flipped(robot)):
flip(robot)
rob.movej(offset_gripper_angle(robot, x, y, z, flip=is_flipped(robot)), vel=2, acc=2)
def pick_up_routine(robot, holder_index, verbose=False):
rob = robot.robot
if verbose:
print('Pickup routine for index', holder_index)
goto_holder_index(robot, holder_index, 0.2)
curr_pos = rob.getl()
new_pos = curr_pos
new_pos[2] = 0
rob.movel(new_pos, vel=0.3, acc=1)
# goto_holder_index(robot, holder_index, 0.0)
# Close Gripper code
time.sleep(0.5)
new_pos[2] = 0.2
rob.movel(new_pos, vel=0.3, acc=1)
was_flipped = is_flipped(robot)
# Tray position 1
rob.movej(offset_gripper_angle(robot, -0.15, -0.15, 0.3, flip=is_flipped(robot), use_closest_path=False), vel=2, acc=2)
rob.movej(get_joints_from_xyz_abs(robot, -0.35, -0.15, 0.0, math.pi/2, 0.1), vel=2, acc=2)
time.sleep(0.5)
# Back to safe position
rob.movej(offset_gripper_angle(robot, -0.205, -0.108, 0.3, flip=True), vel=2, acc=2)
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")
with open('config.yml', 'r') as fileread:
#global config
config = yaml.safe_load(fileread)
robot = Rob(config) # robot of type Rob is the custom class above
robot.init_arm()
rob = robot.robot # rob is robot.robot is the urx robot class, what we've been using previously
print("Current tool pose is: ", rob.getl()) print("Current tool pose is: ", rob.getl())
move_to_home() move_to_home(robot)
home_pose = [-0.4999999077032916, home_pose = [-0.4999999077032916,
-0.2000072960336574, -0.2000072960336574,
@ -356,81 +498,45 @@ if __name__ == "__main__":
0.0510] 0.0510]
curr_pos = rob.getl() 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.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 config = None
joints = [] joints = []
for i in np.linspace(-0.2, -0.7, 50): for i in np.linspace(-0.2, -0.7, 10):
joints.append(get_joints_from_xyz_abs(i, 0, 0)) joints.append(get_joints_from_xyz_abs(robot, i, 0, 0))
#rob.movejs(joints, acc=2, vel=2) # rob.movejs(joints, acc=2, vel=2, radius=0.1)
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) # rob.movej(offset_gripper_angle(robot, -0.15, -0.15, 0.3, gripperangle=90, flip=is_flipped(robot)), vel=2, acc=2)
# move_arc(0, 0.3, 0.1)
# move_arc(0, -0.3, 0.3)
for i in range(20, 25):
pick_up_routine(robot, i, verbose=True)
# goto_holder_index(robot, 7, 0.0)
# pick_up_routine(robot, 8)
# rob.movej(get_joints_from_xyz_abs(robot, -0.35, -0.15, 0.0, math.pi/2, 0.1), vel=2, acc=2)
#rob.movej(goto_holder_index(24, 0.2, 0), acc=2, vel=2).
#joints = [] #joints = []
#for i in np.linspace(0, 340, 340):
# joints.append(goto_holder_index(24, 0.5, i)) # angle = 30
#rob.movejs(joints, acc=1, vel=3) # goto_holder_index(robot, 26, 0.1, angle)
angle = 30 # time.sleep(1)
rob.movej(goto_holder_index(26, 0.1, angle), acc=2, vel=2) # goto_holder_index(robot, 25, 0.1, angle)
time.sleep(1) # time.sleep(1)
rob.movej(goto_holder_index(25, 0.1, angle), acc=2, vel=2) # goto_holder_index(robot, 24, 0.1, angle)
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) #rob.movej(angles, acc=2, vel=2)
#time.sleep(10) #time.sleep(10)
@ -443,25 +549,6 @@ if __name__ == "__main__":
# time.sleep(5) # time.sleep(5)
# angles = get_joints_from_xyz_abs(0, -0.6, 0)
# rob.movej(angles, acc=2, vel=2)
# set_pos_abs(*p1)
# move = move_to_polar(p1, p2)
# for p in move:
# print(math.degrees(p))
# print("Safe? :", is_safe_move(p1, p2))
# #set_pos_rel_rot_abs(0, 0, -0.2, math.pi, 0, -math.pi)
# set_pos_abs(0.3, -0.2, 0.5, math.pi, 0, -math.pi)
# set_pos_abs(0, 0.2, 0.6, math.pi, 0, -math.pi)
# set_pos_abs(-0.5, -0.2, 0.4, math.pi, 0, -math.pi)
# #set_pos_rel_rot_abs(0, 0, 0, math.pi, 0, -math.pi)
# print("Current tool pose is: ", rob.getl()) # print("Current tool pose is: ", rob.getl())
# print("getj(): ", rob.getj()) # print("getj(): ", rob.getj())