Controlling a Robotic Hand Using EMG Signals and Arduino & ESP32

 Controlling a Robotic Hand Using EMG Signals




Introduction to UpsideDownLabs

UpsideDownLabs is an innovative company specializing in advanced bio-sensing technologies, wearable devices, and neuroscience-based solutions. The company focuses on creating high-quality sensors and tools for developers, researchers, and hobbyists interested in bio-signal processing. With a strong commitment to making neuroscience and biomedical engineering accessible, UpsideDownLabs has developed various products that simplify complex signal acquisition and processing for projects related to EMG (electromyography), EEG (electroencephalography), and ECG (electrocardiography).

Their product line includes both hardware and software solutions, empowering users to explore applications in robotics, prosthetics, human-computer interaction, and health monitoring.



Muscle BioAmp Candy Sensor

                               

The Muscle BioAmp Candy Sensor is a high-precision analog front-end designed for capturing bio-signals such as EMG, ECG, and EEG. It offers an excellent balance of signal clarity and ease of integration, making it ideal for beginners as well as professionals working on bio-sensing applications. Key features of this sensor include:

  • High Signal-to-Noise Ratio (SNR): Ensures minimal interference and maximum signal clarity.

  • Plug-and-Play Design: Comes with pre-soldered connectors for quick and hassle-free setup.

  • Compatibility: Works seamlessly with microcontrollers like Arduino, Raspberry Pi, and ESP32.

  • Low Power Consumption: Ideal for portable and wearable applications.

  • Applications: Suitable for EMG-controlled robotic arms, muscle-signal-based games, and wearable health monitoring devices.

Heart BioAmp Candy Sensor

                               

                              

The Heart BioAmp Candy Sensor is designed for users who require robust signal acquisition in demanding environments. It offers enhanced signal filtering, making it ideal for applications where noise and interference are significant concerns. Key properties of this sensor include:

  • Advanced Filtering: Built-in filters to remove noise and artifacts for accurate signal detection.

  • Durability: Designed with a sturdy enclosure for long-term use in lab and field conditions.

  • High Sampling Rate: Allows detailed signal processing for advanced applications in neuroscience and robotics.

  • Wide Use Cases: Perfect for professional-grade prosthetic control, rehabilitation robotics, and real-time biofeedback systems.






Muscle control via electrical signals is a fascinating topic in neuroscience, robotics, and wearable technology. In this project, we will learn how to build a system using an Arduino, an EMG (Electromyography) sensor, and servo motors to control a robotic hand based on muscle activity. We'll walk through every aspect—from preparing the hardware to understanding how the code works.

What is EMG and How Does It Work?

EMG measures electrical signals produced by muscle cells when they contract. These signals can be captured using electrodes placed on the skin surface. By processing these signals, we can detect muscle activity and use it to control devices like robotic arms, prosthetics, or even video games.


Components Required

  1. Arduino Uno or Nano – Acts as the microcontroller to process the EMG signals and control the servos.
  2. EMG Sensor (like MyoWare or Muscle BioAmp Candy Sensor) – Detects muscle activity and outputs an analog signal proportional to the muscle’s electrical activity.
  3. Servo Motors (x2) – Used to simulate hand movement by rotating in response to muscle activity.
  4. Electrodes – To be attached to the skin for capturing muscle signals.
  5. LED – Indicates when muscle activity crosses a threshold.
  6. Resistors – For current limiting purposes.
  7. Connecting wires – To connect components.
  8. Breadboard – For easy circuit assembly.
  9. Power supply – Either through USB or a 9V battery.








Step 1: Preparing the Skin and Applying Electrodes

To ensure accurate signal measurement, follow these steps to prepare the skin:

  1. Clean the Skin – Use alcohol wipes to clean the area where the electrodes will be placed. This removes oils and dirt, improving conductivity.

  2. Attach Electrodes

    • Electrode Placement:
      • Place one electrode on the muscle (e.g., biceps) whose activity you want to monitor.
      • Place the second electrode on a nearby part of the same muscle group.
      • Place the third electrode (ground) on a bony or less active part of the body, such as the elbow or wrist.
  3. Connect the EMG Sensor – Attach the electrode cables to the EMG sensor according to the manufacturer’s instructions.

Step 2: Circuit Connections

  • Connect the EMG Sensor to the Arduino:

    • Connect the sensor’s signal output to A0 (analog input pin) on the Arduino.
    • Connect the sensor’s VCC to the 5V pin and GND to the ground pin on the Arduino.
  • Connect the Servo Motors:

    • Attach the first servo motor’s signal wire to pin 2 and the second servo motor’s signal wire to pin 12 on the Arduino.
    • Connect the servo motors’ power (VCC) to the 5V pin and ground (GND) to the GND pin on the Arduino.
  • Connect the LED:

    • Connect a resistor in series with the LED’s positive (anode) leg.
    • Connect the other end of the resistor to pin 13 on the Arduino.
    • Connect the LED’s negative leg (cathode) to GND.

    Step 3: Code for Arduino

    Here’s the code that processes the EMG signals and controls the servos:

    #include <Servo.h> // Include the standard Servo library

    #define SAMPLE_RATE 500
    #define BAUD_RATE 115200
    #define INPUT_PIN A0 // Sensor connected to analog pin A0
    #define LED_PIN 13    // LED connected to GPIO2
    #define SERVO_PIN1 2 // Servo 1 connected to digital pin 9 (right hand)
    #define SERVO_PIN2 12 // Servo 2 connected to digital pin 10 (left hand)
    #define BUFFER_SIZE 128
    #define THRESHOLD 100 // Define a threshold for significant muscle activity

    int circular_buffer[BUFFER_SIZE];
    int data_index, sum;

    Servo rightServo; // Servo for the right hand
    Servo leftServo;  // Servo for the left hand

    void setup() {
        // Serial connection begin
        Serial.begin(BAUD_RATE);

        // Initialize LED pin
        pinMode(LED_PIN, OUTPUT);
        digitalWrite(LED_PIN, LOW); // Ensure LED starts off

        // Attach the servo motors to their pins
        rightServo.attach(SERVO_PIN1);
        leftServo.attach(SERVO_PIN2);

        // Set both servos to initial positions
        rightServo.write(0); // Start right hand at 0 degrees
        leftServo.write(0);  // Start left hand at 0 degrees

        // Display author information
        Serial.println("Made by Aryan Pandey, Techno Sap");
    }

    void loop() {
        // Calculate elapsed time
        static unsigned long past = 0;
        unsigned long present = micros();
        unsigned long interval = present - past;
        past = present;

        // Run timer
        static long timer = 0;
        timer -= interval;

        // Sample and get envelope
        if (timer < 0) {
            timer += 1000000 / SAMPLE_RATE;

            int sensor_value = analogRead(INPUT_PIN); // Read from A0
            int signal = EMGFilter(sensor_value);
            int envelope = getEnvelope(abs(signal));

            // Control LED and servos based on muscle activity
            if (envelope > THRESHOLD) {
                digitalWrite(LED_PIN, HIGH);  // Turn LED on
                rightServo.write(90);        // Move right hand to 90 degrees
                leftServo.write(180);        // Move left hand to 180 degrees
            } else {
                digitalWrite(LED_PIN, LOW);  // Turn LED off
                rightServo.write(0);         // Reset right hand to 0 degrees
                leftServo.write(0);          // Reset left hand to 0 degrees
            }

            // Send data for debugging or monitoring
            Serial.print(signal);
            Serial.print(",");
            Serial.println(envelope);
        }
    }

    // Envelope detection algorithm
    int getEnvelope(int abs_emg) {
        sum -= circular_buffer[data_index];
        sum += abs_emg;
        circular_buffer[data_index] = abs_emg;
        data_index = (data_index + 1) % BUFFER_SIZE;
        return (sum / BUFFER_SIZE) * 2;
    }

    // Band-Pass Butterworth IIR digital filter, generated using filter_gen.py
    float EMGFilter(float input) {
        float output = input;
        {
            static float z1, z2; // filter section state
            float x = output - 0.05159732 * z1 - 0.36347401 * z2;
            output = 0.01856301 * x + 0.03712602 * z1 + 0.01856301 * z2;
            z2 = z1;
            z1 = x;
        }
        {
            static float z1, z2; // filter section state
            float x = output - -0.53945795 * z1 - 0.39764934 * z2;
            output = 1.00000000 * x + -2.00000000 * z1 + 1.00000000 * z2;
            z2 = z1;
            z1 = x;
        }
        {
            static float z1, z2; // filter section state
            float x = output - 0.47319594 * z1 - 0.70744137 * z2;
            output = 1.00000000 * x + 2.00000000 * z1 + 1.00000000 * z2;
            z2 = z1;
            z1 = x;
        }
        {
            static float z1, z2; // filter section state
            float x = output - -1.00211112 * z1 - 0.74520226 * z2;
            output = 1.00000000 * x + -2.00000000 * z1 + 1.00000000 * z2;
            z2 = z1;
            z1 = x;
        }
        return output;
    }

     Connection Diagram for Muscle BioAmp Candy Sensor and ESP32

                                        



    1. Power Supply Connection ( Muscle BioAmp Candy Sensor to ESP32)

    • VCC (Power Pin):
      Connect the VCC pin of the Muscle BioAmp Candy sensor to the 5V pin of the ESP32.

    • (Important: Since the sensor operates at 5V, it should be powered by the 5V pin of the ESP32.)

    • GND (Ground Pin):
      Connect the GND pin of the Muscle BioAmp Candy sensor to the GND pin of the ESP32.


    2. Signal Output Connection ( Muscle BioAmp Candy Sensor to ESP32)

    • The Muscle BioAmp Candy sensor outputs an analog signal that represents muscle activity.
      Connect the OUT pin of the BioAmp Candy sensor to GPIO 34 (an analog-capable input pin on the ESP32).

    3. Electrode Placement for  Muscle BioAmp Candy Sensor

    Proper electrode placement is crucial for accurate muscle signal detection:

    • Vin+ (Positive Electrode):
      Attach this electrode directly on the muscle where you want to measure activity.

    • Vin− (Negative/Reference Electrode):
      Attach this electrode near a bony area close to the muscle (but outside the active muscle region).

    • GND (Ground Electrode):
      Attach the ground electrode to a neutral, non-muscular part of the body (e.g., a bony surface like the elbow or wrist).


    4. Servo Motor Connections 

    You are using two servo motors for hand movement control:

    • Right Servo:

      • Signal wire to GPIO 25.
      • VCC wire to the 5V pin.
      • GND wire to the GND pin.
    • Left Servo:

      • Signal wire to GPIO 13.
      • VCC wire to the 5V pin.
      • GND wire to the GND pin.

    5. LED Connection 

    • Anode (long pin) of the LED should connect to GPIO 2 via a 220-ohm resistor.
    • Cathode (short pin) should connect directly to GND.

    : Code for ESP32


    #include <Servo.h> // Include the standard Servo library

    #define SAMPLE_RATE 500

    #define BAUD_RATE 115200
    #define INPUT_PIN 34   // Change to GPIO 34 for SP-32 sensor
    #define LED_PIN 2     // LED connected to GPIO 13
    #define SERVO_PIN1 25   // Servo 1 connected to GPIO 2 (right hand)
    #define SERVO_PIN2 13  // Servo 2 connected to GPIO 12 (left hand)
    #define BUFFER_SIZE 128
    #define THRESHOLD 100  // Define a threshold for significant muscle activity

    int circular_buffer[BUFFER_SIZE];
    int data_index, sum;

    Servo rightServo; // Servo for the right hand
    Servo leftServo;  // Servo for the left hand

    void setup() {
        // Serial connection begin
        Serial.begin(BAUD_RATE);

        // Initialize LED pin
        pinMode(LED_PIN, OUTPUT);
        digitalWrite(LED_PIN, LOW); // Ensure LED starts off

        // Attach the servo motors to their pins
        rightServo.attach(SERVO_PIN1);
        leftServo.attach(SERVO_PIN2);

        // Set both servos to initial positions
        rightServo.write(0); // Start right hand at 0 degrees
        leftServo.write(0);  // Start left hand at 0 degrees

        // Display author information
        Serial.println("Made by Aryan Pandey, Techno Sap - Modified for ESP32");
    }

    void loop() {
        // Calculate elapsed time
        static unsigned long past = 0;
        unsigned long present = micros();
        unsigned long interval = present - past;
        past = present;

        // Run timer
        static long timer = 0;
        timer -= interval;

        // Sample and get envelope
        if (timer < 0) {
            timer += 1000000 / SAMPLE_RATE;

            int sensor_value = analogRead(INPUT_PIN); // Read from GPIO 34
            int signal = EMGFilter(sensor_value);
            int envelope = getEnvelope(abs(signal));

            // Control LED and servos based on muscle activity
            if (envelope > THRESHOLD) {
                digitalWrite(LED_PIN, HIGH);  // Turn LED on
                rightServo.write(90);        // Move right hand to 90 degrees
                leftServo.write(180);        // Move left hand to 180 degrees
            } else {
                digitalWrite(LED_PIN, LOW);  // Turn LED off
                rightServo.write(0);         // Reset right hand to 0 degrees
                leftServo.write(0);          // Reset left hand to 0 degrees
            }

            // Send data for debugging or monitoring
            Serial.print(signal);
            Serial.print(",");
            Serial.println(envelope);
        }
    }

    // Envelope detection algorithm
    int getEnvelope(int abs_emg) {
        sum -= circular_buffer[data_index];
        sum += abs_emg;
        circular_buffer[data_index] = abs_emg;
        data_index = (data_index + 1) % BUFFER_SIZE;
        return (sum / BUFFER_SIZE) * 2;
    }

    // Band-Pass Butterworth IIR digital filter, generated using filter_gen.py
    float EMGFilter(float input) {
        float output = input;
        {
            static float z1, z2; // filter section state
            float x = output - 0.05159732 * z1 - 0.36347401 * z2;
            output = 0.01856301 * x + 0.03712602 * z1 + 0.01856301 * z2;
            z2 = z1;
            z1 = x;
        }
        {
            static float z1, z2; // filter section state
            float x = output - -0.53945795 * z1 - 0.39764934 * z2;
            output = 1.00000000 * x + -2.00000000 * z1 + 1.00000000 * z2;
            z2 = z1;
            z1 = x;
        }
        {
            static float z1, z2; // filter section state
            float x = output - 0.47319594 * z1 - 0.70744137 * z2;
            output = 1.00000000 * x + 2.00000000 * z1 + 1.00000000 * z2;
            z2 = z1;
            z1 = x;
        }
        {
            static float z1, z2; // filter section state
            float x = output - -1.00211112 * z1 - 0.74520226 * z2;
            output = 1.00000000 * x + -2.00000000 * z1 + 1.00000000 * z2;
            z2 = z1;
            z1 = x;
        }
        return output;
    }


    Step 4: Running the Project

  • Power the Arduino – Connect it to your computer via USB or use a battery.
  • Monitor the Output – Open the Serial Monitor in the Arduino IDE to see the raw signal and                  envelope values.
  • Test Muscle Activity – Contract the muscle where the electrodes are attached. If the envelope value exceeds the threshold, the servos will move, simulating hand movement, and the LED will turn on.
  • How It Works

  • The EMG sensor reads muscle activity and sends an analog signal to the Arduino.
  • The Arduino processes this signal using a band-pass filter and an envelope detection algorithm.
  • If the processed signal exceeds the threshold, it activates the servos and LED.
  • The servos move to simulate hand movement, demonstrating how muscle activity can control           external devices.


  • Displaying Dynamic Animations on an OLED Screen for a Robot Face

    In this project, I created a robot face using an Adafruit SH1106 OLED display and programmed it to show both animations and static text based on an input signal. The OLED screen, mounted on the front of the robot, gives it a lively and interactive personality. Below, I’ll explain how the system works and the basic connections used.


    How It Works

    The setup involves displaying two different states on the OLED screen:

    1. Static Text Display – When a signal is detected on a specific input pin, the screen displays a message, “upsidedownlabs” and “Techno SAP”.
    2. Animation Mode – In the absence of the signal, the screen plays a simple walking animation, switching frames continuously to simulate motion. The animation toggles on and off automatically after each loop.

    Connections

    Here’s a quick overview of how everything is connected:

    • OLED Display:
      • The SDA and SCL pins of the display are connected to the corresponding SDA and SCL pins of the microcontroller.
      • The display is powered using the 3.3V and GND pins.
    • Input Signal:
      • A digital input is connected to pin 2, which is used to detect high or low signals.
      • When the pin reads HIGH, the display switches to text mode. Otherwise, the walking animation is shown.

                                                       


    Code Overview

    The code is written using the Adafruit GFX and Adafruit SH110X libraries, which simplify drawing graphics on the OLED. The walkFrames array holds the frame data for the walking animation, and the display toggles between frames with a small delay to simulate movement.


    This project not only adds an expressive element to the robot but also provides a simple example of combining input detection with dynamic screen output. By adding animations and messages, the robot becomes more engaging and interactive.

    Feel free to experiment with different animations or messages to give your robot its unique personality!

    #include <Adafruit_GFX.h>
    #include <Adafruit_SH110X.h>

    #define SCREEN_I2C_ADDR 0x3C // OLED display I2C address
    #define SCREEN_WIDTH 128     // OLED display width, in pixels
    #define SCREEN_HEIGHT 64     // OLED display height, in pixels
    #define OLED_RST_PIN -1      // Reset pin (-1 if not available)

    #define PIN_INPUT 2         // Pin to check for high signal

    Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire, OLED_RST_PIN);

    // First animation: walk
    #define FRAME_DELAY (42)
    #define FRAME_WIDTH (64)
    #define FRAME_HEIGHT (64)
    #define WALK_FRAME_COUNT (sizeof(walkFrames) / sizeof(walkFrames[0]))
    const byte PROGMEM walkFrames[][512] = { 0000000000000000000000000000
      OO};

    bool isWalkAnimation = true;
    int frame = 0;

    void setup() {
      pinMode(PIN_INPUT, INPUT);  // Set pin 2 as input

      display.begin(0x3C);
      display.clearDisplay();
      display.display();
    }

    void loop() {
      display.clearDisplay();

      // Check if pin 2 is HIGH
      if (digitalRead(PIN_INPUT) == HIGH) {
        display.setTextSize(2);
        display.setTextColor(SH110X_WHITE);  // Use SH110X_WHITE instead of SSD1306_WHITE
        display.setCursor(0, 0);
        display.print("upsidedownlabs");
        display.setCursor(0, 30);
        display.print("Techno SAP");
      } else {
        if (isWalkAnimation) {
          display.drawBitmap(32, 0, walkFrames[frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
          frame = (frame + 1) % WALK_FRAME_COUNT;
          delay(FRAME_DELAY);
        }
      }

      display.display();

      // Switch between animations after one second
      if (frame == 0) {
        isWalkAnimation = !isWalkAnimation;
      }
    }

    Applications in Neuroscience

    This project showcases how EMG signals can be used in assistive devices, prosthetics, and rehabilitation technologies. By combining neuroscience with electronics, we can create life-changing solutions for people with motor impairments.

    Conclusion: Bringing It All Together

    This project demonstrates how accessible bio-sensing technology, like the Muscle BioAmp Candy and Heart BioAmp Candy sensors from UpsideDownLabs, can open doors to exciting innovations in neuroscience, robotics, and wearable devices. By using simple components and an Arduino, we've shown how muscle signals can be processed to control a robotic hand in real-time a concept that holds vast potential in prosthetics, rehabilitation, and interactive applications.
    For those interested in diving deeper into the project, I have created a detailed video tutorial that walks through the entire process from unboxing the sensors to building and coding the robotic hand. You can watch it on my YouTube channel, Techno Sap, where I regularly share tech-related projects and innovations.

    About the Author

    My name is Aryan Pandey, and I’m passionate about exploring cutting-edge technologies in robotics, neuroscience, and bio-sensing. Through my platform, Techno Sap, I aim to inspire and guide others in building practical, hands-on projects using emerging technologies. If you're excited about similar projects, don't forget to check out my YouTube channel for more exciting content.

    Call to Action

    _________________________________________________________ 🄸🄽🅂🅃🄰🄶🅁🄰🄼 👇🏾 https://z-p42.www.instagram.com/aryanpandey699/ _______________________________________________________

    If you enjoyed this project or found it helpful, feel free to leave a comment below, share it with others, and subscribe to my YouTube channel Techno Sap for more such detailed tutorials. Whether you’re a beginner or a seasoned developer, I hope this project has inspired you to explore the fascinating world of bio-sensing and robotics.   🙏




    Post a Comment

    Previous Post Next Post