查看: 5248|回复: 11

【Arduino101教程】神经元与IMU动作识别

[复制链接]
  • TA的每日心情
    奋斗
    2018-7-3 21:30
  • 签到天数: 46 天

    [LV.5]常住居民I

    发表于 2017-3-12 17:36 | 显示全部楼层 |阅读模式
    什么是机器学习
    机器学习领域的先驱ArthurSamuel,在其论文《Some Studies in Machine Learning Using the Game of Checkers》中,将机器学习非正式定义为:“在不直接针对问题进行编程的情况下,赋予计算机学习能力的一个研究领域。”例如要让Genuino 101判断其自身姿态是正面朝上,还是朝下时。常规做法是,计算出姿态角,并判断其是否在某一区间中;而使用机器学习,可以通过多次将Genuino 101朝上或朝下放置,并将此时传感器数据及姿态输入模式匹配引擎进行学习,此后Genuino 101即可根据新的传感器数据判断当前的姿态了。
    intel Curie的模式匹配引擎(patternmatching engine),带有128个神经元,支持k近邻法(k-Nearest Neighbors)和径向基核函数(Radial Basis Function)两种匹配算法。其让Curie具有了像人一样的学习、归类能力,进而可以省去某些繁琐的编程过程。
    Intel提供了CuriePME库用于驱动模式匹配引擎,其下载地址为:
    下载安装CuriePME后,可通过示例程序了解其使用方法。如下示例程序可用于学习并识别手势动作。
    /* * This example demonstrates using the pattern matching engine (CuriePME) * to classify streams of accelerometer data from CurieIMU. * * First, the sketch will prompt you to draw some letters in the air (just * imagine you are writing on an invisible whiteboard, using your board as the * pen), and the IMU data from these motions is used as training data for the * PME. Once training is finished, you can keep drawing letters and the PME * will try to guess which letter you are drawing. * * This example requires a button to be connected to digital pin 4 * https://www.arduino.cc/en/Tutorial/Button * * NOTE: For best results, draw big letters, at least 1-2 feet tall. * * Copyright (c) 2016 Intel Corporation.  All rights reserved. * See license notice at end of file. */ #include "CurieIMU.h" #include "CuriePME.h" /*  This controls how many times a letter must be drawn during training. *  Any higher than 4, and you may not have enough neurons for all 26 letters *  of the alphabet. Lower than 4 means less work for you to train a letter, *  but the PME may have a harder time classifying that letter. */ const unsigned int trainingReps = 4; /* Increase this to 'A-Z' if you like-- it just takes a lot longer to train */ const unsigned char trainingStart = 'A'; const unsigned char trainingEnd = 'F'; /* The input pin used to signal when a letter is being drawn- you'll * need to make sure a button is attached to this pin */ const unsigned int buttonPin = 4; /* Sample rate for accelerometer */ const unsigned int sampleRateHZ = 200; /* No. of bytes that one neuron can hold */ const unsigned int vectorNumBytes = 128; /* Number of processed samples (1 sample == accel x, y, z) * that can fit inside a neuron */ const unsigned int samplesPerVector = (vectorNumBytes / 3); /* This value is used to convert ASCII characters A-Z * into decimal values 1-26, and back again. */ const unsigned int upperStart = 0x40; const unsigned int sensorBufSize = 2048; const int IMULow = -32768; const int IMUHigh = 32767; void setup() {     Serial.begin(9600);     while(!Serial);     pinMode(buttonPin, INPUT);     /* Start the IMU (Intertial Measurement Unit) */     CurieIMU.begin();     /* Start the PME (Pattern Matching Engine) */     CuriePME.begin();     CurieIMU.setAccelerometerRate(sampleRateHZ);     CurieIMU.setAccelerometerRange(2);     trainLetters();     Serial.println("Training complete. Now, draw some letters (remember to ");     Serial.println("hold the button) and see if the PME can classify them."); } void loop () {     byte vector[vectorNumBytes];     unsigned int category;     char letter;     /* Record IMU data while button is being held, and      * convert it to a suitable vector */     readVectorFromIMU(vector);     /* Use the PME to classify the vector, i.e. return a category      * from 1-26, representing a letter from A-Z */     category = CuriePME.classify(vector, vectorNumBytes);     if (category == CuriePME.noMatch) {         Serial.println("Don't recognise that one-- try again.");     } else {         letter = category + upperStart;         Serial.println(letter);     } } /* Simple "moving average" filter, removes low noise and other small * anomalies, with the effect of smoothing out the data stream. */ byte getAverageSample(byte samples[], unsigned int num, unsigned int pos,                    unsigned int step) {     unsigned int ret;     unsigned int size = step * 2;     if (pos < (step * 3) || pos > (num * 3) - (step * 3)) {         ret = samples[pos];     } else {         ret = 0;         pos -= (step * 3);         for (unsigned int i = 0; i < size; ++i) {             ret += samples[pos - (3 * i)];         }         ret /= size;     }     return (byte)ret; } /* We need to compress the stream of raw accelerometer data into 128 bytes, so * it will fit into a neuron, while preserving as much of the original pattern * as possible. Assuming there will typically be 1-2 seconds worth of * accelerometer data at 200Hz, we will need to throw away over 90% of it to * meet that goal! * * This is done in 2 ways: * * 1. Each sample consists of 3 signed 16-bit values (one each for X, Y and Z). *    Map each 16 bit value to a range of 0-255 and pack it into a byte, *    cutting sample size in half. * * 2. Undersample. If we are sampling at 200Hz and the button is held for 1.2 *    seconds, then we'll have ~240 samples. Since we know now that each *    sample, once compressed, will occupy 3 of our neuron's 128 bytes *    (see #1), then we know we can only fit 42 of those 240 samples into a *    single neuron (128 / 3 = 42.666). So if we take (for example) every 5th *    sample until we have 42, then we should cover most of the sample window *    and have some semblance of the original pattern. */ void undersample(byte samples[], int numSamples, byte vector[]) {     unsigned int vi = 0;     unsigned int si = 0;     unsigned int step = numSamples / samplesPerVector;     unsigned int remainder = numSamples - (step * samplesPerVector);     /* Centre sample window */     samples += (remainder / 2) * 3;     for (unsigned int i = 0; i < samplesPerVector; ++i) {         for (unsigned int j = 0; j < 3; ++j) {             vector[vi + j] = getAverageSample(samples, numSamples, si + j, step);         }         si += (step * 3);         vi += 3;     } } void readVectorFromIMU(byte vector[]) {     byte accel[sensorBufSize];     int raw[3];     unsigned int samples = 0;     unsigned int i = 0;     /* Wait until button is pressed */     while (digitalRead(buttonPin) == LOW);     /* While button is being held... */     while (digitalRead(buttonPin) == HIGH) {         if (CurieIMU.accelDataReady()) {             CurieIMU.readAccelerometer(raw[0], raw[1], raw[2]);             /* Map raw values to 0-255 */             accel = (byte) map(raw[0], IMULow, IMUHigh, 0, 255);             accel[i + 1] = (byte) map(raw[1], IMULow, IMUHigh, 0, 255);             accel[i + 2] = (byte) map(raw[2], IMULow, IMUHigh, 0, 255);             i += 3;             ++samples;             /* If there's not enough room left in the buffers             * for the next read, then we're done */             if (i + 3 > sensorBufSize) {                 break;             }         }     }     undersample(accel, samples, vector); } void trainLetter(char letter, unsigned int repeat) {     unsigned int i = 0;     while (i < repeat) {         byte vector[vectorNumBytes];         if (i) Serial.println("And again...");         readVectorFromIMU(vector);         CuriePME.learn(vector, vectorNumBytes, letter - upperStart);         Serial.println("Got it!");         delay(1000);         ++i;     } } void trainLetters() {     for (char i = trainingStart; i <= trainingEnd; ++i) {         Serial.print("Hold down the button and draw the letter '");         Serial.print(String(i) + "' in the air. Release the button as soon ");         Serial.println("as you are done.");         trainLetter(i, trainingReps);         Serial.println("OK, finished with this letter.");         delay(2000);     } }



    编译并上传以上程序到Genuino101,按串口提示,即可体验使用Genuino 101学习并识别动作。运行该示例需要在4号引脚上接一个按键模块,按下按键即会开始一次新的学习,松开按键结束该次学习。
    该示例主要使用的了CuriePME中learn和classify两个函数,这也是机器学习的两个主要过程。

    学习
      
    uint16_t  CuriePME.learn (uint8_t vector[], int32t  vector_length, uint16_t category)
      
    其中参数vector要进行学习的数据,参数vector_length为数据长度,参数category该次学习对应的分类类别。 调用learn函数,即可告知CuriePME,数据vector属于类别category。
    CuriePME是由128个特殊存储单元组成的神经元网络。每个存储单元可以容纳128字节的数据。每次调用learn函数,都会将输入的新数据写入网络中的一个神经元,即CuriePME在清空重置的状态下,可以进行128次学习操作,每次用于学习的数据vector长度最大为128字节。

    分类
      
    uint16_t  CuriePME.classify (uint8_t vector[], int32_t  vector_length)
      
    其中参数vector是要进行识别的数据,vector_length是要该数据的长度。调用classify函数,CuriePME即会判断数据vector属于哪一个别类,并返回别类对应的编号。

    以上程序中,CurieIMU设定加速度采样频率200Hz,采样缓冲区2 kb,最多可以录制3.41秒的动作,再经过程序处理将2kb数据缩小到128 byte,进行学习和分类。如果需要录制更长时间的动作,可以将加速度采样频率降低,或扩大采样缓冲区。
    由于实际用于学习和分类的特征数据只有128 byte,所以理论上越简单的动作,约少的录制时间,会得到更好的学习和识别效果。
    CuriePME主要用来结合CurieIMU进行姿态、动作的学习和识别,但实际上也可以用于其他类型数据的处理,本书篇幅有限,不做过多论述。


    -------------------------------------------------------------------------------------------------------------
    本教程分为五部分:
    1.配置IMU及获取数据   http://www.arduino.cn/thread-42850-1-1.html
    2.解算AHRS姿态   http://www.arduino.cn/thread-42851-1-1.html
    3.姿态数据可视化   http://www.arduino.cn/thread-42852-1-1.html
    4.IMU中断检测   http://www.arduino.cn/thread-42853-1-1.html
    5.神经元与机器学习   http://www.arduino.cn/thread-42854-1-1.html
    如果以上内容对你有帮助,你可以通过打赏支持作者

    该用户从未签到

    发表于 2017-3-17 13:16 | 显示全部楼层
    Arduino:1.8.1 (Windows 10), 开发板:"Arduino/Genuino 101"

    C:\Users\pc\AppData\Local\Temp\arduino_modified_sketch_204514\sketch_mar17b.ino: In function 'void readVectorFromIMU(byte*)':

    sketch_mar17b:150: error: 'class CurieIMUClass' has no member named 'accelDataReady'

      if (CurieIMU.accelDataReady()) {

                   ^

    sketch_mar17b:152: error: incompatible types in assignment of 'byte {aka unsigned char}' to 'byte [2048] {aka unsigned char [2048]}'

    accel = (byte) map(raw[0], IMULow, IMUHigh, 0, 255);

           ^

    exit status 1
    'class CurieIMUClass' has no member named 'accelDataReady'

    这是怎么回事?

    点评

    新版函数有变更,accelDataReady已作废,新的函数为DataReady  详情 回复 发表于 2017-3-17 15:26
  • TA的每日心情
    奋斗
    2018-7-3 21:30
  • 签到天数: 46 天

    [LV.5]常住居民I

     楼主| 发表于 2017-3-17 15:26 | 显示全部楼层
    987621305@QQ.CO 发表于 2017-3-17 13:16
    Arduino:1.8.1 (Windows 10), 开发板:"Arduino/Genuino 101"

    C:%users\pc\AppData\Local\Temp\arduino_mo ...

    新版函数有变更,accelDataReady已作废,新的函数为DataReady
    如果以上内容对你有帮助,你可以通过打赏支持作者

    该用户从未签到

    发表于 2017-3-17 15:52 | 显示全部楼层
    Arduino:1.8.1 (Windows 10), 开发板:"Arduino/Genuino 101"

    E:\cz-Arduino\sketch_mar17b\sketch_mar17b.ino: In function 'void readVectorFromIMU(byte*)':

    sketch_mar17b:151: error: 'class CurieIMUClass' has no member named 'DataReady'

       if(CurieIMU.DataReady()){

                   ^

    exit status 1
    'class CurieIMUClass' has no member named 'DataReady'
    还是不好使?????

    该用户从未签到

    发表于 2017-3-17 15:55 | 显示全部楼层
    使用 1.0  版本的库 CurieIMU 在文件夹: C:\Users\pc\AppData\Local\Arduino15\packages\Intel\hardware\arc32\1.0.7\libraries\CurieIMU
    使用 0.1  版本的库 Intel-Pattern-Matching-Technology-master 在文件夹: E:\cz-Arduino\libraries\Intel-Pattern-Matching-Technology-master

    点评

    http://www.arduino.cn/thread-42890-1-1.html  详情 回复 发表于 2017-3-17 16:49
  • TA的每日心情
    奋斗
    2018-7-3 21:30
  • 签到天数: 46 天

    [LV.5]常住居民I

     楼主| 发表于 2017-3-17 16:49 | 显示全部楼层
    987621305@QQ.CO 发表于 2017-3-17 15:55
    使用 1.0  版本的库 CurieIMU 在文件夹: C:%users\pc\AppData\Local\Arduino15\packages\Intel\hardware\a ...
    更新版的扩展包才有
    http://www.arduino.cn/thread-42890-1-1.html
    如果以上内容对你有帮助,你可以通过打赏支持作者

    该用户从未签到

    发表于 2017-3-17 18:33 | 显示全部楼层
    好使了,是CurieIMU.dataReady()。学了
  • TA的每日心情
    开心
    2017-3-30 19:56
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2017-3-28 16:40 来自手机 | 显示全部楼层
    大哥们,我全试了,都不行啊,我在文件夹里面搜索curielIMU发现有dataReady但是每次编译都会出现上述错误,好气啊。
  • TA的每日心情
    开心
    2017-3-30 19:56
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2017-3-28 16:40 来自手机 | 显示全部楼层
    在cpp文件里面看的
    高级模式  
    您需要登录后才可以回帖 登录 | 立即注册  

    本版积分规则

    热门推荐

    新人求教,如何使用Arduino同时控制4台步进电机
    新人求教,如何使用Arduin
    想通过Arduino控制四台不同的步进电机(57步),不同转速,转不同时间,板子如下(伊
    红外遥控+温湿度采集+SD卡存储
    红外遥控+温湿度采集+SD卡
    我用红外遥控发送信号,启动温湿度采集并存储到SD卡中,发现红外遥控信号检测不出来,
    有关hx711算法问题
    有关hx711算法问题
    我用hx711做电子秤,称的是小量程的,1kg的传感器,但是卖家给的程序称出来的值不但不
    求助:HX711读取压力传感器读数不稳定
    求助:HX711读取压力传感
    最近在做一个基于arduino压力检测装置,用的传感器是10KG的TAL220,接线如下: 我用来
    小白求助
    小白求助
    下载了无法安装,提示是这样的
    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   ( 蜀ICP备14017632号-3 )
    快速回复 返回顶部 返回列表