Arduino to Linux (RPi) Путаница с последовательным кодом - PullRequest
0 голосов
/ 29 апреля 2019

В настоящее время я работаю с отличным исходным кодом hackboard-firmware-hack на GitHub, и это действительно здорово. В настоящее время я работаю с протоколом UART, поэтому могу общаться с материнской платой на ховерборде через последовательный UART. Хост милостиво предоставил пример кода Arduino для отправки базовой команды с использованием пользовательского протокола прошивки:

SoftwareSerial mySerial(10, 11); // RX, TX

typedef struct MsgToHoverboard_t{
  unsigned char SOM;  // 0x02
  unsigned char len;  // len is len of ALL bytes to follow, including CS
  unsigned char cmd;  // 'W'
  unsigned char code; // code of value to write
  int16_t base_pwm;   // absolute value ranging from -1000 to 1000 .. base_pwm plus/minus steer is the raw PWM value
  int16_t steer;      // absolute value ranging from -1000 to 1000 .. wether steer is added or substracted depends on the side R/L
  unsigned char CS;   // checksumm
};

uint16_t baseSpeed = 0;

typedef union UART_Packet_t{
  MsgToHoverboard_t msgToHover;
  byte UART_Packet[sizeof(MsgToHoverboard_t)];
};

void setHoverboardPWM( int16_t base_pwm, int16_t steer )
{
  UART_Packet_t ups;

  ups.msgToHover.SOM = 2 ;  // PROTOCOL_SOM; //Start of Message;
  ups.msgToHover.len = 7;   // payload + SC only
  ups.msgToHover.cmd  = 'W'; // PROTOCOL_CMD_WRITEVAL;  // Write value
  ups.msgToHover.code = 0x07; // speed data from params array
  ups.msgToHover.base_pwm = base_pwm;
  ups.msgToHover.steer = steer;
  ups.msgToHover.CS = 0;

  for (int i = 0; i < ups.msgToHover.len; i++){
    ups.msgToHover.CS -= ups.UART_Packet[i+1];
  }

  mySerial.write(ups.UART_Packet,sizeof(UART_Packet_t));
}

Это отлично работает! В настоящее время я пытаюсь сделать это на RPi и не захожу слишком далеко, потому что Python может сбить с толку тем, что он не очень строго типизирован, а размеры байтов могут быть затруднены.

Я попробовал свои силы в C ++, используя termios, но не захожу слишком далеко. Функция выглядит так:

//Hover couch Serial test

#include <cstdint>
#include <iostream>
#include <stdio.h>
#include <unistd.h>  //Used for UART
#include <fcntl.h>   //Used for UART
#include <termios.h> //Used for UART

using namespace std;

typedef struct MsgToHoverboard_t
{
    unsigned char SOM;  // 0x02
    unsigned char len;  // len is len of ALL bytes to follow, including CS
    unsigned char cmd;  // 'W'
    unsigned char code; // code of value to write
    int16_t base_pwm;   // absolute value ranging from -1000 to 1000 .. base_pwm plus/minus steer is the raw PWM value
    int16_t steer;      // absolute value ranging from -1000 to 1000 .. wether steer is added or substracted depends on the side R/L
    unsigned char CS;   // checksumm
} MsgToHoverboard_t;

uint16_t baseSpeed = 0;

typedef union UART_Packet_t {
    MsgToHoverboard_t msgToHover;
    uint8_t UART_Packet[sizeof(MsgToHoverboard_t)];
} UART_Packet_t;

void setHoverboardPWM(int16_t base_pwm, int16_t steer, int &handle)
{
    UART_Packet_t ups;

    ups.msgToHover.SOM = 2;     // PROTOCOL_SOM; //Start of Message;
    ups.msgToHover.len = 7;     // payload + SC only
    ups.msgToHover.cmd = 'W';   // PROTOCOL_CMD_WRITEVAL;  // Write value
    ups.msgToHover.code = 0x07; // speed data from params array
    ups.msgToHover.base_pwm = base_pwm;
    ups.msgToHover.steer = steer;
    ups.msgToHover.CS = 0;

    for (int i = 0; i < ups.msgToHover.len; i++)
    {
        ups.msgToHover.CS -= ups.UART_Packet[i + 1];
    }

    //   mySerial.write(ups.UART_Packet,sizeof(UART_Packet_t));
    if (handle != -1)
    {
        int count = write(handle, &ups.UART_Packet, sizeof(UART_Packet_t)); //Filestream, bytes to write, number of bytes to write
        // cout << "count: " << count << endl;
        if (count < 0)
        {
            printf("UART TX error\n");
        }
    }
}

int main()
{

    //-------------------------
    //----- SETUP USART 0 -----
    //-------------------------
    //At bootup, pins 8 and 10 are already set to UART0_TXD, UART0_RXD (ie the alt0 function) respectively
    int uart0_filestream = -1;

    //OPEN THE UART
    //The flags (defined in fcntl.h):
    //  Access modes (use 1 of these):
    //      O_RDONLY - Open for reading only.
    //      O_RDWR - Open for reading and writing.
    //      O_WRONLY - Open for writing only.
    //
    //  O_NDELAY / O_NONBLOCK (same function) - Enables nonblocking mode. When set read requests on the file can return immediately with a failure status
    //                                          if there is no input immediately available (instead of blocking). Likewise, write requests can also return
    //                                          immediately with a failure status if the output can't be written immediately.
    //
    //  O_NOCTTY - When set and path identifies a terminal device, open() shall not cause the terminal device to become the controlling terminal for the process.
    uart0_filestream = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY); //Open in non blocking read/write mode
    if (uart0_filestream == -1)
    {
        //ERROR - CAN'T OPEN SERIAL PORT
        printf("Error - Unable to open UART.  Ensure it is not in use by another application\n");
    }

    //CONFIGURE THE UART
    //The flags (defined in /usr/include/termios.h - see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html):
    //  Baud rate:- B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000
    //  CSIZE:- CS5, CS6, CS7, CS8
    //  CLOCAL - Ignore modem status lines
    //  CREAD - Enable receiver
    //  IGNPAR = Ignore characters with parity errors
    //  ICRNL - Map CR to NL on input (Use for ASCII comms where you want to auto correct end of line characters - don't use for bianry comms!)
    //  PARENB - Parity enable
    //  PARODD - Odd parity (else even)
    struct termios options;
    tcgetattr(uart0_filestream, &options);
    options.c_cflag = B19200 | CS8 | CLOCAL | CREAD; //<Set baud rate
    options.c_iflag = IGNPAR;
    options.c_oflag = 0;
    options.c_lflag = 0;
    tcflush(uart0_filestream, TCIFLUSH);
    tcsetattr(uart0_filestream, TCSANOW, &options);

    cout << "Beginning serial output\n";
    while (1)
    {
        setHoverboardPWM(200, 0, uart0_filestream);
    }

    //----- CLOSE THE UART -----
    close(uart0_filestream);
    return 0;
}

Это в значительной степени заимствованный код. Я старался изо всех сил, чтобы заставить его работать. Тем не менее, я получаю тонну «UART TX error!» (Изнутри SetHoverBoard PWM). Я не очень опытен с протоколами связи UART, но я знаю, что моя скорость передачи данных верна, а последовательный порт работает. Я просто делаю упаковку неправильно?

Может ли кто-нибудь, имеющий опыт работы с этим материалом, помочь мне либо воспроизвести этот код на python, либо исправить мой текущий код на c ++?

Я также предоставлю пример кода TX, с которым я работал, на случай, если я только что испортил это:

ссылка на код: https://raspberry -projects.com / pi / program-in-c / uart-serial-port / using-the-uart

Сам код:

    //----- TX BYTES -----
    unsigned char tx_buffer[20];
    unsigned char *p_tx_buffer;

    p_tx_buffer = &tx_buffer[0];
    *p_tx_buffer++ = 'H';
    *p_tx_buffer++ = 'e';
    *p_tx_buffer++ = 'l';
    *p_tx_buffer++ = 'l';
    *p_tx_buffer++ = 'o';

    if (uart0_filestream != -1)
    {
        int count = write(uart0_filestream, &tx_buffer[0], (p_tx_buffer - &tx_buffer[0]));      //Filestream, bytes to write, number of bytes to write
        if (count < 0)
        {
            printf("UART TX error\n");
        }
    }

Я предполагаю битовый паритет, и все в порядке. Кажется, настройки совпадают.

...