Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support to multiple robot model #8

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7f62a43
WIP: ADD support to dobot
rmatsuda Aug 25, 2023
354b4d3
WIP: refactor
rmatsuda Aug 25, 2023
1a3ee9a
ENH: uses feedback port
rmatsuda Sep 4, 2023
08ef124
ADD: try and except
rmatsuda Sep 5, 2023
53941dd
WIP
rmatsuda Sep 21, 2023
1c76bd0
ADD: new elfin API and MOD: arc motion function
rmatsuda Sep 25, 2023
2c76ba3
FIX: sleep time for initialization
rmatsuda Sep 25, 2023
75c5baf
ADD: replace arc motion for bezier curve
rmatsuda Sep 26, 2023
55eed5a
FIX: dobot control
rmatsuda Oct 2, 2023
6ede0ed
ADD: bezier init angles and change servop to movel
rmatsuda Oct 5, 2023
ff52ad8
MOD: change IP to local host name
rmatsuda Oct 23, 2023
6eb8d0e
FIX: arc motion
rmatsuda Oct 23, 2023
e6a3d41
ENH: check robot connection
rmatsuda Oct 23, 2023
ba840a2
FIX: force stop
rmatsuda Oct 24, 2023
c9a130a
ADD: ForceStop function to all robots
rmatsuda Oct 24, 2023
d48ae2f
Update constants.py
rmatsuda Oct 24, 2023
bbcb743
ADD: AthKand fork
rmatsuda Oct 27, 2023
3c32024
Merge branch 'force-and-torque-control-from-AthKand-fork' into suppor…
rmatsuda Oct 30, 2023
0f6ca08
FIX: force control
rmatsuda Oct 30, 2023
ca48b28
Update .gitignore
rmatsuda Oct 30, 2023
0bb2487
MOD: gitignore tmp file
rmatsuda Oct 30, 2023
202618b
Update .gitignore
rmatsuda Oct 30, 2023
bb55a6f
Refactor SendCoordinatesControl to SendTargetToControl
rmatsuda Oct 30, 2023
2055296
FIX: robot elfin
rmatsuda Nov 6, 2023
411767b
ADD: elfin linux model
rmatsuda Nov 16, 2023
3d87366
FIX: remote host ip
rmatsuda Nov 16, 2023
3433b6c
ADD: pynput lib requirement
rmatsuda Nov 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,7 @@ dmypy.json

# Pyre type checker
.pyre/

*.patch

tmp
64 changes: 64 additions & 0 deletions display.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import os
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import atexit

from matplotlib.patches import FancyBboxPatch
import matplotlib.animation as animation
import robot.constants as const

matplotlib.use('TkAgg')

def delete_file(file):
if os.path.exists(file):
os.remove(file)
else:
print(file)


class PointOfApp:

def __init__(self):
# create plots for point of application
self.fig = plt.figure()
self.ax = self.fig.add_subplot(1, 1, 1)
self.square = FancyBboxPatch((-5, -5), 10, 10, alpha=0.5, boxstyle="round,pad=3")
self.ax.add_patch(self.square)
self.ax.set_xlim(-12, 12)
self.ax.set_ylim(-12, 12)
self.point, = self.ax.plot(0, 0, 'ro', markersize=10)

ani = animation.FuncAnimation(self.fig, self.animate, fargs=(), interval=1)
plt.show()

atexit.register(delete_file, const.TEMP_FILE)

def animate(self, i):
'''
Loop to read live sensor data and perform relevant operations.

'''
if os.path.exists(const.TEMP_FILE) and os.path.getsize(const.TEMP_FILE) > 0:
with open(const.TEMP_FILE, 'rb') as file:
try: # catch OSError in case of a one line file
file.seek(-2, os.SEEK_END)
while file.read(1) != b'\n':
file.seek(-2, os.SEEK_CUR)
except OSError:
file.seek(0)
data = file.readline().decode()

data = data[data.find("[")+1:data.find("]")]
data = np.array(data.split(", "), dtype = 'float64')

self.point.set_data(data[0], data[1])

# Redraw the plot
self.fig.canvas.draw()
else:
pass

if __name__ == '__main__' :
PointOfApp()

3 changes: 2 additions & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ dependencies:
- websockets
- numpy
- opencv
- wxPython
- wxPython
- pynput
3 changes: 1 addition & 2 deletions main_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,4 @@ def reset_robot(data):
rc.send_message(topic, data)
previous_robot_status = robot_status

#time.sleep(const.SLEEP_ROBOT)

time.sleep(const.SLEEP_ROBOT)
97 changes: 72 additions & 25 deletions robot/constants.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
#Robot
# Please set up the site or coil, choose the robot model, and decide if you want to use force sensing
SITE = "usp_coil"
ROBOT = "dobot" #elfin, dobot, or ur
FORCE_TORQUE_SENSOR = True
DISPLAY_POA = True

TEMP_FILE = 'tmp'

# Define the required offset to align the coil and robot end effector
if SITE == "usp_coil":
ROBOT_RX_OFFSET = 0
ROBOT_RY_OFFSET = 0
ROBOT_RZ_OFFSET = -90
ROBOT_RZ_OFFSET = 0
elif SITE == "usp_neurosoft":
ROBOT_RX_OFFSET = -90
ROBOT_RY_OFFSET = 0
Expand All @@ -13,37 +19,78 @@
ROBOT_RX_OFFSET = 0
ROBOT_RY_OFFSET = 0
ROBOT_RZ_OFFSET = 157.5
elif SITE == "tubingen":
ROBOT_RX_OFFSET = 0
ROBOT_RY_OFFSET = 0
ROBOT_RZ_OFFSET = 157.5
else:
ROBOT_RX_OFFSET = 0
ROBOT_RY_OFFSET = 0
ROBOT_RZ_OFFSET = 0

SLEEP_ROBOT = 0.01

ROBOT_ElFIN_PORT = 10003

ROBOT_MOTIONS = {"normal": 0, "linear out": 1, "arc": 2, 'force linear out': 3}
ROBOT_HEAD_VELOCITY_THRESHOLD = 20 #mm/s
ROBOT_ARC_THRESHOLD_DISTANCE = 80 #mm
ROBOT_ARC_THRESHOLD_DISTANCE_ANGLE = 30 #°
ROBOT_THRESHOLD_TO_UPDATE_TARGET_ARC = 40 #mm
ROBOT_VERSOR_SCALE_FACTOR = 50
ROBOT_TRANSFORMATION_MATRIX_THRESHOLD = 1 #mm
ROBOT_FORCE_SENSOR_THRESHOLD = 10 #N
ROBOT_FORCE_SENSOR_SCALE_THRESHOLD = 30 #% of init force
ROBOT_TARGET_TUNING_THRESHOLD_DISTANCE = 30
ROBOT_TARGET_TUNING_THRESHOLD_ANGLE = 5
if ROBOT == "dobot":
# Robot settings
ROBOT_WORKING_SPACE = 1500 # mm
ROBOT_DOBOT_DASHBOARD_PORT = 29999
ROBOT_DOBOT_MOVE_PORT = 30003
ROBOT_DOBOT_FEED_PORT = 30004
ROBOT_DOBOT_TOOL_ID = 0
ROBOT_DOBOT_TIMEOUT_START_MOTION = 10
ROBOT_DOBOT_TIMEOUT_MOTION = 45
SLEEP_ROBOT = 0.005
# Filtering head motion
ROBOT_HEAD_VELOCITY_THRESHOLD = 30 #mm/s
# Tunning motion
ROBOT_TARGET_TUNING_THRESHOLD_DISTANCE = 50
ROBOT_TARGET_TUNING_THRESHOLD_ANGLE = 15
# Arc motion
ROBOT_ARC_THRESHOLD_DISTANCE = 100 #mm
ROBOT_ARC_THRESHOLD_DISTANCE_ANGLE = 45 #°
ROBOT_ARC_BEZIER_CURVE_STEP = 0.4 # step size between 0 and 1. 0.1 generates 10 points; 0.01 generates 100 points along the curve path
ROBOT_THRESHOLD_TO_UPDATE_TARGET_ARC = 40 #mm
ROBOT_VERSOR_SCALE_FACTOR = 50
ROBOT_MIDDLE_ARC_SCALE_FACTOR = 4
# Check robot tracker registration
ROBOT_TRANSFORMATION_MATRIX_THRESHOLD = 1 #mm
# Force and torque sensor
ROBOT_FORCE_SENSOR_THRESHOLD = 10 #N
ROBOT_FORCE_SENSOR_SCALE_THRESHOLD = 100 #% of init force
# Robot States
ROBOT_DOBOT_MOVE_STATE = {"error": 9}
elif ROBOT == "elfin":
# Robot settings
# Robot Working Space is defined as 800mm in Elfin 5 manual. For safety, the value is reduced by 5%.
# For debug, feel free to use 1000 mm
ROBOT_WORKING_SPACE = 1000 #mm
ROBOT_ElFIN_PORT = 10003
SLEEP_ROBOT = 0.0
# Filtering head motion
ROBOT_HEAD_VELOCITY_THRESHOLD = 20 # mm/s
# Tunning motion
ROBOT_TARGET_TUNING_THRESHOLD_DISTANCE = 30
ROBOT_TARGET_TUNING_THRESHOLD_ANGLE = 5
# Arc motion
ROBOT_ARC_THRESHOLD_DISTANCE = 80 # mm
ROBOT_ARC_THRESHOLD_DISTANCE_ANGLE = 30 # °
ROBOT_MIDDLE_ARC_SCALE_FACTOR = 1.5
ROBOT_THRESHOLD_TO_UPDATE_TARGET_ARC = 40 # mm
ROBOT_VERSOR_SCALE_FACTOR = 50
# Check robot tracker registration
ROBOT_TRANSFORMATION_MATRIX_THRESHOLD = 1 # mm
# Force and torque sensor
ROBOT_FORCE_SENSOR_THRESHOLD = 10 # N
ROBOT_FORCE_SENSOR_SCALE_THRESHOLD = 30 # % of init force
# Robot States
ROBOT_ELFIN_MOVE_STATE = {"free to move": 0,
"in motion": 1009,
"waiting for execution": 1013,
"error": 1025}

FORCE_TORQUE_SENSOR = False
# Please, do not change the following constants.

#Robot Working Space is defined as 800mm in Elfin manual. For safety, the value is reduced by 5%.
ROBOT_WORKING_SPACE = 1000 #mm
ROBOT_MOVE_STATE = {"free to move": 0,
"in motion": 1009,
"waiting for execution": 1013,
"error": 1025}
ROBOT_MOTIONS = {"normal": 0, "linear out": 1, "arc": 2, 'force linear out': 3, 'tunning': 4}

#Publisher messages
# Publisher messages from invesalius
PUB_MESSAGES = ['Connect to robot',
'Robot navigation mode',
'Update robot target',
Expand Down
Empty file added robot/control/PID.py
Empty file.
3 changes: 0 additions & 3 deletions robot/control/coordinates.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@

import numpy as np

import robot.control.elfin_processing as elfin_process


class RobotCoordinates:
"""
Expand Down
59 changes: 59 additions & 0 deletions robot/control/ft.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize


# Rotation and Translation matrices to find pos on mTMS head
R = np.load('robot/resources/Rot.npy')
T = np.load('robot/resources/Tr.npy')
# Set tool origin and size bounds
# ..... based on size of mTMS

ORIG = np.array([0.0, 0.0, 0.06])
BOUNDS_X = (-0.08, 0.08)
BOUNDS_Y = (-0.08, 0.08)
BOUNDS_Z = (0, 0.06)

def _func(r, F, M, orig):
'''
Function to minimise objective function

Returns: Norm of r x F - M (Np Array)
'''
# Check if r is outside the box
return np.linalg.norm(np.cross(r - orig, F) - M)


def find_r(F, M):
'''
Find point of application of force

Returns: transformed point of application (list)
'''

# initial guess
r0 = np.array([0.0, 0.0, 0.06])

# find r that minimizes the objective function
res = minimize(_func, r0,
args=(F, M, ORIG),
method='Nelder-Mead',
bounds=(BOUNDS_X, BOUNDS_Y, BOUNDS_Z))

r_min = res.x * 100 # multiply by 100 to get value in cm
r_tran = R @ r_min + T

# conditions to identify p.o.a
if not (-8 <= r_tran[0] <= 8 and
-8 <= r_tran[1] <= 8):
r_tran[0], r_tran[1] = 0, 0

else:
if F[2] < 1:
#print(r_tran)
pass
else:
r_tran[0], r_tran[1] = 0, 0

return [round(r_tran[i], 1) for i in range(0, len(r_tran))]

Loading