Electromyography (EMG) measures muscle response or electrical activity in response to a nerve's stimulation of the muscle. This project describes the process of obtaining the raw EMG data from a muscle flex and converting it into a real-time signal that can communicate with a PIC® microcontroller to be used in various embedded control applications.
The project uses a Curiosity High Pin Count (HPC) Development Board and a PIC16F18875 microcontroller in conjunction with an EMG click™ board, 3-connector sensor cable, and electrode pads.
The raw EMG data obtained from a muscle flex is rather noisy with rapid and random changes. This article outlines how to use a PIC microcontroller to condition the signal, essentially smoothing it out, to make it effective for further use in embedded control. We use a combination of rectification, peak-to-peak filter, and a moving average filter to achieve a smooth signal. You may use this signal conditioning module for any application that needs EMG signals. These projects demonstrate the use of the modules: "Controlling a Motorized Prosthetic Arm using EMG Signals" and "Push-Up Counter Bluetooth Application Using EMG Signals".
- Curiosity HPC Development Board
- EMG Click: MIKROE-2621
- EMG Cable: MIKROE-2457
- Sensor Adhesive Electrodes
| Windows|| Linux|| Mac OSX|
Integrated Development Environment
MPLAB® Code Configurator
Dynamic Code Generation
| Windows|| Linux|| Mac OSX|
Project and Source Files
Signal Processing Implementation
The raw EMG signals output by the EMG sensor are noisy with many rapid changes, which makes it hard to use these signals in conjunction with a microcontroller. Hence, we need to process the signals further to achieve a smoother signal that is more tolerant of noise. The processing of the signals has been achieved by two filters: a peak-to-peak filter and a moving average filter. This signal has been further rectified to produce a smoother signal capable of communicating with a PIC microcontroller for embedded control.
Circular Buffer Implementation
Since the 8-bit microcontrollers have a limited memory to implement multiple filters, circular buffers have been used for storing and operating on data. Circular buffers are fixed-sized FIFO queues that behave like they were connected end-to-end and as though the memory was contiguous and circular. The advantage of a circular buffer is that when any new data point is added or consumed, the elements do not need to be shuffled around like in most other data structures. When data is added, the front pointer advances; when data is consumed, the tail pointer advances. If the end of the buffer is reached, we simply wrap around to the beginning to replace the oldest data.
A total of three circular buffers have been used:
- Signal Buffer (sb_data): To continuously store the sampled EMG signals incoming from the sensor
- Peak Buffer (pk_data): Stores elements in a moving window to calculate a neutral peak value
- Moving Average Buffer (ma_data): Stores moving average that updates for every new data point
Each buffer has the functions _isfull, _isempty, _insert, _remove, and _peek that are used as necessary for the implementation of the filters. A .c source file and a .h header file together contain the declarations and definitions of all these functions for each buffer in the files of their namesakes:
- signal_buffer.c and signal_buffer.h – Functions for Signal Buffer
- peak_filter.c and peak_filter.h – Functions for Peak Buffer
- moving_avg_filter.c and moving_avg_filter.h – Functions for Moving Average Buffer
The filters for processing the signal are implemented in the signal_processing.c source file and the corresponding signal_processing.h header file. There are two main functions:
- get_neutral_peaktopeak(): This function implements the Peak Filter and returns neutral_datapoint calculated using highest and lowest peaks among the elements present in the Peak Buffer (pk_data) at a given point of time.
- get_moving_average(): This function implements the Moving Average Filter and returns the average of data points present in the Moving Average Buffer (ma_data) for a given window. The sum is updated for every new data point added (and/or removed).
Functional Flow Diagram
- A timer interrupt is generated every 20 ms which triggers the Timer Interrupt Handler to start acquiring ADC samples from the EMG sensor.
- The A/D conversion result at the current time is added to the FIFO Signal Circular Buffer (sb_data).
- The first element from the buffer is added to another set of elements whose neutral peak values are calculated.
- A moving average is calculated for a window of fixed size that is updated with every new addition of a data point.
- We compare the obtained moving average value with a threshold to see if it passes as an intended muscle flex to eliminate noise.
- This data can now be used in any embedded control application.
Make the following hardware connections:
- Connect the USB power to the board to turn it on.
- Connect the 3.5 mm phone jack to the EMG sensor module.
- Connect three sensor pads to the three electrodes attached to the cable for metallic contact.
- Insert the EMG click module on the mikroBUS™ Slot 2 of the Curiosity board (refer to the Hardware Setup Diagram).
- Prepare the skin where you would like to attach the electrodes by wiping it clean and letting the area dry.
- Your forearm is recommended for best results, although any muscle group would give you EMG signals.
- Place the red electrode at the center of the muscle group and blue electrode adjacent to it at the end of the muscle group
- Place the black electrode (reference electrode) where a bone is prominent (such as the side of your wrist).
Installation and Setup
You need to have MPLAB® X IDE installed on your computer along with the MPLAB XC8 Compiler and the MPLAB Code Configurator (MCC). If you haven't used these tools before, the setup is described in more detail here: "Installation and Setup".
Create a New Project
Create a new standalone project in MPLAB X for a PIC16F18875. If this is your first time using MPLAB X, follow the instructions in the following article: "Create a Standalone Project".
Setup Project Resources
These peripherals need to be selected for this project:
- System Module
- Interrupt Module
- Pin Module
- Analog-to-Digital Converter with Computation (ADCC)
The System Module, Interrupt Module, and Pin Module are automatically included, but the ADCC, TMR6 and EUSART must be selected for the project. The list of peripherals shows up under the "Device Resources" list. Double-click on each to have them added to the project. The result should look like the picture below:
System Module Setup
Click on the 'System Module' and the MCC screen will show the 'Easy Setup' menu.
- Select 'HFINTOSC' from the Oscillator Select drop-down.
- Select '16_MHz' from the HF Internal Clock drop-down.
- Select '1' from the Clock Divider drop-down.
- For the Watchdog Timer Enable Option, select 'WDT Disabled, SWDTEN is ignored'.
- At the "Programming" section, check the box for 'Low-Voltage Programming Enable'.
- On the 'Registers' tab, all registers can be left to their default values.
Timer Module Setup
Click on the TMR6 Module and the MCC screen shows the 'Easy Setup' menu.
- Check the box 'Enable Timer' option.
- Select 'FOSC/4' as the Clock Source .
- Choose the Postscaler value as '1:8'.
- Choose the Prescaler value as '1:64'.
- Choose 'Rising Edge' for Polarity.
- Type 20 ms in the Timer Period box and press Enter. The nearest available period will show under 'Actual Period'.
- Check the box for 'Enable Timer Interrupt'.
- All other fields can be left to their default values.
ADC Module Setup
Click on the ADCC Module and the MCC screen will show the 'Easy Setup' menu.
- Check the box for 'Enable ADC'.
- Choose 'Basic_mode' for Operating.
- Choose 'FOSC/ADCLK' for Clock Source.
- Choose 'FOSC/16' for Clock.
- Select 'left' as theResult Alignment from the drop-down menu.
- All other fields can be left to their default values.
UART Module Setup
The UART module can be used to communicate with any peripheral to send control signals using the EMG click. Steps are given below to configure UART for the development board for further use.
If your application does not use a UART protocol, you can skip this step and replace it with any other protocol you might need.
Click on the EUSART Module and the MCC screen will show the 'Easy Setup' menu.
- Select 'asynchronous mode' from the drop-down.
- Check the box for 'Enable EUSART'.
- Check the box for 'Enable Transmit'.
- Check the box for 'Enable Receive'.
- Set the Baud Rate to '19200'.
- Choose '8-bit' for Transmission and Reception.
- Check the box for 'Enable EUSART Interrupts'.
- Check the box for 'Redirect STDIO to USART'.
- Leave Buffer Size as '8' for Transmit and Receive buffers.
- All other fields in the 'Registers' tab can be left to their default values.
Configure Pin Manager
To assign pins on the microcontroller, open the Pin Manager window at the bottom of the screen. To select a pin, click on the corresponding blue unlocked lock button, turning it into a green locked symbol. Ensure the pins look as shown in the picture below:
- Choose the 'PDIP40' package from the drop-down menu.
- Module ADCC: Click on Analog inputs (ANx) for (Port A – Pin 0) and (Port A – Pin 2) so they turn green.
- Module EUSART: Similarly, click on (Port C – Pin 7) for RX and (Port C – Pin 6) for TX.
- Pin Module: Click on (Port B – Pin 4) and (Port C – Pin 5) for GPIO Input and (Port A – Pin 7) for GPIO Output.
- RESET: Click on (Port E – Pin 3) for MCLR (or leave it if it already shows green and locked).
- TMR6: Ensure (Port B – Pin 7) is green for T6IN input.
Customize Names for Pins
Pin Module Setup
To easier understand and program, we can have custom names for the pins on the microcontroller that we intend to observe or control. Click on 'Pin Module' in the 'Project Resources' tab on the left while MCC is open.
Rename the pins according to the following diagram. To rename a pin, click on the 'Custom Name' for the pin and type in the new name.
Now you can see the names on the Pin Manager: Package View window change as well.
Add Signal Processing Module
The processing module consists of a total of eight files that you need to copy or move into your project’s working folder. Download the project ZIP file from the "Exercise Files" section of this page and expand the contents. Then move or copy the following files to the working project folder:
Follow these steps to copy the files above if you haven’t already done so:
- Go back to MPLAB X IDE. Right-click on 'Source Files' in the 'Projects' tab.
- Click on ‘Add Existing Item’ from the list.
- Navigate to the folder containing the downloaded exercise files and choose peak_filter.c, moving_avg_filter.c, signal_buffer.c, and signal_processing.c.
- You have now added the .c source files.
- Right-click on the header files and select ‘Add Existing Item’ from the list.
- Again, navigate to the folder containing the downloaded exercise files and choose peak_filter.h, moving_avg_filter.h, signal_buffer.h, and signal_processing.h.
- The final projects tab will now look like this:
The main file needs to be edited to include function calls to the signal processing modules and your custom application. Double-click on the main.c file to open it up in the editor window.
The main.c file requires a few lines to be uncommented for global and peripheral interrupts to work. MCC already has the control commands in the default main.c file, but they are commented out with two forward slashes (//). The forward slashes need to be removed to enable these lines of code.
The following header files are to be included before the main function with the #include directive:
#include "mcc_generated_files/mcc.h" #include "peak_filter.h" #include "moving_avg_filter.h" #include "signal_buffer.h" #include "signal_processing.h" #include <stdio.h> #include <stdint.h> #include <stdbool.h> #include <stdlib.h> #include <math.h>
Some flags need to be defined for event-marking. Please include the following variable declarations after the #include statements:
Sampling of the EMG signal is done every 20 ms using a timer interrupt. Your interrupt handler routine needs to be included next. Include the following code snippet to your main.c file before the main function:
Now we move on to initialize the timer interrupt handler in the main() function. Add the following code to the main function:
We run an infinite loop to continuously check for user-initiated changes. Changes can be made to the mode of control and to start the process with two switches. Add the following code to achieve that functionality:
Another infinite loop is required for the signal processing functions. Add the following code to add that functionality:
You will now have added all files and functionality to your project to begin EMG signal acquisition and subsequent use in embedded applications. You may tailor this project to suit the needs of your specific application. The variable, result, stores the processed real-time EMG data and can be used with any number of routines that store, display, manipulate or use it as a control signal. The variable, count, gives the number of data points present in the signal buffer. The filters used to achieve the signal processing are discussed in the next section.
The tutorial above will help you add the module files to your own project. Alternatively, you can download this project from the "Exercise Files" section and choose to build your application on top of it.
The following projects are built on top of this module for reference: "Controlling a Motorized Prosthetic Arm using EMG Signals" and "Push-Up Counter Bluetooth Application using EMG Signals". Both of these projects use the UART protocol for embedded control. You may choose to use any other protocol by making the required selections while configuring the MCC before generating code.
To reference the results obtained by the signal processing module, a comparison is presented below. Given below are the signals before processing, right out of the Analog Out pin of the EMG sensor and the same signals after processing using a peak-to-peak filter and a moving average filter:
Conclusions can be drawn from the graphs on the necessity of having a signal processing module for easy, robust and convenient control of the EMG signals. You may make use of the module in any EMG application you see fit.