Робот управляемый нейронной сетью



Предисловие:

Привет всем тем, кто это читает. Я хотел бы рассказать Вам об одном своем эксперименте. Собственно описанная ниже идея не нова и наверняка приходила в голову многим людям, увлекающимся данной темой. На самом деле от простых размышлений до практической реализации прошло достаточно много времени. Начать работу мешало абсолютная уверенность в том, что в голове все работает, и вроде как реализовывать все в железе не имеет смысла. Но набравшись «смелости» и приступив к делу, все оказалось намного сложнее. На пути к достижению к цели пришлось немного повозиться. Об этом и история…

Цели эксперимента:

1) Установить возможность запуска нейронной сети на контроллере Arduino.
2) Установить пригодность ее работы в поставленных условиях.
3) Определить наилучшую топологию сети.

Для решения поставленной задачи были выбраны следующие комплектующие:

1) Контроллер –Arduino 328
2) Колесная платформа – самодельная.
3) Датчик расстояния – HC – SR04
4) Датчик света – фоторезистор.
5) Датчик звука – китайский микрофон с логическим выходом.
6) Нейронная сеть – 2 слоя, 5 нейронов в каждом

Так же были сформированы дополнительные требования:

1) Сеть должна обучаться отдельно (На ПК).
2) Параметры сети должны загружаться в контроллер на лету, без перепрашивки.

Забегая немного вперед, хочу пояснить третий пункт. С топологией «проиграться» практические не удалось, оперативная память контроллера наложила ограничения. Изначально топология сети была трехслойной (5 – 8 — 5).

Чему и как будем учить?

Из конструкции робота видно, что даже без использования нейронной сети, его возможности ограничены. Максимум что можно «логически» запрограммировать, это обход препятствий с выбором наилучшего направления, включение/выключение робота по звуку или уровню освещенности и. т.д, одним словом в интернете масса подобных поделок. Но вот какая штука – все это быстро надоедает,… Что если захотелось что- то поменять, например реакцию на свет или звук или получить некоторую непредсказуемость в поведении. Конечно, можно предусмотреть все это в программе контроллера, данные грузить с SD карточки, а непредсказуемость получить простым рандомом. Но мы не ищем легких путей…:).
Делать будем так: пусть все выше перечисленные задачи решает нейронная сеть.
Обучать будем методом обратного распространения ошибки. Кстати о том что такое нейронная сеть и алгоритм обратного распространения можно прочитать здесь и здесь
Коэффициенты сети будут переноситься в контроллер посредством SD карты.

Как же это работает?

Был заложен следующий принцип работы:

На компьютере:
1) Создается обучающая выборка
2) Сеть обучается до тех пор, пока глобальная ошибка на всех выборках не станет равной нулю.(на самом деле будет немного не так)
3) После обучения создается отчет и файл для контроллера.
4) Файл записывается на карточку.

На Arduino:
1) После включения с SD карточки загружаются параметры сети.
2) После загрузки сеть готова к работе.
3) На основании показаний датчиков формируется «вектор данных».
4) Этот вектор подается на вход сети.
5) После просчета, выходной вектор сети подается на дешифратор.
6) Дешифратор, в зависимости от результата работы сети, определяет тип команды и выполняет ее.
7) Цикл повторяется с пункта 3,

Вектором данных я буду называть одномерный массив определенной размерности, элементы этого массива – числа. Скажем, что в нулевом элементе будет храниться расстояние до препятствия справа, в первом расстояние в прямой видимости и.т.д.
Почему же все-таки вектор? Когда я только начинал разбираться с нейронными сетями я сформировал для себя следующие понятие: «любой набор данных есть точка в N мерном пространстве». В нашем случае пространство будет размерности 5. Да, да такие бывают :).
Вот точное расположение данных в массиве:

input[0] – расстояние с права.
input[1] – расстояние в прямой видимости.
input[2] – расстояние слева.
input[3] – значение фоторезистора.
Input[4] – уровень микрофона (1 или 0)

Собственно куда же без картинки 🙂



Железо:

Честно говоря, я не очень сильно хочу уделять сильное внимание этому пункту. Причина этого желания в том, что сам робот в первую очередь не является объектом исследования а его реализация банальна. Единственное о чем я хочу рассказать, это об драйвере двигателей L293D. Эту замечательную микросхему я использовал в силу отсутствия готового шилда. Честно говоря, в электронике я не селен и подключил ее по первой загугленной схеме. В итоге оказалось, что для управления направлением вращения приходилось переводить ножку в состояние INPUT. Это было весьма не привычно, и я до сих пор не знаю чем это может аукнуться…
Насчет колес…в качестве редукторов были использованы серво — машинки, переделанные на постоянное вращение. Все остальные примочки как датчик расстояния и SD card модуля были подключены по стандартным схемам.

Немного фото:

Да, качество сборки на 3 🙂

Часть программная:

Даже не знаю с чего начать. С одной стороны тут нет ни каких велосипедов все стандартно:

Начнем с программы для ПК:
Написана она, а точнее они на C#. Потому что это достаточно простой язык и я часто использую его в своей работе, но не об этом. В программах нет классов все сделано в «функциональном» стиле для более простого понимания начинающим. Как Вы успели понять программ две: Первая это простой интерфейс, код которого не заслуживает тут присутствовать ибо та все очень просто. Будет только скриншот:

Тут все предельно просто: движками крутим значение на входах, выбираем мысленно реакцию на эти данные из предложенных пяти и ставим галочку. Жмем «добавить».

В результате работы получается файл вот с таким содержанием:

Слева двоеточия что подаем на вход, справа то, что хотим получить.

После того как мы заполнили этот файл, нажимаем кнопку «Создать» и он автоматически передается другой программе. Собственно та другая программа выполняет две функции: учит сеть на предъявленных данных и формирует отчет. Начнем с конца:

Вот такой отчет хороший:

Хороший он потому, что строки Input Res и NET OUT совпадают. Это говорит о том, что при подачи на вход Input data мы хотели бы получить Input Res, а получаем NET OUT. Так что о качестве работы сети мы будем судить из этого отчета.

Теория гласит, что при обучении сети образцы стоит предъявлять в случайном порядке. К чему я это – в моей практике это, на первый взгляд, незначительное утверждение в действительности влияет на скорость сходимости алгоритма. Так же на скорость влияет и первоначально выбранные веса. Бывало что с первой попытки алгоритм не сходился, приходилось по несколько раз запускать обучение для того что бы добиться результата.

Я не знаю стоит ли приводить полный код программы вместе с парсером файлов и созданием выходного файла для контроллера. Так что приведу на свой взгляд только самые важны моменты в одном листинге:

static int InputN = 5,  //Входные нейронны
                   OutN = 5;    //Выходные нейроны

        static int InputW = 5,  //Веса на входе
                   OutW = 5;    //Веса на выходе


        static Random run = new Random();                           //Гениратор случайностей

        static float[,] INPUT_W  = new float[InputN, InputW];       //Входной слой
        static float[,] OUTPUT_W = new float[OutN,OutW];            //Выходной слой

        static float[] INPUT_RESULT  = new float[InputN];           //Выход первого слоя
        static float[] OUTPUT_RESULT = new float[OutN];             //Выход последнего слоя

        static float[] OUTPUT_ERROR = new float[OutN];              //Ошибка на выходе
        static float[] INPUT_ERROR  = new float[InputN];            //Ошибка на входе

        static float Sig = 0.5f;                                    //Значение порога
        static float etta = 0.001f;                                 //Значение параметра скорости

        static List Input_patern = new List();    //Входные данные

        static List Out_patern = new List();      //Ответы


        /*Инициализация весов*/
       static void init_net() {
            for (int i = 0; i < InputN; i++){
                for (int j = 0; j < InputW; j++){
                    INPUT_W[i, j] = (float)run.NextDouble() - 0.5f;
                }
            }
            for (int i = 0; i < OutN; i++){
                for (int j = 0; j < OutW; j++){
                    OUTPUT_W[i, j] = (float)run.NextDouble() - 0.5f;
                }
            }
        }


        /*Прямой проход*/
        static void DirectMotion(float[] vector) {

            if (vector.Length > InputW) { return; }

            /*Первый слой*/
            for (int i = 0; i < InputN; i++){
                INPUT_RESULT[i] = 0.0f;
                for (int j = 0; j < InputW; j++){
                    INPUT_RESULT[i] += INPUT_W[i, j] * vector[j];
                }
                INPUT_RESULT[i] = Sigma(INPUT_RESULT[i]);
            }

            /*Выходной слой*/
            for (int i = 0; i < OutN; i++){
                OUTPUT_RESULT[i] = 0.0f;
                for (int j = 0; j < OutW ; j++){
                    OUTPUT_RESULT[i] += OUTPUT_W[i, j] * INPUT_RESULT[j];
                }
                OUTPUT_RESULT[i] = Sigma(OUTPUT_RESULT[i]);
            }

        }

        static float BackPropagation(float[] vector, float[] target) {
            /*--------------------------------Прямой проход-------------------------------------------*/

            DirectMotion(vector);

            /*----------------------------------------------------------------------------------------*/

            /*--------------------------------Расчет ошибки-------------------------------------------*/

            /*Ошибка на выходе*/
            for (int i = 0; i < OUTPUT_ERROR.Length; i++) {
                OUTPUT_ERROR[i] = 0.0f;
                OUTPUT_ERROR[i] = target[i] - OUTPUT_RESULT[i];
            }
            /*Ошибка на входе*/
            for (int neurons = 0; neurons < INPUT_ERROR.Length; neurons++){
                INPUT_ERROR[neurons] = 0.0f;
                for (int out_n = 0; out_n < OutN; out_n++) {
                    INPUT_ERROR[neurons] += OUTPUT_ERROR[out_n] * OUTPUT_W[out_n, neurons];
                }
            }

            /*-----------------------------------------------------------------------------------------*/

            /*---------------------------------Коррекция ошибки----------------------------------------*/

            /*  Входной слой */
            for (int n = 0; n < InputN; n++){
                for (int w = 0; w < InputW; w++){
                    INPUT_W[n, w] += (etta * INPUT_ERROR[n] * vector[w]);
                }
            }
            /*Выходной слой*/
            for (int n = 0; n < OutN; n++){
                for (int w = 0; w < OutW; w++){
                    OUTPUT_W[n, w] += (etta * OUTPUT_ERROR[n] * INPUT_RESULT[w]);
                }
            }

            /*------------------------------------------------------------------------------------------*/

            /*возвращаем ошибку на текущем наборе...*/
            return calculate_global_error();
        }

        static float calculate_global_error() {
            float error = 0.0f;
            for (int i = 0; i < OUTPUT_ERROR.Length; i++) {
                error += Math.Abs(OUTPUT_ERROR[i] * OUTPUT_ERROR[i]);
            }
            return error * 0.5f;
        }


        static void Learn() {
            int Iteration = 0;
            float Error = 0.0f;
            while (Iteration < 250000) {
                Error = 0.0f;
                for (int paterns = 0; paterns <  Input_patern.Count; paterns++) {
                   Error += BackPropagation(Input_patern[paterns], Out_patern[paterns]);
                }
                Console.WriteLine(Error);
                Iteration++;
            }
        }

        /*Пороговая функция активации*/
        static float Sigma(float value) { if (value >= Sig) { return 1.0f; } return 0.0f; }

Собственно ни чего сложного. Как мы видим из кода в качестве функции активации нейронов выбрана пороговая функция с параметром срабатывания 0,5. Это позволяет избавиться от производных при обучении, а на контроллере не тратить время на вычисление значения логистической функции. Хотя при этом мы жертвуем временем сходимости алгоритма (это не научная теория, а лишь мои наблюдения на практике).
Да, возможно кто то заметил, что в процессе обучения стоит константное число итераций. Это связанно с тем, что иногда сеть проваливается в локальные минимумы, при этом ошибка равно нулю, а вот качество обучения порой ужасное. Так что пришлось сделать так..Возможно я что то делаю неверно…если кто то заметит, скажите пожалуйста.

Собственно код Arduino:

#include <Servo.h>
#include <SD.h>
#include <Ultrasonic.h>


#define R_F   5
#define L_F   8

#define R_R   6
#define L_R   9

#define TRIG  4
#define ECHO  7

#define INPUT_W_COUNT  5    //
#define INPUT_N_COUNT  5    //

#define OUTPUT_W_COUNT 5    //
#define OUTPUT_N_COUNT 5    //

#define INPUT_VECTOR_SIZE  5  //
#define TMP_VECTOR_SIZE   50  //

#define START_ANGLE        130
#define RIGHT_ANGLE        55
#define LEFT_ANGLE         180

#define SERVO_PIN          3
#define MIC_PIN            2
#define REZISTOR_PIN       0

/*Для чтения данных с флешки*/
File myFile;
/*Датчик растояния*/
Ultrasonic dist(TRIG, ECHO);
/*голова :)*/
Servo servo;

float input[INPUT_VECTOR_SIZE];
float Wtmp[TMP_VECTOR_SIZE];

/*Веса первого слоя*/
float INPUT_W[INPUT_N_COUNT][INPUT_W_COUNT];
/*Веса выходного слоя*/
float OUTPUT_W[OUTPUT_N_COUNT][OUTPUT_W_COUNT];

float INPUT_OUT[INPUT_N_COUNT];     //Выход первого слоя

float NET_OUT[OUTPUT_N_COUNT];       //Выход сети


int FileCount = 0, CountW = 0;

void setup(){

  servo.attach(SERVO_PIN);

  servo.write(START_ANGLE);

  delay(1000);

  ReadDataFromSD();

  delay(1000);
}

void loop(){
    /*Получаем данные с датчиков*/
    CreateVector();
    /*Расчитываем выход сети*/
    NeuralNetUpdate();
}

/*Пересчет выхода сети*/
void NeuralNetUpdate(){
  /*Входной слой*/

  for(int N = 0; N < INPUT_N_COUNT; N++){
    INPUT_OUT[N] = 0.0;
      for(int W = 0; W < INPUT_W_COUNT; W++){
        INPUT_OUT[N] += input[W] * INPUT_W[N][W];
      }
      INPUT_OUT[N] = Sigmoid(INPUT_OUT[N]);
    }
  /*Выходной слой*/
  for(int N = 0; N < OUTPUT_N_COUNT; N++){
    NET_OUT[N] = 0.0;
      for(int W = 0; W < OUTPUT_W_COUNT; W++){
        NET_OUT[N] += INPUT_OUT[W] * OUTPUT_W[N][W];
      }
        NET_OUT[N] = Sigmoid(NET_OUT[N]);
       if(NET_OUT[N] == 1.0){ command(N); }
    }
}

float Sigmoid(float value){
  if(value > 0.50f){return 1.0;}
  return 0.0f;
}

void CreateVector(){
  input[1] = (float)dist.Ranging(CM);
  input[3] = analogRead(0);
  input[4] = digitalRead(2);
}

void LoadInputW(){
    for(int N = 0; N < INPUT_N_COUNT; N++){
      for(int W = 0; W < INPUT_W_COUNT; W++){
        INPUT_W[N][W] = Wtmp[CountW];
        CountW++;
      }
    }
}
void LoadOutputW(){
    for(int N = 0; N < OUTPUT_N_COUNT; N++){
      for(int W = 0; W < OUTPUT_W_COUNT; W++){
        OUTPUT_W[N][W] = Wtmp[CountW];
        CountW++;
      }
    }
}
/*Заполняет временный массив коэфиуиентами с SD карты*/
void ReadDataFromSD(){


   pinMode(10, OUTPUT);

      if (!SD.begin(10)) {return; }

      myFile = SD.open("test.txt");
        if (myFile) {
          int i = 0;
           char tmp[32];
            while (myFile.available())
            {
            	tmp[i] = myFile.read();
                if(tmp[i] == ';'){
                    tmp[i] = ' ';
                    Wtmp[FileCount] = atof(tmp);
                    FileCount++;
                    i = 0;
                }
            else
            {
             i++;
            }
        }
    myFile.close();
 }
    /*Загружаем первый слой*/
    LoadInputW();
    /*Загружаем второй слой*/
    LoadOutputW();
}

void command(int value){
  if(value == 0){ Run();    delay(2000); Stop();  return;}
  if(value == 1){ Stop();   delay(2000); return;}
  if(value == 2){ Revers(); delay(2000); Left();  delay(2000);  Stop(); return; }
  if(value == 3){ Revers(); delay(2000); Right(); delay(2000);  Stop(); return;}
  if(value == 4){ View();   return;}
}

void Stop(){
    pinMode(R_R, OUTPUT);
    pinMode(L_R, OUTPUT);
    pinMode(R_F, OUTPUT);
    pinMode(L_F, OUTPUT);
}

void Run(){
  input[2] = 0.0f;
  input[0] = 0.0f;
  pinMode(R_R, OUTPUT);
  pinMode(L_R, OUTPUT);
  pinMode(R_F, INPUT);
  pinMode(L_F, INPUT);
}
void Revers(){
    pinMode(R_R, INPUT);
    pinMode(L_R, INPUT);
    pinMode(R_F, OUTPUT);
    pinMode(L_F, OUTPUT);
}
void Left(){
  input[2] = 0.0f;
  input[0] = 0.0f;
   pinMode(R_R, OUTPUT);
   pinMode(L_F, OUTPUT);
   pinMode(L_R, INPUT);
   pinMode(R_F, INPUT);
}

void Right(){
    input[2] = 0.0f;
    input[0] = 0.0f;
   pinMode(R_R, INPUT);
   pinMode(L_F, INPUT);
   pinMode(L_R, OUTPUT);
   pinMode(R_F, OUTPUT);
}

void View(){
   input[1] = 0.0f;
   servo.write(RIGHT_ANGLE);  delay(500); input[0] = (float)dist.Ranging(CM); delay(800);
   servo.write(LEFT_ANGLE);   delay(500); input[2] = (float)dist.Ranging(CM); delay(800);
   servo.write(START_ANGLE);  delay(500);
}

Вот оно видео:

http://www.youtube.com/watch?v=Z_8qCkqgKos&feature=youtu.be

Выводы:

Запустить сеть на Arduino возможно и она даже будет работать. Временами конечно же начинаются глюки. Я думаю они связаны с обучающей выборкой. Я не тратил особо много времени на ее подборку и по этому не могу утверждать точно. Возможно в скором времени будут внесены некоторые коррективы. Ну а сейчас пока вот так. Спасибо за внимание.


0 комментариев на «“Робот управляемый нейронной сетью”»

  1. Интересные результаты. Но для такого небольшого количества вводных параметров лучше было бы использовать деревья принятия решений.

    • Здравствуйте. Действительно существует достаточное количество алгоритмов призванных решать по сути одни и те же задачи. Но в данном эксперименте интерес вызывали именно ИНС. Я не спорю об их избыточности в данном примере. Но в конце концов, можно было бы в конечном итоге просто написать маленький код, который однозначно бы решал конкретную задачу.Спасибо.

  2. интересный робот, а какой алгоритм работы у него получается в результате? к чему он стремиться? искать где светлее тише и больше места? или наоборот дискотечный вариант, ищем где потемнее и пошумнее? 🙂

    и вопрос не по теме, а у вас нет опыта соединить 2 ардуины вместе?
    roboforum.ru/forum86/topic15339.html

    • Здравствуйте. Что касается алгоритма работы, то все зависит от обучающей выборки и от фантазии. В примере показанном на видео не учитывались показания датчика звука, а значения фоторезистора было константным на всех обучающих примерах.

      Нет, я к сожалению не имею такого опыта. Но судя по Вашему описанию(читал не все, могу ошибаться) следует посмотреть в сторону сдвиговых регистров.

  3. Мне очень понравилась реализация и как и написано у Вас в начале я тот кто читал и подбирался давно к этому. К сожалению я не программист и достаточно сложно для меня реализовать данный алгоритм, хотя я постоянно читаю об этом (издания) и пытаюсь. Спасибо за пример. В качестве критикиВам даже те кто понимает что это задет вопросы о том что мы настраиваем, думаю новичкам совершенно это будет непонятно! Если можно добавьте в самое начало в условия задачи! Основная ошибка всего что я прочитал (с точки зрения новичка) не объясняется что мы делаем? понятно что будет как то хорошо работать, понятно что робот научится сам рулить от стен, но об этом нужно догадаться!

    • Не хватает запятых в предыдущем посте, прошу прощения. Пришла такая идея. Вместо звука и света поставить пару датчиков столкновения и использовать их как отрицательный стимул для обучения. Еще такой вопрос, как долго бы эти данные обрабатывала ардуино?

    • Здравствуйте. В первую очередь спасибо за конструктивную критику. В ближайшее время я постараюсь добавить более грамотное объяснение.

    • Что касается замены датчиков и «отрицательных стимулов»: Датчики можно поставить любые, какие только можно. Самый главный вопрос — это грамотная подборка обучающих примеров. Все в руках Вашей фантазии. Что касается скорости, то я не мерил и точных цифр назвать не смогу.
      P.S Тим Джонс — «Программирование искусственного интеллекта в приложениях», я начинал с нее.

  4. Привет. А нет ли желания поучаствовать в похожем проекте?
    Я работаю примерно над такой же задачей. Просто большей размерности. Грубо говоря вместо 3 направлений (право-лево-прямо) сделать сеть под сканирование сонаром на 360 и прикрутить еще несколько входов-выходов.

    • Привет. Желание поработать над интересными проектами есть всегда. Вопрос времени.
      Хотелось бы поподробнее узнать о Вашем проекте. О том что уже сделано и что необходимо еще доделать.

  5. Здравствуйте, у меня возникла проблема с кодом который вы написали. Я пытался также написать код для робота управляемым нейронной сетью и наткнулся на эту статью. Arduino IDE выдаёт следующую ошибку:

    Arduino: 1.8.3 (Windows 7), Плата:«Arduino/Genuino Uno»

    Neironnai_set:8: error: ‘Random_run’ does not name a type

    Neironnai_set:10: error: expected unqualified-id before ‘[‘ token

    Neironnai_set:11: error: expected unqualified-id before ‘[‘ token

    Neironnai_set:13: error: expected unqualified-id before ‘[‘ token

    Neironnai_set:14: error: expected unqualified-id before ‘[‘ token

    Neironnai_set:16: error: expected unqualified-id before ‘[‘ token

    Neironnai_set:17: error: expected unqualified-id before ‘[‘ token

    Neironnai_set:22: error: ‘List’ does not name a type

    Neironnai_set:24: error: ‘List’ does not name a type

    Neironnai_set:43: error: expected ‘,’ or ‘…’ before ‘vector’

    Neironnai_set:67: error: expected ‘,’ or ‘…’ before ‘vector’

    C:\Users\Р? ван Robotics\Desktop\РўРёРїР° нейронная сеть\Neironnai_set\Neironnai_set.ino: In function ‘void init_net()’:

    Neironnai_set:31: error: ‘INPUT_W’ was not declared in this scope

    Neironnai_set:31: error: ‘run’ was not declared in this scope

    Neironnai_set:36: error: ‘OUTPUT_W’ was not declared in this scope

    Neironnai_set:36: error: ‘run’ was not declared in this scope

    C:\Users\Р? ван Robotics\Desktop\РўРёРїР° нейронная сеть\Neironnai_set\Neironnai_set.ino: At global scope:

    Neironnai_set:43: error: expected ‘,’ or ‘…’ before ‘vector’

    C:\Users\Р? ван Robotics\Desktop\РўРёРїР° нейронная сеть\Neironnai_set\Neironnai_set.ino: In function ‘void DirectMotion(float*)’:

    Neironnai_set:45: error: ‘vector’ was not declared in this scope

    Neironnai_set:49: error: ‘INPUT_RESULT’ was not declared in this scope

    Neironnai_set:51: error: ‘INPUT_W’ was not declared in this scope

    Neironnai_set:51: error: ‘vector’ was not declared in this scope

    Neironnai_set:58: error: ‘OUTPUT_RESULT’ was not declared in this scope

    Neironnai_set:60: error: ‘OUTPUT_W’ was not declared in this scope

    Neironnai_set:60: error: ‘INPUT_RESULT’ was not declared in this scope

    C:\Users\Р? ван Robotics\Desktop\РўРёРїР° нейронная сеть\Neironnai_set\Neironnai_set.ino: At global scope:

    Neironnai_set:67: error: expected ‘,’ or ‘…’ before ‘vector’

    C:\Users\Р? ван Robotics\Desktop\РўРёРїР° нейронная сеть\Neironnai_set\Neironnai_set.ino: In function ‘float BackPropagation(float*)’:

    Neironnai_set:70: error: ‘vector’ was not declared in this scope

    Neironnai_set:77: error: ‘OUTPUT_ERROR’ was not declared in this scope

    Neironnai_set:79: error: ‘target’ was not declared in this scope

    Neironnai_set:79: error: ‘OUTPUT_RESULT’ was not declared in this scope

    Neironnai_set:82: error: ‘INPUT_ERROR’ was not declared in this scope

    Neironnai_set:85: error: ‘OUTPUT_ERROR’ was not declared in this scope

    Neironnai_set:85: error: ‘OUTPUT_W’ was not declared in this scope

    Neironnai_set:96: error: ‘INPUT_W’ was not declared in this scope

    Neironnai_set:96: error: ‘INPUT_ERROR’ was not declared in this scope

    Neironnai_set:102: error: ‘OUTPUT_W’ was not declared in this scope

    Neironnai_set:102: error: ‘OUTPUT_ERROR’ was not declared in this scope

    Neironnai_set:102: error: ‘INPUT_RESULT’ was not declared in this scope

    C:\Users\Р? ван Robotics\Desktop\РўРёРїР° нейронная сеть\Neironnai_set\Neironnai_set.ino: In function ‘float calculate_global_error()’:

    Neironnai_set:114: error: ‘OUTPUT_ERROR’ was not declared in this scope

    Neironnai_set:115: error: ‘Math’ was not declared in this scope

    C:\Users\Р? ван Robotics\Desktop\РўРёРїР° нейронная сеть\Neironnai_set\Neironnai_set.ino: In function ‘void Learn()’:

    Neironnai_set:126: error: ‘Input_patern’ was not declared in this scope

    Neironnai_set:127: error: ‘Out_patern’ was not declared in this scope

    Neironnai_set:129: error: ‘Console’ was not declared in this scope

    exit status 1
    ‘Random_run’ does not name a type

    Этот отчёт будет иметь больше информации с
    включенной опцией Файл -> Настройки ->
    «Показать подробный вывод во время компиляции»

    Пожалуйста, помогите мне с ней. Может надо установить дополнительную библиотеку.

    • Попробуйте переместить директорию скетча в корневой каталог (чтобы в пути не было символов отличных от английских).

Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Android Arduino Bluetooth CraftDuino DIY IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение