The design sketch is as follows:
#include
#include
#include
#include
#include
#define PRINT_RAW_DATA 0
#define PRINT_STD_DATA 0
bool mouse_disabled=false;
void setup()
{
Serial.begin(9600); //Equip 9600
voice_init();
mouse_move_init();
musle_click_init();
Mouse.begin();
Keyboard.begin();
Serial.print("Initialized\n");
}
void loop()
{
handle_voice();
if(!mouse_disabled){
mouse_move();
handle_musle_click();
}
}
/*---------------------------------------------------------------mouse movement-------------------------------------------------------------------------*/
float Angles[3];
float xLast,yLast;
bool right_clicked=false;
bool left_click=false;
float view_center;
float view_angle=30;
int shake_x,shake_y;
#define SHAKE_LIMIT 16
void mouse_move_init(){
Serial1.begin(9600);
}
void mouse_move(){
int x,y;
float xDelta,yDelta;
float xNow,yNow;
float X_RATE=0.06;//0.05;
float Y_RATE=0.04;//0.05;
get_IMU_data();
xNow=Angles[2];
yNow=Angles[0];
if(xLast==0){
xLast=xNow;
}
if(yLast==0){
yLast=yNow;
}
xDelta=xNow-xLast;
yDelta=yNow-yLast;
x=xDelta/X_RATE;
y=yDelta/Y_RATE;
if((x!=0 || y!=0)){
if(xLast*xNow<0){
x=xLast/abs(xLast)*(360/X_RATE-abs(x));
}
int out_x=x, out_y=y;
if(left_click==true){ //do not let mouse move when left button pressed, in case it's during right pressing.
shake_x+=x;
shake_y+=y;
}else{
while(abs(out_x)>120){
out_x=out_x/abs(out_x)*(abs(out_x)-120);
Mouse.move(-(out_x/abs(out_x)*120), 0);
}
while(abs(out_y)>120){
out_y=out_y/abs(out_y)*(abs(out_y)-120);
Mouse.move(0,-(out_y/abs(out_y)*120));
}
Mouse.move(-out_x, -out_y);
Serial.print("xNow=");Serial.print(xNow);Serial.print(" yNow=");Serial.print(yNow);
Serial.print(" xDelta=");Serial.print(xDelta);Serial.print(" yDelta=");Serial.print(yDelta);Serial.print(" x=");Serial.print(x);Serial.print(" y=");Serial.println(y);
}
}
xLast=xLast+((int)(xDelta/X_RATE))*X_RATE;
yLast=yLast+((int)(yDelta/Y_RATE))*Y_RATE;
}
void get_IMU_data(){
if(Serial1.available()) {
JY901.CopeSerialData(Serial1.read()); //Call JY901 data cope function
for(int i=0; i<3; i++){
Angles[i]=(float)JY901.stcAngle.Angle[i]/32768*180;
//Angles[i]=(float)JY901.stcGyro.w[i]/32768*2000;
}
}
}
/*-------------------------------------------------------voice detect--------------------------------------------------------------------*/
#define buzzerPin 7
#define VOICE_ARRAY 16
bool start_switch = false;
int current_mode=0;
VoiceRecognition Voice; //classify a voice recognition object
char *voices[VOICE_ARRAY]=
{"mushroom cloud", //0
"input mode", //1
"command mode", //2
"new open", //3 ctrl+n
"close", //4 alt+f4
"copy", //5 ctr+c
"paste", //6 ctr+v
"good weather", //7
"maker contest",//8
"tou kong shu ru she bei", //9
"qiao", //10
"I am so happy", //11
"everything is fine", //12
"turn on the mouse", //13
"disable the mouse", //14
"normal mode" //15
};
void voice_init(){
pinMode(buzzerPin, OUTPUT);
Voice.init(); //Initial VoiceRecognition mode
for(int i=0; i2){
Keyboard.print(voices[voice_id]);
}
}
if(current_mode==2){ //command mode
char ctrlKey = KEY_LEFT_CTRL;
char altKey = KEY_LEFT_ALT;
switch(voice_id){
case 3:
Keyboard.press(ctrlKey);
Keyboard.press('n');
delay(10);
Keyboard.release('n');
Keyboard.release(ctrlKey);
break;
case 4:
Keyboard.press(altKey);
Keyboard.press(KEY_F4);
delay(10);
Keyboard.release(KEY_F4);
Keyboard.release(altKey);
break;
case 5:
Keyboard.press(ctrlKey);
Keyboard.press('c');
delay(10);
Keyboard.release('c');
Keyboard.release(ctrlKey);
break;
case 6:
Keyboard.press(ctrlKey);
Keyboard.press('v');
delay(10);
Keyboard.release('v');
Keyboard.release(ctrlKey);
break;
}
}
}
int voice_control(){
int id = Voice.read();
if(id >= VOICE_ARRAY || id < 0){
return -1;
}
Serial.println(voices[id]);
switch(id)
{
case 0: //start the order
start_switch = true;
Serial.print("Start command\n");
tone(buzzerPin, 5000, 200);
delay(350);
tone(buzzerPin, 5000, 200);
break;
case 1: //input mode
if(start_switch){
current_mode=1;
start_switch = false;
Serial.print("input mode\n");
tone(buzzerPin, 5000, 200);
}
break;
case 2: //command mode
if(start_switch){
current_mode=2;
start_switch = false;
Serial.print("Command mode\n");
tone(buzzerPin, 5000, 200);
}
break;
case 15: //normal mode
if(start_switch){
current_mode=0;
start_switch = false;
Serial.print("normal mode\n");
tone(buzzerPin, 5000, 200);
}
break;
case 14:
if(start_switch){ //disable the mouse
mouse_disabled=true;
start_switch = false;
Serial.print("Mouse disabled\n");
tone(buzzerPin, 5000, 200);
}
break;
case 13:
if(start_switch){ //turn on the mouse
mouse_disabled=false;
start_switch = false;
Serial.print("Mouse turn on\n");
tone(buzzerPin, 5000, 200);
}
break;
default:
//Serial.print("nothing...");
start_switch = 0;
break;
}
return id;
}
/*----------------------------------------------------------- musle click---------------------------------------------------------------------------*/
int sensorPin = A0; // select the input pin for the potentiometer
int sensorData = 0; // variable to store the value coming from the sensor
int errorPin = 13;
bool errorHappen = false;
int calib_count=0;
long calib_data=0;
unsigned long errorTime=0;
#define DATA_SIZE 15
int musle_data[DATA_SIZE];
int diff_data[DATA_SIZE];
#define MIN_VALUE 150
#define MAX_VALUE 600
#define STD_ABNORMAL 250
#define STD_VALUE 10
#define STD_EDGE 3
unsigned long press_timestamp=0;
unsigned long release_timestamp=0;
int show_press_real=0;
#define PRESS_DELAY 40
#define RELEASE_DELAY 15
#define RIGHT_BT_DETECT 600
#define SAMPLE_DELAY 10
unsigned long last_sample_time=millis();
void musle_click_init() {
Serial.begin(9600);
pinMode(errorPin, OUTPUT);
digitalWrite(errorPin, HIGH);
errorTime = millis();
Mouse.begin();
}
void handle_musle_click() {
if(millis()-last_sample_time > SAMPLE_DELAY){
sensorData = analogRead(sensorPin);
#if PRINT_RAW_DATA
Serial.println(sensorData);
#endif
for(int i=0; iSTD_VALUE){
show_press=30;
}
#if PRINT_STD_DATA
Serial.print(show_press);Serial.print(" ");
Serial.print(show_press_real);Serial.print(" ");
Serial.println(std_value);
#endif
if(std_value>=STD_ABNORMAL || std_value<0){
errorTime = millis();
digitalWrite(errorPin, HIGH);
errorHappen = true;
calib_data=0;
calib_count=0;
}
if(errorHappen){
if(std_value=0){ //when error happened, make sure musle std data is below STD_VALUE for 1s.
calib_data+=std_value;
calib_count++;
}else{
errorTime = millis();
}
if(millis()-errorTime > 1500){
digitalWrite(errorPin, LOW);
errorHappen = false;
calib_data=calib_data/calib_count; //re-calibrate the musle average data.
}
}
if(errorHappen){
release_timestamp=millis();
press_timestamp=0;
show_press_real=0;
if(Mouse.isPressed(MOUSE_LEFT)){
Mouse.release(MOUSE_LEFT);
}
}
if(!errorHappen){
if(std_value>calib_data+STD_EDGE){
if(press_timestamp==0){
press_timestamp=millis();
}else{
unsigned long current_time = millis();
if (current_time-press_timestamp>PRESS_DELAY && current_time-press_timestamp<=RIGHT_BT_DETECT) { //make sure left-click can be detected.
left_click=true;
}
if(sqrt(shake_x*shake_x+shake_y*shake_y)>SHAKE_LIMIT){ //when mouse moved, let left button "press"
if(!Mouse.isPressed(MOUSE_LEFT)){
Mouse.press(MOUSE_LEFT);
}
left_click=false;
}else{
if(current_time-press_timestamp>RIGHT_BT_DETECT && right_clicked==false){ //mouse did not move, and is pressed bigger than threshold value.
Mouse.click(MOUSE_RIGHT);
right_clicked=true;
left_click=false;
}
}
release_timestamp=0;
show_press_real=calib_data+STD_EDGE;
}
}else{
if(release_timestamp==0){
release_timestamp=millis();
}else if (millis()-release_timestamp>RELEASE_DELAY) { //when musle released, clear all the flags.
if(left_click==true){
Mouse.click(MOUSE_LEFT);
}
if(Mouse.isPressed(MOUSE_LEFT)){
Mouse.release(MOUSE_LEFT);
}
right_clicked=false;
left_click = false;
shake_x=0;
shake_y=0;
press_timestamp=0;
show_press_real=calib_data;
}
}
}
}
long int get_std(){
int average = 0;
int sum = 0;
long int std = 0;
for(int i=0; i MAX_VALUE){
return STD_ABNORMAL;
}
}
average = sum/DATA_SIZE;
for(int i=0; i