Hangjun (Jerry) LiuWeihao Cheng
Published

Building the Leaning Bridge of Lire with UR3 robot arm

Blob detection using a web camera and OpenCV and pick-and-place of blocks via a UR3 robot arm.

IntermediateShowcase (no instructions)100
Building the Leaning Bridge of Lire with UR3 robot arm

Things used in this project

Software apps and online services

Robot Operating System
ROS Robot Operating System
Snappy Ubuntu Core
Snappy Ubuntu Core

Story

Read more

Code

main file

Python
contains functions to place the blocks at desired locations
#!/usr/bin/env python

import sys
import copy
import time
import rospy

import numpy as np
from lab5_header import *
from lab5_func import *
from blob_search import *


# ========================= Student's code starts here =========================

# Position for UR3 not blocking the camera
go_away = [270*PI/180.0, -90*PI/180.0, 90*PI/180.0, -90*PI/180.0, -90*PI/180.0, 135*PI/180.0]

# Store world coordinates of green and yellow blocks
xw_yw_G = []
xw_yw_Y = []
xw_yw_P = []

# for calibration
xw_yw_O = []

# Any other global variable you want to define
# Hints: where to put the blocks?


# ========================= Student's code ends here ===========================

################ Pre-defined parameters and functions no need to change below ################

# 20Hz
SPIN_RATE = 20

# UR3 home location
home = [150*PI/180.0, -90*PI/180.0, 90*PI/180.0, -90*PI/180.0, -90*PI/180.0, 0*PI/180.0]
home_dest = [210*PI/180.0, -64.5*PI/180.0, 67.5*PI/180.0, -92.3*PI/180.0, -92*PI/180.0, 120*PI/180.0]

# UR3 current position, using home position for initialization
current_position = copy.deepcopy(home)

thetas = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

digital_in_0 = 0
analog_in_0 = 0.0

suction_on = True
suction_off = False

current_io_0 = False
current_position_set = False

image_shape_define = False


"""
Whenever ur3/gripper_input publishes info this callback function is called.
"""
def input_callback(msg):

    global gripper_input
    gripper_input = msg.DIGIN
    gripper_input = gripper_input & 1 # Only look at least significant bit, meaning index 0


"""
Whenever ur3/position publishes info, this callback function is called.
"""
def position_callback(msg):

    global thetas
    global current_position
    global current_position_set

    thetas[0] = msg.position[0]
    thetas[1] = msg.position[1]
    thetas[2] = msg.position[2]
    thetas[3] = msg.position[3]
    thetas[4] = msg.position[4]
    thetas[5] = msg.position[5]

    current_position[0] = thetas[0]
    current_position[1] = thetas[1]
    current_position[2] = thetas[2]
    current_position[3] = thetas[3]
    current_position[4] = thetas[4]
    current_position[5] = thetas[5]

    current_position_set = True


"""
Function to control the suction cup on/off
"""
def gripper(pub_cmd, loop_rate, io_0):

    global SPIN_RATE
    global thetas
    global current_io_0
    global current_position

    error = 0
    spin_count = 0
    at_goal = 0

    current_io_0 = io_0

    driver_msg = command()
    driver_msg.destination = current_position
    driver_msg.v = 1.0
    driver_msg.a = 1.0
    driver_msg.io_0 = io_0
    pub_cmd.publish(driver_msg)

    while(at_goal == 0):

        if( abs(thetas[0]-driver_msg.destination[0]) < 0.0005 and \
            abs(thetas[1]-driver_msg.destination[1]) < 0.0005 and \
            abs(thetas[2]-driver_msg.destination[2]) < 0.0005 and \
            abs(thetas[3]-driver_msg.destination[3]) < 0.0005 and \
            abs(thetas[4]-driver_msg.destination[4]) < 0.0005 and \
            abs(thetas[5]-driver_msg.destination[5]) < 0.0005 ):

            #rospy.loginfo("Goal is reached!")
            at_goal = 1

        loop_rate.sleep()

        if(spin_count >  SPIN_RATE*5):

            pub_cmd.publish(driver_msg)
            rospy.loginfo("Just published again driver_msg")
            spin_count = 0

        spin_count = spin_count + 1

    return error


"""
Move robot arm from one position to another
"""
def move_arm(pub_cmd, loop_rate, dest, vel, accel):

    global thetas
    global SPIN_RATE

    error = 0
    spin_count = 0
    at_goal = 0

    driver_msg = command()
    driver_msg.destination = dest
    driver_msg.v = vel
    driver_msg.a = accel
    driver_msg.io_0 = current_io_0
    pub_cmd.publish(driver_msg)

    loop_rate.sleep()

    while(at_goal == 0):

        if( abs(thetas[0]-driver_msg.destination[0]) < 0.0005 and \
            abs(thetas[1]-driver_msg.destination[1]) < 0.0005 and \
            abs(thetas[2]-driver_msg.destination[2]) < 0.0005 and \
            abs(thetas[3]-driver_msg.destination[3]) < 0.0005 and \
            abs(thetas[4]-driver_msg.destination[4]) < 0.0005 and \
            abs(thetas[5]-driver_msg.destination[5]) < 0.0005 ):

            at_goal = 1
            #rospy.loginfo("Goal is reached!")

        loop_rate.sleep()

        if(spin_count >  SPIN_RATE*5):

            pub_cmd.publish(driver_msg)
            rospy.loginfo("Just published again driver_msg")
            spin_count = 0

        spin_count = spin_count + 1

    return error

################ Pre-defined parameters and functions no need to change above ################


def move_block(pub_cmd, loop_rate, start_xw_yw_zw, target_xw_yw_zw, yaw, vel, accel):
    """
    start_xw_yw_zw: where to pick up a block 
    target_xw_yw_zw: where to place the block

    hint: you will use lab_invk(), gripper(), move_arm() functions to
    pick and place a block

    """

    
    # ========================= Student's code starts here =========================
        
    # start xyz coordinates
    start_above_xyz = [start_xw_yw_zw[0],start_xw_yw_zw[1], 100]
    
    # global variable1
    error = 0
    vel = 4.0
    accel = 4.0    # velocity and acceleration

    # move to home
    move_arm(pub_cmd, loop_rate, home, vel, accel)
       
    # move to block (yaw goes to correct value)
    move_arm(pub_cmd, loop_rate, lab_invk(start_xw_yw_zw[0],start_xw_yw_zw[1],start_xw_yw_zw[2], yaw*180/PI), vel, accel)
    
    # turn on gripper
    gripper(pub_cmd, loop_rate, suction_on)
    #wait for 1 second
    time.sleep(1.0)
    
    # # check if block is sucked
    # if (digital_in_0 == 0):
    #     gripper(pub_cmd, loop_rate, suction_off)    # turn off gripper
    #     error = 1
    #     move_arm(pub_cmd, loop_rate, home, vel, accel)
    #     sys.exit()                                          # move to home and terminate
    
    
    # move straight up with block
    move_arm(pub_cmd, loop_rate, lab_invk(start_above_xyz[0], start_above_xyz[1], start_above_xyz[2], yaw*180/PI), vel, accel)
    
    # move to home with block
    move_arm(pub_cmd, loop_rate, home, vel, accel)
      

    # move block to destination
    move_arm(pub_cmd, loop_rate, lab_invk(target_xw_yw_zw[0], target_xw_yw_zw[1], target_xw_yw_zw[2], 0), vel, accel)
    
    # turn off gripper to drop the block
    gripper(pub_cmd, loop_rate, suction_off)
    
    #wait for 1 second
    time.sleep(1.0)
    
    # move back to home location
    move_arm(pub_cmd, loop_rate, home_dest, vel, accel)
    
    # move back to home location
    move_arm(pub_cmd, loop_rate, home, vel, accel)

    error = 0

    # ========================= Student's code ends here ===========================

    return error


class ImageConverter:

    def __init__(self, SPIN_RATE):

        self.bridge = CvBridge()
        self.image_pub = rospy.Publisher("/image_converter/output_video", Image, queue_size=10)
        self.image_sub = rospy.Subscriber("/cv_camera_node/image_raw", Image, self.image_callback)
        self.loop_rate = rospy.Rate(SPIN_RATE)

        # Check if ROS is ready for operation
        while(rospy.is_shutdown()):
            print("ROS is shutdown!")


    def image_callback(self, data):

        global xw_yw_G # store found green blocks in this list
        global xw_yw_Y # store found yellow blocks in this list
        global xw_yw_P # store found purple blocks in this list

        try:
          # Convert ROS image to OpenCV image
            raw_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
        except CvBridgeError as e:
            print(e)

        cv_image = cv2.flip(raw_image, -1)
        cv2.line(cv_image, (0,50), (640,50), (0,0,0), 5)

        # You will need to call blob_search() function to find centers of green blocks
        # and yellow blocks, and store the centers in xw_yw_G & xw_yw_Y respectively.

        # If no blocks are found for a particular color, you can return an empty list,
        # to xw_yw_G or xw_yw_Y.

        # Remember, xw_yw_G & xw_yw_Y are in global coordinates, which means you will
        # do coordinate transformation in the blob_search() function, namely, from
        # the image frame to the global world frame.

        xw_yw_G = blob_search(cv_image, "green")
        xw_yw_Y = blob_search(cv_image, "yellow")
        xw_yw_P = blob_search(cv_image, "purple")
        
        # xw_yw_O = blob_search(cv_image, "orange")


"""
Program run from here
"""
def main():

    global go_away
    # global xw_yw_Y
    # global xw_yw_G
    global home
    global home_dest
    global yaw

    # Initialize ROS node
    rospy.init_node('lab5node')

    # Initialize publisher for ur3/command with buffer size of 10
    pub_command = rospy.Publisher('ur3/command', command, queue_size=10)

    # Initialize subscriber to ur3/position & ur3/gripper_input and callback fuction
    # each time data is published
    sub_position = rospy.Subscriber('ur3/position', position, position_callback)
    sub_input = rospy.Subscriber('ur3/gripper_input', gripper_input, input_callback)

    # Check if ROS is ready for operation
    while(rospy.is_shutdown()):
        print("ROS is shutdown!")

    # Initialize the rate to publish to ur3/command
    loop_rate = rospy.Rate(SPIN_RATE)

    vel = 4.0
    accel = 4.0
    move_arm(pub_command, loop_rate, go_away, vel, accel)

    ic = ImageConverter(SPIN_RATE)
    time.sleep(5)

    # ========================= Student's code starts here =========================

    """
    Hints: use the found xw_yw_G, xw_yw_Y to move the blocks correspondingly. You will
    need to call move_block(pub_command, loop_rate, start_xw_yw_zw, target_xw_yw_zw, vel, accel)
    """
    
    list_yaw = [0]*11
    dist = [0]*11          # list of distance between a yellow block with all purple blocks
    for i in range(0,len(xw_yw_Y)):
        for j in range(0,len(xw_yw_P)):
            dist[j] = np.sqrt((xw_yw_Y[i][0]-xw_yw_P[j][0])**2 + (xw_yw_Y[i][1]-xw_yw_P[j][1])**2)
            
                # if (yaw > 3*PI/4):
                #     yaw -= 2*PI
                # elif (yaw < -PI/3):
                #     yaw += 2*PI
                # if (yaw < -PI/3):
                #     yaw += 2*PI
                # list_yaw.append(yaw)
        min_dist = min(dist)                     # store the minimum distance
        min_index = dist.index(min_dist)         # index of the minimum distance (corresponding purple block to pick)
        delta_x = xw_yw_Y[i][0]-xw_yw_P[min_index][0]
        delta_y = xw_yw_Y[i][1]-xw_yw_P[min_index][1]
        
        yaw = np.arctan2(delta_y, delta_x)    # yaw angle between (-PI, PI)[rad]        
        if (yaw < -PI/2):
            yaw += 2*PI
            list_yaw[min_index] = yaw
        else:
            list_yaw[min_index] = yaw
                    
    
    print('list_yaw:',list_yaw)
    print('length_yaw:',len(list_yaw)) 
    
    # for calibration
    # print('orange:',xw_yw_O)
    print('purple:',xw_yw_P)
               

    # convert xy from meters to mm, blocks are ~25mm high
    # list of xyz coordinates to pick up purple(center) blocks
    list_P = []
    for i in range (0,len(list_yaw)):
        
        # list_P.append(lab_invk(xw_yw_P[i][0]*1000, xw_yw_P[i][1]*1000, 25, list_yaw[i]*180/PI))
        list_P.append([xw_yw_P[i][0]*1000, xw_yw_P[i][1]*1000, 25])
        
    
    # # list of destinations (sets of joint angles) for the blocks   
    # D1 = lab_invk(0.115*1000,0.45*1000,27,0)
    # D2 = lab_invk(0.280*1000,0.45*1000,27,0)     # 1st floor
    
    # D3 = lab_invk(0.125*1000,0.45*1000,51.5,0)
    # D4 = lab_invk(0.272*1000,0.45*1000,51.5,0)     # 2nd floor
    
    # D5 = lab_invk(0.135*1000,0.45*1000,76.5,0)   
    # D6 = lab_invk(0.264*1000,0.45*1000,76.5,0)     # 3rd floor
    
    # D7 = lab_invk(0.145*1000,0.45*1000,101.5,0)   
    # D8 = lab_invk(0.256*1000,0.45*1000,101.5,0)    # 4th floor
    
    # D9 = lab_invk(0.155*1000,0.45*1000,126.5,0)   
    # D10 = lab_invk(0.243*1000,0.45*1000,126.5,0)   # 5th floor
    
    # D11 = lab_invk(0.202*1000,0.45*1000,151.5,0)   # final block
    
    
    # # list of destinations (xyz coordinates) for the blocks     (units in mm)
    D1 = [0.125*1000, 0.45*1000, 27]
    D2 = [0.280*1000, 0.45*1000, 27]     # 1st floor
    
    D3 = [0.135*1000, 0.45*1000, 51.5]
    D4 = [0.272*1000, 0.45*1000, 51.5]    # 2nd floor
    
    D5 = [0.145*1000, 0.45*1000, 76.5]  
    D6 = [0.264*1000, 0.45*1000, 76.5]     # 3rd floor
    
    D7 = [0.155*1000, 0.45*1000, 101.5]  
    D8 = [0.256*1000, 0.45*1000, 101.5]    # 4th floor
    
    D9 = [0.165*1000, 0.45*1000, 126.5]   
    D10 = [0.243*1000,0.45*1000, 126.5]   # 5th floor
    
    D11 = [0.202*1000, 0.45*1000, 151.5]   # final block
    
    
    # move block to destination
    move_block(pub_command, loop_rate, list_P[0], D1, list_yaw[0], vel, accel)
    
    # move block to destination
    move_block(pub_command, loop_rate, list_P[1], D2, list_yaw[1], vel, accel)
    
    # move block to destination
    move_block(pub_command, loop_rate, list_P[2], D3, list_yaw[2], vel, accel)

    # move block to destination
    move_block(pub_command, loop_rate, list_P[3], D4, list_yaw[3], vel, accel)
    
    # move block to destination
    move_block(pub_command, loop_rate, list_P[4], D5, list_yaw[4], vel, accel)

    # move block to destination
    move_block(pub_command, loop_rate, list_P[5], D6, list_yaw[5], vel, accel)
    
    # move block to destination
    move_block(pub_command, loop_rate, list_P[6], D7, list_yaw[6], vel, accel)

    # move block to destination
    move_block(pub_command, loop_rate, list_P[7], D8, list_yaw[7], vel, accel)
    
    # move block to destination
    move_block(pub_command, loop_rate, list_P[8], D9, list_yaw[8], vel, accel)
    
    # move block to destination
    move_block(pub_command, loop_rate, list_P[9], D10, list_yaw[9], vel, accel)

    # move block to destination
    move_block(pub_command, loop_rate, list_P[10], D11, list_yaw[10], vel, accel)

    # ========================= Student's code ends here ===========================

    move_arm(pub_command, loop_rate, go_away, vel, accel)
    rospy.loginfo("Task Completed!")
    print("Use Ctrl+C to exit program")
    rospy.spin()

if __name__ == '__main__':

    try:
        main()
    # When Ctrl+C is executed, it catches the exception
    except rospy.ROSInterruptException:
        pass

blob search function

Python
function that transforms from camera's frame to the world frame, as well as detecting colors based on the HSV ranges and output the centroid of each detected blob in to lists categorized based on their color.
#!/usr/bin/env python

import cv2
import numpy as np

# ========================= Student's code starts here =========================

# Params for camera calibration
theta = -3.6933*np.pi/180.0     # in radians  -3.3 -3.6933 -4.6933   -3.0
beta = 730.0                    # pixels per meter
tx = 0.250     # meters    0.263   0.253  0.250 
ty = -0.001    # meters   -0.105682   -0.006     -0.001   0.041

# Function that converts image coord to world coord in meters
def IMG2W(col, row):
    xc=(row - 240)/beta
    yc=(col - 320)/beta
    xw = xc*np.cos(theta) - yc*np.sin(theta) + tx
    yw = xc*np.sin(theta) + yc*np.cos(theta) + ty
    return xw,yw

# ========================= Student's code ends here ===========================

def blob_search(image_raw, color):

    # Setup SimpleBlobDetector parameters.
    params = cv2.SimpleBlobDetector_Params()

    # ========================= Student's code starts here =========================

    # Filter by Color
    params.filterByColor = False

    # Filter by Area.
    params.filterByArea = True
    # params.minArea = 0
    params.minArea = 50
    params.maxArea = 400    # units in pixels^2
    
    # Filter by Circularity
    params.filterByCircularity = False
    # params.minCircularity = 0.7
    # params.maxCircularity = 0.9
    
    # Filter by Inerita
    params.filterByInertia = False

    # Filter by Convexity
    params.filterByConvexity = False

    # ========================= Student's code ends here ===========================

    # Create a detector with the parameters
    detector = cv2.SimpleBlobDetector_create(params)

    # Convert the image into the HSV color space
    hsv_image = cv2.cvtColor(image_raw, cv2.COLOR_BGR2HSV)

    # ========================= Student's code starts here =========================

    if (color == "yellow"):
        # lower = (20,75,100)     # yellow lower
        # upper = (35,255,255)    # yellow upper
        lower = (20, 170, 170)     # yellow lower
        upper = (25,255,255)    # yellow upper

    if (color == "green"):
        # lower = (40,100,50)     # green lower
        # upper = (75,255,255)     # green upper
        lower = (35,80,130)     # green lower
        upper = (100,220,210)     # green upper
        
    if (color == "purple"):
        # lower = (125,150,50)     # purple lower
        # upper = (150,255,255)     # purple upper
        # lower = (125,100,100)     # purple lower
        # upper = (150,255,255)     # purple upper
        # lower = (120,50,50)     # purple lower
        # upper = (160,255,255)     # purple upper
        lower = (120,130,100)     # purple lower
        upper = (140,255,225)     # purple upper

        # lower = (20, 100, 100)     # yellow lower
        # upper = (32,255,255)    # yellow upper
        # lower = (40,100,100)     # green lower
        # upper = (85,255,255)     # green upper
        # lower = (125,100,100)     # purple lower
        # upper = (158,255,255)     # purple upper


    # Define a mask using the lower and upper bounds of the target color
    mask_image = cv2.inRange(hsv_image, lower, upper)
   
    # color masks for yellow and green
    
    # ========================= Student's code ends here ===========================

    keypoints = detector.detect(mask_image)

    # Find blob centers in the image coordinates
    blob_image_center = []
    num_blobs = len(keypoints)
    for i in range(num_blobs):
        blob_image_center.append((keypoints[i].pt[0],keypoints[i].pt[1]))

    # ========================= Student's code starts here =========================

    # Draw the keypoints on the detected block
    im_with_keypoints = cv2.drawKeypoints(image_raw, keypoints, 0)

    # ========================= Student's code ends here ===========================

    xw_yw = []

    if(num_blobs == 0):
        print("No block found!")
    else:
        # Convert image coordinates to global world coordinate using IMG2W() function
        for i in range(num_blobs):
            xw_yw.append(IMG2W(blob_image_center[i][0], blob_image_center[i][1]))


    cv2.namedWindow("Camera View")
    cv2.imshow("Camera View", image_raw)
    cv2.namedWindow("Mask View")
    cv2.imshow("Mask View", mask_image)
    cv2.namedWindow("Keypoint View")
    cv2.imshow("Keypoint View", im_with_keypoints)

    cv2.waitKey(2)

    # print(blob_image_center)
    
    return xw_yw

kinematics functions

Python
contains the forward kinematics and inverse kinematics functions.
#!/usr/bin/env python
import numpy as np
from scipy.linalg import expm, logm
from lab5_header import *

"""
Use 'expm' for matrix exponential.
Angles are in radian, distance are in meters.
"""
def Get_MS():
	# =================== Your code starts here ====================#
	# Fill in the correct values for w1~6 and v1~6, as well as the M matrix
	# M = np.eye(4)
	# S = np.zeros((6,6))
	S1 = np.array([[0],[0],[1],[150],[150],[0]])
	S2 = np.array([[0],[1],[0],[-162],[0],[-150]])
	S3 = np.array([[0],[1],[0],[-162],[0],[94]])
	S4 = np.array([[0],[1],[0],[-162],[0],[307]])
	S5 = np.array([[1],[0],[0],[0],[162],[-260]])
	S6 = np.array([[0],[1],[0],[-162],[0],[390]])

	S = np.block([S1,S2,S3,S4,S5,S6])
	M = np.array([[0, -1, 0, 390],[0, 0, -1, 401],[1, 0, 0, 215.5],[0, 0, 0, 1]])

	# ==============================================================#
	return M, S, S1, S2, S3, S4, S5, S6

def skew(x):
	return  np.array([[0, -x[2], x[1]], [x[2], 0, -x[0]], [-x[1], x[0], 0]])

"""
Function that calculates encoder numbers for each motor
"""
def lab_fk(theta1, theta2, theta3, theta4, theta5, theta6):
	M,S,S1, S2, S3, S4, S5, S6 = Get_MS()
	# Initialize the return_value
	return_value = [None, None, None, None, None, None]

	# =========== Implement joint angle to encoder expressions here ===========
	print("Foward kinematics calculated:\n")

	# =================== Your code starts here ====================#

	wb1 = skew(S[0:3,0])   # omega bracket
	wb2 = skew(S[0:3,1])
	wb3 = skew(S[0:3,2])
	wb4 = skew(S[0:3,3])
	wb5 = skew(S[0:3,4])
	wb6 = skew(S[0:3,5])
	v1 = np.array([[150],[150],[0]])
	v2 = np.array([[-162],[0],[-150]])
	v3 = np.array([[-162],[0],[94]])
	v4 = np.array([[-162],[0],[307]])
	v5 = np.array([[0],[162],[-260]])
	v6 = np.array([[-162],[0],[390]])
 
	Sb1 = np.block([[wb1,v1],[np.zeros([1,4])]])
	Sb2 = np.block([[wb2,v2],[np.zeros([1,4])]])
	Sb3 = np.block([[wb3,v3],[np.zeros([1,4])]])
	Sb4 = np.block([[wb4,v4],[np.zeros([1,4])]])
	Sb5 = np.block([[wb5,v5],[np.zeros([1,4])]])
	Sb6 = np.block([[wb6,v6],[np.zeros([1,4])]])
 
	e1 = expm(Sb1*theta1)
	e2 = expm(Sb2*theta2)
	e3 = expm(Sb3*theta3)
	e4 = expm(Sb4*theta4)
	e5 = expm(Sb5*theta5)
	e6 = expm(Sb6*theta6)
 
	e12 = np.matmul(e1,e2)
	e34 = np.matmul(e3,e4)
	e56 = np.matmul(e5,e6)
	term_a = np.matmul(e12,e34)
	term_b = np.matmul(e56,M)
	T06 = np.matmul(term_a,term_b)

	# ==============================================================#

	print(str(T06) + "\n")

	return_value[0] = theta1 + PI
	return_value[1] = theta2
	return_value[2] = theta3
	return_value[3] = theta4 - (0.5*PI)
	return_value[4] = theta5
	return_value[5] = theta6

	return return_value


"""
Function that calculates an elbow up Inverse Kinematic solution for the UR3
"""
def lab_invk(xWgrip, yWgrip, zWgrip, yaw_WgripDegree):
	# =================== Your code starts here ====================#
	L1 = 152
	L2 = 120
	L3 = 244
	L4 = 93
	L5 = 213
	L6 = 83
	L7 = 83
	L8 = 82
	L9 = 53.5   # mm
	L10 = 59    # mm
	yaw_radian = (yaw_WgripDegree*np.pi)/180.0
 
	x_grip = xWgrip +150
	y_grip = yWgrip - 150
	z_grip = zWgrip - 10
  
	xcen = x_grip - L9*np.cos(yaw_radian)
	ycen = y_grip - L9*np.sin(yaw_radian)
	zcen = z_grip

	alpha = np.arctan2(ycen,xcen)
	beta = np.arcsin(110/np.sqrt(xcen**2 + ycen**2))
	theta1 = alpha - beta
	theta6 = np.pi/2 + theta1 - yaw_radian      # find theta1 and theta6
 
	x0 = -83*np.cos(theta1) + 110*np.sin(theta1)
	y0 = -83*np.sin(theta1) - 110*np.cos(theta1)
	x3end = xcen + x0
	y3end = ycen + y0
	z3end = zcen + L8 + L10
	L = np.sqrt(x3end**2 + y3end**2 + (z3end-L1)**2)
 
	a = np.arccos((L5**2 - L3**2 - L**2)/(-2*L*L3))
	b = np.arccos(np.sqrt(x3end**2 + y3end**2)/(L))
	theta2 = -a - b
	theta3 = np.pi - np.arccos((L**2 - L3**2 - L5**2)/(-2*L3*L5))
	theta4 = -theta3 - theta2                      
	theta5 = -np.pi/2          # find theta2, 3, 4, and 5
 
	# theta1 = 0.0
	# theta2 = 0.0
	# theta3 = 0.0
	# theta4 = 0.0
	# theta5 = 0.0
	# theta6 = 0.0
	print(theta1, theta2, theta3, theta4, theta5, theta6)
 
	# ==============================================================#
	return lab_fk(theta1, theta2, theta3, theta4, theta5, theta6)

Credits

Hangjun (Jerry) Liu
3 projects • 2 followers
Master of Science student as UC San Diego studying mechanical engineering
Weihao Cheng
3 projects • 0 followers
Thanks to ECE470 TAs.

Comments