Problem with measuring vibrations (Arduino UNO + step motor + accelerometer)

Dear all,

I’m trying to measure vibrations of the motor’s shaft that is oscillating due to an eccentric load. For that, I am using the MPU 6050 6 axis accelerometer. The motor is a NEMA 17 stepper, connected to Arduino UNO via the EasyDriver v4.4.
I first uploaded my code for the stepper, where I have 2 buttons to control the rotation direction (if you press the left, it goes clockwise and if you press the right button it goes counter clockwise). This code works fine.
Later I uploaded the code only for the accelerometer and it worked fine, however when I’m trying to combine both so that the vibrations could be measured while the motor is running, apparently I’m losing steps of the motor. Here is the code:

#include<Wire.h>
const int MPU_addr = 0x68; // I2C address of the MPU-6050
int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;

#define RPMS                300.0
#define STEP_PIN                9
#define DIRECTION_PIN           8
#define GO_PIN_L                3
#define GO_PIN_R                4

#define STEPS_PER_REV         200
#define MICROSTEPS_PER_STEP     8
#define MICROSECONDS_PER_MICROSTEP   (1000000/(STEPS_PER_REV * MICROSTEPS_PER_STEP)/(RPMS / 60))

uint32_t LastStepTime = 0;
uint32_t CurrentTime = 0;

int Distance = 0;

void setup() {
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(9600);

  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIRECTION_PIN, OUTPUT);
  digitalWrite(STEP_PIN, LOW);
  digitalWrite(DIRECTION_PIN, LOW);
  pinMode(GO_PIN_L, INPUT);
  pinMode(GO_PIN_R, INPUT);
}

void loop() {
  Distance = Distance + 1;   // record this step
  if (digitalRead(GO_PIN_L) == LOW)
  {
    CurrentTime = micros();
    digitalWrite(8, LOW);
    if ((CurrentTime - LastStepTime) > MICROSECONDS_PER_MICROSTEP)
    {
      LastStepTime = CurrentTime;
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds((MICROSECONDS_PER_MICROSTEP * 0.9) / 2);
      digitalWrite(STEP_PIN, LOW);
      delayMicroseconds((MICROSECONDS_PER_MICROSTEP * 0.9) / 2);
    }
  }
  if (digitalRead(GO_PIN_R) == LOW)
  {
    CurrentTime = micros();
    digitalWrite(8, HIGH);
    if ((CurrentTime - LastStepTime) > MICROSECONDS_PER_MICROSTEP)
    {
      LastStepTime = CurrentTime;
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds((MICROSECONDS_PER_MICROSTEP * 0.9) / 2);
      digitalWrite(STEP_PIN, LOW);
      delayMicroseconds((MICROSECONDS_PER_MICROSTEP * 0.9) / 2);
    }
  }
//  Wire.beginTransmission(MPU_addr);
//  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
//  Wire.endTransmission(false);
//  Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers
//  float AcX = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
//  float AcY = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
//  float AcZ = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
//  Tmp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
//  // GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
//  // GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
//  // GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
//  Serial.print("AcX = "); Serial.println(AcX / 16384);
//  Serial.print(" AcY = "); Serial.println(AcY / 16384);
//  Serial.print(" AcZ = "); Serial.println(AcZ / 16384);
//  Serial.print(" Tmp = "); Serial.print(Tmp / 340.00 + 36.53);
//  Serial.println("");
//  // Serial.print(" | GyX = "); Serial.print(GyX);
//  // Serial.print(" | GyY = "); Serial.print(GyY);
//  // Serial.print(" | GyZ = "); Serial.println(GyZ);
//  delay(333);
}

So the commented portion of the code is used to read and print accelerations. Since this is in the same loop as the code for the motor, I’m sure that the delay(333) has a negative effect, but also when I tried step-by-step to include lines of code for accelerometer, the motor slowly starter to losing speed and steps…

Does anyone of you have a clue how this could be done so that both devices (the motor with EasyDriver v 4.4 and the accelerometer) could run simultaneously?
Kind regards,

Luka

The motor is a NEMA 17 stepper

But, what color is it?

I'm sure that the delay(333) has a negative effect

Of course it does. The blink without delay example shows how to do something (blink an LED, but what doesn't really matter) some time after an event, without using delay().

It's very similar to what you are already using to step periodically.

Okay thank you, Paul, I am well aware of these problems but I don't know how I could run both codes (for step motor and accelerometer) simultaneously, without interfering steppers code with the accelerometer's one... There wouldn't be a problem if I had 2 arduinos, but only having one, it seems quite difficult to be able to do both things at the same time...

I found some projects where people control the stepper with the accelerometer's signal, but that is different, because the stepper depends on the accelerometer's measurements, in my case, they both run independently on each other...

Luka

Ok so since no-one was able to give me straight-forward answers on this, my best friend who is an electric guru as far as I am concerned, helped me. He proposed to use timer settings in the void setup, like this:

#include<Wire.h>
const int MPU_addr = 0x68; // I2C address of the MPU-6050
int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;

#define RPMS                300.0
#define STEP_PIN                9
#define DIRECTION_PIN           8
#define GO_PIN_L                3
#define GO_PIN_R                4

#define STEPS_PER_REV         200
#define MICROSTEPS_PER_STEP     8
#define MICROSECONDS_PER_MICROSTEP   (1000000/(STEPS_PER_REV * MICROSTEPS_PER_STEP)/(RPMS / 60))

uint32_t LastStepTime = 0;
uint32_t CurrentTime = 0;

int Distance = 0;

void setup() {
  bitClear(SREG, 7);
  pinMode(10, OUTPUT);

  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  TCCR1A = _BV(COM1B1) | _BV(WGM10) | _BV(WGM11);
  TCCR1B = _BV(WGM12) | _BV(WGM13) | _BV(CS10); //prescaler 1, fast PWM, OCR1A as TOP
  OCR1A = 2423; //timer šteje do 444, tako dobim PWM frekvenco 36,363kHz
  OCR1B = int(OCR1A / 2); //prilagajam duty cyle, naj bo kar 50%

  bitSet(SREG, 7); //global interrupt enable

  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(9600);

  pinMode(DIRECTION_PIN, OUTPUT);
  digitalWrite(DIRECTION_PIN, LOW);
  pinMode(GO_PIN_L, INPUT);
  pinMode(GO_PIN_R, INPUT);
}

void loop() {
  Distance = Distance + 1;   // record this step
  if (digitalRead(GO_PIN_L) == LOW)
  { TCCR1A = 0;
    TCCR1B = 0;
    TCNT1 = 0;
    delay(100);
    TCCR1A = _BV(COM1B1) | _BV(WGM10) | _BV(WGM11);
    TCCR1B = _BV(WGM12) | _BV(WGM13) | _BV(CS10); //prescaler 1, fast PWM, OCR1A as TOP
    OCR1A = 2423; //timer šteje do 444, tako dobim PWM frekvenco 36,363kHz
    OCR1B = int(OCR1A / 2); //prilagajam duty cyle, naj bo kar 50%

    digitalWrite(8, LOW);
  }
  if (digitalRead(GO_PIN_R) == LOW)
  {
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  TCCR1A = _BV(COM1B1) | _BV(WGM10) | _BV(WGM11);
  TCCR1B = _BV(WGM12) | _BV(WGM13) | _BV(CS10); //prescaler 1, fast PWM, OCR1A as TOP
  OCR1A = 2423; //timer counts to 444, PWM frequency is thereby 36,363kHz
  OCR1B = int(OCR1A / 2); //duty cyle is 50%

    digitalWrite(8, HIGH);
  }
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers
  float AcX = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
  float AcY = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  float AcZ = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  // GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  // GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  // GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  Serial.print("AcX = "); Serial.println(AcX / 16384);
  Serial.print(" AcY = "); Serial.println(AcY / 16384);
  Serial.print(" AcZ = "); Serial.println(AcZ / 16384);
  Serial.print(" Tmp = "); Serial.print(Tmp / 340.00 + 36.53);
  Serial.println("");
  // Serial.print(" | GyX = "); Serial.print(GyX);
  // Serial.print(" | GyY = "); Serial.print(GyY);
  // Serial.print(" | GyZ = "); Serial.println(GyZ);
  delay(333);
}

So the portion in void setup

  bitClear(SREG, 7);
  pinMode(10, OUTPUT);

  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  TCCR1A = _BV(COM1B1) | _BV(WGM10) | _BV(WGM11);
  TCCR1B = _BV(WGM12) | _BV(WGM13) | _BV(CS10); //prescaler 1, fast PWM, OCR1A as TOP
  OCR1A = 2423; //timer counts to 444, PWM frequency is thereby 36,363kHz
  OCR1B = int(OCR1A / 2); //duty cyle is 50%

  bitSet(SREG, 7); //global interrupt enable

rotates the step motor WITHOUT any code in the void loop, void loop is only used to change the rotation direction of the motor by using the buttons that I incorporated (GO_PIN_L and GO_PIN_R) and to measure the acceleration with the accelerometer.

I hope this helps to anyone that might have similar problems.
Kind regards,

Luka