Проблемма с serial port под linux ubuntu

Тема в разделе "Raspberry Pi", создана пользователем Бачар Константин, 14 мар 2021.

Метки:
  1. Здравствуйте товарищи :)!
    В общем если кратко то проблемка у меня такая
    после 20 ... 23 сообщений UART banana pi(banana pi это аналог raspberry) перестает отправлять данные на ардуино.
    в линуксе использую функцию write(serial_fd,buffer,data_length);
    serial_fd это id порта в системе.
    В начале все отправляется успешно.
    Потом write возвращает количество отправленных данных меньше чем я посылаю.
    каждый пакет это 8 байт.
    Я предполагаю что почему-то переполняется буфер на отправку но как с этим бороться правльно не знаю.
    добавил функции для очистки буфера но это не помогает.
     
  2. Вот код программы на banana pi
    Код (C++):
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <termios.h>


    int server(int serv_sock,int ser_sock);

    struct letter
    {
        int len;
        char *data;
    }let;


    int main()
    {
        int err=-1;
        int server_sockfd;
        socklen_t server_len;
        struct sockaddr_in server_address;
        struct termios serialconf;
        char serialname[] = "/dev/ttyS0";



        server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

        server_address.sin_family = AF_INET;
        server_address.sin_addr.s_addr = htonl(INADDR_ANY);
        server_address.sin_port = htons(55000);
        server_len = sizeof(server_address);

        err=bind(server_sockfd, (struct sockaddr *) &server_address, server_len);

        if(err!=0)
        {
            printf("bind error!\n");
            return 0;
        }
        else printf("bind is ok\n");

        while(1)
        {
        printf("init serial port");
        //serial port configuring (begin)
            int serialfd = open(serialname, O_RDWR | O_NOCTTY | O_NDELAY);

            if (serialfd == -1) {
                printf(serialname);
                return -1;
            }

            if (tcgetattr(serialfd, &serialconf) < 0) {
                printf("Getting configuration");
                return -1;
            }

        // Set up Serial Configuration
            serialconf.c_iflag = 0;
            serialconf.c_oflag = 0;
            serialconf.c_lflag = 0;
            serialconf.c_cflag = 0;

            serialconf.c_cc[VMIN] = 0;
            serialconf.c_cc[VTIME] = 0;

            serialconf.c_cflag = B38400 | CS8 | CREAD;

            tcsetattr(serialfd, TCSANOW, &serialconf);
        //serial port configuring (end)
            int ret = server(server_sockfd,serialfd);
            printf("server process ended with code = %d\n",ret);
            if(ret != 0)
            {
                close(serialfd);
                return 0;
            }

            close(serialfd);
        }
    }
    /*процедура сервера*/
    int server(int serv_sock,int ser_sock)
    {
        char serbuffer[1600];
        char command[14];
        int pos = 0;
        int offset = 0;
        bool rbeg = false;

        if(serv_sock == 0) return 1;
        int err=-1;
        int client_sockfd;
        socklen_t client_len;
        struct sockaddr_in client_address;

        err=listen(serv_sock, 5);
        if(err!=0)
        {
            printf("listen error!\n");
            close(client_sockfd);
            return 2;
        }
        else printf("listen is ok\n");

        printf("server waiting\n");

        client_len = sizeof(client_address);
        client_sockfd = accept(serv_sock, (struct sockaddr *) &client_address, &client_len);

        printf("server send test string\n");
        char tmp[] = "test string";
        int tmplen = strlen(tmp);
        write(client_sockfd, tmp, tmplen);

        char *ch = (char *)calloc (160, sizeof(char));
        while(1)
        {
            int len=0;

            if(!ch)
            {
                printf("memory error ch\n");
                close(client_sockfd);
                return 3;
            }

            len = read(client_sockfd, ch, 160); /*считываем данные в массив*/
            if(len == 0)
            {
                printf("socket closed\n");
                close(client_sockfd);
                return 0;
            }

            offset = 0;
            while(offset < len)
            {
                if(ch[offset] == 255 && !rbeg)
                {
                    rbeg = true;
                    pos = 1;
                }
                else if(ch[offset] == 254 && rbeg)
                {
                    command[0] = 255;
                    command[7] = 254;

                    int wcount = write(ser_sock, command, 8);
                    if(wcount >= 8)
                    {
                        printf("*");
                    }
                    else
                    {
                        printf("X");
                        tcdrain(ser_sock);
                        tcflush(ser_sock,TCOFLUSH);
                    }

                    rbeg = false;
                }

                else
                {
                    if(rbeg && pos < 7)
                    {
                        if(pos == 1)
                        {
                            command[pos] = ch[offset];
                        }
                        else
                        {

                            float convert = (float)ch[offset];
                            convert = (convert / 200) * 180;
                            unsigned char value = (unsigned char)convert;
                            command[pos] = value;
                        }
                        pos++;
                    }
                }
                offset++;
            }

            int rcount = read(ser_sock, serbuffer, sizeof(serbuffer));
                if(rcount > 0)
                {
                    write(client_sockfd, serbuffer, rcount);
                    printf("$");
                }
        }
        return 5;
    }
     
  3. Это код прошивки ардуины
    Код (C++):
    #include <Wire.h>
    #include <Multiservo.h>

    #define COMAND_VECTOR_SIZE 6
    Multiservo neckx;
    Multiservo necky;
    byte boof[COMAND_VECTOR_SIZE];
    byte offset = 0;
    bool rbegin = false;
    int speed_left = 0;
    int speed_right = 0;

    class Motor
    {
      public:
      Motor(int enb_pin, int speed_pin)
      :
      enb_pin(enb_pin),
      speed_pin(speed_pin),
      speed_val(0)
      {
        pinMode(enb_pin,OUTPUT);
        pinMode(speed_pin,OUTPUT);
      }
     
      void setSpeed(int new_val)
      {
        speed_val = new_val;
      }
     
      void toFront()
      {
        analogWrite(speed_pin,speed_val);
        digitalWrite(enb_pin,LOW);
      }
     
      void toBack()
      {
        analogWrite(speed_pin,speed_val);
        digitalWrite(enb_pin,HIGH);
      }
     
      void Stop()
      {
        analogWrite(speed_pin,0);
        digitalWrite(enb_pin,LOW);
      }

      int enb_pin;
      int speed_pin;
      int speed_val;
    };

    Motor *right = new Motor(7,6);
    Motor *left = new Motor(4,5);


    void setup() {
       Wire.begin();
     
      // put your setup code here, to run once:
      Serial.begin(115200);
      Serial1.begin(38400);

    char tmp[100]="test program started...";
      Serial.println(tmp);

        necky.attach(0);
        neckx.attach(1);
    }

    byte c = 0;
    void loop() {
      // put your main code here, to run repeatedly:
     
      while(Serial1.available() > 0)
      {
        c = Serial1.read();
        if(c == 255) Serial.println("<");
        if(c == 254) Serial.println(">");
       
        if(c == 255)// && !rbegin)
        {
          rbegin = true;
          offset = 0;
          memset(boof,0x00,COMAND_VECTOR_SIZE);
        }
        else if(c == 254 && rbegin)
        {
          Serial1.print("<");

          necky.write(boof[1]);
          neckx.write(boof[2]);

          speed_left = boof[3] - 90;
          if(speed_left < 0)
          {
            left->setSpeed(abs(speed_left));
            left->toBack();
          }
          else
          {
            left->setSpeed(speed_left);
            left->toFront();
          }
          speed_right = boof[4] - 90;
          if(speed_right < 0)
          {
            right->setSpeed(abs(speed_left));
            right->toBack();
          }
          else
          {
            right->setSpeed(speed_left);
            right->toFront();
          }
         
         
          //char str[100];
          //for(int i = 0; i < COMAND_VECTOR_SIZE;i++)
          //{
          //  sprintf(str,"[%d]",boof[i]);
          //  Serial.print(str);
          //  Serial1.print(str);
          //}

          Serial1.println(">");
          rbegin = false;
        }
        else
        {
          if(rbegin)
          {
            if(offset < COMAND_VECTOR_SIZE)
            {
              boof[offset] = c;
              offset++;
            }
          }
        }
      }
    }
     
  4. В общем я делаю робота пока-что управляется только движение и поворот камеры.
    На "банане пи" запуская программу которая по сути сервер TCP соединений.
    а потом принятые команды эта программа передает по serial порту в ардуину.
    В начале все работает но после 20..23 пакетов отправлятся на ардуину перестает (по serial).

    подскажите плиз почему может на "банана пи" (аналог raspberry pi)сериал порт затыкаться ?

    на банане стоит ubuntu mate 16.04
     
    Последнее редактирование модератором: 14 мар 2021
  5. ZAZ-965

    ZAZ-965 Гуру

    Вопрос по размеру буферов - у Arduino по умолчанию SERIAL_BUFFER_SIZE=64, у вас один - 1600 (char serbuffer[1600]), второй - 160 (char *ch = (char *)calloc (160, sizeof(char))). Может попробовать их привести к одинаковым значениям, например, у Arduino увеличить до 128 (или 256) и на banana pi использовать такие же значения.
     
  6. Тут проблема мне кажется на стороне бананы пи ... те функция write ... просто если была проблема на стороне ардуины то в буфер не влезлобы более 8-ми сообщений
     
  7. надо короче прогу переработать однако порядок навести
     
  8. есть новые данные добавил вывод ERRNO для сокетов теперь видно что когда прерывается передача ошибка 5 возникает это проблема передачи
    чтобы это значило ... попробовал на ардуину по другому питание завести через motor shield на него подается 12в(у ардуины стабилизатор есть свой) до этого было питание через multiservo на ней 7 вольт
     
  9. Igor68

    Igor68 Гуру

    Доброго времени суток!
    Простите, но мне страшно делать такое... я разделяю обмен по SERIAL и TCP по разным потокам. А сейчас придерживаюсь и на разные процессы. Хуже того сервер ещё должен поддерживать и разные потоки(для разных соединений) - одно соединение один поток(а вдруг разрыв - пересоединение по TCP). Это конечно не укладывается в цикл, но каждый поток имеет свой цикл.
    Простите, но это мой личный подход и я по другому не хочу.
    Тут
    http://forum.amperka.ru/threads/raspberry-pi-3-opencv-arduino-uno-поледнее-решение-и-вопрос-в-последнем-сообщении.10001/
    и тут
    https://moxa.ru/forum/index.php?/topic/7110-ia240-lx-modbus-rtu-master/
    я делаю это... правда код придётся ковырять.
    Если что не так сказал не ругайте!
     
    Последнее редактирование: 14 мар 2021
    Un_ka нравится это.
  10. Спасибо за участие а то активность пользователей немного огорчает :)
    Я пока не стал разносить по потокам это только проба чтобы хоть както заработало
    кроме того более одного соединения не планируется.
    А можете чтото по коду ошибки ERRNO = 5 сказать?
     
  11. Igor68

    Igor68 Гуру

    Строго контролируйте соединения тогда... и чаще перезапускайте сервер.
     
  12. Вобщем я нашел как командами посмотреть настройки UART в линуксе и у видел в настройках что задано что приниматься будет 24 строки по 80 символов.
    Как можно отключить это ограничение я нашел еще функцию fcmakeraw (с++)она по идее должна переключить настройки порта в "raw" режим те переключить из режима терминала в "сырой режим" но это не помогло