In our previous project, we built a DIY 6-DOF robotic arm with potentiometers, initially operated by connecting the potentiometers directly to an Arduino. This setup allowed us to manually control each servo by adjusting the potentiometers. While this method worked well, it was limited to manual operation.
To enhance the flexibility and ease of use, we’re now upgrading the project to a DIY 6-DOF robotic arm with Bluetooth control. This upgrade allows for wireless control using a smartphone app, making it much more user-friendly and functional. By integrating Bluetooth communication, we can now remotely control the robotic arm, eliminating the need for manual adjustments and adding convenience to the process.
In this guide, we’ll walk you through the steps to modify our existing DIY 6-DOF robotic arm with Bluetooth control by designing a custom app using MIT App Inventor. This project builds on our previous work, introducing wireless capabilities while maintaining a simple structure, ultimately making the robotic arm more versatile for a variety of tasks.
Let’s dive into the process of upgrading our DIY 6-DOF robotic arm with Bluetooth control.
Design with Autodesk Inventor
The first stage is to design each component of the robot arm using Autodesk Inventor. This CAD software allows precise 3D modelling, ensuring that the components are perfectly tailored to accommodate SG90 Micro Servos and MG996R 180° servos – chosen for their balance of weight, size and torque capabilities: SG90 Micro Servos are ideal for smaller arm joints due to their compact size and sufficient precision. MG996R Servos 180° are used for the base and other high load areas due to their robust torque capabilities.
3D printing the arm components
Once the models are complete, the next step is 3D printing. Each part is printed using a filament such as PLA for its ease of use and good detail accuracy. Print settings should be optimised for strength, especially for joints that will experience higher mechanical loads. Post-processing may include assembly adjustments and aesthetic enhancements.
Assembling the Robotic Arm
Once all the parts have been printed, assembly involves carefully placing the servos in their designated mounts and accurately connecting the arm segments. Joints should be tested for smooth operation to ensure they can handle the expected range of motion without stressing the servos.
Step 1: Assembling the Base
- Securing the Servo Motor
Start by installing the first servo motor onto the base of your robotic arm. Utilize the screws that come with the servo package to ensure it is firmly attached (you can use cross-self-tapping screw M3x12). This servo acts as the pivotal rotation point for the entire structure of the arm, allowing for the foundational movement.
- Adding a Ball Bearing 6806ZZ 30*42*7
Install a ball bearing to facilitate smooth rotational movement between the base and the arm’s upper rotating part. Carefully place the ball bearing into the designated slot on the base. This component is critical for reducing friction and wear during the arm’s operations, enhancing both the precision and longevity of the movement.
- Connecting the Servo Horn
Attach the servo horn to the rotating upper part of the arm. Use the screws provided in the servo package to secure the horn directly to the rotating part that sits atop the ball bearing (you can use cross-self-tapping screw M2x12). Ensure that the connection is snug and secure, as this will transmit the rotational forces from the servo motor through to the upper parts of the arm.
Step 2: Mounting the Servo Horns to Robot Arm Links
To assemble the servo horns to the robot arm links, align the servo horns with the arm’s attachment points, ensuring the holes line up correctly. Secure each horn with two screws, firmly tightening them to ensure stability and prevent slippage during operation. Double-check each connection to confirm the horns are attached securely, as this will be crucial for the precise and reliable functioning of your robotic arm.
Step 3: Mounting Servo Motors to Robot Arm Links
To mount the servo motors to the robot arm links, align each motor with the designated mounting points on the arm links, ensuring correct orientation. Secure each motor using two screws, threading through the arm into the motor’s mounting holes for a tight fit. After securing, test each connection for stability by applying gentle pressure to ensure the servo is firmly attached without any movement. This step is vital for the durability and functionality of the robotic arm during operation.
Step 4: Connecting Robot Arm Links
After securing the servo motors and horns to the robot arm links, align and connect the links. Position the links so the holes on one link’s horn match the next link’s attachment points. Secure them using screws to ensure a firm connection crucial for seamless joint movement. Tighten the screws properly to maintain stability and functionality during the robotic arm’s operation. This step ensures structural continuity and effective motion across the robotic arm’s joints.
Step 5: Assembling the Gripper
In the final assembly step, attach the gripper to the robot arm’s end link. Ensure it aligns properly and secure it with screws (Screws used in gripper joints are M3x20), checking that the gripper operates smoothly and without hindrance. This integration completes the physical construction of the robotic arm, setting the stage for functional testing and adjustments to ensure precise operation of the articulated movements.
Step 6: Mounting the Robotic Arm on a Wooden Base
Secure the fully assembled robotic arm to a wooden base to ensure stability during operation. Use screws to fasten the arm’s base securely to the wood, allowing for a solid foundation that prevents any movement during its use. I used cross-self-tapping screw M3x12.
Electronic configuration and wiring for the DIY 6-DOF robotic arm with Bluetooth control
The electronics for this project focus on integrating the PCA9685 servo driver with the Arduino Uno to control the six servos via Bluetooth communication for the DIY 6-DOF robotic arm with Bluetooth control:
Arduino Uno: Acts as the main controller. PCA9685 servo driver board: This I2C-controlled PWM driver efficiently manages up to 16 servos, providing room for expansion beyond the six servos used in this project.
Wiring Guide:
- Powering the PCA9685 and servos: It’s crucial to use an independent power source (such as a 5V 10A power supply) to meet the current demands without overloading the Arduino’s power regulator.
- Connect each servo to the PCA9685: The servos are connected to individual channels on the PCA9685, ensuring the correct orientation for power, ground, and control signals.
- Connect the HC-05 Bluetooth module to the Arduino: The HC-05 module connects to the Arduino’s RX and TX pins, allowing for wireless communication between the Arduino and a smartphone app for controlling the servos.
more about PCA9685 servo driver card
Controlling servos directly from an Arduino is easy, but you may run into limitations, especially if your project involves multiple servos or other PWM-dependent components. Using all available PWM pins or potential library conflicts over timer resources are common challenges that can hinder the scalability of your designs.
To efficiently manage multiple servos without overloading the Arduino, integrating a dedicated servo driver board, such as one equipped with the PCA9685 chip, is an excellent strategy. This board uses I2C communication, which simplifies connections to just two wires – CL (clock) and SDA (data) – regardless of the number of servos being controlled. It supports control of up to 16 servos per board, and can be daisy-chained with other PCA9685 boards. This setup allows up to 992 servos to be controlled by cascading multiple boards, ideal for large projects.
Each board has simple connections:
GND: Ground connection.
OE: Output enable, usually left unconnected to keep all outputs enabled.
SCL: Clock line for I2C communication.
SDA: Data signal for I2C communication.
VCC: Logic supply at +5 volts.
V+: Power for the servomotors, which can also be supplied via a protected connector on the top of the board for greater protection against reverse polarity.
The board features sets of 3-pin connectors for each servo motor, greatly simplifying the wiring process and providing a robust solution for projects requiring extensive servo control without taxing the resources of the primary controller. This approach not only increases the reliability of the project, but also streamlines the development process, allowing you to focus on higher-level programming and design tasks.
To effectively manage and control 16 servo motors using a PCA9685-based driver with your Arduino, follow these detailed steps to correctly set up and wire the components:
Connecting to the Arduino
The PCA9685 servo driver uses I2C communication and requires only four connections to your Arduino. Here’s how to connect it depending on your Arduino model:
Classic Arduino (Uno, etc.)
+5V -> VCC (powers the PCA9685 chip, not the servos)
GND -> GND
Analog 4 -> SDA
Analog 5 -> SCL
Powering the servos:
VCC on the PCA9685 board only powers the chip itself. To power the servos you must also connect the V+ pin, which can handle up to 6V even if VCC is at 3.3V.
A polarised terminal block is recommended for connecting the servo power.
As servos can draw considerable current, especially under load, you should consider these power sources:
5V 2A switching power supply for smaller or fewer servos.
4xAA battery holder – Provides 6V from alkaline cells or 4.8V from NiMH cells.
Connecting the servos:
Connect each servo to the PCA9685 board using its standard 3-pin socket. Ensure that the ground wire (usually black or brown) matches the bottom row of pin headers on the board and that the signal wire (usually yellow or white) matches the top row.
Programming for interactive control
The Arduino code provided controls a 6-DOF robotic arm through wireless communication using an HC-05 Bluetooth module. The code allows you to save multiple poses (positions of the arm’s servos) and play them back sequentially or in a loop.
#include <Wire.h> #include <Adafruit_PWMServoDriver.h> #include <SoftwareSerial.h> // Constants and definitions const int numServos = 6; // Number of servos const int maxConfigurations = 10; // Maximum number of storable poses const int stepDelay = 10; // Delay between each step to slow down the servo movement const int stepSize = 1; // The number of degrees to move per step // Servo channels on the PCA9685 const int servoChannels[numServos] = {0, 4, 8, 9, 12, 13}; // Storage structures int savedConfigurations[maxConfigurations][numServos]; int currentServoPositions[numServos] = {375, 375, 375, 375, 375, 375}; // Set default position to middle (around 90 degrees) int configCount = 0; // Counter for stored poses bool isPlaying = false; // Status indicating if poses are being played bool loopPlayback = false; // Status indicating if poses should be played in a loop bool stopPlaying = false; // Status indicating if playback should be stopped int currentPoseIndex = 0; // Index of the current pose during playback bool initialized = false; // Flag to check if initialization happened Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); SoftwareSerial BTSerial(10, 11); // RX, TX for Bluetooth communication void setup() { Serial.begin(9600); // Start serial communication for the monitor BTSerial.begin(9600); // Start Bluetooth serial communication pwm.begin(); pwm.setPWMFreq(60); // Set frequency to 60 Hz for the servos // Move servos to initial positions (middle position) to avoid any jumps for (int i = 0; i < numServos; i++) { pwm.setPWM(servoChannels[i], 0, currentServoPositions[i]); } initialized = true; // Set initialized to true once the servos are moved to the middle position Serial.println("Bluetooth Servo Controller started. Waiting for commands..."); } void loop() { if (BTSerial.available()) { String input = BTSerial.readStringUntil('\n'); // Read the entire line until a newline character input.trim(); // Remove unwanted spaces and newline characters // Output the received data to the serial monitor Serial.println("Received data: " + input); if (input.equalsIgnoreCase("S")) { saveCurrentPose(); } else if (input.equalsIgnoreCase("P")) { startPlayingPoses(); } else if (input.equalsIgnoreCase("R")) { resetPoses(); } else if (input.equalsIgnoreCase("St")) { stopPlayingPoses(); } else if (input.equalsIgnoreCase("LoopON")) { // When the switch is turned ON loopPlayback = true; Serial.println("Loop playback enabled."); } else if (input.equalsIgnoreCase("LoopOFF")) { // When the switch is turned OFF loopPlayback = false; Serial.println("Loop playback disabled."); } else if (input.indexOf(',') > 0) { processLastValue(input); } else { Serial.println("Unknown command: " + input); } } if (isPlaying && !stopPlaying) { if (loopPlayback) { playPosesInLoop(); } else { playNextPose(); } } } // Function to process the last value in the line void processLastValue(String command) { int lastCommaIndex = command.lastIndexOf(','); // Find the last comma in the line if (lastCommaIndex > 0 && lastCommaIndex < command.length() - 1) { int servoIndex = command.substring(0, lastCommaIndex).toInt() - 1; // First value: servo index float lastValue = command.substring(lastCommaIndex + 1).toFloat(); // Last value in the line // Directly use the last value int targetPos = (int)lastValue; // Map the position from 0-180 to PWM values from 150-600 (may vary depending on the servo) int targetPwmValue = map(targetPos, 0, 180, 150, 600); // Smooth movement to target position moveToPositionSmoothly(servoIndex, targetPwmValue); } else { Serial.println("Invalid command for servo control: " + command); } } // Function to move servo smoothly to the target position void moveToPositionSmoothly(int servoIndex, int targetPwmValue) { int currentPwmValue = currentServoPositions[servoIndex]; if (targetPwmValue > currentPwmValue) { for (int pos = currentPwmValue; pos <= targetPwmValue; pos += stepSize) { pwm.setPWM(servoChannels[servoIndex], 0, pos); delay(stepDelay); } } else { for (int pos = currentPwmValue; pos >= targetPwmValue; pos -= stepSize) { pwm.setPWM(servoChannels[servoIndex], 0, pos); delay(stepDelay); } } currentServoPositions[servoIndex] = targetPwmValue; // Update current position Serial.println("Servo " + String(servoIndex + 1) + " set to PWM value: " + String(targetPwmValue)); } // Function to save the current servo positions as a pose void saveCurrentPose() { if (configCount < maxConfigurations) { for (int i = 0; i < numServos; i++) { savedConfigurations[configCount][i] = currentServoPositions[i]; Serial.print("Servo "); Serial.print(i + 1); Serial.print(" saved at PWM value: "); Serial.println(savedConfigurations[configCount][i]); } configCount++; Serial.println("Pose saved. Total saved poses: " + String(configCount)); } else { Serial.println("Memory full, cannot save more poses."); } } // Function to start playing the saved poses void startPlayingPoses() { if (configCount == 0) { Serial.println("No poses saved, nothing to play."); return; } Serial.println("Playback of saved poses started..."); isPlaying = true; stopPlaying = false; currentPoseIndex = 0; } // Function to play the next pose void playNextPose() { if (currentPoseIndex < configCount) { Serial.println("Playing pose " + String(currentPoseIndex + 1)); for (int i = 0; i < numServos; i++) { moveToPositionSmoothly(i, savedConfigurations[currentPoseIndex][i]); } delay(1000); // Standard delay between poses currentPoseIndex++; } else { isPlaying = false; Serial.println("Playback of poses finished."); } } // Function to play the poses in a loop void playPosesInLoop() { for (int j = 0; j < configCount; j++) { Serial.println("Playing pose " + String(j + 1)); for (int i = 0; i < numServos; i++) { moveToPositionSmoothly(i, savedConfigurations[j][i]); } delay(1000); // Standard delay between poses if (stopPlaying) break; } } // Function to stop playback void stopPlayingPoses() { stopPlaying = true; isPlaying = false; Serial.println("Playback of poses stopped."); } // Function to reset all saved poses void resetPoses() { configCount = 0; isPlaying = false; loopPlayback = false; currentPoseIndex = 0; Serial.println("All saved poses have been deleted."); }
Here’s a breakdown of each section of the code and its purpose:
1. Including Libraries
#include <Wire.h> #include <Adafruit_PWMServoDriver.h> #include <SoftwareSerial.h>
- Wire.h: This library facilitates I2C communication between the Arduino and the PCA9685 servo driver board.
- Adafruit_PWMServoDriver.h: This library is used to control the PWM signals sent to the servos through the PCA9685 board.
- SoftwareSerial.h: This library enables serial communication on digital pins, used here to communicate with the HC-05 Bluetooth module.
2. Constants and Definitions
const int numServos = 6; // Number of servos const int maxConfigurations = 10; // Maximum number of storable poses const int stepDelay = 10; // Delay between each step to slow down the servo movement const int stepSize = 1; // The number of degrees to move per step const int servoChannels[numServos] = {0, 4, 8, 9, 12, 13};
- numServos: Defines the total number of servos in the robotic arm.
- maxConfigurations: Specifies how many poses (combinations of servo positions) can be stored in memory.
- stepDelay: Introduces a delay between each step of servo movement to prevent sudden jerks.
- stepSize: Defines the degrees of movement per step for smoother transitions.
- servoChannels: This array defines which PCA9685 channels the servos are connected to (e.g., Servo 1 on channel 0, Servo 2 on channel 4, etc.).
3. Storage Structures
int savedConfigurations[maxConfigurations][numServos]; int currentServoPositions[numServos] = {375, 375, 375, 375, 375, 375}; // Initial positions int configCount = 0; bool isPlaying = false; bool loopPlayback = false; bool stopPlaying = false; int currentPoseIndex = 0;
- savedConfigurations: A 2D array that stores the PWM values for each servo in each pose.
- currentServoPositions: An array that keeps track of the current positions of the servos.
- configCount: Keeps count of how many poses have been saved.
- isPlaying: A flag that indicates whether the system is currently playing back saved poses.
- loopPlayback: A flag to determine whether the playback should loop.
- stopPlaying: A flag to stop the playback process.
- currentPoseIndex: Tracks which pose is currently being played.
4. Initialization in setup()
void setup() { Serial.begin(9600); BTSerial.begin(9600); pwm.begin(); pwm.setPWMFreq(60); // Initialize the servos to a safe start position (midpoint) for (int i = 0; i < numServos; i++) { pwm.setPWM(servoChannels[i], 0, currentServoPositions[i]); } Serial.println("Bluetooth Servo Controller started. Waiting for commands..."); }
- Serial.begin(9600): Initializes the serial monitor for debugging.
- BTSerial.begin(9600): Initializes Bluetooth communication at 9600 baud rate.
- pwm.begin(): Initializes the PCA9685 servo driver.
- pwm.setPWMFreq(60): Sets the PWM frequency to 60 Hz, which is suitable for controlling servos.
- After initializing the servos, they are moved to the midpoint to avoid any sudden jumps when the system starts.
5. Main Loop (loop())
void loop() { if (BTSerial.available()) { String input = BTSerial.readStringUntil('\n'); input.trim(); Serial.println("Received data: " + input); // Process the received command } // Handle playback of poses }
The loop()
function continuously checks for incoming Bluetooth data and processes commands like saving, playing, stopping, or resetting poses.
6. Command Processing
if (input.equalsIgnoreCase("S")) { saveCurrentPose(); } else if (input.equalsIgnoreCase("P")) { startPlayingPoses(); } else if (input.equalsIgnoreCase("R")) { resetPoses(); } else if (input.equalsIgnoreCase("St")) { stopPlayingPoses(); } else if (input.equalsIgnoreCase("LoopON")) { loopPlayback = true; Serial.println("Loop playback enabled."); } else if (input.equalsIgnoreCase("LoopOFF")) { loopPlayback = false; Serial.println("Loop playback disabled."); } else if (input.indexOf(',') > 0) { processLastValue(input); } else { Serial.println("Unknown command: " + input); }
- S: Saves the current servo positions as a pose.
- P: Starts playing the saved poses.
- R: Resets all saved poses.
- St: Stops the playback of poses.
- LoopON/LoopOFF: Toggles looping of the pose playback.
- Other Commands: If the input contains a comma, it is assumed to be a servo position command.
7. Processing the Last Value in a Command
void processLastValue(String command) { int lastCommaIndex = command.lastIndexOf(','); int servoIndex = command.substring(0, lastCommaIndex).toInt() - 1; float lastValue = command.substring(lastCommaIndex + 1).toFloat(); int targetPos = (int)lastValue; int targetPwmValue = map(targetPos, 0, 180, 150, 600); // Smoothly move the servo to the target position moveToPositionSmoothly(servoIndex, targetPwmValue); } void moveToPositionSmoothly(int servoIndex, int targetPwmValue) { int currentPwmValue = currentServoPositions[servoIndex]; if (targetPwmValue > currentPwmValue) { for (int pos = currentPwmValue; pos <= targetPwmValue; pos += stepSize) { pwm.setPWM(servoChannels[servoIndex], 0, pos); delay(stepDelay); } } else { for (int pos = currentPwmValue; pos >= targetPwmValue; pos -= stepSize) { pwm.setPWM(servoChannels[servoIndex], 0, pos); delay(stepDelay); } } currentServoPositions[servoIndex] = targetPwmValue; // Update current position Serial.println("Servo " + String(servoIndex + 1) + " set to PWM value: " + String(targetPwmValue)); }
processLastValue: Handles commands that include specific servo positions, mapping the angle (0-180 degrees) to the PWM values needed to move the servo.
moveToPositionSmoothly: This function moves the servos smoothly to the target position rather than making sudden, jerky movements.
8. Saving the Current Pose
void saveCurrentPose() { if (configCount < maxConfigurations) { for (int i = 0; i < numServos; i++) { savedConfigurations[configCount][i] = currentServoPositions[i]; Serial.print("Servo "); Serial.print(i + 1); Serial.print(" saved at PWM value: "); Serial.println(savedConfigurations[configCount][i]); } configCount++; Serial.println("Pose saved. Total saved poses: " + String(configCount)); } else { Serial.println("Memory full, cannot save more poses."); } }
saveCurrentPose: Stores the current positions of all servos into the savedConfigurations
array and increments the pose count.
9. Starting Pose Playback
void startPlayingPoses() { if (configCount == 0) { Serial.println("No poses saved, nothing to play."); return; } Serial.println("Playback of saved poses started..."); isPlaying = true; stopPlaying = false; currentPoseIndex = 0; }
startPlayingPoses: Initiates the playback of stored poses from the beginning.
10. Playing the Next Pose
void playNextPose() { if (currentPoseIndex < configCount) { Serial.println("Playing pose " + String(currentPoseIndex + 1)); for (int i = 0; i < numServos; i++) { pwm.setPWM(i, 0, savedConfigurations[currentPoseIndex][i]); Serial.print("Servo "); Serial.print(i + 1); Serial.print(" set to PWM value: "); Serial.println(savedConfigurations[currentPoseIndex][i]); } delay(1000); // Standard delay between poses currentPoseIndex++; } else { isPlaying = false; Serial.println("Playback of poses finished."); } }
- playNextPose: Plays the next saved pose by setting each servo to its stored position.
11. Playing Poses in a Loop
void playPosesInLoop() { for (int j = 0; j < configCount; j++) { Serial.println("Playing pose " + String(j + 1)); for (int i = 0; i < numServos; i++) { pwm.setPWM(i, 0, savedConfigurations[j][i]); Serial.print("Servo "); Serial.print(i + 1); Serial.print(" set to PWM value: "); Serial.println(savedConfigurations[j][i]); } delay(1000); // Standard delay between poses if (stopPlaying) break; } }
playPosesInLoop: Continuously plays all saved poses in a loop until the stop command is received.
12. Stopping the Playback
void stopPlayingPoses() { stopPlaying = true; isPlaying = false; Serial.println("Playback of poses stopped."); }
- stopPlayingPoses: Stops the ongoing playback of poses.
13. Resetting Poses
void stopPlayingPoses() { stopPlaying = true; isPlaying = false; Serial.println("Playback of poses stopped."); }
- resetPoses: Deletes all saved poses and resets the system for a fresh start.
This code provides a robust framework for controlling a 6-DOF robotic arm via Bluetooth, allowing for the storage and playback of complex movements.
Developing RobotArmControl App for the DIY 6-DOF Robotic Arm with Bluetooth Control
The RobotArmControl App is a user interface designed to control a DIY 6-DOF robotic arm with Bluetooth control wirelessly via Bluetooth. This app allows users to manipulate each joint of the robotic arm in real-time, save different poses of the arm, and replay these poses either once or in a loop.
Key Features of the App:
Bluetooth Connectivity:
- The app starts with the ability to connect to a Bluetooth module attached to the robotic arm, allowing for wireless control.
Sliders for Servo Control:
- The interface contains six sliders, each corresponding to one of the six joints of the robotic arm (such as Grip, Wrist Pitch, Wrist Roll, Elbow, Shoulder, and Waist). Moving these sliders sends real-time position data to the corresponding servo motor, enabling precise manual control of the robotic arm’s movements.
- Speed Control:
- There’s a slider dedicated to controlling the speed of the servos, allowing you to adjust how quickly the arm transitions between saved positions.
Pose Control:
- The app includes buttons to save a pose, play back saved poses, reset the saved poses, and stop any ongoing playback. The “Save” button stores the current positions of all servos, “Play” initiates the playback of these saved poses, and “Reset” clears the saved data.
Loop Playback:
- A toggle switch enables or disables looped playback of the saved poses. When enabled, the robotic arm will continuously cycle through the saved poses until the loop is stopped.
Pose Count Display:
- The app displays the current number of saved poses, helping the user keep track of their stored configurations.
Let’s break down and explain each block of the App Inventor interface you provided:
1. Global Initialization (initialize global receivedText to 0
)
- Purpose: This block initializes a global variable named
receivedText
and sets its initial value to0
. This variable will be used later in the app to store and manage data received from the Bluetooth connection.
2. Before Picking the Bluetooth Device (when ListPicker1.BeforePicking do
)
- Purpose: This block is executed when the user is about to select a Bluetooth device from the list. The
ListPicker1.Elements
is populated with the available Bluetooth devices’ names and addresses using theBluetoothClient1.AddressesAndNames
method. This ensures that the user can select from the available Bluetooth devices for connection.
3. After Picking the Bluetooth Device (when ListPicker1.AfterPicking do
)
- Purpose: This block is executed after the user selects a Bluetooth device from the list.
- Steps:
- Connection Attempt: The app attempts to connect to the selected Bluetooth device using
BluetoothClient1.Connect
with the selected address fromListPicker1.Selection
. - If Connection Succeeds: If the connection is successful, it updates
Label1.Text
to show “Connected” and changesLabel1.BackgroundColor
to green to indicate a successful connection. - If Connection Fails: If the connection fails, it updates
Label1.Text
to “Not Connected” and changesLabel1.BackgroundColor
to red to indicate the failure.
- Connection Attempt: The app attempts to connect to the selected Bluetooth device using
4. Loop Switch Toggle (when LoopSwitch.Changed do
)
- Purpose: This block handles the toggle switch that controls whether the robot arm’s pose playback should loop.
- Steps:
- If Switch is ON: If the
LoopSwitch
is turned ON, it sends the text “LoopON\n” via Bluetooth to the robot usingBluetoothClient1.SendText
. - If Switch is OFF: If the
LoopSwitch
is turned OFF, it sends the text “LoopOFF\n” to the robot.
- If Switch is ON: If the
5. Slider Position Changed (when SliderX.PositionChanged do
)
- Purpose: Each of these blocks handles the change in position for the respective servo control sliders (e.g.,
Slider1
,Slider2
, etc.). - Steps:
- Send Servo Position: When a slider is moved, the app sends the new position value of the slider via Bluetooth. The value is formatted as “X,Y\n”, where
X
is the servo number (1-6 corresponding toSlider1
–Slider6
), andY
is the current position of the slider (thumbPosition
). - Purpose for Each Slider:
Slider1
sends the position for Servo 1.Slider2
sends the position for Servo 2, and so on.
- Send Servo Position: When a slider is moved, the app sends the new position value of the slider via Bluetooth. The value is formatted as “X,Y\n”, where
6. Stop Button Click (when StopButton.Click do
)
- Purpose: This block is executed when the “Stop” button is clicked.
- Steps:
- Check Connection: It first checks if the app is connected to the Bluetooth device.
- Send Stop Command: If connected, it sends the text “St\n” to the robot arm, instructing it to stop any ongoing actions.
7. Save Button Click (when SaveButton.Click do
)
- Purpose: This block is executed when the “Save” button is clicked, allowing the user to save the current position of the servos as a pose.
- Steps:
- Check Connection: The app checks if it is connected to the Bluetooth device.
- Send Save Command: If connected, it sends the text “S\n” to the robot arm, instructing it to save the current pose.
- Update Pose Count: The global variable
receivedText
is incremented by 1, and thePoseCountLabel.Text
is updated to reflect the total number of saved poses.
8. Play Button Click (when PlayButton.Click do
)
- Purpose: This block is executed when the “Play” button is clicked, initiating the playback of saved poses.
- Steps:
- Check Connection: It first checks if the app is connected to the Bluetooth device.
- Send Play Command: If connected, it sends the text “P\n” to the robot arm, instructing it to start playing back the saved poses.
9. Reset Button Click (when ResetButton.Click do
)
- Purpose: This block is executed when the “Reset” button is clicked, clearing all saved poses and resetting the pose count.
- Steps:
- Check Connection: It first checks if the app is connected to the Bluetooth device.
- Send Reset Command: If connected, it sends the text “R\n” to the robot arm, instructing it to reset all saved poses.
- Reset Pose Count: The global variable
receivedText
is reset to 0, and thePoseCountLabel.Text
is updated to show “0”, indicating that no poses are currently saved.
Calibration and testing
After the programming and hardware setup, the next crucial step is to conduct extensive calibration and testing. This phase ensures that each servo in the robotic arm operates smoothly and responds accurately to the commands sent from the smartphone app.
App Installation and Connection
Before beginning the calibration, you must install and set up the RobotArmControl app on your Android device to interact with the robotic arm.
Downloading the App:
- Download the RobotArmControl app via the provided link (this could be a file shared through a cloud service or directly transferred from a computer).
Installation:
- Open the downloaded APK file to start the installation process. You may need to allow installations from unknown sources in your device settings if the app is not from the Google Play Store.
Granting Permissions:
- During installation or upon first launching the app, ensure that all necessary permissions are granted, particularly access to Nearby Devices and Bluetooth. These permissions are required for the app to discover and connect to the Bluetooth module (HC-05) attached to your Arduino.
Connecting via Bluetooth:
- Open the app and click on the Select Device button, which will bring up a list of available Bluetooth devices.
- Select the Bluetooth module (typically labeled
HC-05
or something similar) connected to the Arduino of your robotic arm. - Once the connection is established, the app will display a “Connected” status, and you can begin sending commands to the robotic arm.
Calibration Process
Once the smartphone is successfully connected to the robotic arm via the app, the calibration of the arm can begin:
Servo Calibration:
- Test each servo individually to ensure it moves to the correct positions according to the commands sent from the app.
- It might be necessary to disassemble the servo linkages, calibrate the servos, and then reassemble them to ensure that the movements are precise and match the expected positions. This step is particularly important for joints requiring specific angle ranges.
Range Adjustment:
- If needed, adjust the range and response of the servos. This can be done in the code or by physically repositioning the servo linkages to ensure each joint reaches the desired range of motion without stressing the servos.
Testing Pose Playback:
- Test the playback of stored poses using the app to ensure that the robotic arm follows the stored sequences smoothly and accurately.
- During this testing phase, monitor the arm’s movements to ensure no obstructions or misalignments occur. If necessary, recalibrate by adjusting servo positions or reprogramming the pose values in the code.
Final Testing:
- After calibration, perform a full test by saving poses and playing them back in sequence. Ensure that the arm moves smoothly through all poses, both in single and loop modes.
- Observe the arm during these tests to confirm that the calibration is correct and that the servos are not being overstrained or reaching their mechanical limits.
Conclusion
Building a 6-DOF robotic arm is a complex yet highly rewarding project that bridges multiple engineering disciplines, including mechanical design, electronics, and programming. By undertaking this project, you will not only enhance your technical skills but also gain valuable hands-on experience that lays the groundwork for further exploration into more advanced robotics and automation applications. Whether you’re a hobbyist looking to deepen your understanding of robotics or an engineer seeking to expand your skill set, this project offers a comprehensive learning experience that combines creativity, precision, and technical expertise.
I bought the model but it doesn’t have the bearing measurement valueReport
Thanks for your comment, Fernando! Please add a ball bearing 6806ZZ with dimensions 30*42*7.
Hi, interesting project also to do with a teenager. Regarding the servo MG996R, it exists in 2 configurations : either 180° or 360°. What you recommend?
Best regards,
Emmanuel
Hi Emmanuel, thank you for your kind words! I recommend using the 180° version of the MG996R servo for this project. This is because the 180° servo allows precise control of the angle, which is essential for positioning and movement in robotic arms or similar applications. The 360° servo is designed for continuous rotation and is better suited for tasks like driving wheels, where angle control is not required. Best regards, OmArTronics.
sir i did the same connection but it is not working ,please tell me how much
current give the pca9685 servo controller
The PCA9685 servo controller itself draws very little current, typically less than 10mA. However, the total current needed depends on the servos you are using. Each MG996R servo, for example, can draw up to 2A (max 2,5 A) under load. Make sure your power supply can provide enough current for all connected servos, considering their combined maximum draw.