Arduino UNO Q support

Hello

Getting SimpleFOC running on an Arduino UNO Q (+ SimpleFOCShield V3.2) is not as easy as I hoped.

Arduino IDE2

These are the steps I’ve taken up to now:

  • You need to use Monitor instead of Serial but there is an easy fix:
    #include <Arduino_RouterBridge.h>
    #define Serial Monitor (you can also replace Serial with Monitor throughout the code)
    (MsgPack library installation is required)

  • Normally you get an error about fmod and strtok, by adding this at the top of the code and changing some settings I got it to upload (should look into what accually fixed it because you probably don’t need everyting):
    #define _XOPEN_SOURCE 700
    #include <Arduino.h>
    #include <math.h>
    #include <string.h>

  • The code now uploads, and I get some SimpleFOC messages on the serial monitor, but no movement from the motor.

Code

#define _XOPEN_SOURCE 700
#include <Arduino.h>
#include <math.h>
#include <string.h>
#include <Arduino_RouterBridge.h>
#include <SimpleFOC.h>

#define Serial Monitor

// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(7);
BLDCDriver3PWM driver = BLDCDriver3PWM(6, 10, 5, 8);

// encoder instance
Encoder encoder = Encoder(2, 3, 1024);
// channel A and B callbacks
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}

// inline current sensor instance
// ACS712-05B has the resolution of 0.185mV per Amp
InlineCurrentSense current_sense = InlineCurrentSense(185.0f, A0, A2);

// commander communication instance
Commander command = Commander(Serial);
void doMotion(char* cmd){ command.motion(&motor, cmd); }
void doMotor(char* cmd){ command.motor(&motor, cmd); }

void setup() {

  // use monitoring with Serial
  Serial.begin(115200);
  // enable more verbose output for debugging
  // comment out if not needed
  SimpleFOCDebug::enable(&Serial);

  // initialize encoder sensor hardware
  encoder.init();
  encoder.enableInterrupts(doA, doB);
  // link the motor to the sensor
  motor.linkSensor(&encoder);
  motor.voltage_sensor_align = 4;

  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 12;
  driver.init();
  // link driver
  motor.linkDriver(&driver);
  // link current sense and the driver
  current_sense.linkDriver(&driver);

  // set control loop type to be used
  motor.controller = MotionControlType::velocity;

  // controller configuration based on the control type
  motor.PID_velocity.P = 0.5f;
  motor.PID_velocity.I = 10;
  motor.PID_velocity.D = 0.001;
  // default voltage_power_supply
  motor.voltage_limit = 6;

  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.01f;

  // angle loop controller
  motor.P_angle.P = 1;
  // angle loop velocity limit
  motor.velocity_limit = 20;

  // comment out if not needed
  motor.useMonitoring(Serial);
  motor.monitor_downsample = 0; // disable intially
  motor.monitor_variables = _MON_TARGET | _MON_VEL | _MON_ANGLE; // monitor target velocity and angle

  // current sense init and linking
  current_sense.init();
  motor.linkCurrentSense(&current_sense);

  // initialise motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();

  // set the inital target value
  motor.target = 0;

  // subscribe motor to the commander
  command.add('T', doMotion, "motion control");
  command.add('M', doMotor, "motor");

  _delay(1000);
}

void loop() {
  // iterative setting FOC phase voltage
  motor.loopFOC();

  // iterative function setting the outter loop target
  motor.move();

  // motor monitoring
  motor.monitor();

  // user communication
  command.run();
}

Arduino App Lab

Getting started:

  1. Create a new app
  2. Add the SimpleFOC library to the app:
  3. Ready to write some code

These are the steps I’ve taken up to now:

  • Tried the same fixes as Arduino IDE2, but that didn’t work:
Starting app "SimpleFOC standalone"
Sketch profile configured: Name="default", Port=""
The library ArxContainer has been automatically added from sketch project.
The library ArxTypeTraits has been automatically added from sketch project.
The library DebugLog has been automatically added from sketch project.
The library MsgPack has been automatically added from sketch project.
The library Simple FOC has been automatically added from sketch project.
/home/arduino/.arduino15/packages/zephyr/tools/arm-zephyr-eabi/0.16.8/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld: /home/arduino/ArduinoApps/simplefoc-standalone/.cache/sketch/libraries/Simple FOC/common/foc_utils.cpp.o: in function `_normalizeAngle(float)':
/home/arduino/.arduino15/internal/Simple_FOC_2.3.5_b04eebd81eadaf6b/Simple FOC/src/common/foc_utils.cpp:80: undefined reference to `fmod'
/home/arduino/.arduino15/packages/zephyr/tools/arm-zephyr-eabi/0.16.8/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld: /home/arduino/ArduinoApps/simplefoc-standalone/.cache/sketch/libraries/Simple FOC/communication/Commander.cpp.o: in function `Commander::target(FOCMotor*, char*, char*)':
/home/arduino/.arduino15/internal/Simple_FOC_2.3.5_b04eebd81eadaf6b/Simple FOC/src/communication/Commander.cpp:571: undefined reference to `strtok'
collect2: error: ld returned 1 exit status
exit status 1
  • Manually solved those problems for now:
extern "C" {
    double fmod(double x, double y) {
        return x - (long)(x / y) * y;
    }
    
    float fmodf(float x, float y) {
        return x - (int)(x / y) * y;
    }

    char* strtok(char* str, const char* delim) {
        static char* last;
        if (str) last = str;
        if (!last) return NULL;
        // Skip leading delimiters
        while (*last && strchr(delim, *last)) last++;
        if (!*last) return NULL;
        char* result = last;
        // Find end of token
        while (*last && !strchr(delim, *last)) last++;
        if (*last) {
            *last = '\0';
            last++;
        }
        else {
            last = NULL;
        }
        return result;
    }
}
  • Tried some variations like replacing the pin definitons with ‘D6’ instead of just ‘6’.
  • Code runs, but no movement, just like Arduino IDE2 .

Thanks in advance for any tips or fixes or … .

Kind regards

Stijn

Hey @CarelsberghStijn , awesome that you’re working on this :slight_smile:

I also ordered an UNO Q, and was playing with it a bit. I’m not very sold yet on the new App Lab - seems to me you can’t even compile your code without running it, and (at least on my machine) it’s very slow :frowning:

But it does seem to work if you’re patient, so at least that’s something.

The STM32U585 MCU with its Cortex M33 core isn’t officially supported by SimpleFOC, but the PWM drivers should probably work. The current sense will not be supported so you should probably remove that from your test code.

The problems I see in my tests right now:

  1. The STM32 PWM driver isn’t being used - it’s defaulting to analogWrite() I guess, but that won’t realistically work well.
  2. So you need to run a modified version of the library (dev branch + some changes) to get it working, but it’s not obvious how to run a custom library build on this setup.

I’ll look into that some more, and I think I’ll get that solved, but I’m not sure if it will work even if I solve that. We’ll see.

The problem I see is that Arduino has once again switched the basis of their framework. Instead of working with stm32duino (provided free by ST Micro) they have chosen to write a wrapper on top of Zephyr. They already did this once for their Portenta and Nicla boards, which are based on H7 MCUs and they chose to make a new framework based on mbed. Mbed was discontinued so I guess this time they chose Zephyr.

So it remains to be seen if the Zephyr layer exposes the STM32 HAL in a way that is needed for our drivers to work, and whether they included PinMaps in the required formats.

I’ll let you know what I find out.

Hello

My thinking was (or at least I hoped so): “If they say its compatible with arduino uno code I will start by ignoring that its an STM32 and they will fix it in the background (using STM32duino or some custom code)”

This is clearly not the case so this will indeed require some more work from the community or future updates from them. The problems are clear but the solutions will take some time and effort.

Hi @CarelsberghStijn ,

Another update on this:

I spent a little more time and got my UNO Q compiling with a local version of SimpleFOC. After a little more effort to figure out how to get at the verbose compiler output, I modified the library to compile with the STM32 drivers when compiling on UNO Q.

The result? In summary, not good. The new zephyr based framework not only doesn’t include the math functions you already found, but also doesn’t include a bunch of other stuff we expect and use with stm32duino… that includes:

  • the STM32 HAL LL interfaces, which don’t seem to be accessible
  • the PinMap structures commonly used in other Arduino frameworks,
  • associated definitions and some macros we’re using to do with those

So I’m not sure if these things are buried somewhere in zephyr and we just need to find them, or what the solution is to that yet. With MBed on the Portenta, the Mbed layer contained the HAL underneath and our stm32 drivers more or less just worked with it… that doesn’t seem to be as easy this time.

But another problem is the way Arduino seems to be integrated into zephyr - I’m getting a loop speed of about 850 iterations/second on SimpleFOC main loop with the motor disabled… that’s terrible :frowning: my assumption is that the main loop is scheduled at a rate of 1kHz or something like that. In any case, it’s not at all the performance I would expect from a cortex-m33, and more or less makes further experimentation pointless.

I think a better direction to take here would be a proper zephyr integration, with scheduling of the motor tasks at the right frequency, if that can be done in zephyr. However I don’t know if the UNO Q as a product will be really popular enough for motor control purposes to make that worth it…

Feedback is welcome :slight_smile: