Цикл выполняется не до конца
- Войдите на сайт для отправки комментариев
Ср, 15/04/2020 - 13:48
Здравствуйте! Только начал знакомиться с программированием на ардуино. Нашел в интернете скетч для обучения нейронной сети на базе ардуино. Сейчас пытаюсь модифицировать под свои нужды. Столкнулся с такой проблемой: в функции get_data осуществляется заполнение массива данными для обучения, но цикл доходит только до 59 итерации, строка Serial.print("out_data");, которую я поместил для проверки выхода из цикла, конечно же не срабатывает. Не могу понять в чем проблема. За ранее извиняюсь, если этот ужасный код кровоточит вам глаза)).
/****************************************************************** * ArduinoANN - An artificial neural network for the Arduino * All basic settings can be controlled via the Network Configuration * section. * See robotics.hobbizine.com/arduinoann.html for details. ******************************************************************/ #include <math.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> /****************************************************************** * Network Configuration - customized per network ******************************************************************/ #define DEBUG #define left_b 2 #define right_b 3 // Set the LCD address to 0x27 for a 16 chars and 2 line display LiquidCrystal_I2C lcd(0x27, 16, 2); byte curr_menu=0; byte menu_items=3; byte prog_start = 0; const byte PatternCount = 10; const byte InputNodes = 7; const byte HiddenNodes = 8; const byte OutputNodes = 4; const float LearningRate = 0.3; const float Momentum = 0.9; const float InitialWeightMax = 0.5; const float Success = 0.0004; const byte Input[PatternCount][InputNodes] = { { 1, 1, 1, 1, 1, 1, 0 }, // 0 { 0, 1, 1, 0, 0, 0, 0 }, // 1 { 1, 1, 0, 1, 1, 0, 1 }, // 2 { 1, 1, 1, 1, 0, 0, 1 }, // 3 { 0, 1, 1, 0, 0, 1, 1 }, // 4 { 1, 0, 1, 1, 0, 1, 1 }, // 5 { 0, 0, 1, 1, 1, 1, 1 }, // 6 { 1, 1, 1, 0, 0, 0, 0 }, // 7 { 1, 1, 1, 1, 1, 1, 1 }, // 8 { 1, 1, 1, 0, 0, 1, 1 } // 9 }; const byte Target[PatternCount][OutputNodes] = { { 0, 0, 0, 0 }, { 0, 0, 0, 1 }, { 0, 0, 1, 0 }, { 0, 0, 1, 1 }, { 0, 1, 0, 0 }, { 0, 1, 0, 1 }, { 0, 1, 1, 0 }, { 0, 1, 1, 1 }, { 1, 0, 0, 0 }, { 1, 0, 0, 1 } }; /****************************************************************** * End Network Configuration ******************************************************************/ int i, j, p, q, r; int ReportEvery1000; int RandomizedIndex[PatternCount]; long TrainingCycle; float Rando; float Error; float Accum; float Hidden[HiddenNodes]; float Output[OutputNodes]; float HiddenWeights[InputNodes+1][HiddenNodes]; float OutputWeights[HiddenNodes+1][OutputNodes]; float HiddenDelta[HiddenNodes]; float OutputDelta[OutputNodes]; float ChangeHiddenWeights[InputNodes+1][HiddenNodes]; float ChangeOutputWeights[HiddenNodes+1][OutputNodes]; void setup(){ //pinMode(A1, INPUT); //pinMode(A2, INPUT); //pinMode(A3, INPUT); //pinMode(A4, INPUT); Serial.begin(9600); pinMode(left_b, INPUT_PULLUP); pinMode(right_b, INPUT_PULLUP); // initialize the LCD lcd.begin(); // Turn on the blacklight and print a message. lcd.backlight(); //attachInterrupt(digitalPinToInterrupt(2), menu_change, LOW); //attachInterrupt(digitalPinToInterrupt(3), load_prog, LOW); attachInterrupt(0, menu_change, FALLING);//0 is Dpin2 attachInterrupt(1, load_prog, FALLING);//1 is Dpin3 randomSeed(analogRead(3)); ReportEvery1000 = 1; for( p = 0 ; p < PatternCount ; p++ ) { RandomizedIndex[p] = p ; } } //const int val_num, const int data_size, float mass[100][4] void loop(){ const int val_num = 4; //количество снимаемых параметров const int data_size = 100; //размер массива сколько будем собирать данных float mass[data_size][val_num]; do { menu_select(); } while (prog_start==0); if ((curr_menu == 1) && (prog_start == 1)) { lcd.clear(); lcd.print(F("Getting data")); #ifdef DEBUG //val_num, data_size, mass Serial.println("Inn"); get_data(val_num, data_size, mass); Serial.println("Out"); for (int i=1; i<=100;i++) { for (int j=1; j<=4;j++){ Serial.print("Mass["); Serial.print(i); Serial.print(","); Serial.print(j); Serial.print("] = "); Serial.print(mass[i][j]); Serial.println(); } } #endif prog_start=0; } if ((curr_menu == 2) && (prog_start == 1)) { lcd.clear(); lcd.print(F("Training NN")); train_nn(); prog_start=0; } if ((curr_menu == 3) && (prog_start == 1)) { lcd.clear(); lcd.print(F("Running Observer")); run_net(); prog_start=0; } } //Левая кнопка листает меню, правая подтверждает выбранный пункт void menu_change(void) { static unsigned long last_interrupt_time = 0; unsigned long interrupt_time = millis(); // If interrupts come faster than 200ms, assume it's a bounce and ignore if (interrupt_time - last_interrupt_time > 50) { int buttState = digitalRead(left_b); if (buttState == 0) { curr_menu++; if (curr_menu > menu_items) { curr_menu = 1; } } //Serial.print(F(" Curr_menu "));// Удалить потом //Serial.print(curr_menu); //Serial.print(F(" Prog_start ")); //Serial.print(prog_start); } last_interrupt_time = interrupt_time; } void load_prog(){ prog_start = 1; } void menu_select() { lcd.clear(); switch (curr_menu) { case 1: lcd.clear(); lcd.setCursor(6,0); lcd.print(F("Menu")); lcd.setCursor(0,1); lcd.print(F("Get data")); break; case 2: lcd.setCursor(6,0); lcd.print(F("Menu")); lcd.setCursor(0,1); lcd.print(F("Train NN")); break; case 3: lcd.setCursor(6,0); lcd.print(F("Menu")); lcd.setCursor(0,1); lcd.print(F("Run Observer")); break; default: break; } //prog_start=0; } void train_nn(){ /******************************************************************++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * Initialize HiddenWeights and ChangeHiddenWeights ******************************************************************/ for( i = 0 ; i < HiddenNodes ; i++ ) { for( j = 0 ; j <= InputNodes ; j++ ) { ChangeHiddenWeights[j][i] = 0.0 ; Rando = float(random(100))/100; HiddenWeights[j][i] = 2.0 * ( Rando - 0.5 ) * InitialWeightMax ; } } /****************************************************************** * Initialize OutputWeights and ChangeOutputWeights ******************************************************************/ for( i = 0 ; i < OutputNodes ; i ++ ) { for( j = 0 ; j <= HiddenNodes ; j++ ) { ChangeOutputWeights[j][i] = 0.0 ; Rando = float(random(100))/100; OutputWeights[j][i] = 2.0 * ( Rando - 0.5 ) * InitialWeightMax ; } } Serial.println(F("Initial/Untrained Outputs: ")); toTerminal(); /******************************************************************+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * Begin training ******************************************************************/ for( TrainingCycle = 1 ; TrainingCycle < 2147483647 ; TrainingCycle++) { /****************************************************************** * Randomize order of training patterns ******************************************************************/ for( p = 0 ; p < PatternCount ; p++) { q = random(PatternCount); r = RandomizedIndex[p] ; RandomizedIndex[p] = RandomizedIndex[q] ; RandomizedIndex[q] = r ; } Error = 0.0 ; /****************************************************************** * Cycle through each training pattern in the randomized order ******************************************************************/ for( q = 0 ; q < PatternCount ; q++ ) { p = RandomizedIndex[q]; /****************************************************************** * Compute hidden layer activations ******************************************************************/ for( i = 0 ; i < HiddenNodes ; i++ ) { Accum = HiddenWeights[InputNodes][i] ; for( j = 0 ; j < InputNodes ; j++ ) { Accum += Input[p][j] * HiddenWeights[j][i] ; } Hidden[i] = 1.0/(1.0 + exp(-Accum)) ; } /****************************************************************** * Compute output layer activations and calculate errors ******************************************************************/ for( i = 0 ; i < OutputNodes ; i++ ) { Accum = OutputWeights[HiddenNodes][i] ; for( j = 0 ; j < HiddenNodes ; j++ ) { Accum += Hidden[j] * OutputWeights[j][i] ; } Output[i] = 1.0/(1.0 + exp(-Accum)) ; OutputDelta[i] = (Target[p][i] - Output[i]) * Output[i] * (1.0 - Output[i]) ; Error += 0.5 * (Target[p][i] - Output[i]) * (Target[p][i] - Output[i]) ; } /****************************************************************** * Backpropagate errors to hidden layer ******************************************************************/ for( i = 0 ; i < HiddenNodes ; i++ ) { Accum = 0.0 ; for( j = 0 ; j < OutputNodes ; j++ ) { Accum += OutputWeights[i][j] * OutputDelta[j] ; } HiddenDelta[i] = Accum * Hidden[i] * (1.0 - Hidden[i]) ; } /****************************************************************** * Update Inner-->Hidden Weights ******************************************************************/ for( i = 0 ; i < HiddenNodes ; i++ ) { ChangeHiddenWeights[InputNodes][i] = LearningRate * HiddenDelta[i] + Momentum * ChangeHiddenWeights[InputNodes][i] ; HiddenWeights[InputNodes][i] += ChangeHiddenWeights[InputNodes][i] ; for( j = 0 ; j < InputNodes ; j++ ) { ChangeHiddenWeights[j][i] = LearningRate * Input[p][j] * HiddenDelta[i] + Momentum * ChangeHiddenWeights[j][i]; HiddenWeights[j][i] += ChangeHiddenWeights[j][i] ; } } /****************************************************************** * Update Hidden-->Output Weights ******************************************************************/ for( i = 0 ; i < OutputNodes ; i ++ ) { ChangeOutputWeights[HiddenNodes][i] = LearningRate * OutputDelta[i] + Momentum * ChangeOutputWeights[HiddenNodes][i] ; OutputWeights[HiddenNodes][i] += ChangeOutputWeights[HiddenNodes][i] ; for( j = 0 ; j < HiddenNodes ; j++ ) { ChangeOutputWeights[j][i] = LearningRate * Hidden[j] * OutputDelta[i] + Momentum * ChangeOutputWeights[j][i] ; OutputWeights[j][i] += ChangeOutputWeights[j][i] ; } } } /****************************************************************** * Every 1000 cycles send data to terminal for display ******************************************************************/ ReportEvery1000 = ReportEvery1000 - 1; if (ReportEvery1000 == 0) { Serial.println(); Serial.println(); Serial.print (F("TrainingCycle: ")); Serial.print (TrainingCycle); Serial.print (F(" Error = ")); Serial.println (Error, 5); toTerminal(); if (TrainingCycle==1) { ReportEvery1000 = 999; } else { ReportEvery1000 = 1000; } } /****************************************************************** * If error rate is less than pre-determined threshold then end ******************************************************************/ if( Error < Success ) break ; } Serial.println (); Serial.println(); Serial.print (F("TrainingCycle: ")); Serial.print (TrainingCycle); Serial.print (F(" Error = ")); Serial.println (Error, 5); toTerminal(); Serial.println (); Serial.println (); Serial.println (F("Training Set Solved! ")); Serial.println (F("--------")); Serial.println (); Serial.println (); ReportEvery1000 = 1; } void toTerminal() { for( p = 0 ; p < PatternCount ; p++ ) { Serial.println(); Serial.print (F(" Training Pattern: ")); Serial.println (p); Serial.print (F(" Input ")); for( i = 0 ; i < InputNodes ; i++ ) { Serial.print (Input[p][i], DEC); Serial.print (F(" ")); } Serial.print (F(" Target ")); for( i = 0 ; i < OutputNodes ; i++ ) { Serial.print (Target[p][i], DEC); Serial.print (F(" ")); } /****************************************************************** * Compute hidden layer activations ******************************************************************/ for( i = 0 ; i < HiddenNodes ; i++ ) { Accum = HiddenWeights[InputNodes][i] ; for( j = 0 ; j < InputNodes ; j++ ) { Accum += Input[p][j] * HiddenWeights[j][i]; } Hidden[i] = 1.0/(1.0 + exp(-Accum)) ; } /****************************************************************** * Compute output layer activations and calculate errors ******************************************************************/ for( i = 0 ; i < OutputNodes ; i++ ) { Accum = OutputWeights[HiddenNodes][i] ; for( j = 0 ; j < HiddenNodes ; j++ ) { Accum += Hidden[j] * OutputWeights[j][i]; } Output[i] = 1.0/(1.0 + exp(-Accum)) ; } Serial.print (F(" Output ")); for( i = 0 ; i < OutputNodes ; i++ ) { Serial.print (Output[i], 5); Serial.print (" "); } } } //const int val_num, const int data_size, float mass[100][4] ////////////////////////////////GET_DATA Изменить ихсходя из требований//////////////////////////// void get_data(const int val_num, const int data_size, float mass[100][4]){ Serial.print(F("Inn_data")); //int Sensor=analogRead(A0); //Serial.println(Sensor); for (int i=1; i<=data_size; i++) { Serial.println(i); delay(1000); mass[i][1]={analogRead(A0)}; mass[i][2]={analogRead(A0)+0.2}; mass[i][3]={analogRead(A0)+0.3}; mass[i][4]={analogRead(A0)+0.4}; } Serial.print("out_data"); } void run_net(){ } void prepare_data(){ }
Так же для проверки вынес этот участок кода в отдельный скетч. Там он работает корректно:
наверное памяти не хватает
а Ардуина какая?
а Ардуина какая?
ардуино Uno. После компиляции скетча пишет, что занято 75% динамической памяти и пишет предупреждение, якобы может работать нестабильно. Сократил использование памяти до 74% предупреждение больше не пишет, проблема осталась та же.
Налицо крайне нерациональное использование памяти. Только в описании глобальных переменных (строчки с 35 по 94) я уже насчитал порядка 1.5Кб оперативки.
а вот это вообще что?
массив размером в 400 флоатов. описанный в параметрах? :)
У тебя только двухуровневый массив на 400 элементов типа float, съедает 1600 байт, а ещё дисплей 512байт и математика.
Напомню , ОЗУ у 328меги 2кб
Налицо крайне нерациональное использование памяти. Только в описании глобальных переменных (строчки с 35 по 94) я уже насчитал порядка 1.5Кб оперативки.
а вот это вообще что?
массив размером в 400 флоатов. описанный в параметрах? :)
Для моей задачи необходим большой массив данных, 100 на 4 это еще маленький. Я собираюсь заполнять его по ходу выполнения программы и изменять его значения в других функциях. Насколько я понял в таком случае PROGMEM с ним мне не поможет. Как я могу освободить динамическую память в таком случае, если работу с большими массивами именно float не избежать?
сдается мне, что таких массивов у него два - один в процедуре loop(), другой - в get_data. По-моему это два разных массива, если не ошибаюсь.
Это не считая кучи массивов в начале кода.
Суммарно у него потребность в оперативке превышает обьем памяти Уно раза этак в три...
Как я могу освободить динамическую память в таком случае, если работу с большими массивами именно float не избежать?
в вашем случае, думаю, никак. Уменьшить можно раза в два - но все равно в Уно не влезет. Берите мегу .
И крайне полезно было бы прочесть учебник по Си в плане описания переменных и передачи парметров в функции. А то вам и меги не хватит
что-то добрые вы сегодня, не дали студенту самому посчитать память )))
если работу с большими массивами именно float не избежать?
это особенно забавно с учетом того, что "массив флоат" заполняется с помощью команды analogread().
Стоило бы эту ветку отправить вашим преподавателям, такое долбо..во нужно наказывать.
что-то добрые вы сегодня, не дали студенту самому посчитать память )))
да лан. он такое дерево. что даже с подсказками не решит
если работу с большими массивами именно float не избежать?
это особенно забавно с учетом того, что "массив флоат" заполняется с помощью команды analogread().
Стоило бы эту ветку отправить вашим преподавателям, такое долбо..во нужно наказывать.
Мне с преобразователя нужно будет снять несколько изменяющихся во времени параметров, сформировав тот самый массив float. Если я правильно понимаю то это делается с помощью analogread().
Почему так грубо? Я же написал в старт посте, что только начал ознакомление с ардуино.
Если я правильно понимаю ...
неправильно
Уважаемые админы. все же обьясните, кто втихую чистит ветки и по какому принципу?
Из ардуино.ру решили сделать бретборд.ру
Придётся и тут блокироваться
Мне с преобразователя нужно будет снять несколько изменяющихся во времени параметров, сформировав тот самый массив float. Если я правильно понимаю то это делается с помощью analogread().
У Ардуино УНО 10-и разрядный АЦП. Из 10-и двоичных разрядов реально достоверны только старшие 8.
С АЦП читают в формате int. См.: http://arduino.ru/Reference/AnalogRead
Мне с преобразователя нужно будет снять несколько изменяющихся во времени параметров, сформировав тот самый массив float. Если я правильно понимаю то это делается с помощью analogread().
У Ардуино УНО 10-и разрядный АЦП. Из 10-и двоичных разрядов реально достоверны только старшие 8.
С АЦП читают в формате int. См.: http://arduino.ru/Reference/AnalogRead
Спасибо за разъяснения, это помогло решить проблему
С АЦП читают в формате int. См.: http://arduino.ru/Reference/AnalogRead
Спасибо за разъяснения, это помогло решить проблему
да ну? Два массива по 400 элементов, плюс куча массивов в начале. плюс буфер экрана - волшебно поместились в 2К оперативы? :)
Спасибо за разъяснения, это помогло решить проблему
Пожалуйста. Я позволю себе сделать ещё несколько замечаний и уточнений.
1. Я не знаю, что вынудило Вас использовать МК Ардуино УНО для задач ИИ с методами, по сути, относящимися к анализу "БигДата". На мой взгляд, это можно было сделать только от полного безисхода. Эти МК ориентированы совершенно на другой класс задач и обладают весьма ограниченными ресурсами.
2. Если Вы действительно взялись изучать Ардуино, "таки надо изучать". Если Вы собрались использовать какие-либо возможности аппаратуры и языка программирования, то следует плотно ознакомиться с их особенностями до попытки их применить. Пример с analogRead() очень "режет глаз".
3. Я не зря написал, что у АЦП Ардуино "честные" только 8 старших двоичных разрядов. Если Ваш процесс физический, и Вас устраивает реальная точность в 8 двоичных разрядов (а это лучше 0,5%, между прочим), то исходные данные вообще можно помещать в беззнаковые байтовые массивы. При их математической обработке, возможно, придется делать преобразования типов, чтобы избежать переполнений и не потерять точность, а результат потом снова приводить, для экономии памяти при хранении, к 8-и двоичным разрядам. Я Вашу программу не смотрел и, если честно, смотреть не буду. Здесь есть реальные специалисты в области программирования вообще и программирования Ардуино, в частности. Прислушайтесь к их рекомендациям.