Tag: accelerometer

Sending motion data to the Blynk app (part 2 of the Blynk tutorial)

In the first blog post we explained the basics of controlling the body interaction 2 (BI2) vibrator development board using the concept of  (virtual) pins. This time we want to send data from the BI2 board to the Blynk app. The BI2 has the MPU-9250 9DoF (9 Degrees of Freedom) IMU (Inertial Measurement Unit) sensor on board. This sensor is a combination of an accelerometer, gyroscope and magnetometer. Especially the accelerometer is important for motion detection. This could be used for controlling the vibrator as show with the body interaction 1 (BI1).

For measuring the motion data we use the asukiaa library. Please search and install the library in the Arduino library manager.

In the program code the library must be included and a MPU9250 sensor object must be defined. Finally we need several variables of the type float.

#include <MPU9250_asukiaaa.h>
MPU9250 mySensor;
float aX, aY, aZ, mDirection, pitch, roll, yaw;

In the setup part of the program we need to tell the MPU9250 how it is connected to the ESP8266 microcontroller. [The MPU9250 IMU is connected by the I2C bus to the ESP8266 microcontroller: the sda pin of the IMU is connected to pin 4, the scl pin to pin 5. The connection between MPU9250 and ESP8266 is managed with the standard Wire library.]

For using the accelerometer and magnetometer we have to initialize the sensor with a begiAccel() call to the IMU library.

Wire.begin(4, 5); //sda, scl
mySensor.setWire(&Wire);
mySensor.beginAccel();
mySensor.beginMag();

We have to tell the program how often data is sent to the app. Therefore we need an important concept in microcontroller programming:

Timer

With the help of the timer we can tell the microcontroller to do a given tasks again and again e.g. after 1000 microsecond. You cannot use the delay function to pass time as this would interrupt the important call to the Blynk.run(); function which is located in the loop part of the program.

First we have to define an object of type Timer.

BlynkTimer timer;

In the setup part we have to say how often what the timer has to do. in this example the timer will call the function myTimerEvent every 1000 microsecond.

timer.setInterval(1000L, myTimerEvent);

In the loop part of the program we have to call the timer to keep things going:

timer.run(); // Initiates BlynkTimer

Now we need the function myTimerEvent what has to be done every 1000 seconds.

void myTimerEvent()
{
  // here add was has to be done
}

First we have to update the sensors (accelUpdate, magUpdate). Then we read out the acceleration data in the X, Y and direction. You can already use this data but they are hard to catch. Therefore we can calculate the pitch, roll and yaw. These are angles from -180° to +180°. The calculation is complicated and I don’t understand it. But with the given formulas you get a very rough approximation which makes the data quite accessible.

void myTimerEvent() {
  mySensor.accelUpdate();
  aX = mySensor.accelX();
  aY = mySensor.accelY();
  aZ = mySensor.accelZ();

  // calculate pitch, roll, yaw (raw approximation)
  float pitch = 180 * atan (aX/sqrt(aY*aY + aZ*aZ))/M_PI;
  float roll = 180 * atan (aY/sqrt(aX*aX + aZ*aZ))/M_PI;
  float yaw = 180 * atan (aZ/sqrt(aX*aX + aZ*aZ))/M_PI;

  // read gyroscope update
  mySensor.magUpdate();
  mDirection = mySensor.magHorizDirection();
}

Finally we send the data back to the Blynk app. Now we use the virtual pins. For the variables pitch we  use virtual pin 2 (V2), for roll V3, for yaw V4 and for mDirection V5. We have to add the following line to the myTimerEvent function.

void myTimerEvent() {
  // send data to app via virtual ports, e.g. virtual pin V2 is set to pitch
  Blynk.virtualWrite(V2, pitch);
  Blynk.virtualWrite(V3, roll);
  Blynk.virtualWrite(V4, yaw);
  Blynk.virtualWrite(V5, mDirection);
}

Now the data are continously sent to the Blynk app. To visualize the data we add the widget SuperChart.

For each variable we have to define the input (virtual) pin. For pitch we use the virtual pin V2. In addition we define the color and style of the graph and more.

 

Finally the super graph shows us the date from the accelerometer which are updated every second.

First part of the tutorial (setup Arduino, setup Blynk, LED and motor control) is here

Here is the complete code:

 

/*************************************************************
bodyinteraction.org
sample program for reading MPU data, setting LED color and motor speed
*/
#define BLYNK_PRINT Serial
// include this library in the Arduino library manager
#include "FastLED.h"

// How many leds in your strip?
#define NUM_LEDS 1
// LED data pin is connected to pin?
#define DATA_PIN 14

// Define the array of leds
CRGB leds[NUM_LEDS];
int wave;

// include this library in the Arduino library manager
#include <MPU9250_asukiaaa.h>
MPU9250 mySensor;
float aX, aY, aZ, mDirection, pitch, roll, yaw;

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "Your Auth Token XXXXXXXXXX";

// Your WiFi credentials.
char ssid[] = "YOUR SSID   XXXXXXXXXXXXXX";
char pass[] = "YOUR Password XXXXXXXXXXXX";
BlynkTimer timer;

void myTimerEvent()
{
  // read acceleration data
  mySensor.accelUpdate();
  aX = mySensor.accelX();
  aY = mySensor.accelY();
  aZ = mySensor.accelZ();
  // read gyroscope update
  mySensor.magUpdate();
  mDirection = mySensor.magHorizDirection();
  // calculate pitch, roll, yaw (raw approximation)
  float pitch = 180 * atan (aX/sqrt(aY*aY + aZ*aZ))/M_PI;
  float roll = 180 * atan (aY/sqrt(aX*aX + aZ*aZ))/M_PI;
  float yaw = 180 * atan (aZ/sqrt(aX*aX + aZ*aZ))/M_PI;
  // send data to app via virtual ports, e.g. virtual pin V2 is set to pitch
  Blynk.virtualWrite(V2, pitch);
  Blynk.virtualWrite(V3, roll);
  Blynk.virtualWrite(V4, yaw);
  Blynk.virtualWrite(V5, mDirection);
}

BLYNK_WRITE(V0) // set RGB color values which are transmitted from the app as V0 (virtual pin 0)
{ 
  int i = param[0].asInt();
  int j = param[1].asInt();
  int k = param[2].asInt();
  leds[0].setRGB(j,i,k);
  FastLED.show();
}

void setup()
{
  Serial.begin(115200);
  FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);

  Wire.begin(4, 5); //sda, scl
  mySensor.setWire(&Wire);
  mySensor.beginAccel();
  mySensor.beginMag();

  Blynk.begin(auth, ssid, pass);
  timer.setInterval(1000L, myTimerEvent);
}

void loop()
{
  Blynk.run();
  timer.run(); // Initiates BlynkTimer
}

 

Please feel free to comment or write to jacardano@gmail.com

Programming the body interaction 1 (BI) part 2

Reading the accelerometer data

The BI has built in the accelerometer Bosch BMA020. The BMA020 is a 3-axis accelerometer and reads acceleration data in X, Y and Z direction. The accelerometer is used to control the operation of the BI. It captures changes in movement eg. slowing, speed up, change of direction. Steady movement can not be captured. Nevertheless it is possible to calculate the orientation of the BI eg. upright or downright.

To read out the data we use the JeeLib – a great library we will use to control other devices and read out sensors (read here how to install). The library must be included, add:

#include <JeeLib.h>

In JeeLib the accelerometer is called GravityPlug. It is not connected to a pin directly (as the vibration motor). Instead it is connected to the I2C bus, but at this point ignore the details. Just add:

PortI2C myBus (1);
GravityPlug sensor (myBus);

Now we can read out the accelerometer using the name “sensor”.

Now we want to read out the sensor. This is done by adding “.getAxes()” to “sensor”. But before we declare a new variable called p, where we the acceleration in X-, Y- and Z-axis is stored:

const int* p = sensor.getAxes();

The acceleration in x-direction is stored in p[0], y-direction in p[1] and z-direction in p[2].

p[0], p[1] and p[2] are integers. When there is no acceleration (eg. the BI is not moved) the value would be approx 0. If you move it horizontally to the right it will return positive values. If you move it horizontal to the left it will return negative values. (Could be vice versa, it depends on the orientation of the accelerometer).

We introduce 3 new variables x, y and z for storing the values:

int x,y,z;

As we are not interested in the direction of the acceleration we convert negative values to positives. This is known as the absolute value and is computed with the function abs(), see: https://www.arduino.cc/en/Reference/Abs

x = abs(p[0]); 
y = abs(p[1]); 
z = abs(p[2]);

We also introduce a further variable called “threshold”. Only values above a given threshold will change the behaviour of the vibration motor. This is useful to ignore the gravity which influences at least of the axises.

int threshold = 250;

Now we put everything together. The script should start the vibration motor if there is acceleration either in x, y or z direction above a threshold. Otherwise the motor is off.

#include JeeLib.h;
PortI2C myBus (1);
GravityPlug sensor (myBus);

int motor = 3;
int threshold = 100;
int x, y, z;

void setup() {
 pinMode(motor, OUTPUT);
}

void loop() {
  const int* p = sensor.getAxes();
  x = abs(p[0]);
  y = abs(p[1]);
  z = abs(p[2]);
  analogWrite(motor, 0); //motor off
  if (x &amp;gt; threshold || y &amp;gt; threshold || z &amp;gt; threshold) {
    analogWrite(motor, 255); //motor on
 }
 delay(2000);  // wait for 2 second
}

Let’s take a further look at the loop. Every time when the instruction in the loop are executed, the sensor will be read out. The absolute values are stored in x, y and z by using the abs() function. Then the motor is set off.

The following statement

analogWrite(motor, 255);

will turn the motor on if the following condition is true:

(x > threshold || y > threshold || z > threshold)

The condition is true when either x > threshold or y > threshold or z > threshold. You can read “||” as logical or. Read more about the if function and boolean operators (or, and, not).

Finally a delay functions stops further processing for 2 seconds. Then the loop will be executed again, starting to read out the accelerometer values.

In depth example of reading the BMA020:

http://playground.arduino.cc/Main/SoftwareI2CLibrary

Jeelib GravityPlug  – how to read out the BMA020 with the JeeLib library.

http://jeelabs.org/2010/03/22/gravity-plug/

More about Acceleration and Gyros and how to calculate the orientation:

http://www.instructables.com/id/Accelerometer-Gyro-Tutorial/

 

Copy the source code (script) into an Arduino window. Then click compile . If everything is ok you get the message done compiling. sucessful compiling

Then upload the code to the body interaction 1. If everything is ok you get the message done uploading. You can ignore the warnings. done uploadingBut if you don’t get the done uploading message something went wrong. in this case read the following post:

https://bodyinteraction.com/2016/01/08/get-started-with-arduino-1-6-7-and-windows-10/

Go to the next tutorial (part 3): ramps

%d bloggers like this: