Robotic Arm Controller


This Robotic Arm Controller App is designed to wirelessly control a robotic arm using an Android smartphone and an HC-05 Bluetooth module. Built with MIT App Inventor, the app features sliders to adjust individual servo positions and control speed, along with buttons for saving and running automated movements. The app sends commands via Bluetooth, allowing precise control over each joint. Users can program sequences of movements and execute them automatically, making the robotic arm adaptable for various tasks.

Robotic Arm Controller Via Bluetooth


Code Breakdown


In this guide, we will go through the Arduino code for controlling a robotic arm via Bluetooth. The code is divided into sections for easy understanding. At the end, you’ll find the complete source code.


1.Including Libraries & Defining Components


The first step is to include the necessary libraries and define the hardware components.


Libraries Required

  • SoftwareSerial.h – Enables serial communication for the HC-05 Bluetooth module.
  • Servo.h – Controls the six servo motors.

Both libraries come pre-installed with the Arduino IDE, so no extra installation is required.


  • Create six servo objects for controlling different joints.
  • Define pins for HC-05 Bluetooth module.
  • Declare variables to store current and previous servo positions.
  • Use arrays to store steps for automatic mode.
Code

                    #include   // For Bluetooth communication
                      #include            // For controlling servos
                      
                      // Define Bluetooth Module RX & TX pins
                      #define BT_RX 10
                      #define BT_TX 11
                      
                      // Initialize Bluetooth serial communication
                      SoftwareSerial Bluetooth(BT_RX, BT_TX);
                      
                      // Define servo motors
                      Servo base, shoulder, elbow, wrist, gripper, extraServo;
                      
                      // Variables to store positions
                      int basePos = 90, shoulderPos = 90, elbowPos = 90, wristPos = 90, gripperPos = 90, extraPos = 90;
                      int prevBase, prevShoulder, prevElbow, prevWrist, prevGripper, prevExtra;
                      
                      // Arrays for automatic mode
                      int autoSteps[10][6];  // Stores 10 positions for the 6 servos
                      int stepIndex = 0;
                      
                  

2. Setup: Initializing Servos & Bluetooth Module


In the setup() function, we initialize:


  • Servo motors – Attach them to their respective Arduino pins.
  • Bluetooth module – Start serial communication with the HC-05 module.
  • Initial arm position – Move the robotic arm to a neutral position using the write() function.
div class="code-container">
Code

                  void setup() {
                    // Attach servos to their respective pins
                    base.attach(3);       
                    shoulder.attach(5);
                    elbow.attach(6);
                    wrist.attach(9);
                    gripper.attach(10);
                    extraServo.attach(11);
                
                    // Start serial communication with Bluetooth module
                    Bluetooth.begin(9600);
                    Serial.begin(9600);
                
                    // Set initial positions for all servos (90° - neutral position)
                    base.write(90);
                    shoulder.write(90);
                    elbow.write(90);
                    wrist.write(90);
                    gripper.write(90);
                    extraServo.write(90);
                
                    // Allow some time for servos to reach position
                    delay(500);
                }     
                

Why is this important?
  • Ensures all servos are correctly assigned to their pins.
  • Moves the robotic arm to a neutral position before accepting commands.
  • Initializes Bluetooth communication so the robot can receive data from a mobile app or controller.

3. Loop: Receiving Bluetooth Commands & Controlling the Arm


In the loop() function, the robotic arm constantly monitors incoming Bluetooth data from a smartphone or controller. Based on the received data, the servos adjust their positions accordingly.


How It Works:
  • Check for incoming data using Bluetooth.available().
  • Read the received command using readString().
  • Store the command in a variable (dataIn).
  • Interpret the command and move the corresponding servo motor.
Code

                        void loop() {
                          // Check if data is available from the Bluetooth module
                          if (Bluetooth.available()) {
                              String dataIn = Bluetooth.readString();  // Read incoming data as a string
                              Serial.println("Received: " + dataIn);   // Print received data for debugging
                      
                              // Control the robotic arm based on the received command
                              if (dataIn == "BASE_LEFT") {
                                  base.write(base.read() - 5);  // Rotate base to the left
                              } 
                              else if (dataIn == "BASE_RIGHT") {
                                  base.write(base.read() + 5);  // Rotate base to the right
                              } 
                              else if (dataIn == "SHOULDER_UP") {
                                  shoulder.write(shoulder.read() + 5);
                              } 
                              else if (dataIn == "SHOULDER_DOWN") {
                                  shoulder.write(shoulder.read() - 5);
                              }
                              else if (dataIn == "ELBOW_UP") {
                                  elbow.write(elbow.read() + 5);
                              }
                              else if (dataIn == "ELBOW_DOWN") {
                                  elbow.write(elbow.read() - 5);
                              }
                              else if (dataIn == "WRIST_UP") {
                                  wrist.write(wrist.read() + 5);
                              }
                              else if (dataIn == "WRIST_DOWN") {
                                  wrist.write(wrist.read() - 5);
                              }
                              else if (dataIn == "GRIPPER_OPEN") {
                                  gripper.write(gripper.read() + 10);  // Open gripper
                              }
                              else if (dataIn == "GRIPPER_CLOSE") {
                                  gripper.write(gripper.read() - 10);  // Close gripper
                              }
                          }
                      
                          delay(100);  // Small delay to avoid excessive loop execution
                      }
                      
                          
                      

Why Is This Important?
  • Ensures real-time control of the robotic arm via Bluetooth.
  • Smooth and incremental movement for precise positioning.
  • Prevents excessive movement by limiting changes to small steps.

Understanding the Android App Communication


Now, let’s examine how the Android app communicates with the Arduino. Specifically, we’ll analyze the commands it sends when controlling the robotic arm via Bluetooth.


How the App Sends Data:

  • When a button is pressed in the app, it sends a specific text command via Bluetooth.
  • The Arduino receives this command and interprets it to move the corresponding servo motor.
  • Each button in the app corresponds to a predefined action, such as moving the base, shoulder, elbow, wrist, or gripper.

Visualizing the Communication Flow:

  • User presses a button in the Android app.
  • The app sends a text command via Bluetooth (e.g., "ELBOW_UP").
  • Arduino receives the command and moves the corresponding servo.
  • The robotic arm moves accordingly.


The robotic arm control app was developed using MIT App Inventor, a simple yet powerful online tool for creating Android applications. Here's how the app works:


App Layout & Components


1. Bluetooth Connectivity:

At the top of the app interface, there are two buttons designed for Bluetooth connection. These allow the smartphone to pair and communicate with the HC-05 Bluetooth module.


2. Robot Arm Visualization:

On the left side, there is an image of the robotic arm, giving users a visual reference while controlling the servos.


3. Servo Control Sliders:

On the right side, there are six sliders, each responsible for controlling a specific servo of the robotic arm. Moving a slider adjusts the corresponding servo position in real-time.


4. Speed Control Slider:

In addition to servo controls, there is a seventh slider at the bottom, which allows users to adjust the movement speed of the robotic arm.








How the App Works

  • The user connects to the HC-05 Bluetooth module using the Bluetooth buttons.
  • The user adjusts the sliders, sending position data for each servo to the Arduino.
  • The Arduino interprets the commands and moves the servos accordingly.
  • The speed control slider modifies the movement speed of the robotic arm.

App Functionality & Controls


The robotic arm control app includes customized sliders and programming buttons to enhance user control and automation.


Slider Configuration

Each slider is uniquely configured with:

  • Different initial values – ensuring each servo starts from an optimal position.
  • Custom minimum and maximum values – tailored to match the movement range of each joint.

This setup prevents the robotic arm from exceeding its physical limits while ensuring smooth and precise movements.

Automation & Programming Controls

At the bottom of the app, there are three essential buttons:


  • SAVE: Stores the current servo positions, allowing users to create a sequence of movements.
  • RUN: Executes the saved sequence, enabling the robotic arm to operate automatically.
  • RESET: Clears all saved steps, resetting the system for a new motion sequence.

Below these buttons, a label displays the number of saved steps, providing real-time feedback on the programmed sequence.


Bluetooth Connectivity in the App




The first step in controlling the robotic arm is establishing a Bluetooth connection between the smartphone and the HC-05 module.


Connection Setup






On the left side of the MIT App Inventor interface, we have blocks dedicated to:

  • Scanning for available Bluetooth devices – The app searches for nearby Bluetooth modules.
  • Displaying a list of detected devices – The user can select the HC-05 module from this list.
  • Establishing a connection – Once selected, the app initiates a connection to the module.
  • Providing connection feedback – A message appears confirming whether the connection was successful.

This setup ensures a seamless pairing process, allowing smooth communication between the app and the robotic arm.


Servo Control via Sliders & Buttons


The MIT App Inventor blocks for controlling the robotic arm include sliders for servo positioning and buttons for automated programming.


Sliders for Servo Control












How It Works:
  • Each slider corresponds to a specific servo motor.
  • When a slider is moved, the SendText function transmits a command via Bluetooth.
  • The command includes: A prefix indicating which servo is being adjusted & The current slider value (position of the servo in degrees).
  • The Arduino receives this data and adjusts the corresponding servo.

Processing Incoming Bluetooth Data on Arduino


On the Arduino side, we need to decode the received Bluetooth commands and move the corresponding servo motors accordingly.


Decoding Bluetooth Commands


How It Works:
  • The Bluetooth module sends data as text strings (e.g., "s1 90").
  • Using the startsWith() function, the Arduino checks the prefix to determine which servo to move.
  • Using the substring() function, it extracts the position value from the received data.
  • The extracted position value is converted into an integer and used to set the servo angle.

Smooth Servo Motion Control on Arduino


Instead of moving the servos instantly using write(), we implement smooth motion control to prevent jerky movements and mechanical stress on the robot arm.


How It Works:


  • Directly calling write(position) moves the servo instantly at maximum speed.
  • To control the speed, we use a for loop to gradually move the servo from its previous position to the new position.
  • A delay between each step determines the speed of movement.
  • By adjusting the delay value, we can control the servo's transition speed.
Code

                        int stepDelay = 5;  // Adjust this value to change the speed
                        for (int pos = prevPosition; pos <= newPosition; pos++) {
                        servo1.write(pos);
                        delay(stepDelay);
                        } 
                      

Key Benefits:

  • Prevents sudden jerks and reduces stress on servo motors.
  • Improves precision by making smooth transitions between positions.
  • Allows dynamic speed control by adjusting the stepDelay value.

Resetting the Robot Arm for New Programming


When the RESET button is pressed, all stored motion data is cleared, and the robot arm is ready for new programming.


How It Works (Based on Your Arduino Code)
  • Clears all stored positions by resetting the arrays to zero.
  • Resets the index to allow new motion steps to be recorded.
  • Moves servos to their default position for a fresh start.
Code

                        void resetArm() {
                          // Clear all stored positions
                          for (int i = 0; i < maxSteps; i++) {
                              for (int j = 0; j < 6; j++) {
                                  steps[i][j] = 0;
                              }
                          }
                      
                          // Reset index to start fresh
                          stepIndex = 0;
                      
                          // Move servos to their initial position
                          servo1.write(initialPos1);
                          servo2.write(initialPos2);
                          servo3.write(initialPos3);
                          servo4.write(initialPos4);
                          servo5.write(initialPos5);
                          servo6.write(initialPos6);
                      
                          // Send confirmation message via Bluetooth
                          Bluetooth.println("RESET_DONE");
                      }
                      
                          
                      

Key Features:

  • Instantly clears previous programming for a fresh start.
  • Ensures servos return to their initial position.
  • Bluetooth confirmation message indicates reset completion.


Overall Code


Code

                        #include   // For Bluetooth communication
                          #include            // For controlling servos
                          
                          // Define Bluetooth Module RX & TX pins
                          #define BT_RX 10
                          #define BT_TX 11
                          
                          // Initialize Bluetooth serial communication
                          SoftwareSerial Bluetooth(BT_RX, BT_TX);
                          
                          // Define servo motors
                          Servo base, shoulder, elbow, wrist, gripper, extraServo;
                          
                          // Variables to store positions
                          int basePos = 90, shoulderPos = 90, elbowPos = 90, wristPos = 90, gripperPos = 90, extraPos = 90;
                          int prevBase, prevShoulder, prevElbow, prevWrist, prevGripper, prevExtra;
                          
                          // Arrays for automatic mode
                          int autoSteps[10][6];  // Stores 10 positions for the 6 servos
                          int stepIndex = 0;
                          bool runMode = false;  // Flag for running stored movements
                          int speedDelay = 10;   // Delay time for smooth movement
                          
                          void setup() {
                              Bluetooth.begin(9600); // Start Bluetooth communication
                              base.attach(3);
                              shoulder.attach(5);
                              elbow.attach(6);
                              wrist.attach(9);
                              gripper.attach(10);
                              extraServo.attach(11);
                              
                              Serial.begin(9600);
                              Serial.println("Robotic Arm Ready...");
                          }
                          
                          void loop() {
                              if (Bluetooth.available()) { // Check if data is received
                                  String dataIn = Bluetooth.readString(); // Read incoming data
                                  
                                  // Identify servo control command
                                  if (dataIn.startsWith("s1")) {
                                      basePos = dataIn.substring(2).toInt();
                                      moveServoGradually(base, prevBase, basePos);
                                  } 
                                  else if (dataIn.startsWith("s2")) {
                                      shoulderPos = dataIn.substring(2).toInt();
                                      moveServoGradually(shoulder, prevShoulder, shoulderPos);
                                  } 
                                  else if (dataIn.startsWith("s3")) {
                                      elbowPos = dataIn.substring(2).toInt();
                                      moveServoGradually(elbow, prevElbow, elbowPos);
                                  } 
                                  else if (dataIn.startsWith("s4")) {
                                      wristPos = dataIn.substring(2).toInt();
                                      moveServoGradually(wrist, prevWrist, wristPos);
                                  } 
                                  else if (dataIn.startsWith("s5")) {
                                      gripperPos = dataIn.substring(2).toInt();
                                      moveServoGradually(gripper, prevGripper, gripperPos);
                                  } 
                                  else if (dataIn.startsWith("s6")) {
                                      extraPos = dataIn.substring(2).toInt();
                                      moveServoGradually(extraServo, prevExtra, extraPos);
                                  } 
                                  else if (dataIn.startsWith("SAVE")) { // Save current position
                                      savePosition();
                                  } 
                                  else if (dataIn.startsWith("RUN")) { // Start auto mode
                                      runMode = true;
                                      runServoSequence();
                                  } 
                                  else if (dataIn.startsWith("RESET")) { // Reset positions
                                      resetPositions();
                                  } 
                                  else if (dataIn.startsWith("SPD")) { // Adjust speed
                                      speedDelay = dataIn.substring(3).toInt();
                                  }
                              }
                          }
                          
                          // Gradual movement function
                          void moveServoGradually(Servo servo, int &prevPos, int targetPos) {
                              if (prevPos != targetPos) {
                                  int step = (prevPos < targetPos) ? 1 : -1;
                                  for (int pos = prevPos; pos != targetPos; pos += step) {
                                      servo.write(pos);
                                      delay(speedDelay);
                                  }
                                  servo.write(targetPos);
                                  prevPos = targetPos;
                              }
                          }
                          
                          // Save the current position into array
                          void savePosition() {
                              if (stepIndex < 10) {
                                  autoSteps[stepIndex][0] = basePos;
                                  autoSteps[stepIndex][1] = shoulderPos;
                                  autoSteps[stepIndex][2] = elbowPos;
                                  autoSteps[stepIndex][3] = wristPos;
                                  autoSteps[stepIndex][4] = gripperPos;
                                  autoSteps[stepIndex][5] = extraPos;
                                  stepIndex++;
                                  Serial.println("Position Saved");
                              } else {
                                  Serial.println("Memory Full!");
                              }
                          }
                          
                          // Run the saved sequence
                          void runServoSequence() {
                              while (runMode) {
                                  for (int i = 0; i < stepIndex; i++) {
                                      moveServoGradually(base, prevBase, autoSteps[i][0]);
                                      moveServoGradually(shoulder, prevShoulder, autoSteps[i][1]);
                                      moveServoGradually(elbow, prevElbow, autoSteps[i][2]);
                                      moveServoGradually(wrist, prevWrist, autoSteps[i][3]);
                                      moveServoGradually(gripper, prevGripper, autoSteps[i][4]);
                                      moveServoGradually(extraServo, prevExtra, autoSteps[i][5]);
                                      
                                      // Check for new commands while running
                                      if (Bluetooth.available()) {
                                          String dataIn = Bluetooth.readString();
                                          if (dataIn.startsWith("PAUSE")) {
                                              runMode = false;
                                          } 
                                          else if (dataIn.startsWith("SPD")) {
                                              speedDelay = dataIn.substring(3).toInt();
                                          }
                                      }
                                  }
                              }
                          }
                          
                          // Reset all stored positions
                          void resetPositions() {
                              for (int i = 0; i < 10; i++) {
                                  for (int j = 0; j < 6; j++) {
                                      autoSteps[i][j] = 0;
                                  }
                              }
                              stepIndex = 0;
                              runMode = false;
                              Serial.println("Positions Reset");
                          }