Skip to content

Question about UART communication #154

Description

@JesusHimself

My goal is to control the hooverboard through commands that will be send from an Arduino. I however want to use more commands than the ones in the example file. I would like to send the following:
-Speed left wheel
-Speed right wheel
-Reverse left wheel
-Reverse right wheel
-Cruise control left wheel
-Cruise control right wheel
I know that I will also have to adjust a lot of code on the hooverboard firmware but could someone check my Arduino code. I don't have experience with UART so it's nice if someone can confirm.

// *******************************************************************
// Arduino Nano 5V example code
// for https://github.com/EmanuelFeru/hoverboard-firmware-hack-FOC
//
// Copyright (C) 2019-2020 Emanuel FERU aerdronix@gmail.com
//
// *******************************************************************
// INFO:
// • This sketch uses the the Serial Software interface to communicate and send commands to the hoverboard
// • The built-in (HW) Serial interface is used for debugging and visualization. In case the debugging is not needed,
// it is recommended to use the built-in Serial interface for full speed perfomace.
// • The data packaging includes a Start Frame, checksum, and re-syncronization capability for reliable communication
//
// CONFIGURATION on the hoverboard side in config.h:
// • Option 1: Serial on Right Sensor cable (short wired cable) - recommended, since the USART3 pins are 5V tolerant.
#define CONTROL_SERIAL_USART3
#define FEEDBACK_SERIAL_USART3
#define DEBUG_SERIAL_USART3
// • Option 2: Serial on Left Sensor cable (long wired cable) - use only with 3.3V devices! The USART2 pins are not 5V tolerant!
// #define CONTROL_SERIAL_USART2
// #define FEEDBACK_SERIAL_USART2
// // #define DEBUG_SERIAL_USART2
// *******************************************************************

// ########################## DEFINES ##########################
#define HOVER_SERIAL_BAUD 115200 // [-] Baud rate for HoverSerial (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 TIME_SEND 100 // [ms] Sending time interval
#define SPEED_MAX_TEST 300 // [-] Maximum speed for testing
//#define DEBUG_RX // [-] Debug received data. Prints all bytes to serial (comment-out to disable)

#include <SoftwareSerial.h>
SoftwareSerial HoverSerial(2,3); // RX, TX

// 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 speed1;
int16_t speed2;
uint8_t reverse1;
uint8_t reverse2;
uint8_t cruise1;
uint8_t cruise2;
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;

int sensorPin = A0;
int sensorPin2 = A1;
int ledPin = 13;
int sensorValue = 0;
int speed1;
int speed2;
int reverse1;
int reverse2;
int cruise1;
int cruise2;

// ########################## SETUP ##########################
void setup()
{
Serial.begin(SERIAL_BAUD);
Serial.println("Hoverboard Serial v1.0");

HoverSerial.begin(HOVER_SERIAL_BAUD);
pinMode(LED_BUILTIN, OUTPUT);
}

// ########################## SEND ##########################
void Send(int16_t uSpeed1, int16_t uSpeed2, uint8_t uReverse1, uint8_t uReverse2, uint8_t uCruise1, uint8_t uCruise2)
{
// Create command
Command.start = (uint16_t)START_FRAME;
Command.speed1 = (int16_t)uSpeed1;
Command.speed2 = (int16_t)uSpeed2;
Command.reverse1 = (int16_t)uReverse1;
Command.reverse2 = (int16_t)uReverse2;
Command.cruise1 = (int16_t)uCruise1;
Command.cruise2 = (int16_t)uCruise2;
Command.checksum = (uint16_t)(Command.start ^ Command.speed1 ^ Command.speed2 ^ Command.reverse1 ^ Command.reverse2 ^ Command.cruise1 ^Command.cruise2);

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

// ########################## RECEIVE ##########################
void Receive()
{
// Check for new data availability in the Serial buffer
if (HoverSerial.available()) {
incomingByte = HoverSerial.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);
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");
        // 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);
    }
    idx = 0;    // Reset the index (it prevents to enter in this if condition in the next cycle)
}

// Update previous states
incomingBytePrev = incomingByte;

}

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

unsigned long iTimeSend = 0;

void loop(void)
{
unsigned long timeNow = millis();

// Check for new received data
Receive();

speed1 = analogRead(sensorPin);
speed2 = analogRead(sensorPin2);
reverse1 = 0;
reverse2 = 0;
cruise1 = 0;
cruise2 = 0;

if (speed1 < 85){
speed1 = 0;
}
if (speed2 < 85) {
speed2 = 0;
}

Send(speed1, speed2, reverse1, reverse2, cruise1, cruise2);

// Blink the LED
digitalWrite(LED_BUILTIN, (timeNow%2000)<1000);
}

// ########################## END ##########################

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions