项目要求
基于FDC2214电容检测模块的手势识别装置,装置具有两种模式,在判决模式下能对指定人员进行猜拳游戏和划拳游戏的判决。在训练模式下,对任意人员进行有限次训练之后,能正确进行上一模式中的手势判决。(主要手势有石头、剪刀、布、1、2、3、4和5)
模块划分
根据最基本的系统框架图,一步步抽象出模块,得到七个部分
- FDC2214的驱动代码
- 数据采集与处理
- 手势的判别
- 按键
- LCD显示屏
- 汉字点阵
- 算法框架搭建
在项目中,我负责的编码部分比较多,包括FDC2214的驱动代码,数据的采集与处理以及手势的判别。话不多说,贴代码。
代码部分
- FDC2214的驱动代码
.h文件
#ifndef __FDC2214_H
#define __FDC2214_H
#include "iic.h"
#include "sys.h"
typedef enum
{
FDC2214_channel_0 = 0x00,
FDC2214_channel_1 = 0x01,
FDC2214_channel_2 = 0x02,
FDC2214_channel_3 = 0x03,
}FDC2214_channel;
#define FILTERGROUP 8 //滤波数组长度
#define FDC_Address_W 0x54
#define FDC_Address_R 0x55
#define FDC_DATA_CH0_HIGH 0x00
#define FDC_DATA_CH0_LOW 0x01
#define FDC_DATA_CH1_HIGH 0x02
#define FDC_DATA_CH1_LOW 0x03
#define FDC_DATA_CH2_HIGH 0x04
#define FDC_DATA_CH2_LOW 0x05
#define FDC_DATA_CH3_HIGH 0x06
#define FDC_DATA_CH3_LOW 0x07
#define MANUDACTURER_ID 0x5449
#define MANUDACTURER_ID_ADDR 0x7E
#define DEVICE_ID 0x3055
#define DEVICE_ID_ADDR 0x7F
extern u16 Receive_Date[2];
extern u16 C_Data;
void FDC_Init(void); //FDC2214初始化函数
void FDC_write_reg(u8 addr,u16 value); //向FDC2214寄存器写的函数
u16 FDC_read_reg(u8 addr); //从FDC2214读16位数据的函数
u8 FDC_read_reg_high(u8 addr); //从FDC2214读高8位数据的函数
u8 FDC_read_reg_low(u8 addr); //从FDC2214读低8位数据的函数
u16 FDC_CH2_GetData(void);
int FilterWeightedSliding(int data);
u16 FrequencyToCapacitance(u32 frequency);
//void FDC_GetChannelData(FDC2214_channel channel,u32 *DATA);
#endif
.c文件
#include "FDC2214.h"
#include "delay.h"
#include "lcd.h"
#include "stdio.h"
/*-----------将频率值降低512倍--------------*/
u16 FrequencyToCapacitance(u32 frequency)
{
return frequency >> 9;
}
/*-----------加权滑动滤波Weighted sliding filtering--------------*/
int FilterWeightedSliding(int data)
{
static short int DataGroup[FILTERGROUP] = {0};
int sum = 0;
//权值数组的选取很重要!!!
static unsigned char power[8] = {1,2,3,4,5,6,7,8};
// static unsigned char power[8] = {1,1,2,2,2,4,4,8};
// static unsigned char power[8] = {1,2,4,7,11,16,22,29};
// static unsigned char power[8] = {1,2,4,8,16,32,64,128};
// static unsigned char power[8] = {1,1,2,3,5,8,20,60};
// static unsigned char power[8] = {1,8,14,19,23,26,28,29};
static unsigned char p = 0;//队列指针
int i, k;
//队列指针不要乱来
if(p == FILTERGROUP)
{
p = 0;
}
DataGroup[p] = data;
p++;
//这个队列只有入队,没有出队,所以不用考虑队首队尾指针的问题
for(i=0; i<FILTERGROUP; i++)
{
k = (p+i) % (FILTERGROUP);//就这么一句,我折腾了一晚上,简直!@#$%^&*
sum += DataGroup[k] * power[i];//乘上对应的权值
}
return sum >> 4;//除以合适的数值,方便处理
}
/*-----------FDC2214初始化函数--------------*/
void FDC_Init(void)
{
u16 D_ID = 0; //制造商ID
u16 M_ID = 0; //驱动ID
M_ID = FDC_read_reg(MANUDACTURER_ID_ADDR); //读取制造商ID
D_ID = FDC_read_reg(DEVICE_ID_ADDR); //读取驱动ID
if(M_ID != MANUDACTURER_ID || D_ID != DEVICE_ID)
{
printf("初始化失败\r\n");
return;
}
LCD_ShowxNum(10,40,D_ID,5,24,0);
LCD_ShowxNum(10,70,M_ID,5,24,0);
FDC_write_reg(0x08,0x8329); //(CHx_RCOUNT*16)/55M ==9.76ms,,每10ms左右可以读一次值
FDC_write_reg(0x09,0x8329);
FDC_write_reg(0x0A,0x8329);
FDC_write_reg(0x0B,0x8329);
FDC_write_reg(0x10,0x000A); //设置4个通道最小稳定时间
FDC_write_reg(0x11,0x000A);
FDC_write_reg(0x12,0x000A);
FDC_write_reg(0x13,0x000A);
FDC_write_reg(0x14,0x1001); //时钟除以1,设置传感器频率在0.01M到8.5M之间
FDC_write_reg(0x15,0x1001);
FDC_write_reg(0x16,0x1001);
FDC_write_reg(0x17,0x1001);
FDC_write_reg(0x19,0x0000); //不设置中断标志位
FDC_write_reg(0x1B,0xC20D);//使能0,1,2,3通道,且带宽设置为10M
// FDC_write_reg(0x1E,0x8000); //设置1个通道的驱动电流
// FDC_write_reg(0x1F,0x8000);
FDC_write_reg(0x20,0x8000);
// FDC_write_reg(0x21,0x8000);
FDC_write_reg(0x1A,0x1401); //使能FDC2214,且取内部时钟为参考时钟
}
/*-----------向FDC2214寄存器写的函数--------------*/
//这里 FDC_Address_W =0x54
void FDC_write_reg(u8 addr,u16 value) //addr 为寄存器地址,value为需要写入的寄存器数据
{
IIC_Start(); //产生START信号
IIC_Send_Byte(FDC_Address_W); //发送从机地址和写信号
IIC_Wait_Ack(); //等待ACK
IIC_Send_Byte(addr); //发送需要写入的寄存器地址
IIC_Wait_Ack(); //等待ACK
IIC_Send_Byte(value>>8); //发送高8位数据
IIC_Wait_Ack(); //等待ACK
IIC_Send_Byte(value&0xFF); //发送低8位数据
IIC_Wait_Ack(); //等待ACK
IIC_Stop(); //产生STOP信号
delay_ms(1);
}
/*-----------从FDC2214读16位数据的函数--------------*/
//FDC_Address_W =0x54
//FDC_Address_R =0x55
//Receive_Date[] 为接收数据的数组
//C_Data 为一个16位无符号的整型
u16 FDC_read_reg(u8 addr)
{
IIC_Start(); //产生START信号
IIC_Send_Byte(FDC_Address_W); //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(addr); //发送需要读的寄存器的地址
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(FDC_Address_R); //发送读命令
IIC_Wait_Ack();
Receive_Date[0]=IIC_Read_Byte(1); //读高8位
Receive_Date[1]=IIC_Read_Byte(0); //读低8位
IIC_Stop(); //产生STOP信号
C_Data=(Receive_Date[0]<<8)+ Receive_Date[1];
return C_Data;
}
/*-----------从FDC2214读高8位数据的函数--------------*/
u8 FDC_read_reg_high(u8 addr)
{
IIC_Start();
IIC_Send_Byte(FDC_Address_W);
IIC_Wait_Ack();
IIC_Send_Byte(addr);
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(FDC_Address_R);
IIC_Wait_Ack();
Receive_Date[0]=IIC_Read_Byte(1);
Receive_Date[1]=IIC_Read_Byte(0);
IIC_Stop();
return Receive_Date[0];
}
/*-----------从FDC2214读低8位数据的函数--------------*/
u8 FDC_read_reg_low(u8 addr)
{
IIC_Start();
IIC_Send_Byte(FDC_Address_W);
IIC_Wait_Ack();
IIC_Send_Byte(addr);
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(FDC_Address_R);
IIC_Wait_Ack();
Receive_Date[0]=IIC_Read_Byte(1);
Receive_Date[1]=IIC_Read_Byte(0);
IIC_Stop();
return Receive_Date[1];
}
- 数据采集处理及手势判别代码
.h文件
#ifndef __HANDLE_H
#define __HANDLE_H
#include "sys.h"
#define CAIBENGCAI 0
#define NUMBER 1
#define GESTURE1 1
#define GESTURE2 2
#define GESTURE3 3
#define GESTURE4 4
#define GESTURE5 5
#define ROCK 6
#define SCISSOR 7
#define CLOTH 8
typedef struct gesture //存放录入的手势的数据并计算范围
{
u16 Data[3];
u16 Data_low;
u16 Data_high;
u16 standard;
}Gesture;
void Gesture_Init(Gesture *Rock,Gesture *Scissor,Gesture *Cloth,Gesture G[],u16 nothing); //给各个手势范围赋初值
void Judgment_main(Gesture Rock,Gesture Scissor,Gesture Cloth,Gesture *G,u16 CH2_DATA); //判决模式
void Judgment(Gesture Rock,Gesture Scissor,Gesture Cloth,Gesture *G,u16 CH2_DATA,int mode); //选择判决的模式
void FingerGuessing_Rock(Gesture Rock,Gesture Scissor,Gesture Cloth,u16 DATA); //石头剪刀布判决函数
void FingerGesture_12345(Gesture *G,u16 DATA); //12345判决函数
void Train_main(Gesture Rock,Gesture Scissor,Gesture Cloth,Gesture *G,u16 nothing); //训练主模式
void Train_Rock(Gesture Rock,Gesture Scissor,Gesture Cloth,u16 nothing); //训练猜拳
void Train_12345(Gesture G[],u16 nothing); //训练划拳
void Train(Gesture *gesture,int mode); //训练
void Finger_Mid_Value_Guess_Rock(Gesture *Rock,Gesture *Scissor,Gesture *Cloth,u16 nothing); //求出该游戏模式下的分界点
void Finger_Mid_Value_Guess_12345(Gesture G[],u16 nothing);
void Variance(Gesture *gesture); //求方差,给结构体high和low赋值
void PrintData_Rock(Gesture *gesture); //打印出手势信息,及该游戏模式下的分界点
void PrintData_12345(Gesture *gesture);
#endif
.c文件
#include "handle.h"
#include "usart.h"
#include "math.h"
#include "lcd.h"
#include "hanzi.h"
#include "FDC2214.h"
#include "iic.h"
#include "delay.h"
#include "key.h"
u16 Receive_Date[2];
u16 C_Data;
u16 Finger_Rock[3] = {0}; //存储该游戏模式下的分界点
u16 Finger_12345[5] = {0};
//手势值初始化
//Rock,Scissor,Cloth,G[]是定义的手势值
//nothing不放任何东西时的值
void Gesture_Init(Gesture *Rock,Gesture *Scissor,Gesture *Cloth,Gesture G[],u16 nothing)
{
int i = 0, j = 0;
Rock->standard = 272; //标准差(波动半径)
Rock->Data_high = 33602 + Rock->standard; //拳头范围的最大值
Rock->Data_low = 33058 - Rock->standard;
Rock->Data[0] = 0;
Rock->Data[1] = 0;
Rock->Data[2] = 0;
Scissor->standard = 81;
Scissor->Data_high = 30396 + Scissor->standard; //剪刀范围的最大值
Scissor->Data_low = 30234 - Scissor->standard;
Scissor->Data[0] = 0;
Scissor->Data[1] = 0;
Scissor->Data[2] = 0;
Cloth->standard = 62;
Cloth->Data_high = 27761 + Cloth->standard; //布范围的最大值
Cloth->Data_low = 27637 - Cloth->standard;
Cloth->Data[0] = 0;
Cloth->Data[1] = 0;
Cloth->Data[2] = 0;
for(;i < 5;i++)
{
for(;j < 3;j++)
{
G[i].Data[j] = 0;
}
}
G[0].standard = 100;
G[0].Data_high = 43654 + G[0].standard;
G[0].Data_low = 43536 - G[0].standard;
G[1].standard = 100;
G[1].Data_high = 41504 + G[1].standard;
G[1].Data_low = 40950 - G[1].standard;
G[2].standard = 100;
G[2].Data_high = 40250 + G[2].standard;
G[2].Data_low = 39802 - G[2].standard;
G[3].standard = 100;
G[3].Data_high = 38392 + G[3].standard;
G[3].Data_low = 38332 - G[3].standard;
G[4].standard = 100;
G[4].Data_high = 36103 + G[4].standard;
G[4].Data_low = 35897 - G[4].standard;
}
//判断主函数
//Rock,Scissor,Cloth,G[]是定义的结构体
//CH2_DATA是从寄存器通道2中取出之后经过处理的值
void Judgment_main(Gesture Rock,Gesture Scissor,Gesture Cloth,Gesture *G,u16 CH2_DATA)
{
vu8 t;//接收按键值
printf("判决模式\r\n");
show_panjue_mode();
while(1)
{
vu8 flag = 0;
t=KEY_Scan(0);
switch(t)
{
case KEY0_PRES:
printf("猜拳游戏\r\n");
show_caiquan_mode();
Judgment(Rock,Scissor,Cloth,G,CH2_DATA,CAIBENGCAI);
break;
case KEY1_PRES:
printf("划拳游戏\r\n");
show_huaquan_mode();
Judgment(Rock,Scissor,Cloth,G,CH2_DATA,NUMBER);
break;
case WKUP_PRES:
flag = 1;
LCD_Clear(WHITE);
show_main();
break;
default:
delay_ms(10);
}
if(flag)
break;
}
}
//训练主函数
//Rock,Scissor,Cloth,G[]是定义的手势结构体
//nothing不放任何东西时的值
void Train_main(Gesture Rock,Gesture Scissor,Gesture Cloth,Gesture *G,u16 nothing)
{
vu8 t;//接收按键值
show_xunlian_mode();
printf("训练模式\r\n");
while(1)
{
vu8 flag = 0;
t=KEY_Scan(0);
switch(t)
{
case KEY1_PRES:
printf("录入手势信息,猜拳OR划拳r\n");
show_xunlianxuanze_mode();
while(1)
{
vu8 flag = 0;
t=KEY_Scan(0);
switch(t)
{
case KEY0_PRES://录入猜拳手势
//录入猜拳
Train_Rock(Rock,Scissor,Cloth,nothing);
break;
case KEY1_PRES://录入划拳手势
//录入划拳
Train_12345(G,nothing);
break;
case WKUP_PRES:
flag = 1;
show_xunlian_mode();
break;
default:
delay_ms(10);
}
if(flag)
break;
}
break;
case WKUP_PRES:
{
flag = 1;
}break;
default:
delay_ms(10);
}
if(flag)
break;
}
}
//猜拳训练
//Rock,Scissor,Cloth是定义的手势结构体
//nothing不放任何东西时的值
void Train_Rock(Gesture Rock,Gesture Scissor,Gesture Cloth,u16 nothing)
{
vu8 t;//接收按键值
printf("录入猜拳手势\r\n");
show_caiquanxunlian_mode();
while(1)
{
vu8 flag = 0;
t=KEY_Scan(0);
switch(t)
{
case KEY0_PRES://录入布
printf("录入布\r\n");
show_caiquanxunlian_mode();
Train(&Cloth,CLOTH);
break;
case KEY1_PRES://录入拳头
printf("录入拳头\r\n");
show_caiquanxunlian_mode();
Train(&Rock,ROCK);
break;
case KEY2_PRES://录入剪刀
printf("录入剪刀\r\n");
show_caiquanxunlian_mode();
Train(&Scissor,SCISSOR);
break;
case WKUP_PRES:
flag = 1;
show_xunlianxuanze_mode();
Variance(&Rock);
Variance(&Scissor);
Variance(&Cloth);
Finger_Mid_Value_Guess_Rock(&Rock,&Scissor,&Cloth,nothing);
PrintData_Rock(&Rock);
PrintData_Rock(&Scissor);
PrintData_Rock(&Cloth);
break;
default:
delay_ms(10);
}
if(flag)
break;
}
}
//划拳训练
//G[]是定义的手势结构体数组
//nothing不放任何东西时的值
void Train_12345(Gesture G[],u16 nothing)
{
vu8 t;//接收按键值
printf("录入划拳手势\r\n");
show_huaquanxunlian_mode();
while(1)
{
vu8 flag = 0;
t=KEY_Scan(0);
switch(t)
{
case KEY0_PRES://录入1
printf("录入1\r\n");
show_huaquanxunlian_mode();
Train(&G[0],GESTURE1);
break;
case KEY1_PRES://录入2
printf("录入2\r\n");
show_huaquanxunlian_mode();
Train(&G[1],GESTURE2);
break;
case KEY3_PRES://录入3
printf("录入3\r\n");
show_huaquanxunlian_mode();
Train(&G[2],GESTURE3);
break;
case KEY4_PRES://录入4
printf("录入4\r\n");
show_huaquanxunlian_mode();
Train(&G[3],GESTURE4);
break;
case KEY5_PRES://录入5
printf("录入5\r\n");
show_huaquanxunlian_mode();
Train(&G[4],GESTURE5);
break;
case WKUP_PRES:
flag = 1;
show_xunlianxuanze_mode();
Variance(&G[0]);
Variance(&G[1]);
Variance(&G[2]);
Variance(&G[3]);
Variance(&G[4]);
Finger_Mid_Value_Guess_12345(G,nothing);
printf("G1:\t");
PrintData_12345(&G[0]);
printf("G2:\t");
PrintData_12345(&G[1]);
printf("G3:\t");
PrintData_12345(&G[2]);
printf("G4:\t");
PrintData_12345(&G[3]);
printf("G5:\t");
PrintData_12345(&G[4]);
break;
default:
delay_ms(10);
}
if(flag)
break;
}
}
//判决
//Rock,Scissor,Cloth,G[]是定义的手势结构体数组
//nothing不放任何东西时的值
//CH2_DATA为比较的通道2获取后进行处理的数值
//mode为模式选择位
void Judgment(Gesture Rock,Gesture Scissor,Gesture Cloth,Gesture *G,u16 CH2_DATA,int mode)
{
CH2_DATA = FDC_CH2_GetData();
if(mode == 0)
FingerGuessing_Rock(Rock,Scissor,Cloth,CH2_DATA);
else if(mode == 1)
FingerGesture_12345(G,CH2_DATA);
else ;
LCD_ShowxNum(40,170,CH2_DATA,5,24,0);
}
//猜拳判决
//Rock,Scissor,Cloth是定义的手势结构体
//DATA为需要比较的数值
void FingerGuessing_Rock(Gesture Rock,Gesture Scissor,Gesture Cloth,u16 DATA)
{
if(DATA > Finger_Rock[0]) LCD_ShowxNum(130,200,99,5,16,0);
if(DATA > Finger_Rock[1] && DATA <= Finger_Rock[0]) show_shitou(140,200);
if(DATA > Finger_Rock[2] && DATA <= Finger_Rock[1]) show_jiandao(140,200);
if(DATA < Finger_Rock[2]) {show_bu(140,200);LCD_ShowString(156,200,16,16,16," ");}
}
//划拳判决
//G[]是定义的手势结构体数组
//DATA为需要比较的数值
void FingerGesture_12345(Gesture *G,u16 DATA)
{
if(DATA > Finger_12345[0]) LCD_ShowxNum(130,200,99,5,16,0);
if(DATA > Finger_12345[1] && DATA <= Finger_12345[0]) LCD_ShowxNum(130,200,1,5,16,0);
if(DATA > Finger_12345[2] && DATA <= Finger_12345[1]) LCD_ShowxNum(130,200,2,5,16,0);
if(DATA > Finger_12345[3] && DATA <= Finger_12345[2]) LCD_ShowxNum(130,200,3,5,16,0);
if(DATA > Finger_12345[4] && DATA <= Finger_12345[3]) LCD_ShowxNum(130,200,4,5,16,0);
if(DATA < Finger_12345[4]) LCD_ShowxNum(130,200,5,5,16,0);
}
//训练
//gesture是定义的手势结构体
//mode用来标识手势
//录入一个手势的有效数据必须按三次及三次以上
void Train(Gesture *gesture,int mode)
{
static int count = 0;
int y;
switch(mode)
{
case CLOTH: y = 200;break;
case ROCK: y = 220;break;
case SCISSOR: y = 240;break;
case GESTURE1: y = 160;break;
case GESTURE2: y = 180;break;
case GESTURE3: y = 200;break;
case GESTURE4: y = 220;break;
case GESTURE5: y = 240;break;
default: ;
}
LCD_ShowxNum(132,y,count,5,16,0);
if(count == 3)
{
count = 0;
}
gesture->Data[count++] = FDC_CH2_GetData();
LCD_ShowxNum(40,100,gesture->Data[count - 1],5,24,0);
}
//求手势值的范围
//gesture是定义的手势结构体
void Variance(Gesture *gesture)
{
u16 aver = (gesture->Data[0] + gesture->Data[1] + gesture->Data[2]) / 3;
gesture->standard = sqrt((pow(gesture->Data[0] - aver,2) + pow(gesture->Data[1] - aver,2) + pow(gesture->Data[2] - aver,2)) / 3);
gesture->Data_low = aver - gesture->standard;
gesture->Data_high = aver + gesture->standard;
}
//求猜拳手势值之间的分界点
//Rock,Scissor,Cloth是定义的手势结构体
//nothing不放任何东西时的值
void Finger_Mid_Value_Guess_Rock(Gesture *Rock,Gesture *Scissor,Gesture *Cloth,u16 nothing)
{
Finger_Rock[0] = (Rock->Data_high + nothing) / 2;
Finger_Rock[1] = (Rock->Data_low + Scissor->Data_high) / 2;
Finger_Rock[2] = (Scissor->Data_low + Cloth->Data_high) / 2;
}
//求划拳手势值之间的分界点
//Rock,Scissor,Cloth是定义的手势结构体
//nothing不放任何东西时的值
void Finger_Mid_Value_Guess_12345(Gesture G[],u16 nothing)
{
Finger_12345[0] = (G[0].Data_high + nothing) / 2;
Finger_12345[1] = (G[0].Data_low + G[1].Data_high) / 2;
Finger_12345[2] = (G[1].Data_low + G[2].Data_high) / 2;
Finger_12345[3] = (G[2].Data_low + G[3].Data_high) / 2;
Finger_12345[4] = (G[3].Data_low + G[4].Data_high) / 2;
}
//打印猜拳手势结构体里存储的信息
//gesture是定义的手势结构体
void PrintData_Rock(Gesture *gesture)
{
int i = 0;
for(;i<3;i++)
{
printf("%d\t",gesture->Data[i]);
}
printf("High=%d\t---low=%d==standard=%d\t\r\n",gesture->Data_high,gesture->Data_low,gesture->standard);
printf("%d-----%d-----%d\r\n",Finger_Rock[0],Finger_Rock[1],Finger_Rock[2]);
}
//打印划拳手势结构体里存储的信息
//gesture是定义的手势结构体
void PrintData_12345(Gesture *gesture)
{
int i = 0;
for(;i<3;i++)
{
printf("%d\t",gesture->Data[i]);
}
printf("high==%d\t",gesture->Data_high);
printf("low==%d\t\r\n",gesture->Data_low);
printf("%d-----%d-----%d------%d-------%d\r\n\r\n",Finger_12345[0],Finger_12345[1],Finger_12345[2],Finger_12345[3],Finger_12345[4]);
}
心得体会
在本次的项目设计中,我们摒弃了之前的小毛病,真正做到了设计为先,做到了明确分工,各司其职,项目的顺利进行让我体验到了明确目标有多么重要!
在拿到这个项目的时候,我的内心是比较慌的,因为在开始项目之前对FDC2214工作原理以及特性基本上不清楚。不过这也没有关系,网上的资料也挺多,很快就搞定了FDC2214的驱动流程。
这次项目所用到的电子元器件比较少,只需用到主控板,电源,按键输入,屏幕输出,FDC2214芯片以及前端检测装置。在明确了器件之后,我们先开始写文档,将硬件框图以及大概的软件流程图确定下来,之后进行了各模块间的方案论证,接下来进行编码设计。
我负责的部分是FDC2214的驱动,数据的采集与处理以及手势的判别,处理过程包括从通道中读取数值,将数值移位,加权滑动滤波处理后得到当前的样本数值,再将这一组数值通过方差公式求标准差,确定这个手势所得到的数据的波动范围,之后对这些范围求分界点。如果进行判决模式,那么将手势值与这些分界点作比较,即可判断手势值属于哪一个集合,最后得到判决结果。
在调试过程中遇到一个问题,有时候会出现部分分界值与正常数据不匹配的情况,导致判定结果出错。之后认真查看代码,发现是计算分界值的函数内数组下标出了问题,,在查明了源头之后,这一问题也得到解决。
总的来说,本次项目对我个人的提升是非常明显的。从代码设计方面来讲,我负责的部分都是编码设计,也是整个项目中至关重要的部分。关于代码,我封装的较为合理,也相对完善,具有系统化一层一层深入的思想。正是因为这次编码贯彻了这样的思想,使得代码设计框架较为清晰,条理分明;从分析问题方面来讲,我学会了硬件框架一步步抽象到底层实现,并快速付诸以行动;从实践能 力来讲,我能快速的根据实验现象将可能出现问题的点一个个梳理出来并准确定位是哪里的问题;从团队合作方面来讲,我学会了如何与团队成员进行有效地沟通,也能更清晰、更流畅地表达出自己的思想;这些都是我在之前不擅长或者不具备的技能。