Robotic Arm

Annalisa DeBari and Raven Fournier

Our robot consists of two motors and beams of length 14 cm and 11 cm (first and second beam respectively).

Image Image

Challenge 1: Build the arm and demonstrate the range of motion:

Maximum X position: 25 cm

Maximum Y position: 25 cm

Minimum X position: -11.3 cm

Minimum Y position: -25 cm

Challenge 2: Calculate end effector position based on manual movement of arm.

Image

Challenge 2 was done to ensure that position of the end effector is being properly tracked by the computer.  The video demonstrates the motion and then shows the position of the end effector, denoted x_b & y_b.

Challenge 3: Create program that records positions and “plays” back.

As the first half of Challenge 3, we wanted to demonstrate that our robotic arm moves rigidly to specific points to be played back.  It can be noted that the sampling and playback rates can be altered for a more accurate playback, but this video demonstrates that the robot successfully moves to the predetermined positions.

For the second half, we wanted to demonstrate that our robotic arm can move and follow fluid motions.  This was done by altering the code slightly.  Depending on the desired application, we know what alterations to make in our code.

Code:

#!/usr/bin/env python3 
ev3 = Device("this")
def manageRange(n):
    return max(min(n,1050),-1050)

def main():
    import math

# initialize variables
    position_1 = None
    length1 = None
    length2 = None
    theta1 = None
    theta2 = None
    i = 0

# x_a is the x-coordinate of the end of the beam connected to motor 1, and x_b is the    x-coordinate of the end effector
    x_a = None
    x_b = None
    y_a = None
    y_b = None

# create vectors to hold the motor location data
    theta1_array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    theta2_array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

    while True:
    # set theta1 to the position of the motor in port b (motor 1)
        theta1 = ev3.LargeMotor('outB').position 
        theta1 = -1 * theta1 # had to multiply by -1 for the math to work out

# store that value into the current location of an array
        theta1_array[i] = theta1
        theta2 = ev3.LargeMotor('outD').position
        theta2 = -1 * theta2
        theta2_array[i] = theta2
        length1 = 14 # length of first beam
        length2 = 11 # length of 2nd beam

# from class we calculated these formulas
        x_a = length1 * math.cos(theta1 / 180.0 * math.pi)
        y_a = length1 * math.sin(theta1 / 180.0 * math.pi)
        print('x_a:' + str(x_a))
        print('y_a:' + str(y_a))
        print('motor1 position:' + str(theta1))
        x_b = x_a + length2 * math.cos((theta1+theta2) / 180.0 * math.pi)
        y_b = y_a + length2 * math.sin((theta1+theta2) / 180.0 * math.pi)
        print('x_b:' + str(x_b))
        print('y_b:' + str(y_b))
        print('motor2 position:' + str(theta2))
        sleep(1)
        i = i+1 # increase the counter variable

# once the code has recorded location 14 times, enter this next portion where it “plays back”
        if i >=14:
            print('entered if statement')
            print('theta1_array:')
            print(theta1_array)
            print('theta2_array:')
            print(theta2_array)
# need another counter variable to access the stored values
            j=0
            for count in range(14):
                print('ENTERED FOR LOOP')
                print('j is:' + str(j))
                print('motor1 position:')
                print(theta1_array[j])
                print('motor2 position:')
                print(theta2_array[j])
                current_posA = theta1_array[j] * -1
                current_posB = theta2_array[j] * -1
# needed to keep track of the previous position in order to move to the correct location relative to the original zero location instead of moving relative to its current position
                prev_posA = 0
                prev_posB = 0
                if j >= 1:
                    prev_posA = theta1_array[j-1] * -1
                    prev_posB = theta2_array[j-1] * -1
                outB = ev3.LargeMotor('outB')
                outB.run_to_rel_pos(speed_sp=manageRange(15 * 10.50),position_sp=current_posA - prev_posA, stop_action="hold")
                outD = ev3.LargeMotor('outD')
                outD.run_to_rel_pos(speed_sp=manageRange(15 * 10.50),position_sp=current_posB - prev_posB, stop_action="hold")
                j=j+1
                sleep(1)
            pass
            print('done')
            break

if __name__ == '__main__':
    main()

Disclaimer: Our code logic is correct, but since the EV3 motors are not very precise the locations are not always precise either. The mechanical components have weight to them, and the motors can become misaligned with zero fairly easily. There is also a decent amount of “wiggle room” with the motors where you can mechanically move back and forth a couple of millimeters and the motor reads the same position throughout.

Changing the sleep times also changes the rate of collection. So, to collect more fluidly, changing the sleep time to .5 or less allows the code to store the data more rapidly and collect more fluid motion. We also changed the motor command stop_action set to “coast” instead of “hold” to make the motion even more fluid as seen in the second video of challenge 3.