0

I need some help with programming Arduino with EMG signals to control the solenoid pressure valve.
I wrote some program which is setting high and low state on the output pin, but it's not working properly.
First I create a plot to observe the signal level. And the plot looks like in the picture which I attached.

The basics concept of program is setting the high signal on the output when I flex muscles and when I relax the muscle it's should write low state on the output. My idea was based on triggering the on-off signals at the moment when the muscle is flexed, the value of signal is above 600 (now the diode should be ON and stay in ON state) and it drops and when I relax muscles the value rises once again to value around 600 more or less (now the diode should be OFF) and drops under 100.

const int ledPin=13; 

const int sensorPin= 0; 

int level; 

const int threshold1=400;

const int threshold2 =500;

void setup() {

    pinMode (ledPin, OUTPUT); 

    pinMode (sensorPin, INPUT); 

    Serial.begin(9600); 
    }

void loop(){

    level= analogRead(sensorPin); 

    if (level > threshold1){

    digitalWrite(ledPin, HIGH); 

    if (level > threshold2)

    digitalWrite(ledPin, LOW);

    }

I wrote new code, but I still have problems with proper sending of an ON and OFF signal to the output.

When I flex the muscle I have high state on the output causing by first peak (LED is ON) but when I relax the muscle the second peak won't set the low state on the output. But when I flex the muscle once again the output change state to low and the diode is OFF. Do you have any suggestions what part of the code do I need to improve?

Here's the code:

const int ledPin=13; 

const int sensorPin= 0; 

int level;

int flex= 0;

int PreviousState = 501;

const int threshold1=600;


void setup() {

    pinMode (ledPin, OUTPUT); 

    pinMode (sensorPin, INPUT); 

    Serial.begin(9600); 
}


void loop() {

    level= analogRead(sensorPin); 

          if (level > threshold1 && PreviousState < threshold1){

          {

            flex =!flex;

          }

          if (flex == 1)
          {

            digitalWrite(ledPin, HIGH); 

          }

          else

          {
            digitalWrite(ledPin, LOW);

          }

          PreviousState = level;



        }

    }

}

the state of muscle funcionality - signal from muscle

5
  • To mark code as code: In the editing box, highlight the code and press ctrl-k. Or highlight the code and click the {} icon in the toolbar at the top of the editing box. (To highlight text click-drag across it or use the arrow keys while holding the shift key.) Note, short bits of code are enclosed in back-ticks, like ` which is why part of your text is formatted that way Commented Apr 6, 2017 at 22:37
  • you Can use Switch case. Switch(val) then take action according to value Commented Apr 7, 2017 at 4:36
  • In which case you want to switch the state to LOW? What is the meaning of two thresholds?
    – mico
    Commented Apr 7, 2017 at 8:44
  • What behavior do you want in the 554570-558872 data? I think I'd use some en.wikipedia.org/wiki/CUSUM filtering to debounce the level signal, and maybe use some separate logic for switching into or out of the flex state.
    – Dave X
    Commented Apr 7, 2017 at 18:36
  • I'd think there are 4 distinct states you should to keep track of separately: idle, flexing, flexed, and relaxing.
    – Dave X
    Commented Apr 7, 2017 at 18:58

2 Answers 2

0

I'd use a https://en.wikipedia.org/wiki/CUSUM to filter the level data and track the idle, flexing, flexed, relaxing states and transitions separately:

...

int state = 0 ; // idle >> flexing >>flexed >> relaxing
long int cumsum = 0;

void loop() {
  level= analogRead(sensorPin); 
  cumsum=max(0,cumsum+level-threshold);

  switch(state) {
  case 0 : // idle
      if (cumsum > 50*4) {state = 1 ;  // wait for long pulse
         flex =1;
         digitalWrite(ledPin, HIGH);
      }
      break; 
  case 1 : // flexing 
      if (cumsum ==0 ) state = 2 ; 
      break;
  case 2 : // flexed
      if (cumsum > 50*2 ) state = 3 ;  // wait for shorter pulse
      break;
  case 3 : // relaxing
      if (cumsum == 0 ) {
        state = 0;
        flex = 0;
        digitalWrite(ledPin, LOW);
      }
      break;
  }
}

You might want to add an extra cumsum filter with a lower threshhold to potentially transition out of flexed if there is an exceptional period of low level. e.g.:

...

long int cumsum2 = 0;
...
cumsum2 = max(0,cumsum2+level-200);
...

case 2: 
   ...
   if (cumsum2 == 0) state=3; // missed a relaxing signal
   ...
1

I see this problem more profound than just some if and else. As you may observe, there may be two peaks in flex and always there is one in relax.

What makes difference is the width of the pulse: flex is wide and relax is narrow.

You should detect the width. It can be measured by amount of times, when you detect a value in input that is over the treshold.

When the amount is less than some value when signal is very low again, you detected a LOW for output and if it is more than some value it means HIGH.

in setup

unsigned int times = 0;
unsigned int threshold = xxx;
unsigned int low = xx;
unsigned int high = yyy;

...

in loop

...
if (level > high) { 
      times = times + 1;
} else if (level < low) {
     if (times > threshold) {
          digitalWrite(ledPin, HIGH);
     } else {
          digitalWrite(ledPin, LOW);
     }
     times = 0;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.