Servo/serial monitor relation issues

I have recently started a project to make a robotic arm and have run into a problem. We need a 180 rotation 25kg servo to run simultaneously with an emg sensor, while still constantly checking the sensor. But with this code it is stopping the data coming out of the sensor and executing the servo's command, which makes the arduino read the data incredibly slowly and very late. If anyone has any suggestions on how to get this to work that would be appreciated.

#include <Servo.h>

Servo myServo;

int emgPin = A0;
int emgVal = 0;


void setup() {
  // put your setup code here, to run once:

  myServo.attach(5);
 
  Serial.begin(9600);

}

void loop() {
  // put your main code here, to run repeatedly:

  emgVal = analogRead(emgPin);
Serial.println(emgVal);
delay(100);

  if(emgVal>400;emgVal<1024){
    myServo.write(0);
   delay(10);

  }

  else{
       myServo.write(180);
  }
}

Why do you use delay?

This is not how you test if a value is in between two values… this condition as written is always true

You would need an && but not sur why you need to test against 1024 since the max value you get from your analogRead is 1023 anyway.

The first step, in my opinion, to be able to write non-blocking code is to read and understand the famous LED Blink without delay

Hello @cowboy-frog,

Following the good advice of @J-M-L to not use delay() (note the servo library you used probably used delay()) and @Etienne_74 to use internal timing to drive your servo without blocking mpu access to your sensor, I cobbled a simulation with some explanation in the comments.

You can see two events in the simcode... you need to discover where to insert your sensor-reading code, but it should not be difficult.

Have fun.

1 Like

Great job !

Now, is there someone brave enough to implement that directly in a timer-counter. I used to do that with PIC micro, ages ago...

My (sort of) version of Led Blink looks like this :

const int ON_DURATION    = 100;
const int OFF_DURATION   = 1000-ON_DURATION;
const int SAFETY_MARGIN  = 10;

volatile unsigned int offInterval = OFF_DURATION;
volatile unsigned int pulseWidth  = ON_DURATION;

// internal to counting routine
unsigned int timerTicks  = 0;
unsigned int timerPeriod;
byte LedState = 0;

void startCounting()
{
  // reset Timer 2
  TCCR2A = 0;
  TCCR2B = 0;

  // Timer 2 - gives us our 1 ms counting interval
  // 16 MHz clock (62.5 ns per tick) - prescaled by 128
  TCCR2B =  bit(CS20) | bit(CS22) ;
  //  counter increments every 8 µs.
  // So we count 125 of them, giving exactly 1000 µs (1 ms)
  TCCR2A = bit(WGM21) ;   // CTC mode
  OCR2A  = 125 - 1;       // count up to 125 (zero relative !!!!)

  // Timer 2 - interrupt on match (ie. every 1 ms)
  TIMSK2 = bit(OCIE2A);   // enable Timer2 Interrupt

  TCNT2 = 0;      // Counter to zero

  // Reset prescalers
  GTCCR = bit(PSRASY);        // reset prescaler now
  // start Timer 2

}  // Ready to roll !!!

//******************************************************************
//  Timer2 Interrupt Service is invoked by hardware Timer 2 every 1 ms = 1000 Hz
//  16Mhz / 128 / 125 = 1000 Hz

ISR(TIMER2_COMPA_vect)
{
  // see if we have reached timing period
  if(++timerTicks >= timerPeriod)
  {
    timerTicks = 0;              // reset interrupt counter
    LedState = !LedState;
    digitalWrite(LED_BUILTIN, LedState);
    if(LedState == HIGH)
    {
      timerPeriod = pulseWidth;
    }
    else
    {
      timerPeriod = offInterval;
    }
  }
}  // end of TIMER2_COMPA_vect

void setup()
{
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
  LedState = 0;
  digitalWrite(LED_BUILTIN, LedState);

  while(!Serial)
  {
    ;  // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("Timer Interrupt LED Blink V2");

  startCounting();
} // end of setup

void loop()
{
  
}

but it was mostly a copy-paste from Gammon's Timers...

Changing offInterval and pulseWidth inside the Loop() allowed to change the pace and ratio.

1 Like

I have been looking at "de-abstracting" for my own understanding, especially timers. Sounds like fun... who needs sleep?

I made slight modifications to @xfpd code : I toggled pin D13 up and down for each Loop and added a Logic Analyzer to visualize the signal (or timings) with PulseView.
EDIT : I also added the servo pulse for comparison and centered the pot for "ease of use"

=> the up/down toggle takes 2 x 125ns (a digitalWrite() would have taken 2 x 1.75µs) and a complete loop takes 153.375µs (+ 2 x 125ns). That is the max jitter for the servo signal.

To be tested with interrupt and, even better, with hardware PWM...

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.