limale 发表于 2017-5-16 22:14:19

【Curie Nano试用】 A5.Curie神经元算法库--CurieNeurons

CurieNeurons,即Curie神经元。Neurons能通过示例学习,不用编程,可以通过数据离线学习。
general vision提供了两个版本可供下载,免费版和收费19美刀的专业版。
下载地址:http://www.general-vision.com/software/curieneurons/


为了尝鲜我们先体验一下免费版吧,
相关的文档:









详细的信息可以看文档里的介绍,这里我们就直接切入正题了。
需要的材料很简单,Curie Nano板和一块AD Keyborad板。
这个AD Keyborad DFROBOT商城有卖,不过太贵了买不起,好在提供原理图,我手工做了一个。
5个按键只占用一个模拟IO口,很巧妙的设计。




这里VCC接3.3V,IO口接A5。


示例代码:/*
Name:                CurieNeurons_andIMU2.0.ino
Created:      7/21/2016 11:08:34 AM
Author:      HansYang
*/


#include <CurieIMU.h>
#include <BMI160.h>
#include <CurieNeurons.h>
#include <stdlib.h>
#define DEBUG1
#define ACC_FEATURE_ONLY
#define MANUAL_SCALING

#ifdef ACC_FEATURE_ONLY
#define SAMPLENBR 3
#else
#define SAMPLENBR 6
#endif // ACC_FEATURE_ONLY

#define MAX_SAMPLING_TIME 3000//ms
#define SAMPLING_INTERVAL 50//ms
#define MAX_VECTOR_LEN 60//MAX_SAMPLING_TIME/SAMPLING_INTERVAL

#define DOWNSAMPLER_SEGS 10

//ADkeyboard
int adc_key_val = { 850,900, 940, 960, 980 };
#define NUM_KEYS 5
int adc_key_in;
int key = -1;

//CurieNeurons
CurieNeurons hNN;
int cat, prevcat;
int dist, nid;

//IMU data
int16_t ax, ay, az;
int16_t gx, gy, gz;

int minax, minay, minaz, maxax, maxay, maxaz;
int mingx, mingy, mingz, maxgx, maxgy, maxgz;
int Sax, Say, Saz, Sgx, Sgy, Sgz;

//Others
uint64_t timer;
short vector_len;
byte vector;
byte pattern;
byte learnflag;

void feature_extraction(byte* src_vector, int src_len, byte *dst_vector)
{
      int seg_len = src_len / (DOWNSAMPLER_SEGS * SAMPLENBR);
      double res;
      for (int icol = 0; icol < SAMPLENBR; icol++)
      {
                int sum = 0;
                for (int i = 0; i < src_len; i++)
                {
                        sum += src_vector;
                }
                //mean
                int aver = sum / src_len;
                int e = 0;
                int mad = 0;
                //int rms = 0;
                //byte max = src_vector;
                //byte min = src_vector;
                int ratiocount = { 0 };
                for (int i = 0; i < src_len; i++)
                {
                        e += (src_vector - aver)*(src_vector - aver);
                        mad += abs(src_vector - aver);
                        //rms += src_vector * src_vector;
                        //if (src_vector > max)
                        //      max = src_vector;
                        //if (src_vector < min)
                        //      min = src_vector;
                        if (src_vector <= 200)
                        {
                              if (src_vector <= 150)
                              {
                                        if (src_vector <= 100)
                                        {
                                                if (src_vector <= 50)
                                                {
                                                      ratiocount++;
                                                }
                                                else
                                                      ratiocount++;
                                        }
                                        else
                                                ratiocount++;
                              }
                              else
                                        ratiocount++;
                        }
                        else
                              ratiocount++;
                }
                //standard deviation
                res = sqrt(e / (src_len - 1)) * 2;
                //MAD
                res = mad / src_len * 2;
                //RMS
                //res = sqrt(rms / src_len);
                for (int i = 0; i < 5; i++)
                {
                        res = 0;//ratiocount;// * 255 / src_len;
                }

                for (int iseg = 0; iseg < DOWNSAMPLER_SEGS; iseg++)
                {
                        int sum = 0;
                        for (int ismp = 0; ismp < seg_len; ismp++)
                        {
                              int offset = icol + (iseg * seg_len + ismp)*SAMPLENBR;
                              sum += (int)src_vector;
                              src_vector = 0;
                        }
                        res = sum / seg_len;
                }
      }

      for (int i = 0; i < SAMPLENBR * 17; i++)
      {
                pattern = (int)(res + 0.5) * 0x00FF;
      }

#ifdef DEBUG1
      Serial.print("\n");
      for (int i = 0; i < SAMPLENBR*17; i++)
      {
                Serial.print(pattern);
                Serial.print("\t");
      }
      //Serial.print("\n");
#endif // DEBUG1

}

int get_key(unsigned int input)      //1 2 3 4 5
{
      int k;
      for (k = 0; k < NUM_KEYS; k++)
      {
                if (input < adc_key_val)
                {
                        return k + 1;
                }
      }
      if (k >= NUM_KEYS)
                k = -1;// No valid key pressed
      return k + 1;
}

void read_data_once()
{
      CurieIMU.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

      /*int R = sqrt(ax*ax + ay*ay + az*az);

      double tX = acos(ax / R);
      double tY = acos(ay / R);
      double tZ = acos(az / R);

      ax = ax - 8192 * cos(tX);
      ay = ay - 8192 * cos(tY);
      az = ax - 8192 * cos(tZ);*/
      
      vector = (byte)(((ax - minax) * 255 / Sax) & 0x00FF);
      vector = (byte)(((ay - minay) * 255 / Say) & 0x00FF);
      vector = (byte)(((az - minaz) * 255 / Saz) & 0x00FF);
#ifndef ACC_FEATURE_ONLY
      vector = (byte)(((gx - mingx) * 255 / Sgx) & 0x00FF);
      vector = (byte)(((gy - mingy) * 255 / Sgy) & 0x00FF);
      vector = (byte)(((gz - mingz) * 255 / Sgz) & 0x00FF);
#endif // !ACC_FEATURE_ONLY               

      /*vector = ax;
      vector = ay;
      vector = az;
#ifndef ACC_FEATURE_ONLY
      vector = gx;
      vector = gy;
      vector = gz;
#endif // !ACC_FEATURE_ONLY                */

      if (vector_len < (MAX_VECTOR_LEN - 2)*SAMPLENBR ) {
                vector_len++;
                Serial.print("*");
      }
      else
      {
                Serial.print("O");
      }
}

// the setup function runs once when you press reset or power the board
void setup() {
      Serial.begin(9600);
      while (!Serial);

      Serial.print("CurieNeurons initializing...");
      hNN.begin();
      hNN.forget();
      Serial.println("Done");

      Serial.print("CurieIMU initializing...");
      CurieIMU.begin();
      Serial.println("Done");

      Serial.println("Initializing IMU device...");
      CurieIMU.begin();

      // use the code below to calibrate accel/gyro offset values
      Serial.println("Internal sensor offsets BEFORE calibration...");
      Serial.print(CurieIMU.getXAccelOffset());
      Serial.print("\t"); // -76
      Serial.print(CurieIMU.getYAccelOffset());
      Serial.print("\t"); // -235
      Serial.print(CurieIMU.getZAccelOffset());
      Serial.print("\t"); // 168
      Serial.print(CurieIMU.getXGyroOffset());
      Serial.print("\t"); // 0
      Serial.print(CurieIMU.getYGyroOffset());
      Serial.print("\t"); // 0
      Serial.println(CurieIMU.getZGyroOffset());

      Serial.println("About to calibrate. Make sure your board is stable and upright");
      delay(2000);

      // The board must be resting in a horizontal position for
      // the following calibration procedure to work correctly!
      Serial.print("Starting Gyroscope calibration...");
      CurieIMU.autoCalibrateGyroOffset();
      Serial.println(" Done");
      Serial.print("Starting Acceleration calibration...");
      CurieIMU.autoCalibrateXAccelOffset(0);
      CurieIMU.autoCalibrateYAccelOffset(0);
      CurieIMU.autoCalibrateZAccelOffset(1);
      Serial.println(" Done");

      Serial.println("Internal sensor offsets AFTER calibration...");
      Serial.print(CurieIMU.getXAccelOffset());
      Serial.print("\t"); // -76
      Serial.print(CurieIMU.getYAccelOffset());
      Serial.print("\t"); // -2359
      Serial.print(CurieIMU.getZAccelOffset());
      Serial.print("\t"); // 1688
      Serial.print(CurieIMU.getXGyroOffset());
      Serial.print("\t"); // 0
      Serial.print(CurieIMU.getYGyroOffset());
      Serial.print("\t"); // 0
      Serial.println(CurieIMU.getZGyroOffset());

      Serial.println("Enabling Gyroscope/Acceleration offset compensation");
      CurieIMU.setGyroOffsetEnabled(true);
      CurieIMU.setAccelOffsetEnabled(true);

      CurieIMU.setAccelerometerRange(4);
      //hNN.GCR(128);                        //LSUP distance
      //hNN.MAXIF(600);

#ifdef MANUAL_SCALING

      minax = minay = minaz = maxax = maxay = maxaz = -32768;
      mingx = mingy = mingz = maxgx = maxgy = maxgz = 32767;
      Sax = Say = Saz = Sgx = Sgy = Sgz = 65535;

#else
      Serial.println("\nAssessing the amplitude of motions...Press any key to continue");
      adc_key_in = analogRead(5);
      while (adc_key_in > 980)
      {
                adc_key_in = analogRead(5);
                CurieIMU.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
                if (ax>maxax) maxax = ax; if (ax<minax) minax = ax;
                if (ay>maxay) maxay = ay; if (ay<minay) minay = ay;
                if (az>maxaz) maxaz = az; if (az<minaz) minaz = az;
                if (gx>maxgx) maxgx = gx; if (gx<mingx) mingx = gx;
                if (gy>maxgy) maxgy = gy; if (gy<mingy) mingy = gy;
                if (gz>maxgz) maxgz = gz; if (gz<mingz) mingz = gz;
      }
      Sax = maxax - minax;
      Say = maxay - minay;
      Saz = maxaz - minaz;
      Sgx = maxgx - mingx;
      Sgy = maxgy - mingy;
      Sgz = maxgz - mingz;
      Serial.print("\nSa :\t"); Serial.print(Sax); Serial.print(","); Serial.print(Say); Serial.print(","); Serial.print(Saz);
      Serial.print("\nSg :\t"); Serial.print(Sgx); Serial.print(","); Serial.print(Sgy); Serial.print(","); Serial.println(Sgz);
#endif

      timer = 0;
      prevcat = 0x7FFF;
      learnflag = 0;

      Serial.print("The program will begin in 2 seconds...\n");
      delay(2000);
      Serial.println("Start.");


}

// the loop function runs over and over again until power down or reset
void loop() {

      timer = millis();
      adc_key_in = analogRead(5);
      key = get_key(adc_key_in);

      if (key!=0)
      {
                learnflag = key;
                read_data_once();
      }
      else if (learnflag != 0)
      {
                read_data_once();
                feature_extraction(vector, vector_len, pattern);
                //downsampler_means(vector, vector_len, pattern, SAMPLENBR*DOWNSAMPLER_SEGS);
#ifdef DEBUG
                Serial.print("\n");
                for (int i = 0; i < SAMPLENBR*DOWNSAMPLER_SEGS; i++)
                {
                        Serial.print(pattern);
                        Serial.print("\t");
                }
                Serial.print("\n");
#endif //DEBUG
                if (learnflag != 5)
                {
                        hNN.learn(pattern, SAMPLENBR * 17, learnflag);
                        Serial.print("\nLearned motion #");
                        Serial.print(learnflag);
                        Serial.println("once, please repeat.");
                }
                else
                {
                        int res = hNN.classify(pattern, SAMPLENBR * 17, &dist, &cat, &nid);
                        cat &= 0x00FF;
                        if (res != 0)
                        {
                              Serial.print("\nMotion Detected. #"); Serial.println(cat);
                        }
                        else
                        {
                              Serial.println("\nMotion Unknow.");
                        }
                }
                learnflag = 0;
                vector_len = 0;
      }
      while ((millis() - timer) < SAMPLING_INTERVAL);
}编译示例代码并上传到Curie Nano中,打开串口工具,并将开发板平放等待陀螺仪自动校准。如图所示:


动作学习:
按住黄色、绿色、蓝色或者红色按键做动作,动作完成松手。黄色对应动作1,绿色对应动作2,蓝色对应动作3,红色对应动作4。
每种动作可以多做几次,这样识别的准确率会高一些。
下图是我按住黄色按键1和绿色按键2完成的动作识别。


识别动作:
按住中间的白色按键5,做出刚才的动作,程序会识别属于刚才的哪个动作。
如下图所示,如果做出的动作不是刚才的两种之一会显示未知。


动作的采样时间可以在以下的语句修改,但是时间越来复杂度也就越高,识别的准确率也就越低。

程序说明:
在这个过程中,主要是采用按键按下作为动作的开始,松开表示动作的结束,再将采样的动作进行数据分析,再由CurieNeurons神经网络进行学习。识别动作的方式同理。

slotg 发表于 2017-5-16 23:40:39

这个有意思,感谢分享。

噗噗熊 发表于 2017-5-17 09:37:23

这个好有意思!

我叫逗逗 发表于 2017-5-17 09:46:19

楼主什么时候买收费版,不知道收费版可不可以共享?

limale 发表于 2017-5-17 09:46:28

slotg 发表于 2017-5-16 23:40 static/image/common/back.gif
这个有意思,感谢分享。

谢谢支持            

limale 发表于 2017-5-17 09:47:21

噗噗熊 发表于 2017-5-17 09:37 static/image/common/back.gif
这个好有意思!

这个板子确实有好多好玩的地方。

limale 发表于 2017-5-17 09:50:17

我叫逗逗 发表于 2017-5-17 09:46 static/image/common/back.gif
楼主什么时候买收费版,不知道收费版可不可以共享?

看了一下介绍,专业版识别算法准确率高一些。楼主没有这方面的需求,暂时不会考虑买专业版。
页: [1]
查看完整版本: 【Curie Nano试用】 A5.Curie神经元算法库--CurieNeurons