// Teil 2 folgt, leider WartezeitCode:/* Backpropagation Netz / net optimiert für Arduino Due Version JON 0060 (C) HaWe 2015 to do: - save memory to SD file - plug real physical sensors - pre-emptive Multitasking (currently not possible for Due) */ #include <SPI.h> #include <SD.h> #include <UTFT.h> #include <ardustdio.h> #include <malloc.h> #include <DueTimer.h> //------------------------------------------------------------------------------------- // neural net size #define NMAXIN 108 // max number of inputs (sensors) #define NMAXHID 20 // max number hidden layer neurons #define NMAXOUT 20 // max number output layer neurons #define NMAXPAT 70 // <<< max number of possibly trained patterns; //------------------------------------------------------------------------------------- // neural net: neurons and patterns float WeightLIn[NMAXIN+1][NMAXHID+1]; float WeightLOut[NMAXHID+1][NMAXOUT+1]; float Input[NMAXPAT+1][NMAXIN+1]; float Target[NMAXPAT+1][NMAXOUT+1]; float Output[NMAXPAT+1][NMAXOUT+1]; //float Contxt[NMAXOUT+1]; // Jordan-net: neuron-number == output-number float currIn[NMAXIN+1], // currently polled inputs inbuf[NMAXIN+1]; // intermediate stored inputs for editing float currOut[NMAXOUT+1], // currently computed net outputs outbuf[NMAXOUT+1]; // intermediate stored outputs int16_t NumInput = NMAXIN, NumHidden = NMAXHID, NumOutput = NMAXOUT; int16_t NumPattern = 0; // <<< number of actually trained patterns; int32_t epoch; // training measures uint32_t BPTime; float Error; //------------------------------------------------------------------------------------- // TFT LCD //UTFT myGLCD(Model, SDA=MISO, SCL, CS, RESET, RS) //UTFT myGLCD(QD220A, A2, A1, A5, A4, A3); // adjust model parameter and pins ! UTFT myGLCD(QD220A, 50, 49, 52, 0, 51); // A0->Vc (LED), A4->BoardReset extern uint8_t SmallFont[]; #define LCDWhiteBlack() {myGLCD.setColor(255, 255, 255); myGLCD.setBackColor( 0, 0, 0);} #define LCDNormal() {myGLCD.setColor(255, 255, 255); myGLCD.setBackColor( 0, 0, 0);} #define LCDInvers() {myGLCD.setColor( 0, 0, 0); myGLCD.setBackColor(255, 255, 255);} #define LCDWhiteRed() {myGLCD.setColor(255, 255, 255); myGLCD.setBackColor(255, 0, 0);} #define LCDRedBlack() {myGLCD.setColor(255, 0, 0); myGLCD.setBackColor( 0, 0, 0);} #define LCDYellowBlue() {myGLCD.setColor(255, 255, 0); myGLCD.setBackColor( 64, 64, 64);} uint8_t fontwi= 8; uint8_t fonthi=10; int16_t LCDmaxX , LCDmaxY ; // display size int16_t _curx_, _cury_, // last x,y cursor pos on TFT screen _maxx_, _maxy_; // max. x,y cursor pos on TFT screen char wspace[50]; // line of white space void lcdcls() { myGLCD.clrScr(); _curx_ =0; _cury_ =0; } void curlf() { _curx_=0; if( _cury_ <=(LCDmaxY-10) ) _cury_+=10; else _cury_=0; } void lcdprintxy(int16_t x, int16_t y, char * str) { myGLCD.print(str, x, y); _curx_ = x + strlen(str)*fontwi; _cury_ = y; // check for line overflow! } void curxy(int16_t x, int16_t y) {_curx_ = x;_cury_ = y;} void lcdprint(char * str) { myGLCD.print(str, _curx_, _cury_); _curx_ = _curx_ + strlen(str)*fontwi; //_cury_ = _cury_; // check for line overflow! } //------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------- // SD Card #define SD_CSpin 53 File myFile; char fname[64]; //------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------- // misc #define TimerMS() millis() #define LRAND_MAX 32767 #define srand(seed) randomSeed(seed) #define rand() random(LRAND_MAX) #define rando() ((float)rand()/(LRAND_MAX+1)) int32_t RSeed; #define pswitchon(pin) (!digitalRead(pin)) // btn press for pinMode(pin, INPUT_PULLUP) #define pswitchoff(pin) ( digitalRead(pin)) // btn press for pinMode(pin, INPUT_PULLUP) #define pbtn(pin) (!digitalRead(pin)) // alias //------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------- // user interface: button pad control pins #define PIN_ESC 13 #define PIN_UP 12 #define PIN_OK 11 #define PIN_DN 4 // instead opt.: 6 #define PIN_LE 3 // instead opt.: 5 #define PIN_RI 2 // pins 10,9,8,7 : motor // pins 22 - 37 : motor // pins 49 - 51 : LCD TFT // pin 53: SD CS // available: 5+6, 38-48 for digital touch pins //------------------------------------------------------------------------------------- int16_t btnpressed() { return ( pbtn(PIN_ESC)||pbtn(PIN_UP)||pbtn(PIN_OK)||pbtn(PIN_DN)||pbtn(PIN_LE)||pbtn(PIN_RI) ); } //------------------------------------------------------------------------------------- int16_t getbtn() { int16_t choice= -1; while (! btnpressed() ); // wait until button pad pressed if( pbtn(PIN_ESC) ) choice = PIN_ESC; if( pbtn(PIN_UP) ) choice = PIN_UP; if( pbtn(PIN_OK) ) choice = PIN_OK; if( pbtn(PIN_DN) ) choice = PIN_DN; if( pbtn(PIN_LE) ) choice = PIN_LE; if( pbtn(PIN_RI) ) choice = PIN_RI; while ( btnpressed() ); // wait until button pad released return choice; } //------------------------------------------------------------------------------------- // misc. tools int16_t toggleup(int16_t lo, int16_t hi, int16_t val ) { if ( val < hi ) val++; else val = lo; return val; } int16_t toggledn(int16_t lo, int16_t hi, int16_t val ) { if ( val > lo ) val--; else val = hi; return val; } //------------------------------------------------------------------------------------- // motor control #define MAXMOTORS 4 // max number of encoder motors at Arduino Uno=2 // Due=6 // Mega=8 // motor 0 #define pinenc0A 22 // enc0A yellow #define pinenc0B 23 // enc0B blue #define pinmot0d1 24 // dir0-1 << #define pinmot0d2 25 // dir0-2 #define pinmot0pwm 10 // pwm enable0 // motor 1 #define pinenc1A 26 // enc1A yellow #define pinenc1B 27 // enc1B blue #define pinmot1d1 28 // dir1-1 << #define pinmot1d2 29 // dir1-2 #define pinmot1pwm 9 // pwm enable1 // motor 2 #define pinenc2A 30 // enc2A yellow #define pinenc2B 31 // enc2B blue #define pinmot2d1 32 // dir2-1 << #define pinmot2d2 33 // dir2-2 #define pinmot2pwm 8 // pwm enable2 // motor 3 #define pinenc3A 34 // enc3A yellow #define pinenc3B 35 // enc3B blue #define pinmot3d1 36 // dir3-1 << #define pinmot3d2 37 // dir3-2 #define pinmot3pwm 7 // pwm enable3 //------------------------------------------------------------------------------------- // motor bit patterns const char COAST[]={0,0,0}; const char BREAK[]={0,0,1}; const char FWSLOW[]={0,1,0}; const char RVSLOW[]={0,1,1}; const char FWMED[]={1,0,0}; const char RVMED[]={1,0,1}; const char FWFAST[]={1,1,0}; const char RVFAST[]={1,1,1}; #define fwslow 20 #define rvslow -20 #define fwmed 60 #define rvslow -60 #define fwfast 100 #define rvfast -100 //===================================================================================== // SETUP () //===================================================================================== void setup() { char sbuf[128]; // output string Serial.begin(115200); pinMode(PIN_ESC,INPUT_PULLUP); pinMode(PIN_UP, INPUT_PULLUP); pinMode(PIN_OK, INPUT_PULLUP); pinMode(PIN_DN, INPUT_PULLUP); pinMode(PIN_LE, INPUT_PULLUP); pinMode(PIN_RI, INPUT_PULLUP); myGLCD.InitLCD(); LCDmaxX=myGLCD.getDisplayXSize(); LCDmaxY=myGLCD.getDisplayYSize(); myGLCD.setFont(SmallFont); _maxx_ = LCDmaxX / fontwi; _maxy_ = LCDmaxX / fonthi; memset(wspace, ' ', _maxx_); wspace[_maxx_]='\0'; lcdcls(); sprintf(sbuf, "Serial ok, GLCD=%dx%d",LCDmaxX,LCDmaxY); Serial.println(sbuf); myGLCD.print (sbuf, 0, 0); ResetNet(); RSeed = ( ((analogRead(A8)+1017)%100) * (TimerMS()% LRAND_MAX ) % LRAND_MAX ); srand(RSeed); // # DEBUG sprintf(sbuf, "Seed= %ld", RSeed); myGLCD.print (sbuf, 0,10); sprintf(sbuf, "Rand= %ld", rand() ); myGLCD.print (sbuf, 100,10); // # DEBUG memtest(20, "memtest: setup"); SetNetDefaultPatterns(); RefreshInputs(); // polls inputs and stores values to currIn[] array //*********************************** //******************************************************************************* // debug: test different input sets currIn[1]=1; //currIn[2]=0; currIn[3]=1; //currIn[4]=0; currIn[5]=0; currIn[6]=0; currIn[7]=0; //******************************************************************************* //*********************************** ComputeMatrix(); // applies inputs to net and computes outputs to currOut[] array TrainNet(); // basic training } //===================================================================================== //===================================================================================== //------------------------------------------------------------------------------------- // analog range bit patterns // returns 6 bits for ranges -32768...0...32767 or out of bounds (VOID==[32]) float Ana[64][8]={ {0,0,0,0,0,0,0,0}, // 0 {0,1,0,0,0,0,0,1}, // 0...1 {1,2,0,0,0,0,1,0}, // 1...2 {2,3,0,0,0,0,1,1}, {3,4,0,0,0,1,0,0}, {4,5,0,0,0,1,0,1}, {5,6,0,0,0,1,1,0}, {6,8,0,0,0,1,1,1}, {8,10,0,0,1,0,0,0}, {10,13,0,0,1,0,0,1}, {13,16,0,0,1,0,1,0}, {16,20,0,0,1,0,1,1}, {20,26,0,0,1,1,0,0}, {26,32,0,0,1,1,0,1}, {32,40,0,0,1,1,1,0}, {40,48,0,0,1,1,1,1}, {48,56,0,1,0,0,0,0}, {56,64,0,1,0,0,0,1}, {64,74,0,1,0,0,1,0}, {74,85,0,1,0,0,1,1}, {85,97,0,1,0,1,0,0}, {97,110,0,1,0,1,0,1}, {110,128,0,1,0,1,1,0}, {128,192,0,1,0,1,1,1}, {192,256,0,1,1,0,0,0}, {256,420,0,1,1,0,0,1}, {420,512,0,1,1,0,1,0}, {512,650,0,1,1,0,1,1}, {650,800,0,1,1,1,0,0}, {800,1024,0,1,1,1,0,1}, {1024,2048,0,1,1,1,1,0}, {2048,32767,0,1,1,1,1,1}, // <= SHORTMAX {0,0,1,0,0,0,0,0}, // #32: VOID ! {0,-1,1,0,0,0,0,1}, // 0... -1 {-1,-2,1,0,0,0,1,0}, // -1...-2 {-2,-3,1,0,0,0,1,1}, {-3,-4,1,0,0,1,0,0}, {-4,-5,1,0,0,1,0,1}, {-5,-6,1,0,0,1,1,0}, {-6,-8,1,0,0,1,1,1}, {-8,-10,1,0,1,0,0,0}, {-10,-13,1,0,1,0,0,1}, {-13,-16,1,0,1,0,1,0}, {-16,-20,1,0,1,0,1,1}, {-20,-26,1,0,1,1,0,0}, {-26,-32,1,0,1,1,0,1}, {-32,-40,1,0,1,1,1,0}, {-40,-48,1,0,1,1,1,1}, {-48,-56,1,1,0,0,0,0}, {-56,-64,1,1,0,0,0,1}, {-64,-74,1,1,0,0,1,0}, {-74,-85,1,1,0,0,1,1}, {-85,-97,1,1,0,1,0,0}, {-97,-110,1,1,0,1,0,1}, {-110,-128,1,1,0,1,1,0}, {-128,-192,1,1,0,1,1,1}, {-192,-256,1,1,1,0,0,0}, {-256,-420,1,1,1,0,0,1}, {-420,-512,1,1,1,0,1,0}, {-512,-650,1,1,1,0,1,1}, {-650,-800,1,1,1,1,0,0}, {-800,-1024,1,1,1,1,0,1}, {-1024,-2048,1,1,1,1,1,0}, {-2048,-32768,1,1,1,1,1,1} // >= -SHORTMAX }; //------------------------------------------------------------------------------------- int16_t ana2bits(int16_t aval) { // return array index int16_t i,j; if(aval == 0) return 0; else if( aval > 32767 ) return 32; // VOID else if( aval < -32768 ) return 32; // VOID else { for (i=1; i<32; ++i) { if ( (aval>Ana[0][i]) && (aval<=Ana[1][i]) ) return i; } for (i=32; i<64; ++i) { if ( (aval<Ana[0][i]) && (aval>=Ana[1][i]) ) return i; } } return 32; } //------------------------------------------------------------------------------------- // mem test extern char _end; extern "C" char *sbrk(int i); char *ramstart=(char *)0x20070000; char *ramend=(char *)0x20088000; //===================================================================================== void memtest(int ypos, char * str) { char sbuf[128]; // output string char *heapend=sbrk(0); register char * stack_ptr asm ("sp"); struct mallinfo mi=mallinfo(); sprintf(sbuf,str); Serial.println(); Serial.println(sbuf); myGLCD.print(sbuf, 0, ypos); sprintf(sbuf, "Dyn.RAM used: %-10ld ", mi.uordblks); Serial.println(sbuf); myGLCD.print(sbuf, 0, ypos+10); sprintf(sbuf, "Prg.stat.RAM used %-10ld ", & _end - ramstart); Serial.println(sbuf); myGLCD.print(sbuf, 0, ypos+20); sprintf(sbuf, "Stack RAM used %-10ld ", ramend - stack_ptr); Serial.println(sbuf); myGLCD.print(sbuf, 0, ypos+30); sprintf(sbuf, "Free mem: %-10ld ", stack_ptr - heapend + mi.fordblks); Serial.println(sbuf); myGLCD.print(sbuf, 0, ypos+40); myGLCD.print(wspace, 0, ypos+50); } //===================================================================================== // net: clear, set, reset, patch //===================================================================================== void clrnetbuf() { memset(inbuf, 0, sizeof(inbuf) ); memset(currIn, 0, sizeof(currIn) ); memset(outbuf, 0, sizeof(outbuf) ); memset(currOut, 0, sizeof(outbuf) ); } //===================================================================================== void ResetNet(){ memset(Input, 0, sizeof(Input) ); memset(Target, 0, sizeof(Target) ); //memset(Contxt, 0, sizeof(Contxt) ); clrnetbuf(); NumPattern=0; } //===================================================================================== // set input/target patterns manually //===================================================================================== int16_t setIOpattern(int16_t patt) { int16_t result; char sbuf[128]; // output string if(patt==-1) patt = CheckTestPattern(inbuf); // pattern number if known, if not: -1 if( patt > 0 ) sprintf(sbuf, " PATCH target #%-3d", patt); else sprintf(sbuf, " NEW target #%-3d", NumPattern+1); result=menu_setouttargets(sbuf); if (result == -1) return (result); // break by escape btn if (patt == -1) { // unknown => add new pattern! SetNewPattern( inbuf, outbuf ); result=NumPattern; } else { // override old pattern PatchPattern( patt, inbuf, outbuf); result=patt; } return result; // return written pattern number } //===================================================================================== //===================================================================================== // display net inputs and target outputs //===================================================================================== void DisplayNetTrainingIOs(int16_t code) { int16_t i, o, p; char sbuf[128]; // output string char msg[20]="! SUCCESS !" ; if (code==0) strcpy(msg,"calc.error"); if (code==2) strcpy(msg,"user-break"); /* print network outputs */ Serial.println(); Serial.println(); Serial.println(msg); sprintf(sbuf, "%-6ld: Err= %9.7f", epoch, Error) ; Serial.print("Epoch "); Serial.println(sbuf); myGLCD.print(sbuf, 0, 20); myGLCD.print(msg, 0, 30); sprintf(sbuf, "NET TRAINING TIME = %ld sec \n", BPTime/1000); Serial.println(sbuf); Serial.println(); sprintf(sbuf, "Patt. ") ; Serial.print(sbuf); myGLCD.print(sbuf, 0, 40); for( i = 1 ; i <= NumInput ; i++ ) { sprintf(sbuf, "Inp%-3d ", i) ; Serial.print(sbuf); } for( o = 1 ; o <= NumOutput ; o++ ) { sprintf(sbuf, "Targ%-3d Outp%-3d ", o, o); Serial.print(sbuf); } for(int p = 1 ; p <= NumPattern ; p++ ) { Serial.println(); sprintf(sbuf, "%3d ", p) ; Serial.print(sbuf); myGLCD.print(sbuf, 40, 40); for( i = 1 ; i <= NumInput ; i++ ) { sprintf(sbuf, "%5.2f ", Input[p][i]) ; Serial.print(sbuf); } for( o = 1 ; o <= NumOutput ; o++ ) { sprintf(sbuf, "%5.2f %5.2f ", Target[p][o], Output[p][o]) ; Serial.print(sbuf); } } Serial.println(); Serial.println(); sprintf(sbuf, "BPtrained, returning to main()...!") ; Serial.print(sbuf); Serial.println(); Serial.println(); } //===================================================================================== void displayMatrix(int16_t patt) { int32_t btn=-1; int16_t i, l, o, ibuf, p, lval=1, hval=NumPattern; float fbuf; char msgline[30], sbuf[30]; char valline[30]; p=patt; if(p==0) p=1; if(p>NumPattern) p=NumPattern; do { strcpy(msgline," 12345678901234567890"); sprintf(sbuf, "%-4d", p); strinsert(msgline, sbuf, 0); LCDWhiteRed(); Serial.println(msgline); lcdprintxy(0,0,msgline); curlf(); LCDNormal(); for (i=1; i<=NMAXIN; ++i) { l=(i-1)/20; if (i%20==1) { sprintf(sbuf, "%4d ", i-1); Serial.print(sbuf); lcdprint(sbuf); } ibuf = round(Input[p][i]); sprintf(sbuf, "%1d", ibuf); Serial.print(sbuf); lcdprint(sbuf); if (i%20==0) { Serial.println(); curlf(); } } Serial.println(); curlf(); strcpy(msgline,"TARG 12345678901234567890"); LCDRedBlack(); Serial.println(msgline); lcdprint(msgline); curlf(); LCDNormal(); for (i=1; i<=NMAXOUT; ++i) { l=(i-1)/20; if (i%20==1) { sprintf(sbuf, "%4d ", i-1); Serial.print(sbuf); lcdprint(sbuf); } ibuf = round(Target[p][i]); sprintf(sbuf, "%1d", ibuf); Serial.print(sbuf); lcdprint(sbuf); if (i%20==0) { Serial.println(); curlf(); } } Serial.println(); LCDYellowBlue(); sprintf(msgline, "toggle patt +-1: LEFT/RIGHT"); Serial.println(msgline); lcdprintxy(0, LCDmaxY-20, msgline); sprintf(msgline, "+-10:UP/DN edit:OK quit:ESC"); Serial.println(msgline); lcdprintxy(0, LCDmaxY-10, msgline); LCDNormal(); btn=getbtn(); if ( (btn==PIN_RI) || (btn==PIN_LE) ) { // browse displayed pattern if (btn==PIN_RI) p=toggleup(lval, hval, p); if (btn==PIN_LE) p=toggledn(lval, hval, p); } if ( (btn==PIN_UP) || (btn==PIN_DN) ) { // browse displayed pattern if (btn==PIN_UP) p=toggleup(lval, hval, p+9); if (btn==PIN_DN) p=toggledn(lval, hval, p-9); } if ( (btn==PIN_OK) ) { // change displayed pattern setIOpattern(p); } } while ( (btn!=PIN_ESC ) ); } //===================================================================================== int16_t RefreshInputs() { // polls inputs and stores values to currIn[] array // poll digital touch values and store directly (1 Dpin = 1 input) 16 DPins == 16 // poll analog sensor values and store bit pattern for ranges (1 Apin = 6 inputs) 8 A10bit == 48 // poll motor speed and store bit pattern for speed ranges (1 Apin = 6 inputs) 4 motors == 24 // Jordan/Elman neural context neurons == feedback inputs (1...NMAXCON) 20 inputs == 20 // =108 int16_t i, cx; cx = NMAXIN - NMAXOUT +1; // last NMAXCON inputs reserved for context neurons //for(i=cx; i<= NMAXIN; ++i) { currIn[i] = Contxt[i] ; } // } //===================================================================================== void ComputeMatrix() { // applies currIn[] inputs to net and computes outputs (outbuf[]) int16_t i, j, o; float SumH[NMAXHID+1]; float SumO[NMAXOUT+1]; float HidOut[NMAXHID+1]; float SumDOW[NMAXHID+1]; float lambda= 0.5; // context neuron self activation rate memset(SumH, 0, sizeof(SumH) ); memset(SumO, 0, sizeof(SumO) ); memset(HidOut, 0, sizeof(HidOut) ); memset(SumDOW, 0, sizeof(SumDOW) ); for( j = 1 ; j <= NumHidden ; j++ ) { // compute hidden unit activations SumH[j] = WeightLIn[0][j] ; // bias neuron for( i = 1 ; i <= NumInput ; i++ ) { SumH[j] += currIn[i] * WeightLIn[i][j] ; } HidOut[j] = 1.0/(1.0 + exp(-SumH[j])) ; // Sigmoidal Outputs } for( o = 1 ; o <= NumOutput ; o++ ) { // compute output unit activations and errors SumO[o] = WeightLOut[0][o] ; // bias neuron for( j = 1 ; j <= NumHidden ; j++ ) { SumO[o] += HidOut[j] * WeightLOut[j][o] ; } currOut[o] = 1.0/(1.0 + exp(-SumO[o])) ; // Sigmoidal Outputs } //for( o = 1 ; o <= NumOutput ; o++ ) { // compute context neurons // Contxt[o] = lambda*Contxt[o] + (1-lambda)*currOut[o]; // assign outputs*weight to context neurons //} } //===================================================================================== // check for known patterns //===================================================================================== int16_t CheckTestPattern(float * test) { int16_t i, p; for( p = 1; p <= NumPattern ; ++p) { for( i = 1; (i <= NumInput) && ( Input[p][i] == test[i] ); ++i); if (i > NumInput) {return p; } } return -1; } //===================================================================================== // patch old pattern //===================================================================================== void PatchPattern(int16_t patt, float * _ibuf, float * _obuf ){ int16_t i, o; if ( (NumPattern <= NMAXPAT) && ( NumPattern > 0) ) { // # DEBUG //Serial.print("NumPattern="); Serial.print(NumPattern); Serial.print(" SetNetPattern="); Serial.println(patt); for(i=1; i<=NMAXIN; ++i) { Input[patt][i] = _ibuf[i]; } for(o=1; o<=NMAXOUT; ++o) { Target[patt][o] = _obuf[o]; } } } //===================================================================================== // add new pattern //===================================================================================== void SetNewPattern(float * _ibuf, float * _obuf ){ int16_t i, o; if ( (NumPattern < NMAXPAT) && ( NumPattern >= 0) ) { NumPattern++; // # DEBUG //Serial.print("NumPattern="); Serial.print(NumPattern); Serial.print(" SetNetPattern="); Serial.println(patt); for(i=1; i<=NMAXIN; ++i) { Input[NumPattern][i] = _ibuf[i]; } for(o=1; o<=NMAXOUT; ++o) { Target[NumPattern][o] = _obuf[o]; } } }
Lesezeichen