Raspberry PI 3 + OpenCV + Arduino UNO + ......(поледнее решение и вопрос в последнем сообщении)

Тема в разделе "Флудилка", создана пользователем Igor68, 21 ноя 2016.

  1. Igor68

    Igor68 Гуру

    Наоборот убежал с VisualStudio и QtCreator на браузер. Если в Linux (A1200e) и WinowsMobile есть опыт делать приложения, то на Android полный ноль. И браузеры есть везде. Если Вы заметили то на странице нет ничего, кроме отображения принятой картинки и передача событий мышки. Да и соединение одно непрерывное на всё время. А сервер на Си и не является частью Apache... Apache только для начала... отдать страницу клиенту. А он (клиент) работает онлайн непрерывно и довольно быстро вплоть до реального времени.
     
  2. Igor68

    Igor68 Гуру

    К сожалению из ComMotion и Multiservo нет возможности прочитать текущие значения по I2C... так, что ориентируюсь по программе на малине.
     
  3. Igor68

    Igor68 Гуру

    Доброго времени суток!
    ...вот незадача то. Остановил программы на малине, а "прошивка"(ну не могу... язык не поворачивается произносить слово СКЕТЧ) продолжает крутить моторами. А тем не менее связь(обращение к ардуине) отсутствует. Надо придать приводам некую автономность... думал пока всё, но надо ещё и штрих добавить в прошивку. При отсутствии обращения некое время:
    1) Остановить все моторы,
    2) Перевести все сервомашины в исходное состояние
    Ну и продолжать работу... ожидание обращения...
     
  4. Igor68

    Igor68 Гуру

    ...эге ...ага. Вот что вызнала Яга:
    Добавили в наш r1_uno_plus.ino:
    в начало:
    Код (C++):
    //время ожидания обращения
    uint32_t    tSerialWait;
    в тело setup() в конец:
    Код (C++):
    tSerialWait     = 0;
    потом в виде отдельной функции
    Код (C++):
    void motorsANDservosNULL(void)
    {
        dservo[0]     = 0;
        setcwaitservo1    = 0;
        dservo[1]     = 0;
        setcwaitservo2    = 0;
        dmotor[0]    = 0;
        dmotor[2]    = 0;
        setcwaitmotorL    = 0;
        dmotor[1]    = 0;
        dmotor[3]    = 0;
        setcwaitmotorR    = 0;
        flag_movectrl    = 0;
    }
    в тело loop() ранее было только для измерения времени выполнения, а сейчас вот пригодилось:
    Код (C++):
    uint16_t timeCycleBegin = micros();
    ...
    ...
    uint16_t timeCycle = (uint16_t)GetDifferenceULong((uint32_t)timeCycleBegin, (uint32_t)micros());
        if (timeCycle > timeCycleMax)
                timeCycleMax = timeCycle;
        if((tSerialWait + timeCycle) < 0xFFFFFFFF)
            tSerialWait += timeCycle;
        if(tSerialWait > _tSerialWaitSet)
            motorsANDservosNULL();
    Ну и обнуляем время если есть обращение:
    Код (C++):

    //
    void serialEvent()
    {
       tSerialWait = 0;
       MRTU_rWORK();
    }
     
    А в файле config.h задаём время ожидания до отключения:
    Код (C++):
    #define _tSerialWaitSet        500000
    Таким образом через полсекунды при разрыве связи... если ардуина не принимает команд, всё в исходное состояние и моторы выключены.

    Это надо что бы железка не разбила "морду" (камера, сонар и т.п.) об стену и т.п. если вдруг исчезло управление (малина).
     
    Последнее редактирование: 23 сен 2018
  5. Igor68

    Igor68 Гуру

    Все данные в /dev/shm принимаются этим:
    servoANDmotor.zip
    Эта же программа передаёт/принимает параметры в ардуину:
    r1_uno_plus.zip
    параметры по образу протокола ModbusRTU по USB-SERIAL.
    И что поменялось? При отсутствии обращения от servoANDmotors сам r1_uno_plus1 выключает моторы и переводит сервомашины в исходное состояние.
    А servoANDmotors так же принимает от:
    sonar.zip
    Значение дистанции и так же через /dev/shm и при значении:

    Код (C++):
    if(gdat.sonardistance < 35)        //ограничение по дистанции
        {
            wrmovectl.motors[0]        = 0;
            wrmovectl.motors[1]        = 0;
            wrmovectl.speed_motors[0]    = 0;
            wrmovectl.speed_motors[1]    = 0;
            gdat.scntrl            = _scntrl_servoANDmotors;
        }
    выключает моторы и тоже выключает при:
    Код (C++):
    else if(rdmovectl.servo[0] != 0)    //оганичение по горизонтальному состоянию сервомашин
        {
            wrmovectl.motors[0]        = 0;
            wrmovectl.motors[1]        = 0;
            wrmovectl.speed_motors[0]    = 0;
            wrmovectl.speed_motors[1]    = 0;
            gdat.scntrl            = _scntrl_servoANDmotors;
        }
    А структура данных (пока не окончена) через /dev/shm:
    Код (C++):
    //глобальная структура данных
    #define    _Mcnt_motmove        2    //правые и левые моторы
    #define _MwrmotorL        0    //левые колёса
    #define _MwrmotorR        1    //правые колёсв
    #define _Mcnt_servomove        2    //горизонтальная и вертикальная сервомашины
    #define _MwrservoH        0    //позиционирование по горизонтали
    #define _MwrservoV        1    //позиционирование по вертикали
    typedef struct _GDATA1
    {
        //64-битные параметры
        uint64_t    timeMotorANDservo;            //время от моторов и сервомашин
        uint64_t    timeSonar;                //время от Сонара
        //16-битные параметры
        int16_t        wrmotors[_Mcnt_motmove];        //задание для моторов колёс
        uint16_t    wrspeed_motors[_Mcnt_motmove];        //задание времени реакции моторов
        int16_t        wrservo[_Mcnt_servomove];        //задание позиционирования
        uint16_t    wrservo_speed[_Mcnt_servomove];        //задание втемени позиционирования
        int16_t        rdmotors[_Mcnt_motmove];        //текщее задание для моторов колёс
        int16_t        rdservo[_Mcnt_servomove];        //текущее задание позиционирования
        int16_t        sonardistance;                //дальномер - дистанция см
        int16_t        sonarradius;                //дальномер - радиус "пятна" см
        uint16_t    status1;                //первый регистр флагов
        //8-ми битные параметры
        uint8_t        scntrl;                    //источник управления
    } GDATA1;

    //описание status1
    #define _status1_sonar_ok    0x0001                //сонар в работе
    #define _status1_drive_ok    0x0002                //управление приводами в действии
    #define _status1_servo_pos    0x0080                //блоктровка ро положению сервомашин
    //описание scntrl
    #define _scntrl_free        0x00                //никем не управляется
    #define    _scntrl_servoANDmotors    0x01                //локальное управление самих приводов
    #define    _scntrl_wsbot        0x02                //управление по websocket
    Пока время:
    Код (C++):
     uint64_t    timeMotorANDservo;            //время от моторов и сервомашин
        uint64_t    timeSonar;                //время от Сонара
    не реализовал... точнее не использовал. По ним определяется работоспособность тех или иных программных модулей.
    Так, что теперь мордой не ткнётся железка и при малой дистанции и при повороте сонара вправо/влево и при нарушении связи с ардуиной.
    Это рабочий набросок первого этапа.
     

    Вложения:

    • servoANDmotor.zip
      Размер файла:
      23,8 КБ
      Просмотров:
      368
    • r1_uno_plus.zip
      Размер файла:
      28,4 КБ
      Просмотров:
      399
    • sonar.zip
      Размер файла:
      14,3 КБ
      Просмотров:
      391
  6. Igor68

    Igor68 Гуру

    И ещё есть вопрос:
    После запуска... через какое-то время:
    Код (Text):
    www-data@pi02:~/ramdisk/mainwork/work$ ./work.sh start

    >>> ARBOT (Дата:09.09.2018 Вурсия:02.01.01) <<<
    servoANDmotor: no process found
    sonar: no process found
    Модуль управления приводами... дата и версия: Дата: 23.09.2018  Весия: 01.01.01
    Модуль сонара ультразвукового... дата и версия: Дата: 21.09.2018  Весия: 01.02.01
    www-data@pi02:~/ramdisk/mainwork/work$ mmap: Cannot allocate memory
    libgcc_s.so.1 must be installed for pthread_cancel to work
    sonar оказался в работе:
    Код (Text):
    www-data@pi02:~/ramdisk/mainwork/work$ ps -A | grep sonar
    32142 pts/8    00:00:04 sonar
    www-data@pi02:~/ramdisk/mainwork/work$
    а вот motorANDservo умер:
    Код (Text):
    www-data@pi02:~/ramdisk/mainwork/work$ ps -A | grep motorANDservo
    www-data@pi02:~/ramdisk/mainwork/work$
    Проблему надо ка-то решать... хотя можно написать скрипт контроля на bash, но это как-то грубо. Толи где-то "узко", толи не усмотрел что-то. Гугл пока ничего путного не указал... курю... ну и не понятно пока и вот:
    snapshot9.png
    Это массив данных и часики сонара тикают, а модуля управления приводами молчит.
    Сейчас ещё раз проверю с установленным серво влево... заодно ещё и проверка связи со стороны ардуины. Моторами крутить больно шумно.

    Новая проверка в 18:29... ожидаю повторения ошибки...
     
    Последнее редактирование: 23 сен 2018
  7. Igor68

    Igor68 Гуру

    Вот ещё раз ошибка в 19:30 после запуска в 18:29
    Код (Text):
    www-data@pi02:~/ramdisk/mainwork/work$ ./work.sh start

    >>> ARBOT (Дата:09.09.2018 Вурсия:02.01.01) <<<
    servoANDmotor: no process found
    sonar: no process found
    Модуль управления приводами... дата и версия: Дата: 23.09.2018  Весия: 01.01.01
    Модуль сонара ультразвукового... дата и версия: Дата: 21.09.2018  Весия: 01.02.01
    www-data@pi02:~/ramdisk/mainwork/work$ mmap: Cannot allocate memory
    libgcc_s.so.1 must be installed for pthread_cancel to work
    и то же motorANDservo умер:
    Код (Text):
    www-data@pi02:~/ramdisk/mainwork/work$ ps -A | grep motorANDservo
    www-data@pi02:~/ramdisk/mainwork/work$
     
    а sonar жив:
    Код (Text):
    www-data@pi02:~/ramdisk/mainwork/work$ ps -A | grep sonar
    11115 pts/8    00:00:04 sonar
    www-data@pi02:~/ramdisk/mainwork/work$
     
    Если выход не будет найден из:
    Код (Text):
    www-data@pi02:~/ramdisk/mainwork/work$ mmap: Cannot allocate memory
    libgcc_s.so.1 must be installed for pthread_cancel to work
    То похоже придётся делать контроль состояния программных элементов.
    По поиску в google отыскал только это
    Код (Text):
    mmap() failed: Cannot allocate memory size: 3221225472 offset: 0
    тут:
    https://github.com/realm/realm-cocoa/issues/5482
    и других местах... Но в моём случае ничего про размер не сказано.

    Имел ли кто дело с таким?
    Я использую разделямую память... так:
    старт:
    Код (C++):
    //старт доступа к разделякмой памяти
    int    gdmemstart(void)
    {
        //память - создание
        if ( (shm = shm_open(gdatSHARED_MEMORY_OBJECT_NAME, O_CREAT|O_RDWR, S_IRWXO|S_IRWXG|S_IRWXU)) == -1 )
        {
                perror("shm_open");
                return 1;
            }
        if ( ftruncate(shm, gdatSHARED_MEMORY_OBJECT_SIZE+1) == -1 )
        {
            perror("ftruncate");
            return 2;
            }
        //семафор - создание
        if ( (sem = sem_open(gdatSEMAPHORE_NAME, O_CREAT, 0777, 0)) == SEM_FAILED )
        {
            perror("sem_open");
            return 3;
        }
        sem_post(sem);
        //mutex create
            if(!(pthread_mutex_init(&gdmemMutex,NULL) == 0))
                    return 4;
        pthread_create(&hgdmemnProcess,NULL,(void*) gdmemProcess,NULL);
        //
        return 0;
    }
    применение:
    Код (C++):
    //процесс доступа к разделяемой памяти
    void gdmemProcess(void)
    {
        while(1)
        {
            pthread_mutex_lock(&gdmemMutex);
            sem_wait(sem);
            //
            if ( (addr = mmap(0, gdatSHARED_MEMORY_OBJECT_SIZE+1, PROT_WRITE|PROT_READ, MAP_SHARED, shm, 0)) == (GDATA1*)-1 )
            {
                    perror("mmap");
                    break;
                }
            //чтение задания
            gdat.timeSonar            = addr->timeSonar;
            if(gdat.scntrl    != _scntrl_servoANDmotors)
            {
                gdat.wrmotors[0]        = addr->wrmotors[0];
                gdat.wrmotors[1]        = addr->wrmotors[1];
                gdat.wrspeed_motors[0]        = addr->wrspeed_motors[0];
                gdat.wrspeed_motors[1]        = addr->wrspeed_motors[1];
                gdat.wrservo[0]            = addr->wrservo[0];
                gdat.wrservo[1]            = addr->wrservo[1];
                gdat.wrservo_speed[0]        = addr->wrservo_speed[0];
                gdat.wrservo_speed[1]        = addr->wrservo_speed[1];
                gdat.sonardistance        = addr->sonardistance;
                gdat.status1            = addr->status1;
            }
            gdat.scntrl            = addr->scntrl;
            //запись состояния и новых заданий
            addr->timeMotorANDservo        = gdat.timeMotorANDservo;
            addr->wrmotors[0]        = gdat.wrmotors[0];
            addr->wrmotors[1]        = gdat.wrmotors[1];
            addr->wrspeed_motors[0]        = gdat.wrspeed_motors[0];
            addr->wrspeed_motors[1]        = gdat.wrspeed_motors[1];
            addr->rdmotors[0]        = gdat.rdmotors[0];
            addr->rdmotors[1]        = gdat.rdmotors[1];
            addr->rdservo[0]        = gdat.rdservo[0];
            addr->rdservo[1]        = gdat.rdservo[1];
            addr->status1            |= gdat.status1;
            addr->scntrl            = gdat.scntrl;
            //
            sem_post(sem);
            pthread_mutex_unlock(&gdmemMutex);
            usleep(_gmemSleep);
        }
        pthread_exit(0);
    }
     
    Заранее благодарен за подсказку!
    Применено в Raspbian и там же откомпилировано:
    Makefile:
    Код (Text):
    ###########################
    # Simple Generic Makefile #
    ###########################

    ######################
    #CC=terminal-gcc
    ######################

    ######################
    CC=gcc
    ######################

    ######################
    #PREFIXPATH=/usr/local/arm-linux/bin
    #CC=$(PREFIXPATH)/arm-linux-gcc
    ######################

    CFLAGS=-c -Wall
    LDFLAGS=-lpthread -lcrypto -lm -lrt

    #SOURCES=*.c
    SOURCES=$(shell ls *.c)

    OBJECTS=$(SOURCES:.c=.o)
    EXECUTABLE=servoANDmotor

    all: $(SOURCES) $(EXECUTABLE)

    $(EXECUTABLE): $(OBJECTS)
        $(CC) $(LDFLAGS) $(OBJECTS) -o $@

    .c.o:
        $(CC) $(CFLAGS) $< -o $@

    install:
        install -m 0755 $(EXECUTABLE) $(HOME)/local/bin

    clean:
        rm -rf *o $(EXECUTABLE)
    Вот и прошу помощи.
     
    Последнее редактирование: 23 сен 2018
  8. Igor68

    Igor68 Гуру

    И ардуина отработала своё...
     
  9. Igor68

    Igor68 Гуру

    Простите сосем забыл. Должен быть скрипт, который должен находиться в одной директории с файлами sonar и servoANDmotor, который их оба и запустит. В нём сейчас предусматривается и ещё один модуль, который в разработке.
    Вот он (скрипт):
    Код (Bash):
    #!/bin/bash
    #
    _date="24.09.2018"
    _version="02.01.01"

    par=$1

    case $par in
        "stop")
            killall servoANDmotor
            killall sonar
            killall wsbot
            ;;
        "start")
            echo ""
            echo ">>> ARBOT (Дата:$_date Вурсия:$_version) <<<"
            killall servoANDmotor
            killall sonar
            killall wsbots
            str=$(./servoANDmotor --version)
            echo "Модуль управления приводами...................... дата и версия: $str"
            sleep 3
            ./servoANDmotor --start &
            str=$(./sonar --version)
            echo "Модуль сонара ультразвукового.................... дата и версия: $str"
            sleep 3
            ./sonar --start MB1242_C50 &
            echo=$(./wsbot --version)
            echo "Модуль сервера доступа по HTML через websocket... дата и версия: $str"
            sleep 3      
            ./wsbot --fbmp work.bmp -p 4321 &
        ;;
        *)
            echo "$0 {start|stop}"
        ;;
    esac
    exit 0

     
    Для него должно быть разрешение на запуск (chmod +x <имя скрипта>). Имя в моём случае work.sh
    Ну и запуск если без параметров:
    Код (Text):
    www-data@pi02:~/ramdisk/mainwork/work$ ./work.sh
    ./work.sh {start|stop}
    То есть с параметром start будет запуск/перезапуск комплекта программ с параметрами. А stop соответственно остановку этих программ.
     
  10. Igor68

    Igor68 Гуру

    ...А для работы с i2C и tty(serial) в /etc/rc/local должны быть разрешения при запуске.
    Иначе по su/sudo, но тогда возможно в дальнейшем будут проблемы с доступом через web... там-то пользователь не Rpi и не ROOT, а www-data для сервера apache.
     
  11. Igor68

    Igor68 Гуру

    Доброго времени суток!
    Вот как пример формирую SHM:
    Код (C++):
    //разделяемая память - формирование
    int createSHMbmp(void)
    {
        //определяем параметры шаблона BMP (размер)
        BMP_FileAnalise(&filenameBMP[0], &BMP_DUMP[0]);
        //память - создание
            if ( (shmBMP = shm_open(bmpSHARED_MEMORY_OBJECT_NAME, O_CREAT|O_RDWR, S_IRWXO|S_IRWXG|S_IRWXU)) == -1 )
                    return 1;
        if ( ftruncate(shmBMP, bhfi.bfSize + 1) == -1 )
                    return 2;
        if ( (addrBMP = mmap(0, bhfi.bfSize + 1, PROT_WRITE|PROT_READ, MAP_SHARED, shmBMP, 0)) == (u_int8_t*)-1 )
                    return 3;
        //семафор - создание
        if ( (semBMP = sem_open(bmpSEMAPHORE_NAME, O_CREAT, 0777, 0)) == SEM_FAILED )
            return 4;
        sem_post(semBMP);
        usleep(500000);
        sem_wait(semBMP);
        //
        if ( (addrBMP = mmap(0, bhfi.bfSize + 1, PROT_WRITE|PROT_READ, MAP_SHARED, shmBMP, 0)) == (GDATA1*)-1 )
                return 5;
        memcpy((uint8_t*)(addrBMP), &BMP_DUMP[0], bhfi.bfSize);
        sem_post(semBMP);

        return 0;
    }
    А это применение:
    Код (C++):
    //разделяемая память - обращение
    int readSHMbmp(void)
    {
        pthread_mutex_lock(&serverWSmutex);
        pthread_mutex_lock(&BMPmutex);
        sem_wait(semBMP);
        //if ( (addrBMP = mmap(0, bhfi.bfSize + 1, PROT_WRITE|PROT_READ, MAP_SHARED, shmBMP, 0)) == (GDATA1*)-1 )
            //    return 5;
        memcpy(&BMP_DUMP[0], (uint8_t*)(addrBMP), bhfi.bfSize);
        sem_post(semBMP);
        pthread_mutex_unlock(&BMPmutex);
        pthread_mutex_unlock(&serverWSmutex);
        return 0;
    }
    Обратите внимание на то, что закомментировано. Это устранено из всех программных модулей. По своему незнанию ставил везде, что каждый раз определяло начальный адрес. Сейчас работает устойчиво и слушается управления через браузер(область отображения):
    snapshot10.png
    Повернул от нуля позиции сонара и камеры - при этом движение запрещено... уж больно моторы шумные и (два из них косячат - надо с толкача). Вот сырое изделие для опытов.
    Заказал аккумулятор с платой для малины и логических питаний ардуины и шилдов. А вот для силовых цепей заказал 4 аккумулятора с контейнером для них и зарядкой. Пора на колёса. Ну и завтра думаю вместо чёрного фона будет изображение с камеры. А потом "вылизывать" программные модули. Наверное чёрно-белое(превращаю с помощью OpenCV) будет как и ранее перенесено на красный цвет. Другие цвета будут для индикации и т.п.
    Да! Если бы кто ранее подсказал по работе с /dev/shm. Зато теперь можно отказаться... ну или ограничить применение pthread. А вместо потоков применять процессы.
     
  12. Igor68

    Igor68 Гуру

    Вот и...
    Прикрутили камеру... вид с камеры (сформировано realtime программой camwork) устройства с наложением индикации (сформировано realtime программой wsbot):
    snapshot12.png
    А странно, но может и не прав, то что везде по разному начало координат картинки... а именно по вертикали.
    Простите за картинку, но комната освещена только настольной лампой, напраленой на рабочее место. Да и показывать особо нечего... да и ни к чему.
    Значение из массива OpenCV транслируем в шаблон (в массив) BMP:
    Код (C++):
    void dataToBMP(void)
    {
        U32    cntx, cnty, cntbyte;
        //
        cnty     = 0;
        cntbyte    = 0;
        //
        pthread_mutex_lock(&CamMutex);
        //
        while(cnty < height)
        {
            cntx = 0;
            while(cntx < width)
            {
                BMP_SetPixel(cntx, height - cnty, ga.at<char>(cnty,cntx), 0, 0);
                cntx++;
                cntbyte++;
            }
            cnty++;
        }
        pthread_mutex_unlock(&CamMutex);
    }
    который вызывается из цикла main через wrieteSHMbmp:
    Код (C++):
    while(1)
        {
            mainTime    = time(NULL);
            rwSHMcntrl();
            wrieteSHMbmp();
            usleep(_mainsleep);
        }
    А так мы передаём в /dev/shm картинку BMР
    Код (C++):
    //разделяемая память - обращение
    int wrieteSHMbmp(void)
    {
        dataToBMP();
        sem_wait(semBMP);
        memcpy((uint8_t*)(addrBMP), &BMP_DUMP[0], bhfi.bfSize);
        sem_post(semBMP);
        return 0;
    }
    А тут уже другой программой (обслуживание передачи вэб браузеру) забираем картинку BMP:
    Код (C++):
    //разделяемая память - обращение
    int readSHMbmp(void)
    {
        pthread_mutex_lock(&serverWSmutex);
        pthread_mutex_lock(&BMPmutex);
        sem_wait(semBMP);
        memcpy(&BMP_DUMP[0], (uint8_t*)(addrBMP), bhfi.bfSize);
        sem_post(semBMP);
        pthread_mutex_unlock(&BMPmutex);
        pthread_mutex_unlock(&serverWSmutex);
        return 0;
    }
    где потом на неё и накладываем индикацию:
    Код (C++):
    //реализация индикации
    void manInd(void)
    {
        char    valline[64];
        BMP_textout("pos.horizontal:", 50, 440, 255,255,255, 0,0,0, 0);
        gp_circlesec_ind(120, 400, 25, 45, motCntrl.RDcamHposition, 2, 255, 255, 255);
        BMP_textout("pos.vertical  :", 50, 340, 255,255,255, 0,0,0, 0);
        gp_circlesec_ind(120, 300, 25, 45, motCntrl.RDcamVposition, 1, 255, 255, 255);
        BMP_textout("position control", 50, 245, 255,255,255, 0,0,0, 0);
        memset(&valline[0], 0, 10);
        sprintf(&valline[0], "%i", motCntrl.camHposition);
        BMP_textout(&valline[0], 180, 440, 255,255,255, 0,0,0, 0);
        memset(&valline[0], 0, 10);
        sprintf(&valline[0], "%i", motCntrl.camVposition);
        BMP_textout(&valline[0], 180, 340, 255,255,255, 0,0,0, 0);
        sprintf(&valline[0], "SONAR: dist: %i cm", motCntrl.sonardistance);
        BMP_textout(&valline[0], 365, 8, 255,255,255, 0,0,0, 0);
    }
    А после всего этого передаём клиенту, который подключен по websocket через браузер.
     
    Последнее редактирование: 1 окт 2018
  13. Igor68

    Igor68 Гуру

    Вот это малина, которая раздаёт wifi и содержит proxy, через который выход в инет:
    [​IMG]
    Собственно через неё вся связь. С роутером в другой комнате по USB-WIFI(видно на фото) и вторая локальная сеть wifi на встроенном в малину (она по нему и раздаёт)

    Это с разных ракурсов железка:
    [​IMG][​IMG]
    Тут как раз арматура с 4-мя колёсиками и моторами, две сервы которые перемещают камеру и сонар. Ну и вторая малина которая по wifi соединена с второй локальной сетью первой малины и к которй подключена камера по USB и сонар по I2C. Сверху корпуса малины сразу Arduino UNO R3, которая соединена с малиной по USB-SERIAL и питается так же от неё. Arduino IDE так же в малине... это позволяет что-то изменять в ардуине без телодвижений. Сверху ардуины сразу ComMotion for 4 motors, который крутит 4 мотора и управляется ардуиной по I2C. Питание для контроллера он получает от ардуины, а силовое питание другое внешнее. Сверху ComMotion сразу Multisrvo(Amperka), которая перемещает камеру и сонар и управляется по I2C от ардуины. Питание для контроллера она получает от ардуины, а силовое для сервомашин так же как и для ComMotion внешнее. Таким образом всё питание для контроллеров идёт от малины по USB.
     

    Вложения:

    Последнее редактирование: 29 сен 2018
  14. Igor68

    Igor68 Гуру

    Редактирование, компиляция и отладка кода для малины производится по SSH соединению в самой малине. Для редактирования и навигации по файлам gedit и gnome-commander по SSH с ключом -X. Для компиляции и отладки по SSH использую ещё несколько соединений. Все соединения SSH одновременные. Кроме них ещё и Apache 2 через который и доступ через браузер. SSH соединения деаю от имени www-data, что по умолчанию для пользователя Apache... ну и проект то же в директории этого сервера. Для работы нужен доступ к I2C и ttyUSB0, потому в /etc/rc.local это:
    Код (Text):
    #!/bin/sh -e
    #
    # rc.local
    #
    # This script is executed at the end of each multiuser runlevel.
    # Make sure that the script will "exit 0" on success or any other
    # value on error.
    #
    # In order to enable or disable this script just change the execution
    # bits.
    #
    # By default this script does nothing.

    # Print the IP address
    _IP=$(hostname -I) || true
    if [ "$_IP" ]; then
      printf "My IP address is %s\n" "$_IP"
    fi

    #
    chmod 777 /dev/i2c-1
    chmod 777 /dev/ttyUSB0
    #
    #/etc/init.d/ramdisk restart
    #
    mount --bind /var/tmp /mnt/ram0
    mkdir /mnt/ram0/http
    chmod 777 /mnt/ram0/http
    mount --bind /mnt/ram0/http /home/httpd/ramdisk
    #
    su www-data -c /home/httpd/bash/wwstart &
    #
    /etc/init.d/ssh restart

    exit 0
     
    Тут же и про RAM-диск(монтирование), который через fstab:
    Код (Text):
    proc            /proc           proc    defaults                0       0
    /dev/mmcblk0p1  /boot           vfat    defaults                0       2
    /dev/mmcblk0p2  /               ext4    defaults,noatime        0       1
    tmpfs           /var/tmp        tmpfs   nodev,nosuid,size=40M   0       0

     
    Как видно 40M мне достаточно.
    Сначала копирую из директории пользователя проект в RAM-диск применяя mc, редактирую gnome-commander + gedit, компилю make... ну и испытываю. После работы сохраняю в директории пользователя. Это что бы исключить лишнее обращение для записи к SD карте.
     
    Последнее редактирование: 29 сен 2018
  15. Igor68

    Igor68 Гуру

    Вот тебе и шайтан... тоже мне раздельное питание! При выключенном шнурке USB-SERIAL светодиод питания, что от USB-SERIAL, но при питании силовом подсвечивается. И наоборот. Буду искать... где козёл. И провода, что на моторы, хоть и толстые но гниль. Шли в комплекте с арматурой. Включаю моторы и выползает:
    Код (Text):
    VIDIOC_DQBUF: No such device
    VIDIOC_DQBUF: No such device
    VIDIOC_DQBUF: No such device
    VIDIOC_DQBUF: No such device
    VIDIOC_DQBUF: No such device
    VIDIOC_DQBUF: No such device
    VIDIOC_DQBUF: No such device
    VIDIOC_DQBUF: No such device
    VIDIOC_DQBUF: No such device
    VIDIOC_DQBUF: No such device
    VIDIOC_DQBUF: No such device
    VIDIOC_DQBUF: No such device
    VIDIOC_DQBUF: No such device
     
    То есть потеряли камеру - по USB. Аналогично, хоть и реже:
    Код (C++):

    >>> ARBOT (Дата:24.09.2018 Версия:02.01.01) <<<
    servoANDmotor: no process found
    sonar: no process found
    wsbots: no process found
    camwork: no process found
    Модуль управления приводами...................... дата и версия: Дата: 23.09.2018  Весия: 01.01.01
    Модуль сонара ультразвукового.................... дата и версия: Дата: 23.09.2018  Весия: 01.02.01
    /dev/ttyUSB0: No such file or directory
    Модуль сервера доступа по HTML через websocket... дата и версия: Дата: 24.09.2018  Весия: 01.02.01
    Модуль работы с WEB-камерой...................... дата и версия: Дата: 29.09.2018  Весия: 01.01.02
    res=0
    BMP filename:  work.bmp
    Size Struct info 124 dec  7c hex
    Version "5"
    --- step x 3
    --- step y 1920
    ---------------------------------------------------------------------------------
    Type  : 4d42
    Size  : 921738 bytes
    Start addr: 8a hex
    ---------------------------------------------------------------------------------
    Widht :  640
    Haight : 480
    Bit in Pixel(color) 24
    res=0
    www-data@pi02:~/ramdisk/mainwork/work$ start camm loop...
    BMP filename:  work.bmp
    Size Struct info 124 dec  7c hex
    Version "5"
    --- step x 3
    --- step y 1920
    ---------------------------------------------------------------------------------
    Type  : 4d42
    Size  : 921738 bytes
    Start addr: 8a hex
    ---------------------------------------------------------------------------------
    Widht :  640
    Haight : 480
    Bit in Pixel(color) 24
     
    При перезапуске теряем USB-SERIAL. Вот ёлки-палки:mad:. Куда ни сунься кругом либо рекламная халтура, либо гнилушки:confused:. Только деньги сосут.:mad:
     
    Последнее редактирование: 1 окт 2018
  16. Igor68

    Igor68 Гуру

    Разобрал... проверил по отдельности ComMotion и Multiservo. с Мultiservo вопросов нет. Но ComMotion даже если не применять джампер внешнего силового питания всё равно питает от внешнего через стабилизатор. Исключил его теперь только ошибка с камерой... но реже.
     
  17. Igor68

    Igor68 Гуру

    Раньше на стадии более раннего опыта все провода были разнесены. Жаль конечно, но видно что придётся делать:
    По аппаратной части:
    1) керамические конденсаторы непосредственно на самих движках... мелкие ...пФ.
    2) заменить провода двигателей на типа витая пара.
    3) провод USB к камере сейчас типа "рулетка"(штатный с камерой) не экранирован, на другой с экраном... помягче бы. С разбором камеры разумеется.
    Плата ComMotion выдаёт на двигатели ШИМ, так что ёмкости на двигатели мелкие... чисто на фронт и тыл импульсов.
    По программной части:
    Выяснено, что камера вновь появляется но уже вместо /dev/video0 становится /dev/video1... ну и наверное так далее с каждым восстановлением. Это конечно самый крайний случай, когда узнаёшь название устройства и указываешь имя для этого устройства с другим именем. Но возможно имеются и другие средства.

    Имел ли кто опыт в этом?
    Заранее Спасибо за ответ!
     
  18. Igor68

    Igor68 Гуру

    Доброго времени суток!
    ...скрутил провод типа "витая пара", повесил ёмкости параллельно движкам (какие мог выпаять из хлама 33...47pF мелкие керамические). Вроде проблемы с потерей камеры исчезли. Напомню, что они только при работе коллекторных двигателей от PWM платы ComMotion for 4 motors shield. Но при смене режима работы двигателей (направление и скорость) вдруг стали опять проявляться. Веб-камера по USB, а шнурок от неё тонкий и плоский на катушке... тянешь его со стороны камеры и разъёма в разные стороны и меняешь длину. Вытянул, отнёс подальше и ошибки исчезли.:)
    Но вот один мотор с самого начала дурит... и с толкача его надо и крутится медленнее всех... косяк с мотором.
     
  19. Igor68

    Igor68 Гуру

    Вот не прошло и часа. Разбор этой самой камеры, позвонка проводников шнура до разъёма, отрезаем шнур на нужную длину от разъёма, отпаиваем от платы на камере, зачищаем концы и припаиваем к плате не забыв продеть шнур в отверстие задней крышки и при включении всё в порядке. Собираем камеру, капаем клея типа "Момент" в отверстие крышки с кабелем, дабы потом не натягивался шнурок в месте пайки. Да не ток клей что всё клеит кроме воды и воздуха и к рукам пристаёт... а попроще типа резинового. Ставим на устройство и испытываем. Теперь шнур около 30 см. И всё... работает без сбоев.:):):):):)
    Остался этот самый мотор:mad:
    Ну надо же с какой гадостью приходиться возиться. А ведь они все новые... в смысле моторессурса.
     
  20. Igor68

    Igor68 Гуру

    Да уж моторчик. Разобрал... а коллектор испарился:(. Надо такой искать... какой-то DAGU из набора вместе с 4-х моторным шасси... с редуктором. Ну или нормальное шасси. Да и вроде не крутил их особо. Жаль вроде конструкцию для опытов подготовил...