Things used in this project
Hardware componentsBattery Charger, 1 Cell Lithium Battery ×1
piranha lamp beads ×10
Hand tools and fabrication machines
A small amount of acrylic pigment (green, yellow, blue and brown; if gray and white pigment is provided, the oil paint does not need to be prepared)
Light gray and white oil paint
A good-looking 2-foot button (I bought it on Taobao)Lead wire (2 mm) (If no, replace it with soft iron wire)
40 cm PVC hollow rod (I use the one with outer diameter 9 mm and inner diameter 5 mm)
A screw and nut with the length of 20mm
Story
Thanks giving day and my family’s birthdays made me as poor as a church mouse. Thinking about the coming black Friday...ORZ Think twice and I decide to make a simple but beatiful lamp to my girfriend to celebrate our 2nd year together. All I want to realise is to turn on the light just by simply lightly knocking on the table. Here, I use this BMI160 gyroscope accelerometer as the ultra-sensitive vibration switch.
1. BMI160 test:
Download the routine program of BMI160 on uno, then open the serial port to observe the data, and carry out data sampling through a series of knocking. Then, write the corresponding program through data analysis.
1. After I put it on the table, it barely shakes:
The first tree columns are gyroscope and the last three columns are acceleration. The data indicates that the gyroscope values fluctuate in the range of 0.30 and accelerometer values fluctuate in the range of 0.02 without shake and vibration.
2. After knocking.
After an evident knocking, the gyroscope values varied in the range of 17 approximately and the accelerometer values varied in the range of 0.20.Through repeated knocking and sampling with varied strength, the analysis concludes that, one knock can be determined when the value difference of gyroscope is greater than 0.30 and the value difference of accelerometer is greater than 0.03 in the meantime. Some friends may say, “it’s easy to cause incorrect knocking”. Yes. So, I finally adopt two knocks. There are two cases: 1. Two knocks are determined when the normal state is recovered in 1 s following one knock and then another knock is detected. 2. Two knocks are determined when the normal state of sensor cannot be recovered in 1 s following one knock and a difference value of accelerometer is 0.20 larger than the mean value of previous 5 difference values.
Step 2: Circuit Connection
The microusb port of charging panel is located outside the lamp holder shell for charging.
Step 3: Making Process
1. Weld lamp beams: Weld into triangular prism shape with three beams on each side and the remaining one beam at the bottom.
2. Color the earth model printed through 3D with propylene (I referred to the color of astroreality small earth model).
3. Spray the button switch periphery and screw into gray (blocking the remaining part with textured paper).
4. Take out the lead wire, start winding 10 rolls and provide the balance weight.
5. Drill a small hole at the top of earth model for threading; paint the PVC tube into gray, and make notches at both ends for placing wires:
6. Print the base model. There are model files below. After printing, spray white paint.
Step 4: Assembly
1. Welding
2. Mount it into the base and insert the periphery into the balance weight. Provide a charging panel slot on the back of model to expose the microusb port and paste bmi160 on the base plate.
3. Burn the program after assembly. I firstly tested its effect on uno; bmi160’s effect is great.
When you lightly knock on it, it can also feel. It seems that the whole table top has become a switch. You can turn on the light simply by knocking on any position for two times.
Step 5: With So High Sensitivity, Bmi1 Should Have Many Playing Methods to Be Developed by Geniuses.
Step 6: Some Friends May Ask, “What Else Function Can Bmi160 Realize?” It Can Also Detect Your Hand Shaking!
The data analysis indicates that the shake will cause continuous value change of gyroscope and accelerometer, so I used multiple test difference values in program, and set the threshold value. In case the difference value change exceeds 0.2, all values will be equal to 0.20. You can judge whether bmi160 is shaking at this moment through the mean of 35 difference values.
Some friends may ask, “What’s the meaning for detecting hand shake?”
Haha, it means someone wants to use it and then it will be turned on and become a lantern to accompany you to walk at night. If you give it to a girl, she would feel delighted.
Schematics
Connection Diagram
Code
sketch_oct18aC/C++
#include "DFRobot_BMI160.h"
DFRobot_BMI160 bmi160;
const int8_t i2c_addr = 0x69;
int ledPin=9;
float Gyro_abs[3][35]={{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};//accelX/Y/Z,GyroX/Y/Z
float Gyro_buf[3][35]={{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
float accel_abs[3][5]={{0,0,0,0,0},
{0,0,0,0,0},
{0,0,0,0,0}};
float aG_step[6]={0,0,0,0,0,0};
float aG_now[6]={0,0,0,0,0,0};
float aG_last[6]={0,0,0,0,0,0};
float aG_ave[6]={0,0,0,0,0,0};
boolean shakeFlag=0;
boolean singleFlag=0;
boolean doubleFlag=0;
boolean doubleState=0;
boolean count_begin=0;
boolean noState=1;
boolean ledState=1;
byte count_times=0;
byte state=0b00000000;
void setup(){
Serial.begin(115200);
pinMode(ledPin,OUTPUT);
digitalWrite(ledPin,LOW);
delay(100);
//init the hardware bmin160
if (bmi160.softReset() != BMI160_OK){
Serial.println("reset false");
while(1);
}
//set and init the bmi160 i2c address
if (bmi160.I2cInit(i2c_addr) != BMI160_OK){
Serial.println("init false");
while(1);
}
}
float* readDat()
{
int i = 0;
int rslt;
int16_t accelGyro[6]={0};
float dat[6]={0};
//get both accel and gyro data from bmi160
//parameter accelGyro is the pointer to store the data
rslt = bmi160.getAccelGyroData(accelGyro);
if(rslt == 0){
for(i=0;i<6;i++){
if (i<3){
//the first three are gyro datas
dat[i]=accelGyro[i]*3.14/180.0;
Serial.print(dat[i]);Serial.print("\t");
}else{
//the following three data are accel datas
dat[i]=accelGyro[i]/16384.0;
Serial.print(dat[i]);Serial.print("\t");
}
}
Serial.println();
}else{
Serial.println("err");
}
return dat;
}
void processingDat(float *addr)
{
byte x,y,z;
//Serial.print("step:");
for(x=0;x<6;x++)
{
aG_now[x]=addr[x];
aG_step[x]=aG_now[x]-aG_last[x];
aG_step[x]=abs(aG_step[x]);
//Serial.print(aG_step[x]);
//Serial.print("\t");
aG_last[x]=aG_now[x];
}
//Serial.println();
for(x=0;x<3;x++)
{
for(y=0;y<34;y++)
{
Gyro_abs[x][y]=Gyro_abs[x][y+1];
Gyro_buf[x][y]=Gyro_abs[x][y+1];
}
}
for(x=0;x<3;x++)
{
Gyro_abs[x][34]=aG_step[x];
Gyro_buf[x][34]=aG_step[x];
}
for(x=0;x<3;x++)
{
for(y=0;y<4;y++)
{
accel_abs[x][y]=accel_abs[x][y+1];
}
}
for(x=0;x<3;x++)
{
accel_abs[x][4]=aG_step[x+3];
}
for(x=0;x<3;x++)
{
for(y=0;y<35;y++)
{
if(Gyro_buf[x][y]>=0.35)
{
Gyro_buf[x][y]=0.35;
}
}
aG_ave[x]=(Gyro_buf[x][0]+Gyro_buf[x][1]+Gyro_buf[x][2]+Gyro_buf[x][3]+Gyro_buf[x][4]+
Gyro_buf[x][5]+Gyro_buf[x][6]+Gyro_buf[x][7]+Gyro_buf[x][8]+Gyro_buf[x][9]+
Gyro_buf[x][10]+Gyro_buf[x][11]+Gyro_buf[x][12]+Gyro_buf[x][13]+Gyro_buf[x][14]+
Gyro_buf[x][15]+Gyro_buf[x][16]+Gyro_buf[x][17]+Gyro_buf[x][18]+Gyro_buf[x][19]+
Gyro_buf[x][20]+Gyro_buf[x][21]+Gyro_buf[x][22]+Gyro_buf[x][23]+Gyro_buf[x][24]+
Gyro_buf[x][25]+Gyro_buf[x][26]+Gyro_buf[x][27]+Gyro_buf[x][28]+Gyro_buf[x][29]+
Gyro_buf[x][30]+Gyro_buf[x][31]+Gyro_buf[x][32]+Gyro_buf[x][33]+Gyro_buf[x][34])/35;
}
}
void checkShake()
{
if(aG_ave[0]>=0.30||aG_ave[1]>=0.30||aG_ave[2]>=0.30)
{
shakeFlag=1;
clearBeat();
}
else
{
shakeFlag=0;
}
if(shakeFlag==1)
{
digitalWrite(ledPin,LOW);
ledState=0;
}
else
{
if(doubleState==0)
{
digitalWrite(ledPin,HIGH);
ledState=1;
}
}
}
void doubleAction()
{
if(doubleFlag==1)
{
doubleFlag=0;
if(ledState)
{
ledState=0;
}
else
{
ledState=1;
}
digitalWrite(ledPin,ledState);
}
}
void checkBeat()
{
if(shakeFlag==0)
{
if((((aG_step[0]>=0.2)||(aG_step[1]>=0.2)||(aG_step[2]>=0.2))
&&((aG_step[3]>=0.04)||(aG_step[4]>=0.04)||(aG_step[5]>=0.04)))
||((aG_step[3]>=0.05)||(aG_step[4]>=0.05)||(aG_step[5]>=0.05)))
{
state=state<<1;
state=state|0b00000001;
if((noState==1)&&(singleFlag==0))
{
singleFlag=1;
count_begin=1;
noState=0;
}
else if((noState==1)&&(singleFlag==1))
{
doubleFlag=1;
doubleState=~doubleState;
singleFlag=0;
doubleAction();
count_begin=0;
count_times=0;
noState=0;
}
}
else
{
state=state<<1;
if((state&0b00001111)==0b00000000)
{
noState=1;
}
}
}
//Serial.println("beat");
}
void clearBeat()
{
doubleFlag=0;
singleFlag=0;
count_begin=0;
count_times=0;
}
boolean checkGyro()
{
float a=0.0,b=0.0,c=0.0;
byte x=0;
boolean flag=0;
for(x=0;x<3;x++)
{
aG_ave[x]=(accel_abs[x][3]+accel_abs[x][2]+accel_abs[x][1]+accel_abs[x][0])/4;
}
a=accel_abs[0][4]-aG_ave[0];
b=accel_abs[1][4]-aG_ave[1];
c=accel_abs[2][4]-aG_ave[2];
if((a>=0.5)||(b>=0.5)||(c>=0.5))
{
flag=1;
}
return flag;
}
void countPlus()
{
if(count_begin==1)
{
count_times++;
if((count_times>=4)&&(count_times<=20))
{
if((noState==0)&&(singleFlag==1)&&(checkGyro()))
{
doubleFlag=1;
if(doubleState)
{
doubleState=0;
}
else
{
doubleState=1;
}
doubleAction();
singleFlag=0;
count_begin=0;
count_times=0;
noState=0;
}
}
if(count_times>20)
{
clearBeat();
}
}
//Serial.println("plus");
}
void loop(){
processingDat(readDat());
checkShake();
checkBeat();
countPlus();
}