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 wonder if that is possible? If anyone has any insight on how to do this, it would be greatly appreciated.
Serial communication with simulik should be possible. I’ve done some similar thins in the past, however there is a latency (dead-time) of arround 20ms if I remember correctly. That should still be ok for making the pendulum balance.
I don’t have access to my old projects at the moment, I’ll try to make a small example next week.
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(PA8, PA9, PA10, PC7);
// init encoder
Encoder encoder = Encoder(PB4, PB5, 2048);
// channel A and B callbacks
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
// pendulum encoder init
Encoder pendulum = Encoder(PB6, PB7, 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;
}
Does the motor feel powered, is current being consumed?
Some points about your code:
I don’t know which motor you are using, but you don’t set a voltage limit - so this code is only appropriate for a high ohm motor, with a low ohm motor the currents could rise too high
you have a delay(1) in your loop() function. But SimpleFOC depends on executing as quickly as possible, so you should never call delay() in the main loop. You can replace it with a little bit of logic using a timestamp, and use the micros() function to check for the elapsed time. In this way you can call pendulum.update() at any frequency you want, without incurring delays in the main loop.
I decided to change the approach by using 2 STM32 boards. The first one reads the encoder value, calculates the required torque output, which will be done via Simulink, and sends the value through UART/Serial Communication to the second board. The second one runs the SimpleFOC (flashed by Arduino IDE) by decoding the incoming bytes and using that value for the motor.move() command. The problem right now that I’m having is that the incoming bytes are not being decoded properly. I was able to decode the incoming bytes before adding the SimpleFOC, but after that, the incoming bytes are a bit of a mess. The problem is that there are no start and end marker for the incoming data. I wonder if you could help/give me suggestions on how to adjust the Commander.h for my use.
One thing I can see right away is that you can’t do this:
while (!SUART.available()) {}
You can’t busy-wait in the SimpleFOC main loop. The loopFOC() and move() functions have to be called as quickly as possible, ideally at a rate of 3kHz or more.
So waiting for Serial input in the middle of this loop is not possible. You’ll have to change the logic to be something like
while (SUART.available()>=2) {
// read the value and do something
}
Also the call to listen() isn’t needed, I don’t think.
In general, why use SoftwareSerial? This won’t have as good performance as a real serial port, and might interfere with the SimpleFOC execution. Can’t you use a real serial port? STM32 MCUs typically have more than one…
[Edit]
Can you use I2C? Our drivers repository has code for the I2CCommander, which works for machine to machine communications…
Alternatively, you could also use the normal Serial based Commander to update the target value.
Writing communications code is tricky, so if you can use something existing, then it will make your life easier I think.
Hi. I decided to change it and use HardwareSerial instead of SoftwareSerial.
I have found a way to do it. I added a start and end marker using uint8 values and combined it with the value I wanted to send. And I played around with the examples from the Serial Input Basic thread until it works. I have also lowered down the transmit speed to 9600. And as a result, the transmitted values are being decoded properly. Now I will try to use this for a reaction wheel pendulum. Thanks