EFeru / hoverboard-firmware-hack-FOC

With Field Oriented Control (FOC)
GNU General Public License v3.0
1.13k stars 938 forks source link

USART feedback #175

Closed goosst closed 2 years ago

goosst commented 3 years ago

Hello,

Thank you for all the nice work, I'm able to control the hoverboard motors through UART2 using an ESP32. So that's a good start :). Also nice to see simulink / matlab models related to FOC ;).

However the feedback signals I'm receiving don't seem to come through reliably. I've tried running the Send and Receive functions from the .ino example at different task rates (copied my esp32 code below). It just varies from a lot of rubbish "Non-valid data skipped" to having strange reported values if they come true once.

Additional information in case it would help:

Any advice how to debug or which firmware variants are recommended for debugging is appreciated, seeing quite some issues were opened related to USART, I might want to avoid reinventing known remedies.

thanks!

#include <Arduino.h>

#define HOVER_SERIAL_BAUD 115200 // [-] Baud rate for Serial2 (used to communicate with the hoverboard)
#define SERIAL_BAUD 115200       // [-] Baud rate for built-in Serial (used for the Serial Monitor)
#define START_FRAME 0xABCD       // [-] Start frme definition for reliable serial communication
#define DEBUG_RX                 // [-] Debug received data. Prints all bytes to serial (comment-out to disable)

//only pick one taskrate for this simple test
#define TASK_1000MS 0 //simple task scheduling of 1 second
#define TASK_500MS 0
#define TASK_200MS 1 //simple task scheduling of 200ms
#define TASK_10MS 0

// Global variables
uint8_t idx = 0;        // Index for new data pointer
uint16_t bufStartFrame; // Buffer Start Frame
byte *p;                // Pointer declaration for the new received data
byte incomingByte;
byte incomingBytePrev;

typedef struct
{
  uint16_t start;
  int16_t steer;
  int16_t speed;
  uint16_t checksum;
} SerialCommand;
SerialCommand Command;

typedef struct
{
  uint16_t start;
  int16_t cmd1;
  int16_t cmd2;
  int16_t speedR_meas;
  int16_t speedL_meas;
  int16_t batVoltage;
  int16_t boardTemp;
  uint16_t cmdLed;
  uint16_t checksum;
} SerialFeedback;
SerialFeedback Feedback;
SerialFeedback NewFeedback;

// #define RXD2 16
// #define TXD2 17
void setup()
{
  // put your setup code here, to run once:

  pinMode(BUILTIN_LED, OUTPUT);
  Serial.begin(SERIAL_BAUD); //this is printed to monitor through computer
  Serial.println("Hoverboard Serial test");
  Serial2.begin(HOVER_SERIAL_BAUD); //used to communicate with hoverboard
}

// ########################## SEND ##########################
void Send(int16_t uSteer, int16_t uSpeed)
{
  // Create command
  Command.start = (uint16_t)START_FRAME;
  Command.steer = (int16_t)uSteer;
  Command.speed = (int16_t)uSpeed;
  Command.checksum = (uint16_t)(Command.start ^ Command.steer ^ Command.speed);

  // Write to Serial
  Serial2.write((uint8_t *)&Command, sizeof(Command));
}

// ########################## RECEIVE ##########################
void Receive()
{
  // Check for new data availability in the Serial buffer
  if (Serial2.available())
  {
    incomingByte = Serial2.read();                                      // Read the incoming byte
    bufStartFrame = ((uint16_t)(incomingByte) << 8) | incomingBytePrev; // Construct the start frame
  }
  else
  {
    return;
  }

// If DEBUG_RX is defined print all incoming bytes
#ifdef DEBUG_RX
  Serial.print(incomingByte);
  Serial.println("bytes read");
  return;
#endif

  // Copy received data
  if (bufStartFrame == START_FRAME)
  { // Initialize if new data is detected
    p = (byte *)&NewFeedback;
    *p++ = incomingBytePrev;
    *p++ = incomingByte;
    idx = 2;
  }
  else if (idx >= 2 && idx < sizeof(SerialFeedback))
  { // Save the new received data
    *p++ = incomingByte;
    idx++;
  }

  // Check if we reached the end of the package
  if (idx == sizeof(SerialFeedback))
  {
    uint16_t checksum;
    checksum = (uint16_t)(NewFeedback.start ^ NewFeedback.cmd1 ^ NewFeedback.cmd2 ^ NewFeedback.speedR_meas ^ NewFeedback.speedL_meas ^ NewFeedback.batVoltage ^ NewFeedback.boardTemp ^ NewFeedback.cmdLed);

    // Check validity of the new data
    if (NewFeedback.start == START_FRAME && checksum == NewFeedback.checksum)
    {
      // Copy the new data
      memcpy(&Feedback, &NewFeedback, sizeof(SerialFeedback));

      // Print data to built-in Serial
      Serial.print("1: ");
      Serial.print(Feedback.cmd1);
      Serial.print(" 2: ");
      Serial.print(Feedback.cmd2);
      Serial.print(" 3: ");
      Serial.print(Feedback.speedR_meas);
      Serial.print(" 4: ");
      Serial.print(Feedback.speedL_meas);
      Serial.print(" 5: ");
      Serial.print(Feedback.batVoltage);
      Serial.print(" 6: ");
      Serial.print(Feedback.boardTemp);
      Serial.print(" 7: ");
      Serial.println(Feedback.cmdLed);
    }
    else
    {
      Serial.println("Non-valid data skipped");
    }
    idx = 0; // Reset the index (it prevents to enter in this if condition in the next cycle)
  }

  // Update previous states
  incomingBytePrev = incomingByte;
}

// ########################## LOOP ##########################

void loop(void)
{

#if TASK_10MS
  static long unsigned int a = micros();
  if (micros() >= (a + 10000))
  { //10 ms tasks
    a = micros();
    /* Tasklist: 10 ms */
    Receive();    // Check for new received data
    Send(0, 100); //Send(int16_t uSteer, int16_t uSpeed)
  }
  else if (micros() < a)
    a = 0;
#endif

#if TASK_200MS
  static long unsigned int f = micros();
  if (micros() >= (f + 200000))
  { //200 ms tasks
    f = micros();
    Receive();    // Check for new received data
    Send(0, 100); //Send(int16_t uSteer, int16_t uSpeed)
  }
  else if (micros() < f)
    f = 0;
#endif

#if TASK_500MS
  static long unsigned int f = micros();
  if (micros() >= (f + 500000))
  { //500 ms tasks
    f = micros();
    /* Tasklist: 500 ms */
    Receive();    // Check for new received data
    Send(0, 100); //Send(int16_t uSteer, int16_t uSpeed)
  }
  else if (micros() < f)
    f = 0;
#endif

#if TASK_1000MS
  static long unsigned int g = micros();
  if (micros() >= (g + 1000000))
  { //1000 ms tasks
    g = micros();
    /* Tasklist: 1000 ms */
    Receive();    // Check for new received data
    Send(0, 100); //Send(int16_t uSteer, int16_t uSpeed)
  }

  else if (micros() < g)
    g = 0;
#endif
} 
Candas1 commented 3 years ago

Sorry I closed the issue by mistake. There is no issue with USART variant, there can always be interferences in USART communication, that's why the invalid frames are being discarded.

https://github.com/EmanuelFeru/hoverboard-firmware-hack-FOC/wiki/Variant-USART

goosst commented 3 years ago

ok so I tried the following:

on UART2:

Nothing works.

Then I changed to UART3: everything works fine from the start ...

vamfun commented 3 years ago

I'd be interested to know if you are seeing the dropouts that I am getting with USART3? See issue #162.

goosst commented 3 years ago

I'm currently mechanically rebuilding it, will let you know when it's back alive. I was only commanding relatively constant speeds so far, so I might not have observed the issue.

Maybe for your issue, it's an idea to add an incrementing rolling counter in the feedback structure in the hoverboard firmware. Then you can at least easily filter double messages or know reliably how many messages you've missed at the ESP?

vamfun commented 3 years ago

Best I can tell I’m not losing any messages...but every second or so I get the double frame which causes an extra 1 ms to capture the full data. But I modified the UART3 check code to accomplish this. So no significant performance effects so far on controlling motors. I also tried the UART2 ... tx worked fine but rx was dead. Never figured out why since connections were proper and input ports worked with ADC variant.

http://vamfun.wordpress.com Robot musing blog iPhone

On May 14, 2021, at 7:46 AM, goosst @.***> wrote:

 I'm currently mechanically rebuilding it, will let you know when it's back alive. I was only commanding relatively constant speeds so far, so I might not have observed the issue.

Maybe for your issue, it's an idea to add an incrementing rolling counter in the feedback structure in the hoverboard firmware. Then you can at least easily filter double messages or know reliably how many messages you've missed?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

Candas1 commented 3 years ago

So you guys both had a problem with uart2, but one with RX and one with TX?

goosst commented 3 years ago

So you guys both had a problem with uart2, but one with RX and one with TX?

The commands I had sent were very constant, but they didn't time out. So they were working as far as I'm aware. Getting the feedback over uart2 was indeed not working.

vamfun commented 3 years ago

So you guys both had a problem with uart2, but one with RX and one with TX? I wrote a better USART test program that uses DMA to recheck my board. USART2 works with the test program now so there is something in the USART2 Rx FOC firmware that is the cause. Maybe I'll get time to look into it again.