Цикл выполняется не до конца
- Войдите на сайт для отправки комментариев
Ср, 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(){
}
Так же для проверки вынес этот участок кода в отдельный скетч. Там он работает корректно:
#include <math.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> #include <avr/pgmspace.h> //float get_data(val_num, data_size, mass); //const byte val_num = 4; //количество снимаемых параметров //const byte data_size = 100; //размер массива сколько будем собирать данных //float mass[data_size][val_num]={}; void setup() { Serial.begin(9600); //get_data(val_num, data_size, mass); } void loop() { const int val_num = 4; //количество снимаемых параметров const int data_size = 100; //размер массива сколько будем собирать данных float mass[data_size][val_num]; get_data(val_num, data_size, mass); 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(); } } end_prog(); } // void get_data(const int val_num, const int data_size, float mass[100][4]){ //int Sensor=analogRead(A0); //Serial.println(Sensor); for (int i=1; i<=data_size; i++) { delay(100); mass[i][1]={analogRead(A0)}; mass[i][2]={analogRead(A0)*2}; mass[i][3]={analogRead(A0)*3}; mass[i][4]={analogRead(A0)*4}; } } void end_prog(){наверное памяти не хватает
а Ардуина какая?
а Ардуина какая?
ардуино Uno. После компиляции скетча пишет, что занято 75% динамической памяти и пишет предупреждение, якобы может работать нестабильно. Сократил использование памяти до 74% предупреждение больше не пишет, проблема осталась та же.
Налицо крайне нерациональное использование памяти. Только в описании глобальных переменных (строчки с 35 по 94) я уже насчитал порядка 1.5Кб оперативки.
а вот это вообще что?
void get_data(const int val_num, const int data_size, float mass[100][4]){массив размером в 400 флоатов. описанный в параметрах? :)
У тебя только двухуровневый массив на 400 элементов типа float, съедает 1600 байт, а ещё дисплей 512байт и математика.
Напомню , ОЗУ у 328меги 2кб
Налицо крайне нерациональное использование памяти. Только в описании глобальных переменных (строчки с 35 по 94) я уже насчитал порядка 1.5Кб оперативки.
а вот это вообще что?
void get_data(const int val_num, const int data_size, float mass[100][4]){массив размером в 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-и двоичным разрядам. Я Вашу программу не смотрел и, если честно, смотреть не буду. Здесь есть реальные специалисты в области программирования вообще и программирования Ардуино, в частности. Прислушайтесь к их рекомендациям.