Introduction: Automated Robotic Arm That Learns | Ft. Tinkercad, Arduino Mega, EEZYbotARM

About: I am Aarav Garg. I am 17y/o. I have a keen interest in and passion for robotics and programming. I am the Founder of Tech Nuttiez, a startup that aims to educate the youth globally on technology! I am an incom…

Hi, in this Instructable, you will learn how to build a Robotic Arm that can learn to do any task and can be taught any task. It has two joysticks and also features a colorful 2.4" TFT display which acts as both a touch control panel and also a display to visualise what's going on.

The robotic arm can either be operated directly through the Manual Mode or the robotic arm can be taught new tasks through the Automated Mode and then the robot then goes over those tasks forever in a loop, until you stop it :)

The robotic arm has three Degrees of Freedom (DOF) and also a cute little gripper, including which, there are a total of four servo motors that we will be using in this project. I have used the MG90S metal gear servo motors for better performance and quality!

I have used an Arduino Mega for the Robotic Arm as it has a huge number of I/O pins which I quite needed because with the display, it is impossible to plug in any other I/O devices to the Arduino UNO board and as a result, I chose the Arduino Mega board. I also designed a custom PCB for the project to prevent a mess of wires.

This is a really good project for learning about the various processes carried out by any robot and in particular, this is a great demonstration of the capabilities of the Arduino board at a higher and more complex level!

Sounds Interesting? Let's dive right into the I'ble.

Subscribe to my channel for updates!

Step 1: History and Evolution

The image you see on the left is a picture of the control panel of a 2-year-old iteration of this Robotic Arm. It never worked properly but yes, I did make it, so I felt it would be worth putting in some past details of the project.

1.1 Problems I Faced with the V1.0 😕:

  • The first problem that I faced was a frequent jittering of the SG90 plastic gears that I had previously used in my arm. The arm would frequently start vibrating and sometimes violently shaking as the motors were highly incapable of managing the weight of the arm (which I later realised).
  • Another problem was with the control panel and that was that the 16 x 2 alphanumeric display was not good enough for my application. It had very less viewing space and could not display all the required information.
  • The button panel also was bad because I had used a salvaged button panel from an old laptop which did not work that great.
  • I know that it was not a well-planned project back then but I have made many changes and have got a considerable satisfying result now!

1.2 What Has Changed ✅:

  • I first changed the servo motors fromplastic gear to metal gear (or) from SG90 to MG90S. This surely improved a lot of stability and performance. Metal gear motors do not jitter and the gears in these do not break in adverse conditions, whereas their plastic counterparts do!
  • Then one of the major changes I did was to eliminate the button panel and replace the display with a bigger touchscreen display which would act as both the input and the output for controlling the arm!
  • Also previously I used a prototype PCB board and created a circuit on that on my own in the form of an Arduino Mega shield and this caused the use of a lot of wires which is looking quite messy as you can see in the above image! I have now replaced it with a custom-designed PCB from JLCPCB!
  • The control panel box as you can see in the image on the left is made of cardboard. This time, to improve the quality of my project I have gone for a 3D printed control panel box instead! I designed it in Tinkercad and got it printed from IAmRapid!

These were pretty much all the major changes I had to pull off while transitioning from the first version to the second one! It was a pretty tedious job figuring out the mistakes and I made sure that I resolved them in the best possible manner!

Step 2: The Working Algorithm

The robotic arm has two modes: Manual Mode; Automated Mode

In the manual mode, the arm can directly be controlled using the two joysticks present on the control panel.

In the automated mode, you have two suboptions - you can either record a sequence of actions of a task that you want the robotic arm to perform or you can play an already recorded sequence. When you hit the record button you can manoeuvre the arm using the joysticks and save checkpoints or savepoints which the arm will later repeat when it is in the play mode.

The navigation will take place through the TFT touch display and I have made a neat looking responsive GUI for the smooth functioning of the robotic arm!

Step 3: Gather the Required Material

These are the components, tools and software you will require for this project:

3.1 Components Required:

3.2 Tools (Optional):

3.3 Software:

I always prefer Quartz Components for buying any electronic component!

Gather all the required stuff and move on further to the next step!

Step 4: Building the Robotic Arm

Now, we come to the part where we build the arm itself.

4.1 Why the EEZYbotARM?

In this project, we are solely concerned with the functioning and the logic behind the functioning of the arm! Our aim is to get the robotic arm to learn tasks and then repeat them, in a human-like manner! The shape and design of the arm do not really matter much so to save a bit of time on this part, I just decided to go with an already available open-source robotic arm, the EEZYbotARM. It has a pretty decent design and is perfect for our project.

4.2 Building the Arm:

The.stl files of the EEZYbotARMare available on Thingiverse and there is also a detailed Instructable for building the arm! These are pretty good resources to get the arm printed and assemble it!

After building the arm, proceed to the next step!

Step 5: Custom PCB

There is no big schematic involved in our project as we just need to connect the servos, the joysticks, and the display to the Arduino Mega board.

5.1 Why Custom PCB:

The display can be directly plugged in but the other two cannot. Also, Arduino originally has only 2 to 3 GND and VCC ports and with multiple I/O devices being used in our project, designing a custom PCB saved a huge mess of wires and makes the project a lot easier to build and a lot better on the look!

5.2 How Custom PCB:

So, I designed a PCB in Eagle and then uploaded the Gerber files to JLCPCB. They offer $2/5pcs 2Layer & $5/5pcs 4Layer PCBs: https://jlcpcb.com. The PCBs arrived at my place in around 5 days which is pretty amazing and the quality of the PCB was also fabulous.

5.3 Which Custom PCB:

I ordered white PCBs as this costed nothing extra and I felt that this is a pretty neat change to make by deviating from the common green PCBs that we always use. The PCB has a place where all the servo motors will be directly plugged in and also a place where the jumper wire ribbon coming from the joysticks can be directly plugged in.

The PCB has been designed to be an Arduino Mega Shield and can be directly plugged onto the Arduino Mega board using some bottom male header pins and connects to the I/O devices using the male header pins on the top. I have also added two LEDs where one is the power LED and one is a simple output LED that can be controlled as per the need (the PCB will be inside the main control panel box so it does not really matter much).

5.4 Custom PCB Conclusions:

It is not a mandate to design the PCB in this project and the wires can be directly connected which might be fine for most people. I just wanted to go a level higher and came up with all of this. You can directly connect the motors, the joystick and the display to the Arduino Mega too! Though it might take more wires, a little more time and comparatively more effort, it is possible!

Step 6: The Control Panel Box

This is the part where we need to design and print the control panel box of our robotic arm.

6.1 The Design:

I designed the control panel box inTinkercad which is an amazing 3D CAD software and is always my preferred choice!

If you saw the image from the History and Revolution part in my instructable you might have seen how the control panel needs to be. The control panel has a cutout for the display and two round cutouts for the joysticks. It also has a place at the extreme front where the robotic arm will be placed. For some reason, I was feeling very artistic that day, when I designed this, so you can clearly see what that resulted in! 😜

6.2 Printing the Control Panel:

After designing the control panel, I downloaded the .stl files and then uploaded them to IAmRapid and got an instant quote which was quite affordable! Then I ordered the parts and they were delivered to my doorstep within 2 days (in India). As you can see in the above images, the quality of the prints is pretty satisfying.

After designing and printing the control panel box, let's move on further!

Robotic Arm Control Panel

Step 7: Placing the Components (In Enclosure)

Now we need to place the components of our project into the Control Panel Box.

7.1 Placing the Joystick Module:

I haven't used two individual joysticks and used a single module with two of them instead. I have made an elevated pedestal with four screw holes in the enclosure. We just need to screw the joystick module using fours screws onto the pedestals with holes!

7.2 Placing the Arduino Mega + Custom Shield PCB Attached:

I have made two cutouts for the two ports of the Arduino Mega. The robotic arm will be powered using a DC adapter so one port is for that and the other is the USB port to upload to and change the code on the Arduino Mega! Also attach the custom PCB shield, if you have made one, onto the Arduino board!

7.3 Attaching the Display to the Top Lid:

Now, we need to attach the display to the bottom of the top lid. You can use anything to do that. I have used some hot glue for the same :)

7.4 Placing the Robotic Arm at the Front:

I have made a small impression in the shape of the base of the robotic arm at the front of the control panel where there is an extended base plate coming out from the control panel box and is attached to the box. We need to place the robotic arm on that impression.

After completing all these, move on to the next step!

Step 8: Control Panel Wiring

Now, we need to wire the components that we earlier placed in our control panel. This can be done in a few very easy steps. As I have designed the custom PCB, this step was fairly easier for me as I just had to plug in the components such as the joystick modules and motors into their respective ports on the PCB.

There are three components that we need to connect to the PCB:

  • The Servo Motors (Robotic Arm)
  • The Joystick Modules
  • The Touch Display

If you choose not to go with the PCB, then follow the instructions below for connecting the various components (listed above) to the PCB (Arduino Mega Shield).

Joystick:

X1: A8 of Arduino Mega

Y1: A9 of Arduino Mega

X2: A10 of Arduino Mega

Y2: A11 of Arduino Mega

GND: GND of Arduino Mega

VCC: +5V of Arduino Mega

Touch Display:

Plug it into the Arduino board (or) Connect all pins as you would plug them into the board respectively.

Servo Motors:

S1 OUT: 22 of Arduino Mega

S2 OUT: 24 of Arduino Mega

S3 OUT: 26 of Arduino Mega

S4 OUT: 28 of Arduino Mega

GND: GND of Arduino Mega

VCC: +5V of Arduino Mega

Note: There is a small rectangular opening at the front of the control panel box so that the wires coming from the servo motors of the robotic arm can go inside.

After completing the wiring, close the top lid of the control panel box using some screws. Then move ahead to the next step!

Step 9: Coding Showdown

Now comes the most essential part of the project- writing the code for the robotic arm to actually work! I have attached the code below for you to use/refer to at any point in time.

The code spanned a few thousand lines and would become too complex to comprehend if you just went through it. So, I have added comments, wherever necessary, to provide adequate context and help you in understanding the code way better.

After completing the step, move ahead!

Code for the Robotic Arm:

   ////////////////////////////////////////////////////////  //                Arduino Robotic Arm                 //              //              By Aarav Garg - Tech Nuttiez          //////////////////////////////////////////////////////////#include <Servo.h> #include <Adafruit_GFX.h>#include <MCUFRIEND_kbv.h>#include <TouchScreen.h>#include <Fonts/FreeSansBold12pt7b.h>#include <Fonts/FreeSansBold18pt7b.h>//pressure for tft touch display#define MINPRESSURE 200#define MAXPRESSURE 1000//page variableString page;//clicked stateboolean cs1 = false; boolean cs2 = false; boolean cs3 = false; boolean cs4 = false; boolean cs5 = false; //saved sequence numberint ssn = 0;//init tft objectMCUFRIEND_kbv tft;//define the servosServo s1;Servo s2;Servo s3;Servo s4;//joy pins#define j1x A8#define j1y A9#define j2x A10#define j2y A11//joy valuesint x_out = 0;int y_out = 0;int x_out2 = 0;int y_out2 = 0;//define variable for values of the buttonint button1Pressed = 0;boolean button2Pressed = false;boolean mode = false;//define int variable array for saved position of the servosint servo1PosSave[]={90,90,90,90,90};int servo2PosSave[]={90,90,90,90,90};int servo3PosSave[]={90,90,90,90,90};int servo4PosSave[]={90,90,90,90,90};//tft callibration dataconst int XP = 6, XM = A2, YP = A1, YM = 7; //240x320 ID = 0x9325const int TS_LEFT = 142, TS_RT = 892, TS_TOP = 937, TS_BOT = 187;//init touchscreen objectTouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);//init tft display gui buttonsAdafruit_GFX_Button manual_btn, auto_btn, backmanual_btn, backauto_btn, backrecord_btn, backplay_btn, record_btn, play_btn, save_btn;int pixel_x, pixel_y;     //Touch_getXY() updates global varsbool Touch_getXY(void){    TSPoint p = ts.getPoint();    pinMode(YP, OUTPUT);      //restore shared pins    pinMode(XM, OUTPUT);    digitalWrite(YP, HIGH);   //because TFT control pins    digitalWrite(XM, HIGH);    bool pressed = (p.z > MINPRESSURE && p.z < MAXPRESSURE);    if (pressed) {        pixel_x = map(p.y, TS_TOP, TS_BOT, 0, 320);         pixel_y = map(p.x, TS_RT, TS_LEFT, 0, 240);    }    return pressed;}#define BLACK   0x0000#define BLUE    0x001F#define RED     0xF800#define GREEN   0x07E0#define CYAN    0x07FF#define MAGENTA 0xF81F#define YELLOW  0xFFE0#define WHITE   0xFFFFvoid setup() {  //define the servo pins  s1.attach(22);  s2.attach(24);  s3.attach(26);  s4.attach(28);  s1.write(90);  s2.write(90);  s3.write(90);  s4.write(90);  //define joy pins as input units  pinMode(j1x, INPUT);  pinMode(j1y, INPUT);  pinMode(j2x, INPUT);  pinMode(j2y, INPUT);  //initialize serial communication  Serial.begin(9600);  uint16_t ID = tft.readID();  Serial.print("TFT ID = 0x");  Serial.println(ID, HEX);  Serial.println("Calibrate for your Touch Panel");    tft.begin(ID);  tft.setRotation(1);            //LANDSCAPE - 1; PORTRAIT - 0  tft.fillScreen(BLACK);   page = "home";}void loop(){  if (page == "home"){    chooseModePage();  } else if (page == "manual"){    manualModePage();  } else if (page == "automated"){    automatedModePage();   } else if (page == "record"){    recordPage();  } else if (page == "play"){    playPage();  }    }void chooseModePage(){  cs2 = false;  cs3 = false;  cs4 = false;  cs5 = false;  ssn = 0;  if(cs1 == false){    tft.fillScreen(BLACK);    manual_btn.initButton(&tft,  160, 120, 250, 55, WHITE, CYAN, BLACK, "MANUAL", 3);    auto_btn.initButton(&tft, 160, 190, 250, 55, WHITE, CYAN, BLACK, "AUTOMATED", 3);      manual_btn.drawButton(false);    auto_btn.drawButton(false);    tft.setFont(&FreeSansBold18pt7b);    tft.setCursor(43, 55);                    //x,y    tft.setTextColor(WHITE);                  //color    tft.setTextSize(1);                       //Eg., 1,2,3    tft.print("Choose Mode");                 //Your Text    cs1 = true;  }  bool down = Touch_getXY();    manual_btn.press(down && manual_btn.contains(pixel_x, pixel_y));    auto_btn.press(down && auto_btn.contains(pixel_x, pixel_y));    if (manual_btn.justReleased()){        tft.setFont();        manual_btn.drawButton(false);        Serial.println("a");        page = "manual";    }            if (auto_btn.justReleased()){        tft.setFont();        auto_btn.drawButton(false);        Serial.println("b");        page = "automated";    }    if (manual_btn.justPressed()) {        tft.setFont();        manual_btn.drawButton(true);        Serial.println("c");    }    if (auto_btn.justPressed()) {        tft.setFont();        auto_btn.drawButton(true);        Serial.println("d");    }  }  void manualModePage(){  Serial.print(analogRead(j1x));  Serial.print("\t");  Serial.print(analogRead(j2x));  Serial.print("\t");  Serial.print(analogRead(j1y));  Serial.print("\t");  Serial.println(analogRead(j2y));  cs1 = false;  cs3 = false;  cs4 = false;  cs5 = false;  ssn = 0;  if (cs2 == false){    tft.fillScreen(BLACK);    backmanual_btn.initButton(&tft,  160, 190, 250, 55, WHITE, CYAN, BLACK, "BACK", 3);      backmanual_btn.drawButton(false);    tft.setFont(&FreeSansBold18pt7b);    tft.setCursor(50, 50);                    //x,y    tft.setTextColor(CYAN);                  //color    tft.setTextSize(1);                       //Eg., 1,2,3    tft.print("Manual Mode");                 //Your Text    tft.setFont(&FreeSansBold12pt7b);    tft.setCursor(20, 100);                    //x,y    tft.setTextColor(WHITE);                  //color    tft.setTextSize(1);                       //Eg., 1,2,3    tft.print("Use the Joystick here to");                 //Your Text    tft.setFont(&FreeSansBold12pt7b);    tft.setCursor(20, 130);                    //x,y    tft.setTextColor(WHITE);                  //color    tft.setTextSize(1);                       //Eg., 1,2,3    tft.print("control the Robotic Arm!");     cs2 = true;  }  bool down = Touch_getXY();  backmanual_btn.press(down && backmanual_btn.contains(pixel_x, pixel_y));  if (backmanual_btn.justReleased()){      tft.setFont();      backmanual_btn.drawButton(false);      Serial.println("a");      page = "home";  }          if (backmanual_btn.justPressed()) {      tft.setFont();      backmanual_btn.drawButton(true);      Serial.println("c");  }  //-------------------------------Manual Joystick Control-------------------------------------------------------------------------------------------------------------  if(analogRead(j1x) >= 800){     for (int i = s1.read(); i < 180; i++){      if (analogRead(j1x) < 800){        break;      }      s1.write(i);      delay(20);     }  }  else if(analogRead(j1x) <= 300){     for (int i = s1.read(); i > 0; i--){      if (analogRead(j1x) > 300){        break;      }      s1.write(i);      delay(20);     }  }//-------------------------------------------  if(analogRead(j1y) >= 800){     for (int i = s2.read(); i < 140; i++){      if (analogRead(j1y) < 800){        break;      }      s2.write(i);      delay(20);     }  }  else if(analogRead(j1y) <= 300){     for (int i = s2.read(); i > 70; i--){      if (analogRead(j1y) > 300){        break;      }      s2.write(i);      delay(20);     }  }//-------------------------------------------  if(analogRead(j2x) >= 800){     for (int i = s4.read(); i < 120; i++){      if (analogRead(j2x) < 800){        break;      }      s4.write(i);      delay(30);     }  }  else if(analogRead(j2x) <= 300){     for (int i = s4.read(); i > 50; i--){      if (analogRead(j2x) > 300){        break;      }      s4.write(i);      delay(30);     }  }//-------------------------------------------  if(analogRead(j2y) >= 800){     for (int i = s3.read(); i < 120; i++){      if (analogRead(j2y) < 800){        break;      }      s3.write(i);      delay(20);     }  }  else if(analogRead(j2y) <= 300){     for (int i = s3.read(); i > 60; i--){      if (analogRead(j2y) > 300){        break;      }      s3.write(i);      delay(20);     }  }  }void automatedModePage(){  cs1 = false;  cs2 = false;  cs4 = false;  cs5 = false;  ssn = 0;  if (cs3 == false){    tft.fillScreen(BLACK);    backauto_btn.initButton(&tft,  160, 180, 280, 55, WHITE, CYAN, BLACK, "BACK", 3);      backauto_btn.drawButton(false);    record_btn.initButton(&tft,  103, 115, 162, 55, WHITE, CYAN, BLACK, "RECORD", 3);      record_btn.drawButton(false);    play_btn.initButton(&tft,  245, 115, 110, 55, WHITE, CYAN, BLACK, "PLAY", 3);      play_btn.drawButton(false);    tft.setFont(&FreeSansBold18pt7b);    tft.setCursor(70, 60);                    //x,y    tft.setTextColor(CYAN);                  //color    tft.setTextSize(1);                       //Eg., 1,2,3    tft.print("Auto Mode");                 //Your Text    cs3 = true;  }    bool down = Touch_getXY();    record_btn.press(down && record_btn.contains(pixel_x, pixel_y));    play_btn.press(down && play_btn.contains(pixel_x, pixel_y));    backauto_btn.press(down && backauto_btn.contains(pixel_x, pixel_y));    if (record_btn.justReleased()){        tft.setFont();        record_btn.drawButton(false);        page = "record";    }            if (play_btn.justReleased()){        tft.setFont();        play_btn.drawButton(false);        page = "play";    }    if (backauto_btn.justReleased()){        tft.setFont();        backauto_btn.drawButton(false);        page = "home";    }    if (record_btn.justPressed()) {        tft.setFont();        record_btn.drawButton(true);    }    if (play_btn.justPressed()) {        tft.setFont();        play_btn.drawButton(true);    }      if (backauto_btn.justPressed()) {        tft.setFont();        backauto_btn.drawButton(true);    }  }void recordPage(){  cs1 = false;  cs2 = false;  cs3 = false;  cs5 = false;  if (cs4 == false){    tft.fillScreen(BLACK);    backrecord_btn.initButton(&tft,  160, 205, 260, 55, GREEN, CYAN, BLACK, "BACK", 3);      backrecord_btn.drawButton(false);    save_btn.initButton(&tft,  160, 140, 260, 55, CYAN, GREEN, BLACK, "SAVE", 3);      save_btn.drawButton(false);    tft.setFont(&FreeSansBold18pt7b);    tft.setCursor(67, 50);                    //x,y    tft.setTextColor(CYAN);                  //color    tft.setTextSize(1);                       //Eg., 1,2,3    tft.print("Recording...");     tft.fillRect(35, 70, 250, 30, WHITE);    tft.drawRect(35, 70, 50, 30, BLUE);      tft.drawRect(85, 70, 50, 30, BLUE);     tft.drawRect(135, 70, 50, 30, BLUE);     tft.drawRect(185, 70, 50, 30, BLUE);     tft.drawRect(235, 70, 50, 30, BLUE);     cs4 = true;  }  bool down = Touch_getXY();    backrecord_btn.press(down && backrecord_btn.contains(pixel_x, pixel_y));    save_btn.press(down && save_btn.contains(pixel_x, pixel_y));    if (backrecord_btn.justReleased()){        tft.setFont();        backrecord_btn.drawButton(false);        Serial.println("a");        page = "automated";    }            if (save_btn.justReleased()){        tft.setFont();        save_btn.drawButton(false);        Serial.println("b");        switch(ssn){          case 0:            servo1PosSave[0] = s1.read();            servo2PosSave[0] = s2.read();            servo3PosSave[0] = s3.read();            servo4PosSave[0] = s4.read();            tft.fillRect(35, 70, 50, 30, YELLOW);            break;          case 1:            servo1PosSave[1] = s1.read();            servo2PosSave[1] = s2.read();            servo3PosSave[1] = s3.read();            servo4PosSave[1] = s4.read();            tft.fillRect(85, 70, 50, 30, YELLOW);            break;          case 2:            servo1PosSave[2] = s1.read();            servo2PosSave[2] = s2.read();            servo3PosSave[2] = s3.read();            servo4PosSave[2] = s4.read();            tft.fillRect(135, 70, 50, 30, YELLOW);           break;          case 3:            servo1PosSave[3] = s1.read();            servo2PosSave[3] = s2.read();            servo3PosSave[3] = s3.read();            servo4PosSave[3] = s4.read();            tft.fillRect(185, 70, 50, 30, YELLOW);            break;          case 4:            servo1PosSave[4] = s1.read();            servo2PosSave[4] = s2.read();            servo3PosSave[4] = s3.read();            servo4PosSave[4] = s4.read();            tft.fillRect(235, 70, 50, 30, YELLOW);            break;        }        ssn++;    }    if (backrecord_btn.justPressed()) {        tft.setFont();        backrecord_btn.drawButton(true);        Serial.println("c");    }    if (save_btn.justPressed()) {        tft.setFont();        save_btn.drawButton(true);        Serial.println("d");    }   //-------------------------------Manual Joystick Control-------------------------------------------------------------------------------------------------------------  if(analogRead(j1x) >= 800){     for (int i = s1.read(); i < 180; i++){      if (analogRead(j1x) < 800){        break;      }      s1.write(i);      delay(20);     }  }  if(analogRead(j1x) <= 300){     for (int i = s1.read(); i > 0; i--){      if (analogRead(j1x) > 300){        break;      }      s1.write(i);      delay(20);     }  }//-------------------------------------------  if(analogRead(j1y) >= 800){     for (int i = s2.read(); i < 140; i++){      if (analogRead(j1y) < 800){        break;      }      s2.write(i);      delay(20);     }  }  if(analogRead(j1y) <= 300){     for (int i = s2.read(); i > 70; i--){      if (analogRead(j1y) > 300){        break;      }      s2.write(i);      delay(20);     }  }//-------------------------------------------  if(analogRead(j2x) >= 800){     for (int i = s4.read(); i < 120; i++){      if (analogRead(j2x) < 800){        break;      }      s4.write(i);      delay(30);     }  }  if(analogRead(j2x) <= 300){     for (int i = s4.read(); i > 50; i--){      if (analogRead(j2x) > 300){        break;      }      s4.write(i);      delay(30);     }  }//-------------------------------------------  if(analogRead(j2y) >= 800){     for (int i = s3.read(); i < 120; i++){      if (analogRead(j2y) < 800){        break;      }      s3.write(i);      delay(20);     }  }  if(analogRead(j2y) <= 300){     for (int i = s3.read(); i > 60; i--){      if (analogRead(j2y) > 300){        break;      }      s3.write(i);      delay(20);     }  }}void playPage(){  cs1 = false;  cs2 = false;  cs3 = false;  cs4 = false;  ssn = 0;  if (cs5 == false){    tft.fillScreen(BLACK);    backplay_btn.initButton(&tft,  160, 190, 250, 55, WHITE, CYAN, BLACK, "BACK", 3);      backplay_btn.drawButton(false);    tft.setFont(&FreeSansBold18pt7b);    tft.setCursor(85, 50);                    //x,y    tft.setTextColor(CYAN);                  //color    tft.setTextSize(1);                       //Eg., 1,2,3    tft.print("Playing...");                 //Your Text    tft.setFont(&FreeSansBold12pt7b);    tft.setTextSize(1);                       //Eg., 1,2,3    tft.setCursor(30, 100);    tft.setTextColor(WHITE);    tft.print("Total Positions: 5");    cs5 = true;  }  bool down = Touch_getXY();  backplay_btn.press(down && backplay_btn.contains(pixel_x, pixel_y));  if (backplay_btn.justReleased()){      tft.setFont();      backplay_btn.drawButton(false);      Serial.println("a");      page = "automated";  }          if (backplay_btn.justPressed()) {      tft.setFont();      backplay_btn.drawButton(true);      Serial.println("c");  }    for (int i = 0; i < 5; i++){    tft.fillRect(0, 110, 320, 40, BLACK);    tft.setCursor(30, 130);                      tft.setTextSize(1);                         String a = "Current Position: ";    int j = i + 1;    String b = a + j;    tft.print(b);      bool down = Touch_getXY();    backplay_btn.press(down && backplay_btn.contains(pixel_x, pixel_y));    if (backplay_btn.justReleased()){        tft.setFont();        backplay_btn.drawButton(false);        Serial.println("a");        page = "automated";    }                if (backplay_btn.justPressed()) {        tft.setFont();        backplay_btn.drawButton(true);        Serial.println("c");    }        if (servo1PosSave[i] < s1.read()){      for (int p = s1.read(); p >= servo1PosSave[i]; p--){        s1.write(p);        delay(20);       }    }    if (servo1PosSave[i] > s1.read()){      for (int p = s1.read(); p <= servo1PosSave[i]; p++){        s1.write(p);        delay(20);       }    }    if (servo2PosSave[i] < s2.read()){      for (int p = s2.read(); p >= servo2PosSave[i]; p--){        s2.write(p);        delay(20);       }    }    if (servo2PosSave[i] > s2.read()){      for (int p = s2.read(); p <= servo2PosSave[i]; p++){        s2.write(p);        delay(20);       }    }      if (servo3PosSave[i] < s3.read()){      for (int p = s3.read(); p >= servo3PosSave[i]; p--){        s3.write(p);        delay(20);       }    }    if (servo3PosSave[i] > s3.read()){      for (int p = s3.read(); p <= servo3PosSave[i]; p++){        s3.write(p);        delay(20);       }    }    if (servo4PosSave[i] < s4.read()){      for (int p = s4.read(); p >= servo4PosSave[i]; p--){        s4.write(p);        delay(20);       }    }    if (servo4PosSave[i] > s4.read()){      for (int p = s4.read(); p <= servo4PosSave[i]; p++){        s4.write(p);        delay(20);       }    }  }}/*void loop() {  if(digitalRead(btnmode) == HIGH){    switch(mode){      case false:       mode = true;       break;      case true:        mode = false;       break;    }   }   else{       switch(mode){    case false:      lcd.clear();      lcd.print("Manual Mode");            //---JOY-1-X-AXIS-UP---    if(analogRead(j1x) >= 800){     for(int i = s2.read(); i < 120; i++){      x_out = analogRead(j1x);      if(x_out < 800){        break;      }      s2.write(i);      delay(20);     }    }    //---JOY-1-X-AXIS-DOWN---    else if(analogRead(j1x) <= 200){     for(int i = s2.read(); i > 30; i--){      x_out = analogRead(j1x);      if(x_out > 200){        break;      }      s2.write(i);      delay(20);     }    }    //---JOY-1-Y-AXIS-UP---    if(analogRead(j1y) >= 800){     for(int i = s1.read(); i < 150; i++){      y_out = analogRead(j1y);      if(y_out < 800){        break;      }      s1.write(i);      delay(20);     }    }    //---JOY-1-Y-AXIS-DOWN---    else if(analogRead(j1y) <= 200){     for(int i = s1.read(); i > 30; i--){      y_out = analogRead(j1y);      if(y_out > 200){        break;      }      s1.write(i);      delay(20);     }    }    //---JOY-2-X-AXIS-UP---    if(analogRead(j2x) >= 800){     for(int i = s3.read(); i < 150; i++){      x_out2 = analogRead(j2x);      if(x_out2 < 800){        break;      }      s3.write(i);      delay(20);     }    }    //---JOY-2-X-AXIS-DOWN---    else if(analogRead(j2x) <= 200){     for(int i = s3.read(); i > 60; i--){      x_out2 = analogRead(j2x);      if(x_out2 > 200){        break;      }      s3.write(i);      delay(20);     }    }    //---JOY-2-Y-AXIS-UP---    if(analogRead(j2y) >= 800){     for(int i = s4.read(); i < 180; i++){      y_out2 = analogRead(j2y);      if(y_out2 < 800){        break;      }      s4.write(i);      delay(20);     }    }    //---JOY-2-Y-AXIS-DOWN---    else if(analogRead(j2y) <= 200){     for(int i = s4.read(); i > 75; i--){      y_out2 = analogRead(j2y);      if(y_out2 > 200){        break;      }      s4.write(i);      delay(20);     }    }      break;     case true:      lcd.clear();      lcd.print("Automated Mode");    //if button2 is pressed, set the mode to playing  if(digitalRead(button2) == HIGH){    button2Pressed = true;  }  //if button3 is pressed, go back to recording  if(digitalRead(button3) == HIGH){    button1Pressed = 0;    button2Pressed = false;  }  //--------------------------------------------------PLAYING MODE--------------------------------------------------  if(button2Pressed){    Serial.print("Playing...");    lcd.clear();    lcd.print("Playing...");    lcd.setCursor(0,1);    lcd.print("Automated Mode");    for(int i = 0; i < 5; i++){      if(servo3PosSave[i] < s3.read()){        for(int a = s3.read(); a > servo3PosSave[i]; i--){          s3.write(a);        }      }      else if(servo3PosSave[i] > s3.read()){        for(int a = s3.read(); a < servo3PosSave[i]; i++){          s3.write(a);        }      }      s2.write(servo2PosSave[i]);      delay(500);            s1.write(servo1PosSave[i]);      delay(500);            s4.write(servo4PosSave[i]);      delay(2000);    }  }  //--------------------------------------------------RECORDING MODE--------------------------------------------------  else if(button2Pressed == false){    Serial.println("Recording...");    lcd.clear();    lcd.print("Recording...");    lcd.setCursor(0,1);    lcd.print("Automated Mode");    //---JOY-1-X-AXIS-UP---    if(analogRead(j1x) >= 800){     for(int i = s2.read(); i < 120; i++){      x_out = analogRead(j1x);      if(x_out < 800){        break;      }      s2.write(i);      delay(20);     }    }    //---JOY-1-X-AXIS-DOWN---    else if(analogRead(j1x) <= 200){     for(int i = s2.read(); i > 30; i--){      x_out = analogRead(j1x);      if(x_out > 200){        break;      }      s2.write(i);      delay(20);     }    }    //---JOY-1-Y-AXIS-UP---    if(analogRead(j1y) >= 800){     for(int i = s1.read(); i < 180; i++){      y_out = analogRead(j1y);      if(y_out < 800){        break;      }      s1.write(i);      delay(20);     }    }    //---JOY-1-Y-AXIS-DOWN---    else if(analogRead(j1y) <= 200){     for(int i = s1.read(); i > 0; i--){      y_out = analogRead(j1y);      if(y_out > 200){        break;      }      s1.write(i);      delay(20);     }    }    //---JOY-2-X-AXIS-UP---    if(analogRead(j2x) >= 800){     for(int i = s3.read(); i < 150; i++){      x_out2 = analogRead(j2x);      if(x_out2 < 800){        break;      }      s3.write(i);      delay(20);     }    }    //---JOY-2-X-AXIS-DOWN---    else if(analogRead(j2x) <= 200){     for(int i = s3.read(); i > 60; i--){      x_out2 = analogRead(j2x);      if(x_out2 > 200){        break;      }      s3.write(i);      delay(20);     }    }    //---JOY-2-Y-AXIS-UP---    if(analogRead(j2y) >= 800){     for(int i = s4.read(); i < 180; i++){      y_out2 = analogRead(j2y);      if(y_out2 < 800){        break;      }      s4.write(i);      delay(20);     }    }    //---JOY-2-Y-AXIS-DOWN---    else if(analogRead(j2y) <= 200){     for(int i = s4.read(); i > 75; i--){      y_out2 = analogRead(j2y);      if(y_out2 > 200){        break;      }      s4.write(i);      delay(20);     }    }  //--------SAVING THE SEQUENCE---------    if(digitalRead(button1) == HIGH){    button1Pressed++;    switch(button1Pressed){      case 1:        servo1PosSave[0] = s1.read();        servo2PosSave[0] = s2.read();        servo3PosSave[0] = s3.read();        servo4PosSave[0] = s4.read();        lcd.home();        Serial.println("Position #1 Saved");        lcd.print("Position 1 Saved");       break;       case 2:        servo1PosSave[1] = s1.read();        servo2PosSave[1] = s2.read();        servo3PosSave[1] = s3.read();        servo4PosSave[1] = s4.read();        lcd.home();        Serial.println("Position #2 Saved");        lcd.print("Position 2 Saved");       break;       case 3:        servo1PosSave[2] = s1.read();        servo2PosSave[2] = s2.read();        servo3PosSave[2] = s3.read();        servo4PosSave[2] = s4.read();        lcd.home();        Serial.println("Position #3 Saved");        lcd.print("Position 3 Saved");       break;       case 4:        servo1PosSave[3] = s1.read();        servo2PosSave[3] = s2.read();        servo3PosSave[3] = s3.read();        servo4PosSave[3] = s4.read();        lcd.home();        Serial.println("Position #4 Saved");        lcd.print("Position 4 Saved");       break;       case 5:        servo1PosSave[4] = s1.read();        servo2PosSave[4] = s2.read();        servo3PosSave[4] = s3.read();        servo4PosSave[4] = s4.read();        lcd.home();        Serial.println("Position #5 Saved");        lcd.print("Position 5 Saved");       break;    }  }  }  delay(500);  break;  }  }}*/

Step 10: Troubleshooting

If you are here, then I assume that you have built the project and it either worked which is great or it didn't which is also great because you not only will know how you build something but also how you do not build it and this kind of learning is very useful.

12.1 It Did Not Work 😲:

  • 10.1.1 Display Blank: You have either burnt out your display or there might be an error in your code (for example, you might have forgotten to initialise the display). If everything seems alright, there might even be a possibility of wiring the display to the Arduino Board/PCB in the wrong way (in case you haven't connected it directly into the Arduino board) as there are a huge number of pins to be correspondingly connected.
  • 10.1.2 Manual Mode Error: There is probably an issue either in the wiring of the servo motors of the robotic arm or the servo motors themselves have an internal error/issue which would call for a replacement of the concerned servo motor entirely.
  • 10.1.3 Joystick Opposite Directions: This is just happening due to a reverse polarity in the respective joystick module and can be fixed by just reversing and correcting the polarity.
  • 10.1.4 Automated Mode Error: If the servo motors are working just fine, any kind of discrepancy in the working of the automated mode will only be a result of an error in the code of the robotic arm.

12.2 It Worked 🎉🎊:

Great job mate. You overcame all the obstacles and are finally here, touching victory yourself and that is amazing. There is also a section down here called- "I Made It". Meet me there.

Thank You :)

Microcontroller Contest

Judges Prize in the
Microcontroller Contest