Project tutorial
MK2 Plus Robot Arm Controller

MK2 Plus Robot Arm Controller © LGPL

An easy method to control the stepper motor driven EEZYBOT MK2 robotic arm using a CNC shield and an Arduino Uno.

  • 5,172 views
  • 6 comments
  • 23 respects

Components and supplies

Necessary tools and machines

3drag
3D Printer (generic)

Apps and online services

About this project

The EEZYBOT MK2 Arm

If you've searched around thingiverse.com for cool robotic arms, chances are you've stumbled upon this. The EEZYBOT MK2 arm (designed by the brilliant daghizmo ) shares the kinematic linkage of the ABB IRB460 scaled down with a ratio of 1:7. However, this arm is designed to work with servos, which makes it a little bit shaky and less graceful. There is however, a better solution out there. The MK2 Plus arm found here, https://www.thingiverse.com/thing:2520572 is a remixed version of the original MK2 arm that uses 3 stepper motors to move its linkages.

Printing this does take a while, so bookmark this article, get everything printed and come back after you're done! (It'll take a few days)

If you're having trouble assembling the arm, there are plenty of tutorials online.

Selecting a Home Position

Unlike servos, stepper motors don't have any positional awareness. We'll have to remedy this by first setting up a homing routine when the arm is powered up. We'll be using 3 limit switches to set our home position. The linkages work in a somewhat complex way, but you'll easily understand where to position the switches once you assemble the arm and see how everything moves.

(i.e there's no XY like a Cartesian system but we'll call them that anyway to make things easier)

You can set the Z limit switch anywhere on the main base of the arm. Add a little dab of hot glue so that your wires wont come off when the arm moves around.

Wiring

Wiring is pretty straightforward, since all the terminals are marked on the CNC shield. Just don't plug in your A4988 drivers in the wrong way! The stepper motor at the side with the Y limit switch has to be plugged in to the terminal for the Y stepper motor in your CNC shield. The same goes for the motor at the side of the X limit switch. (We're calling these X and Y since its easier to deal with the CNC shield this way) Connect the final stepper that rotates the base of the arm to the Z terminal, and wire the endstops according to their names. Polarity does not matter.

Find a decent 12V power supply that can provide the current for the motors to run without stalling.

Code

Let's get down to business. We'll be using the AccelStepper library for Arduino to drive the steppers smoothly. This library allows you to easily accelerate, decelerate and run multiple stepper motors simultaneously. You can get this library directly through the Arduino IDE by using the Library Manager (Sketch > Include Library > Library Manager)

You can also get it from the original creators page on airspayce. https://www.airspayce.com/mikem/arduino/AccelStepper/

Now that we have everything that we need, let's go over the code step by step.

First we'll define some names for the pins we're going to use. You can find a pin diagram of the CNC shield with a quick google image search. We'll also create the AccelStepper objects for our 3 stepper motors.

#define XSTEP 2 //Stepper Motor Step pin
#define YSTEP 3
#define ZSTEP 4
#define XDIR 5 // Stepper motor Direction control pin
#define YDIR 6
#define ZDIR 7
#define ENABLE 8 // CNC Shield Enable Pin
#define XLIMIT 9 // Limit switch pins
#define YLIMIT 10
#define ZLIMIT 11
#define XMOTORACC 250 // Acceleration and Max Speed values
#define XMOTORMAXSPEED 1000
#define YMOTORACC 250
#define YMOTORMAXSPEED 1000
#include <AccelStepper.h>
AccelStepper XMOTOR(1,XSTEP,XDIR);
AccelStepper YMOTOR(1,YSTEP,YDIR);
AccelStepper ZMOTOR(1,ZSTEP,ZDIR);

Let's make a little helper function to setup our pins.

void pinsetup(){
 pinMode(ENABLE,OUTPUT);
 digitalWrite(ENABLE,LOW);
 pinMode(XLIMIT,INPUT_PULLUP);
 pinMode(YLIMIT,INPUT_PULLUP);
 pinMode(ZLIMIT,INPUT_PULLUP);
}

Now that that's done, let's go over the logic of our homing routine.

void autohome(){ //We're using this to call our homing routine 
 xyhome();
 zhome();
}
void xyhome() {
 int initial_xhome = -1;
 int initial_yhome = -1;
 //  Set Max Speed and Acceleration of each Steppers at startup for homing
 XMOTOR.setMaxSpeed(500.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
 XMOTOR.setAcceleration(50.0);  // Set Acceleration of Stepper
 YMOTOR.setMaxSpeed(500.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
 YMOTOR.setAcceleration(50.0);  // Set Acceleration of Stepper
 // Start Homing procedure of Stepper Motor at startup
 while (digitalRead(YLIMIT)) { // Make the Stepper move CCW until the switch is activated
   XMOTOR.moveTo(initial_xhome);  // Set the position to move to
   YMOTOR.moveTo(initial_yhome);  // Set the position to move to
   initial_xhome--;  // Decrease by 1 for next move if needed
   initial_yhome--;
   XMOTOR.run();  // Start moving the stepper
   YMOTOR.run();
   delay(5);
 }
 XMOTOR.setCurrentPosition(0);  // Set the current position as zero for now
 YMOTOR.setCurrentPosition(0);
 initial_xhome = -1;
 initial_yhome = 1;
 while(digitalRead(XLIMIT)){
   XMOTOR.moveTo(initial_xhome);  // Set the position to move to
   YMOTOR.moveTo(initial_yhome);  // Set the position to move to
   initial_xhome--;  // Decrease by 1 for next move if needed
   initial_yhome++;
   XMOTOR.run();  // Start moving the stepper
   YMOTOR.run();
   delay(5);
 }
 YMOTOR.setCurrentPosition(0);  // Set the current position as zero for now
 YMOTOR.setMaxSpeed(250.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
 YMOTOR.setAcceleration(10.0);  // Set Acceleration of Stepper
 initial_yhome = 1;
 while (!digitalRead(YLIMIT)) { // Make the Stepper move CW until the switch is deactivated
   YMOTOR.moveTo(initial_yhome);
   YMOTOR.run();
   initial_yhome++;
   delay(5);
 }
 YMOTOR.setCurrentPosition(0);
 YMOTOR.setMaxSpeed(YMOTORMAXSPEED);      // Set Max Speed of Stepper (Faster for regular movements)
 YMOTOR.setAcceleration(YMOTORACC);  // Set Acceleration of Stepper
 XMOTOR.setCurrentPosition(0);  // Set the current position as zero for now
 XMOTOR.setMaxSpeed(250.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
 XMOTOR.setAcceleration(10.0);  // Set Acceleration of Stepper
 initial_xhome = 1;
 while (!digitalRead(XLIMIT)) { // Make the Stepper move CW until the switch is deactivated
   XMOTOR.moveTo(initial_xhome);
   XMOTOR.run();
   initial_xhome++;
   delay(5);
 }
 XMOTOR.setCurrentPosition(0);
 XMOTOR.setMaxSpeed(XMOTORMAXSPEED);      // Set Max Speed of Stepper (Faster for regular movements)
 XMOTOR.setAcceleration(XMOTORACC);  // Set Acceleration of Stepper
}
void zhome() {
 int initial_zhome = -1;
 //  Set Max Speed and Acceleration of each Steppers at startup for homing
 ZMOTOR.setMaxSpeed(100.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
 ZMOTOR.setAcceleration(100.0);  // Set Acceleration of Stepper
 // Start Homing procedure of Stepper Motor at startup
 while (digitalRead(ZLIMIT)) {  // Make the Stepper move CCW until the switch is activated
   ZMOTOR.moveTo(initial_zhome);  // Set the position to move to
   initial_zhome--;  // Decrease by 1 for next move if needed
   ZMOTOR.run();  // Start moving the stepper
   delay(5);
 }
 ZMOTOR.setCurrentPosition(0);  // Set the current position as zero for now
 ZMOTOR.setMaxSpeed(50.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
 ZMOTOR.setAcceleration(50.0);  // Set Acceleration of Stepper
 initial_zhome = 1;
 while (!digitalRead(ZLIMIT)) { // Make the Stepper move CW until the switch is deactivated
   ZMOTOR.moveTo(initial_zhome);
   ZMOTOR.run();
   initial_zhome++;
   delay(5);
 }
 ZMOTOR.setCurrentPosition(0);
 ZMOTOR.setMaxSpeed(1000.0);      // Set Max Speed of Stepper (Faster for regular movements)
 ZMOTOR.setAcceleration(1000.0);  // Set Acceleration of Stepper
}

Okay, so that's a lot of code. What's really happening here? The arm first performs a homing routing on the X and Y motors. Because of the way the linkages work, this is done in a few steps. (You can see the video at the end to see this in action)

  • First, the X and Y motors are moved in opposite directions so that the Y limit switch is pressed first.
  • As soon as the Y limit switch is pressed, both motors turn the same direction so that the X limit switch is pressed.
  • After the X switch is pressed, the motors are moved a little bit so that the switches are depressed ( depressed as in, not the sad kinda depressed.)
  • Finally the Z motor is turned so that the Z limit switch is pressed.

You'll have to be really careful when doing the homing procedure for the first time. If your steppers move the other way, simply TURN OFF THE POWER, and THEN flip the connector of the motor.

Now that that's done, call autohome() from your setup() function so that it only runs once. Leave your loop() blank. And keep a hand on your power supply to turn it off if something goes wrong.

void setup() {
 // put your setup code here, to run once:
 Serial.begin(9600);
 pinsetup();
 autohome();
 Serial.println("HOMING OK");
}

If you're lucky your motors will turn the right way, the limit switches will click just right and the homing routine will work without any problems. But if you're like me, you'll have to do little changes before everything is up and running. So always disconnect the power if the homing goes wrong so that you don't mess up your 3D-printed arm.

Finally, you can write your own logic in the loop() so that your arm moves into the positions you want. Due to the way the arm is linked, the X and Y motors control the end effector in an almost cartesian way.

void loop() {
 XMOTOR.runToNewPosition(100);
 delay(1000);
 YMOTOR.runToNewPosition(50);
 delay(1000);
 YMOTOR.runToNewPosition(-50);
 delay(1000);
 YMOTOR.runToNewPosition(0);
 delay(1000);
 XMOTOR.runToNewPosition(0);
 delay(1000);
}

Conclusion

Video 1 : Homing Process - Watch this before homing your own setup

I've seen lots of tutorials on how to use the popular GRBL firmware to control this arm. However, this means that you need a computer to send serial commands to the arm in order to make it move. If you only need the MK2 arm to do a few movements, you can easily hardcode them into the Arduino and let it do its own thing.

That doesn't mean that you can't control this with serial commands! You can simply incorporate a Serial delimiter code into this one and send the X Y and Z motor steps as a string (delimited with special characters - e.g 5, 6, 7* which would move the X motor by 5 steps, the Y by 6 and the Z by 7. The * is used to indicate the end of the string).

You can also develop this further to send the 3D space coordinates of the end effector, and have the arduino figure out the required steps using inverse kinematics, or even basic trigonometry.

Have fun! And my heartfelt thanks to all the brilliant designers on Thingiverse!

Code

robotArmArduino
Extract the files and open with Arduino IDE
No preview (download only).
MK2 Robot Arm Controller - Github
Link to github repository

Custom parts and enclosures

Robot Arm MK2 Plus on Thingiverse
Credits to ackyltle

Comments

Similar projects you might like

ARMin v2: Simple Robot Car and Arm Controller Using Python

Project tutorial by HyperChiicken

  • 1,033 views
  • 0 comments
  • 6 respects

MeArm Robot Arm - Your Robot - V1.0

Project tutorial by Benjamin Gray

  • 27,102 views
  • 4 comments
  • 41 respects

Tertiarm - 3d Printed Robot Arm

Project tutorial by Karagad

  • 9,225 views
  • 2 comments
  • 20 respects

Littlearm 2C: Build a 3D Printed Arduino Robot Arm

Project tutorial by Slant Concepts

  • 6,546 views
  • 1 comment
  • 45 respects

ARMin: Simple Robot Arm Controller Using Python

Project tutorial by HyperChiicken

  • 2,781 views
  • 0 comments
  • 5 respects
Add projectSign up / Login