Serial Communication between ArduinoIDE and Simulink for controlling motor

I am trying to control a Reaction Wheel Inverted Pendulum using SimpleFOCShield in real-time through Simulink. I have tried porting the SimpleFOCLibrary to Simulink as a S-function, but it hasn’t worked out. That’s why I took another approach, which is to upload the program through Arduino IDE. And then control the motor from Simulik instead of SimpleFOCStudio.

I am not that familiar with Serial Communication between Arduino IDE and Simulink, but I have seen a few examples online. I am trying to do the serial communication step by step. Right now I am trying to control the torque/voltage using the serial communication from simulink as the input for the target voltage. But the motor is not spinning. I took a part of the ReactionWheel example code and what I did was as the following:

#include <SimpleFOC.h>

// Create a union to easily convert float to byte
typedef union{
  float number;
  uint8_t bytes[4];
} FLOATUNION_t;

// Create the variable you want to send
FLOATUNION_t myValue;

// init BLDC motor
BLDCMotor motor = BLDCMotor( 14 );

// init driver
BLDCDriver3PWM driver = BLDCDriver3PWM(5, 9, 6, 8);
// init encoder
Encoder encoder = Encoder(3, 2, 2048);
// channel A and B callbacks
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}

// pendulum encoder init
Encoder pendulum = Encoder(A0, A2, 2048);
// interrupt routine 
void doPA(){pendulum.handleA();}
void doPB(){pendulum.handleB();}

void setup() {

  // initialize motor encoder hardware
  encoder.init();
  encoder.enableInterrupts(doA,doB);
  
  // driver config
  driver.voltage_power_supply = 12;
  driver.init();
  
  // init the pendulum encoder
  pendulum.init();
  pendulum.enableInterrupts(doPA,doPB);

  // set control loop type to be used
  motor.torque_controller = TorqueControlType::voltage;
  motor.controller = MotionControlType::torque;

  Serial.begin(115200);
  // link the motor to the encoder
  motor.linkSensor(&encoder);
  // link the motor to the driver
  motor.linkDriver(&driver);
  
  // initialize motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();

}

void loop() {

  // iterative FOC function
  motor.loopFOC();
  
  float target_voltage;
  target_voltage = getFloat();
  delay(1);
  // pendulum sensor read
  pendulum.update();

  // position motion control loop
  motor.move(target_voltage);
}


float getFloat(){
    int cont = 0;
    FLOATUNION_t f;
    while (cont < 4 ){
        f.bytes[cont] = Serial.read() ;
        cont = cont +1;
    }
    return f.number;
}

But the motor is not running/spinning. Can anyone please help identify what I did wrong?

Thank you.

1 Like

I would suggest to study Serial Input Basics to understand how to deal with Serial communication

Your getFloat() function tries to read 4 bytes in a row from the Serial buffer without checking that the 4 bytes are already there

I am trying to control or for now send data/value from one STM32-L476RG board with another using UART/USART. I have attached the Rx pin of the "master" to the Tx of the "slave" and vice versa.

The "master" board will be controlled from Simulink similar to this first model of this example. While the "slave" board will be flashed from Arduino IDE, because of compatibility issues with another library that will be added if this is a success.

I tried running the code below, but there seems to be no data received by the "slave" board, which I checked through the serial monitor of Arduino IDE. Could you please help me identify the problem that might cause this? Thanks.

The Simulink model is as follows (The values are set to uint16_t):

The Arduino code:

typedef union{
  uint16_t number;
  uint8_t bytes[2];
} INTUNION_t;

INTUNION_t myValue_int;
void setup() {
  Serial.begin(115200);

}
void loop(){

  if(Serial.available()){
    myValue_int.number = getINT();
    int a = myValue_int.bytes[0] | myValue_int.bytes[1] << 8;
    Serial.println();
  }
  else {
    Serial.print("No data received\n");
  }  
}

int getINT(){
  int cont = 0;
  INTUNION_t i;
  while (cont < 2 ){
      i.bytes[cont] = Serial.read();
      cont = cont +1;
  }
  return i.number;
}

Ref.: arduino serial event between two boards - Google Search

I am currently trying to control Arduino Uno with STM32L47RG in Simulink via UART. But I think Arduino Uno isn't receiving any of the data. The STM32's Rx and Tx pins are connected to the Arduino Uno's Rx and Tx.

The Arduino code I wrote is referenced from the Arduino Cookbook , the Serial Input Basics, and this example.
I have used an oscilloscope to check whether it is sending the data, and there is data being sent as shown in the image below. Can anyone help identify where I got wrong?

Simulink model:

Oscilloscope (sending the number 2 through UART):

Arduino Code:

/*
 * SerialReceive sketch
 * Blink the LED at a rate proportional to the received digit value
*/
const int ledPin = 13; // pin the LED is connected to
int   blinkRate=0;     // blink rate stored in this variable

void setup()
{
  Serial.begin(115200); // Initialize serial port to send and receive at 9600 baud
  pinMode(ledPin, OUTPUT); // set this pin as output
}

void loop()
{
  if ( Serial.available()) // Check to see if at least one character is available
  {
    char ch = Serial.read();
    if(ch >= '0' && ch <= '9') // is this an ascii digit between 0 and 9?
    {
       blinkRate = (ch - '0');      // ASCII value converted to numeric value
       blinkRate = blinkRate * 100; // actual blinkrate is 100 mS times received digit
    }
  }
  blink();
}

// blink the LED with the on and off times determined by blinkRate
void blink()
{
  digitalWrite(ledPin,HIGH);
  delay(blinkRate); // delay depends on blinkrate value
  digitalWrite(ledPin,LOW);
  delay(blinkRate);
}

You may damage the STM32 by connecting any of it's pins directly to an UNO. The UNO runs on 5V, the STM32 on 3.3V. You must use level converters between them to adapt the voltage.

Did you cross-over? So UNO's RX is connected to STM32's TX and vice-versa (by a level converter of course).

Thanks for the reply. I have decided to use 2 same STM32 boards instead of the Arduino UNO, to prevent that from happening. I have also find out that the default pins for Rx and Tx are not working properly, so I used the SoftwareSerial.h to use different ones.

You shouldn't start half a dozen thread for the same issue!

I have doubts that the software emulation works better. You may tell us what "are not working properly" means. You may have fried them by connecting directly to the UNO.

I am trying to send a uint16 value(converted to 2 bytes) from a STM32 board through Simulink using serial communication to a STM32 board programmed with Arduino IDE. At first, I was able to read the values being sent after being decoded, but after that the values are a mess. I was wondering if there are ways to help the board read the right bytes in the right order. I have read the Serial Input Basic, but with example 4, it uses a "\n" end marker, which is not possible in my case. I would greatly appreciate it if anyone could suggest a solution to this.

Arduino code:

//Receiver Code
#include<SoftwareSerial.h>
SoftwareSerial  SUART(PC5, PC4); 

uint16_t lastState;
uint16_t currentState;

typedef union{
  uint16_t number;
  uint8_t bytes[2];
} INTUNION_t;

INTUNION_t myValue_int;

void setup()
{
  Serial.begin(115200);
  SUART.begin(115200);
  lastState = 0;
}

void loop()
{
  SUART.listen();

  uint8_t val;
  while (!SUART.available()) {}
  myValue_int.number = getINT();
  currentState = myValue_int.number;
  if (currentState != lastState)
  {
    Serial.print("currentState: ");
    Serial.println(currentState);
  }
  lastState = currentState; 
}

uint16_t getINT(){
  int cont = 0;
  INTUNION_t i;
  while (cont < 2 ){
      i.bytes[cont] = SUART.read();
      cont = cont +1;
  }
  return i.number;
}

can you send the number in ASCII decimal representation and add the trailing line feed ?
then you don't have to worry wether it's a 2 or 4 byte integer, little or big endian etc and you have an end marker to get in sync with the sender

you really need to encapsulate raw data in a message packet with a well know start and end in order to remain synchronized with the sender.

as @J-M-L suggests, sending data as ASCII strings, which require more bytes avoids this headache

SoftwareSerial at 115200 baud probably won't work. Use a hardware serial interface if you need that speed.

I'm sure the order is correct but you probably miss some bits or even bytes with your setup.

Do you tell us the reason? You might have to forget the binary transfer but ASCII transfers are easier to control anyway.

I don't understand the picture you have posted.
How do the boxes relate to the sending STM-device and the receiving "arduino-programmed STM32-board

You have to provide much more details about:

  • the timing when bytes are sent
  • values that can occur in each byte

You must find some detail whatever that inidcates "I'm the first byte" or "bytesequence starts here"

That only works if all systems have the same "endianness". If you send 0xAA, 0x55 to a Little-Endian processor you will get a value of 0x55AA. If you send it to a BigEndian processor you will get 0xAA55.

not to mention that it's undefined behaviour to use union this way (write a member, read from the other)

But it works on all compilers I'm aware of. Do you know any exception?

I think I can send the number in ASCII. I can convert it to string then convert it to ASCII, but I'm not sure if it's right, because there are no integer to ascii block. Unlike Arduino's Serial Transmit Block in Simulink, STM32's SCI Write block has no option to add trailing line feed. So I don't know how to add it yet.

it works indeed but yet in some cases it can fail (compiler adds padding etc). So best not to use it and do it the proper way with memcpy() and the compiler will do the right thing.

simulink is as its name says for simulation.

How does simulink (a simulation) interact with your microcontroller-devices??

Did I understand that correctly, that's Simulink stuff? I have no clue about that one you might have to consult the manual or ask the manufacturer but I doubt that there's no way to do it. Otherwise that software is simply crap.