Git Product home page Git Product logo

Comments (14)

RoboDurden avatar RoboDurden commented on June 26, 2024 1

Yes take your time :-) It is just that when my repo is ready for a youtube tutorial, users should download lib_deps from your main branch so you can continue to experiment with your dev branches !

I now already successfully moved the entire simpleFOC code as well as all io code to a new class Hoverboard and the main.cpp is nicley empty and ready for users to add their code:

https://github.com/RoboDurden/Split_Hoverboard_SimpleFOC/blob/main/include/Hoverboard.h
https://github.com/RoboDurden/Split_Hoverboard_SimpleFOC/blob/main/src/Hoverboard.cpp

#include "Hoverboard.h"

#ifdef DEBUG_STLINK
  #include <RTTStream.h>
  RTTStream rtt;
#endif

Hoverboard oHoverboard;

float target = 0;
LowPassFilter LPF_target(0.5);  //  the higher the longer new values need to take effect

Commander command = Commander(SERIALDEBUG);
void doTarget(char* cmd) { command.scalar(&target, cmd); }
#ifdef IRQMOTOR
void doUsLoopFoc(char* cmd) { float f; command.scalar(&f, cmd); oHoverboard.motor.iUsLoopFOC = f;}
#endif

unsigned long iTimeSetupFinished = 0;
void setup()
{
  #ifdef DEBUG_UART
    DEBUG_UART.begin(DEBUG_UART_BAUD);
    SimpleFOCDebug::enable(&DEBUG_UART);
    motor.useMonitoring(DEBUG_UART);
  #endif
  //Serial2.begin(DEBUG_UART_BAUD); // when using Serial1 as DEBUG_UART

  #ifdef DEBUG_STLINK
    SimpleFOCDebug::enable(&rtt);
    oHoverboard.motor.useMonitoring(rtt);
  #endif

  OUTN("Split Hoverboards with C++ SimpleFOC :-)")

  if (!oHoverboard.Init())
  {
    OUTN("oHoverboard.Init() failed :-(")
    return;
  }


  // add target command T
  command.add('t', doTarget, "target voltage");
  #ifdef IRQMOTOR
    command.add('f', doUsLoopFoc, "set us of loopFoc");
  #endif

  oHoverboard.Blink(3,oHoverboard.oLedGreen);
  iTimeSetupFinished = millis();
}


unsigned long iTimeLast = 0;
unsigned long iTimeSend = 0;
void loop()
{
  unsigned long iNowMs = _micros();
  unsigned long iLoopMS = iNowMs - iTimeLast;
  iTimeLast = iNowMs;
  unsigned long iNow = millis();

  if (  oHoverboard.Move(LPF_target(target)) )   // return only once TRUE when current calibrating is done
  {
    target = 10;
  }

  command.run();  // user communication

  #ifdef IRQMOTOR
    delayMicroseconds(500);
  #endif

  if (iTimeSend > iNow) return;
  iTimeSend = iNow + 100; // TIME_SEND

  OUT2T("A",oHoverboard.GetDcCurrent())
  OUT2T("hall",oHoverboard.sensor.pulse_diff);
#ifdef IRQMOTOR  
  OUT2T("adc us",oHoverboard.motor.iAdcMicros)
  OUT2T("adc Hz",1000000 / oHoverboard.motor.iAdcMicros)
  OUT2T("iAdcMicrosLoop",oHoverboard.motor.iAdcMicrosLoop)
#endif
  OUT2T(target,oHoverboard.motor.target)
  OUT2T("v",oHoverboard.GetRpmPerVolt() )
  OUT2N("loop us",iLoopMS)
}

Next step could already be to add my https://github.com/RoboDurden/GD32_I2C_Slave :-)

from split_hoverboard_simplefoc.

RoboDurden avatar RoboDurden commented on June 26, 2024

Okay i added a nice IrqMotor class extending BLDCMotor:

https://github.com/RoboDurden/Arduino-FOC/blob/master/src/IrqMotor.h

class IrqMotor: public BLDCMotor
{
  public:
    IrqMotor(int pp,  float R = NOT_SET, float KV = NOT_SET, float L = NOT_SET);

	// overriding
	int initFOC() override;
	void loopFOC()	{};
	void move(float target = NOT_SET) override;

	void IrqHandler();

	unsigned long iAdcMicros = 0;
	unsigned long iAdcMicrosLoop = 0;
	int iUsLoopFOC = 300;

  protected:

	unsigned long iAdcLast = 0;
	unsigned long iAdcMicrosLoopLast = 0;
};

https://github.com/RoboDurden/Arduino-FOC/blob/master/src/IrqMotor.cpp

IrqMotor* pIrqMotor = NULL;
boolean bIrqMotorThreadNotRunning = true; // thread safety

IrqMotor::IrqMotor(int pp, float _R, float _KV, float _inductance)
: BLDCMotor(pp, _R, _KV, _inductance)
{
  pIrqMotor = this;
}


int IrqMotor::initFOC() 
{
  int iRet = BLDCMotor::initFOC();
  adc_interrupt_flag_clear(ADC_INT_EOIC);
  adc_interrupt_enable(ADC_INT_EOIC);
  nvic_irq_enable(ADC_CMP_IRQn, 3, 3);
  return iRet;
}

void IrqMotor::move(float new_target)	
{
  if(_isset(new_target)) target = new_target;
}


void IrqMotor::IrqHandler()
{
  unsigned long iNow = _micros();
  iAdcMicros = iNow - iAdcLast;
  iAdcLast = iNow;

  if (enabled)
  {
    if (bIrqMotorThreadNotRunning && (iNow - iAdcMicrosLoopLast > iUsLoopFOC) ) // 250 us = 4 kHz
    {
      bIrqMotorThreadNotRunning = false;

      BLDCMotor::loopFOC();
      BLDCMotor::move(target);
      iAdcMicrosLoop = iNow - iAdcMicrosLoopLast;
      iAdcMicrosLoopLast = iNow;

      bIrqMotorThreadNotRunning = true;
    }
  }
}


extern "C" 
{  
  void ADC_CMP_IRQHandler(void)
  {
    if ( adc_interrupt_flag_get(ADC_INT_EOIC) != RESET)
    {
      adc_interrupt_flag_clear(ADC_INT_EOIC);
      if (pIrqMotor)  pIrqMotor->IrqHandler();
    }
  }
}

And i only have about 1% less performance with no more time restrictions in the loop():

22 Volt
T5 T10 T20 T50

KV [rpm/V]	current [A]
IrqMotor
4.49	0.15
9.17	0.27
9.64	0.28
12.6	1.0

BLDCMotor
4.48	0.15
9,23	0.27
9,75	0.28
13,03	1.2

BLDCMotor + loop()::delayMicroseconds(500);
4.49	0.15
8.89	0.3	:-(
9.28	0.3	:-(
11.33	0.6

It only needs

#define IRQMOTOR
#ifdef IRQMOTOR
  IrqMotor motor = IrqMotor(BLDC_POLE_PAIRS, NOT_SET, NOT_SET, 0.00036858); 
#else
  BLDCMotor motor = BLDCMotor(BLDC_POLE_PAIRS, NOT_SET, NOT_SET, 0.00036858); 
#endif

All the other init and loop code can stay in place: https://github.com/RoboDurden/Split_Hoverboard_SimpleFOC/blob/main/src/main.cpp

@Candas1 where is your _powtwo defined ? I needed to add #define _powtwo(n)(1 << n) to SimpleFOCDrivers\src\voltageGenericVoltageSense.cpp :-/

Ideas welcome !

from split_hoverboard_simplefoc.

robcazzaro avatar robcazzaro commented on June 26, 2024

Maybe @robcazzaro will like to check my ADC_CMP_IRQHandler for thread safty.
Is 3,3 the lowest possible interrupt priority ?

From a very quick look at the docs, a priority of 0, 0 should work and be the highest priority for the processor. But I haven't checked if the Arduino library uses priority 0 (should not)

from split_hoverboard_simplefoc.

RoboDurden avatar RoboDurden commented on June 26, 2024

the Hall interrupts run at 3,0 priority!
If i let the ADC_INT_EOIC = EndOfInsertedConversion run at 0,0 , the hall interrupts seem to get postponed to when the 300 us loopFOC+move have finished :-(
I only get the near loop()::loopFOC() performence when i let it run at lower priority than 3,0. I think that is 3,3.
I guess that there are only two bits for

void nvic_irq_enable(uint8_t nvic_irq, uint8_t nvic_irq_pre_priority, uint8_t nvic_irq_sub_priority)

Then 3,3 would be the highest number possible and therefore the lowest priority that allows the hall interrupts (and whatever code users will add) to be nested = interrupt the ADC_CMP_IRQHandler(void) -> IrqMotor::IrqHandler() and be executed immediately :-)

from split_hoverboard_simplefoc.

RoboDurden avatar RoboDurden commented on June 26, 2024

I first tried the wrapping approach like SmoothedSensor.
But the loop() code reads element variables like motor.enabled which i can not update when some FocMotor function changes the _wrapped.enabled :-/

I do not think that the simpleFOC community will accept a pull request to add my IrqMotor the the Arduino-FOC.
Should i try for a SimpleFOCDrivers/motors/IrqMotor.cpp ?
I guess i better move my class to the Split_Hoverboard_simpleFOC repo.

Hopefully Simple FOC\src\current_sense\hardware_specific\gd32\gd32f130\gd32f130_mcu.cpp will make it into the Arduino-FOC main branch :-)

from split_hoverboard_simplefoc.

robcazzaro avatar robcazzaro commented on June 26, 2024

Then 3,3 would be the highest number possible and therefore the lowest priority that allows the hall interrupts (and whatever code users will add) to be nested = interrupt the ADC_CMP_IRQHandler(void) -> IrqMotor::IrqHandler() and be executed immediately :-)

Well, you could change the Hall interrupt to be 0,0, and the ADC to be 0,1 or even 1,0. The system uses negative priority numbers for the non-maskable hardware interrupts, and you have full control over the others. But if there are no other interrupts, 3.0 and 3,3 are de facto equivalent to 0,0 and 0,3...

from split_hoverboard_simplefoc.

Candas1 avatar Candas1 commented on June 26, 2024

Hi,

I made the interrupt a parameter to keep it in case it's useful.
I synched arduino-foc-drivers thinking _powtwo will be released also in the main library, but it seems it's pending.
If this PR is accepted, loopFOC should be a bit faster.

They will not accept IRQMotor, it's very GD32 specific, and I am not even sure if they will accept my drivers.
There are still many changes pending, arduino-gd32 project is not really active.

I thought about making the gd32 drivers a submodule so it's separated from the library but it seems this can generate other problems.

from split_hoverboard_simplefoc.

RoboDurden avatar RoboDurden commented on June 26, 2024

@robcazzaro

you could change the Hall interrupt to be 0,0,

No, the Hall interrupts use the Arduino-Core attachInterrupt(digitalPinToInterrupt(pinA), doA, CHANGE); which why the HallSensor instantly worked on the GD32. But the nvic priorities are hard coded into the Arduino-Core :-(

and you have full control over the others.

No, i have no control what other interrupt code/libraries end users might want to add. Therefore i need the lowest possible priority.

@Candas1 yes i also think they would never accept it. But they themselves are aware that running loopFOC in the main loop is not ideal.
I added an optional TIMER2 interrupt to my IrqMotor which would make it usuful for any platform:

int IrqMotor::initFOC(unsigned int iHz) 
{
  int iRet = BLDCMotor::initFOC();

  if (iHz)
  {
    oTimer.setPeriodTime(iHz, FORMAT_HZ);
    oTimer.attachInterrupt(&timer_cb);
    nvic_irq_enable(TIMER2_IRQn, 3, 3);
    oTimer.start();
  }
  else
  {
    adc_interrupt_flag_clear(ADC_INT_EOIC);
    adc_interrupt_enable(ADC_INT_EOIC);
    nvic_irq_enable(ADC_CMP_IRQn, 3, 3);
  }
  return iRet;
}

If there would be a SetPriority function in the Arduino-Core, this TimerX interrupt might run on any Arduino platform.
Perfomance with motor.initFOC(3000); is not bad at all:

22 Volt
T5 T10 T20 T50

IrqMotor:Timer2 with loop()::delayMicroseconds(500);
4.45	0.15
9.05	0.3
9.52	0.28
12.33	1.8

IrqMotor:EOIC with loop()::delayMicroseconds(500);
4.45	0.15
9.08	0.26
9.52	0.28
12.33	1.0

BLDCMotor without loop()::delayMicroseconds(500);
4.46	0.15
9,01	0.27
9,43	0.27
11.70	1.3

from split_hoverboard_simplefoc.

Candas1 avatar Candas1 commented on June 26, 2024

That's a library so I think they let you run it from wherever you want.

from split_hoverboard_simplefoc.

RoboDurden avatar RoboDurden commented on June 26, 2024

Okay @Candas1 i have moved my class to #include "../include/IrqMotor.h" and now i am back to

lib_deps = 
	koendv/RTT Stream@^1.3.0
	https://github.com/Candas1/Arduino-FOC.git#dev-gd32
	https://github.com/Candas1/Arduino-FOC-drivers.git#dev

Would be nice if you temporarily add this to GenericVoltageSense.cpp

#ifndef _powtwo
    #define _powtwo(n)(1 << n)
#endif

Would also be nice if you push your dev code to the main branches.
Because i am quite happy with your work already and now would continue with the I2C-Hoverboard code.
You then can happily continue with your dev branches and push to the main branch when the performance gets better :-)

from split_hoverboard_simplefoc.

Candas1 avatar Candas1 commented on June 26, 2024

I won't be able to work on it next few days. You just have to add it to your local copy

from split_hoverboard_simplefoc.

Candas1 avatar Candas1 commented on June 26, 2024

I will let you know when the main is updated.
Feel free to share this is you think it's good enough, but you will have to support those users, please don't send them to me.
I want to focus on Simplefoc improvements.

from split_hoverboard_simplefoc.

RoboDurden avatar RoboDurden commented on June 26, 2024

I am happy to help my users: RoboDurden/Hoverboard-Firmware-Hack-Gen2.x#16
well, happy to try to help..

from split_hoverboard_simplefoc.

Candas1 avatar Candas1 commented on June 26, 2024

That's a good user
I mean, the other users 😂

from split_hoverboard_simplefoc.

Related Issues (10)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.