diff --git a/docs/boards/index.md b/docs/boards/index.md index 248407f..7aafcd1 100644 --- a/docs/boards/index.md +++ b/docs/boards/index.md @@ -18,11 +18,12 @@ There two main formats of the official drivers boards developed by the Shield form factor: These boards are designed to be compatible with the Arduino ecosystem and are intended to be used with the SimpleFOClibrary and the Arduino IDE. They are designed to be easy to use and are intended for low to mid power applications. - SimpleFOCShield - [Find out more](arduino_simplefoc_shield_showcase) - - SimpleFOC PowerShield - ⚠️( development abandoned ) - [Find out more](#arduino-simplefoc-powershield-v02-️-development-abandoned-) + - SimpleFOC PowerShield - ⚠️( development abandoned ) - [Find out more](#simplefoc-powershield-v02-️-development-abandoned-) + - 📢**NEW**: SimpleFOCDrive - [Find out more](boards#simplefoc-drive-v10---find-out-more) - Mini form factor: These boards are designed to be small, low-cost, and easy to use. They are intended for low power applications and are designed to be compatible with the SimpleFOClibrary. - SimpleFOCMini - [Find out more](simplefocmini) - - SimpleFOC StepMini (📢**NEW**) - [Find out more](#simplefoc-stepmini-v10---see-on-github) + - SimpleFOC StepMini - [Find out more](#simplefoc-stepmini-v10---see-on-github) In addition to the official boards, there are many other boards compatible with SimpleFOClibrary that you can explore, see the [docs](supported_hardware). Additionally, some other cool hardware designs have been proposed by the community. Check out our [community forum](https://community.simplefoc.com/) for more info. @@ -111,6 +112,39 @@ This does not mean that the board itself is not functional or that it will not w Read more about this board at [link](https://github.com/simplefoc/Arduino-SimpleFOC-PowerShield) +### SimpleFOC Drive v1.0 - [Find out more](https://github.com/simplefoc/SimpleFOC-DriveShield) + +![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?color=blue) +![GitHub release (latest by date)](https://img.shields.io/github/v/release/simplefoc/SimpleFOC-DriveShield) +![GitHub Release Date](https://img.shields.io/github/release-date/simplefoc/SimpleFOC-DriveShield?color=blue) + +
+ +
+ +This is an open-source low-cost BLDC driver boards in the form of a Arduino shield. It is a part of the SimpleFOC project. The board is the big brother of the SimpleFOCShield and is designed to drive motors with higher current requirements, up to 30Amps. The board is created with the same philosophy as the SimpleFOCShield - to be simple to use, low-cost, and open-source and fully compatible with the SimpleFOClibrary. + +Additionally the aim of the board is to serve as a template project for the community to build their own motor drivers. + +- The board is relatively simple and can be easily modified to fit different requirements. +- The board is designed in EasyEDA and all the fabrication files are available for download + +### Features +{: .no_toc } + +- **Boards absolute max ratings** + - Max current: 20A continuous (peak 30A - measured) + - Max input voltage: 30V +- **Stackable**: running 2 motors in the same time +- **Encoder/Hall sensors interface**: Integrated 3.3kΩ pullups (configurable) +- **I2C interface**: Integrated 4.7kΩ pullups (configurable) +- **Configurable pinout**: Hardware configuration - soldering connections +- **Arduino headers**: Arduino UNO, Arduino MEGA, STM32 Nucleo boards... +- **Open Source**: + - Fully designed in EasyEDA: [EasyEDA project](https://oshwlab.com/the.skuric/SimpleFOC-Drive) + - Fully available on github: [GitHub project](https://github.com/simplefoc/SimpleFOC-DriveShield) +- **Low-cost**: Estimated price of 25-40€ - Will be available in the SimpleFOC shop + ## Boards in the Mini form factor diff --git a/docs/simplefoc_library/code/current_sense/index.md b/docs/simplefoc_library/code/current_sense/index.md index a09d639..753e7da 100644 --- a/docs/simplefoc_library/code/current_sense/index.md +++ b/docs/simplefoc_library/code/current_sense/index.md @@ -52,7 +52,8 @@ stm32f1 family | ✔️ | ✔️ (one motor) | ❌ stm32f4 family | ✔️ | ✔️ (one motor) | ❌ stm32g4 family | ✔️ | ✔️ (one motor) | ❌ stm32l4 family | ✔️ | ✔️ (one motor) | ❌ -stm32f7 family | ✔️ | ✔️ (initial) | ❌ +stm32f7 family | ✔️ | ✔️ (one motor) | ❌ +stm32h7 family | ✔️ | ✔️ (one motor) | ❌ stm32 B_G431B_ESC1 | ❌ | ✔️ (one motor) | ❌ esp32/esp32s3 | ✔️ | ✔️ | ❌ esp32s2/esp32c3 | ✔️ | ❌ | ❌ diff --git a/docs/simplefoc_library/code/current_sense/low_side.md b/docs/simplefoc_library/code/current_sense/low_side.md index 54bd3de..b35f327 100644 --- a/docs/simplefoc_library/code/current_sense/low_side.md +++ b/docs/simplefoc_library/code/current_sense/low_side.md @@ -21,7 +21,15 @@ Low side current sensing for all the architectures is on our road-map and we are Stepper motors

-

+
+ + + +
+

Other topologies for low-side current sensing for Steppers

+See the link Low-side current sensing for stepper motors in the community forum for more information about other topologies for low-side current sensing for stepper motors. +
+
@@ -44,6 +52,7 @@ STM32f4 family | ✔️ (one motor) | DMA| ~25kHz| all STM32g4 family | ✔️ (one motor) | DMA| ~25kHz| all STM32l4 family | ✔️ (one motor) | DMA| ~25kHz| all STM32f7 family | ✔️ (one motor) | DMA| ~25kHz | all +STM32h7 family | ✔️ (one motor) | DMA| ~25kHz | all STM32 B_G431B_ESC1 | ✔️ | DMA| ~25kHz| all ESP32 with MCPWM |✔️ | Interrupts| ~20kHz| all ESP32 with LEDC | ❌ | -| -| - diff --git a/docs/simplefoc_library/code/drivers/bldc_driver/bldc_driver_3pwm.md b/docs/simplefoc_library/code/drivers/bldc_driver/bldc_driver_3pwm.md index a860693..6f38204 100644 --- a/docs/simplefoc_library/code/drivers/bldc_driver/bldc_driver_3pwm.md +++ b/docs/simplefoc_library/code/drivers/bldc_driver/bldc_driver_3pwm.md @@ -23,8 +23,26 @@ Examples: - X-NUCLEO-IHM07M1 - etc. +BLDCMotor +HybridStepperMotor + + +
+
+ +
+ + +
+⚠️ **Note:** When using the 3PWM BLDC driver with a stepper motor, ensure that the common phase `Uo` is connected to the driver's C phase pin. +
+ +
+ + + ## Step 1. Hardware setup @@ -46,6 +64,39 @@ BLDCDriver3PWM driver = BLDCDriver3PWM(9, 10, 11, 8, 7, 6);
📢 Here is a quick guide to choosing appropriate PWM pins for different MCU architectures see in docs.
+
+

⚠️ Note: When using the 3PWM BLDC driver with a stepper motor, ensure that the common phase `Uo` is connected to the driver's C phase pin.

+ +Even if the common phase `Uo` is physically connected to some other driver output (`A` or `B`), please provide it as the `C` phase pin in the driver constructor. This is important for the correct operation of the stepper motor. + +Consider an example of the driver connected to the MCU pins as follows: + +```cpp +#define PIN_A 9 +#define PIN_B 10 +#define PIN_C 11 +#define ENABLE 8 +``` + +If the common phase `Uo` is connected to the driver pin `A`, you should still provide it as the `C` phase pin in the driver constructor: +```cpp +// common phase `Uo` connected to driver pin `A` so it is provided as the `C` phase pin +BLDCDriver3PWM driver = BLDCDriver3PWM(PIN_C, PIN_B, PIN_A, ENABLE); +``` + +If the common phase `Uo` is connected to the driver pin `B`, you should provide it as the `C` phase pin in the driver constructor: +```cpp +// common phase `Uo` connected to driver pin `B` so it is provided as the `C` phase pin +BLDCDriver3PWM driver = BLDCDriver3PWM(PIN_A, PIN_C, PIN_B, ENABLE); +``` + +Or if the common phase `Uo` is connected to the driver pin `C`, you should provide it as the `C` phase pin in the driver constructor: +```cpp +// common phase `Uo` connected to driver pin `C` so it is provided as the `C` phase pin +BLDCDriver3PWM driver = BLDCDriver3PWM(PIN_A, PIN_B, PIN_C, ENABLE); +``` +
+ ### Low-side current sensing considerations As ADC conversion has to be synchronised with the PWM generated on ALL the phases, it is important that all the PWM generated for all the phases have aligned PWM. Since the microcontrollers usually have more than one timer for PWM generation on its pins, different architectures of microcontrollers have different degrees of alinement in between the PWM generated from different timers. @@ -105,7 +156,16 @@ driver.voltage_power_supply = 12; driver.voltage_limit = 12; ``` +BLDCMotor +HybridStepperMotor + +
+ +
+
+ +
This parameter is used by the `BLDCMotor` class as well. As shown on the figure above the once the voltage limit `driver.voltage_limit` is set, it will be communicated to the FOC algorithm in `BLDCMotor` class and the phase voltages will be centered around the `driver.voltage_limit/2`. diff --git a/docs/simplefoc_library/code/drivers/bldc_driver/bldc_driver_6pwm.md b/docs/simplefoc_library/code/drivers/bldc_driver/bldc_driver_6pwm.md index 19da689..81529f5 100644 --- a/docs/simplefoc_library/code/drivers/bldc_driver/bldc_driver_6pwm.md +++ b/docs/simplefoc_library/code/drivers/bldc_driver/bldc_driver_6pwm.md @@ -21,8 +21,22 @@ Examples: - ODrive 3.6 - etc. +BLDCMotor +HybridStepperMotor +
+
+ +
+ + + +
+⚠️ **Note:** When using the 3PWM BLDC driver with a stepper motor, ensure that the common phase `Uo` is connected to the driver's C phase pin. +
+ +
6 PWM control mode gives much more freedom for BLDC motor control than 3PWM control since each of the 6 half-bride mosfets can be controlled separately. @@ -42,6 +56,43 @@ BLDCDriver6PWM driver = BLDCDriver6PWM(5,6, 9,10, 3,11, 8);
📢 Here is a quick guide to choosing appropriate PWM pins for different MCU architectures see in docs.
+ +
+

⚠️ Note: When using the 6PWM BLDC driver with a stepper motor, ensure that the common phase `Uo` is connected to the driver's C phase pin.

+ +Even if the common phase `Uo` is physically connected to some other driver output (`A` or `B`), please provide it as the `C` phase pin in the driver constructor. This is important for the correct operation of the stepper motor. + +Consider an example of the driver connected to the MCU pins as follows: + +```cpp +#define PIN_A_H 9 +#define PIN_A_L 10 +#define PIN_B_H 11 +#define PIN_B_L 12 +#define PIN_C_H 13 +#define PIN_C_L 14 +#define ENABLE 8 +``` + +If the common phase `Uo` is connected to the driver pin `A`, you should still provide it as the `C` phase pin in the driver constructor: +```cpp +// common phase `Uo` connected to driver pin `A` so it is provided as the `C` phase pin +BLDCDriver6PWM driver = BLDCDriver6PWM(PIN_C_H, PIN_C_L, PIN_B_H, PIN_B_L, PIN_A_H, PIN_A_L, ENABLE); +``` + +If the common phase `Uo` is connected to the driver pin `B`, you should provide it as the `C` phase pin in the driver constructor: +```cpp +// common phase `Uo` connected to driver pin `B` so it is provided as the `C` phase pin +BLDCDriver6PWM driver = BLDCDriver6PWM(PIN_A_H, PIN_A_L, PIN_C_H, PIN_C_L, PIN_B_H, PIN_B_L, ENABLE); +``` + +Or if the common phase `Uo` is connected to the driver pin `C`, you should provide it as the `C` phase pin in the driver constructor: +```cpp +// common phase `Uo` connected to driver pin `C` so it is provided as the `C` phase pin +BLDCDriver6PWM driver = BLDCDriver6PWM(PIN_A_H, PIN_A_L, PIN_B_H, PIN_B_L, PIN_C_H, PIN_C_L, ENABLE); +``` +
+ ### Arduino UNO support Arduino UNO and all the atmega328 based boards have only 6 PWM pins and in order to use the `BLDCDrievr6PWM` we need to use all of them. Those are `3`,`5`,`6`,`9`,`10` and `11`. Furthermore in order for the algorithm to work well we need to use the PWM pins that belong to the same timer for each high/low side pair of each phase. @@ -174,7 +225,16 @@ driver.voltage_power_supply = 12; driver.voltage_limit = 12; ``` +BLDCMotor +HybridStepperMotor + +
+ +
+
+ +
This parameter is used by the `BLDCMotor` class as well. As shown on the figure above the once the voltage limit `driver.voltage_limit` is set, it will be communicated to the FOC algorithm in `BLDCMotor` class and the phase voltages will be centered around the `driver.voltage_limit/2`. diff --git a/docs/simplefoc_library/code/drivers/index.md b/docs/simplefoc_library/code/drivers/index.md index dc3da87..34aef6a 100644 --- a/docs/simplefoc_library/code/drivers/index.md +++ b/docs/simplefoc_library/code/drivers/index.md @@ -17,10 +17,10 @@ has_toc: False Arduino SimpleFOClibrary supports BLDC and stepper motor drivers: -- [BLDC driver ](bldcdriver) +- [BLDC driver ](bldcdriver) (BLDC or Hybrid stepper motors) - **3 PWM signals** ( 3 phase ) - `BLDCDriver3PWM` - **6 PWM signals** ( 3 phase ) - `BLDCDriver6PWM` -- [Stepper drivers ](stepperdriver) +- [Stepper drivers ](stepperdriver) (Stepper motors) - **4 PWM signals** ( 2 phase ) - `StepperDriver4PWM` - **2 PWM signals** ( 2 phase ) - `StepperDriver2PWM` diff --git a/docs/simplefoc_library/code/index.md b/docs/simplefoc_library/code/index.md index 04eb01a..a5202b2 100644 --- a/docs/simplefoc_library/code/index.md +++ b/docs/simplefoc_library/code/index.md @@ -316,11 +316,12 @@ For full documentation of the setup and all configuration parameters please visi ## Step 4. Motor setup -After the position sensor and the driver we proceed to initializing and configuring the motor. The library supports BLDC motors handled by the `BLDCMotor` class as well as stepper motors handled by the `StepperMotor` class. Both classes are instantiated by providing just the `pole_pairs` number of the motor and optionally the motors´ phase resistance and the KV rating. +After the position sensor and the driver we proceed to initializing and configuring the motor. The library supports BLDC motors handled by the `BLDCMotor` class as well as stepper motors handled by the `StepperMotor` and `HybridStepperMotor` classes. Both classes are instantiated by providing just the `pole_pairs` number of the motor and optionally the motors' phase resistance and the KV rating. BLDC motor Stepper motor +HybridStepper motor
@@ -386,12 +387,60 @@ void setup() { // init driver // link the motor to the driver motor.linkDriver(&driver); + // link driver and the current sense + + // link the motor to current sense + motor.linkCurrentSense(¤t_sese); + + // set control loop type to be used + motor.controller = MotionControlType::velocity; + // initialize motor + motor.init(); + + // init current sense + +} + +void loop() { + +} +``` +
+ + +
-### Motor phase resistance and KV rating +### Motor phase resistance, inductance and KV rating Providing the KV rating in combination with the phase resistance (not very used for current based torque modes `foc_current` and `dc_current`) will enable the user to control the motor's current without measuring it. The user will be able to control (and limit) the estimated current of the motor using the voltage control mode. Read more in the [torque control docs](voltage_torque_mode). Working with currents instead of voltages is better in may ways, since the torque of the BLDC motor is proportional to the current and not voltages and especially since the same voltage value will produce very different currents for different motors (due to the different phase resistance). Once when the phase resistance is provided the user will be able to set current limit for its BLDC motor instead of voltage limit which is much easier to understand. @@ -65,6 +65,90 @@ Finally, this parameter is suggested to be used if one whats to switch in real t KV rating and the pahse resitance values will be used in te open loop contol as well to let the user to limit the current drawn by the motor instead of limitting the volatge. Read more in the open-loop motion control docs. +### How can I measure the phase resistance and inductance? + +The phase resistance is relatively easy to measure, you can use a multimeter to measure the resistance of the motor phases. Here is a [short guide ](phase_resistance) on how to measure the phase resistance and inductance of a BLDC motor. The phase inductance is a bit more complicated to measure as not many multimeters can measure inductance directly. + +However, SimpleFOClibrary provides the tools to measure the motor phase resistance and inductance. In order to measure them you will need to be able to measure the current. + +Once you have the current sensor set up, you can use the `motor.characteriseMotor()` function to measure the phase resistance and inductance. This function will run a series of tests to determine these parameters and will print them to the serial monitor. + + +
+ +
+ Example code for motor phase characterisation + +```cpp + +#include + +// Stepper motor & BLDC driver instance +BLDCMotor motor = BLDCMotor(11); +// SimpleFOCShield +BLDCDriver3PWM driver = BLDCDriver3PWM(6, 10, 5, 8); + +// inline current sensor instance +// ACS712-05B has the resolution of 0.185mV per Amp +LowsideCurrentSense current_sense = LowsideCurrentSense(185.0f, A0, A2); + +void setup() { + + // use monitoring with serial + Serial.begin(115200); + // enable more verbose output for debugging + // comment out if not needed + SimpleFOCDebug::enable(&Serial); + + // driver config + // power supply voltage [V] + driver.voltage_power_supply = 20; + driver.init(); + // link driver + motor.linkDriver(&driver); + // link current sense and the driver + current_sense.linkDriver(&driver); + + // current sense init and linking + current_sense.init(); + motor.linkCurrentSense(¤t_sense); + + // initialise motor + motor.init(); + + // find the motor parameters + motor.characteriseMotor(3.5f); + + + _delay(1000); +} + + +void loop() { + // do nothing + _delay(1000); +} +``` + +The output of the `characteriseMotor` function will be printed to the serial monitor and will look like this: + +``` +MOT: Init +MOT: Enable driver. +MOT: Measuring phase to phase resistance, keep motor still... +MOT: Estimated phase to phase resistance: 5.94 +MOT: Measuring inductance, keep motor still... +MOT: Inductance measurement complete! +MOT: Measured D-inductance in mH: 0.50 +MOT: Measured Q-inductance in mH: 0.59 +``` + +For the moment SimpleFOClibrary considers the inductance value to be the same for q and d axis. So once the example is executed use the q axis inductance value for `motor.phase_inductance`. + +
+
+ + ## Step 2. Linking the sensor Once when you have the `motor` defined and the sensor initialized you need to link the `motor` and the `sensor` by executing: ```cpp diff --git a/docs/simplefoc_library/code/motors/index.md b/docs/simplefoc_library/code/motors/index.md index d7d9be9..79a906c 100644 --- a/docs/simplefoc_library/code/motors/index.md +++ b/docs/simplefoc_library/code/motors/index.md @@ -21,8 +21,8 @@ Arduino SimpleFOClibrary su - 3 phase (3 wire): - Gimbal and High-performance BLDC motors - [Stepper motors ](steppermotor) - - 2 phase (4 wire) - + - StepperMotor: 2 phase (4 wire) + - 📢 NEW: HybridStepperMotor: 2 phase (3 wire) The motor code is written in a way to support as many different motors out there as possible and in a way to be fully interchangeable. diff --git a/docs/simplefoc_library/code/motors/stepper_motors.md b/docs/simplefoc_library/code/motors/stepper_motors.md index afdd150..11f5b48 100644 --- a/docs/simplefoc_library/code/motors/stepper_motors.md +++ b/docs/simplefoc_library/code/motors/stepper_motors.md @@ -1,6 +1,6 @@ --- layout: default -title: StepperMotor +title: Stepper Motors nav_order: 2 permalink: /steppermotor parent: Motor code @@ -21,15 +21,46 @@ All stepper motor are handled by `StepperMotor` class. The class implements: - Motion control loops - Monitoring +There are two main types of driving the stepper motors with the SimpleFOClibrary: + +Class | Driver type | Pros | Cons +---- | ---- | ---- +`StepperMotor` | `StepperDriver4PWM`
`StepperDriver2PWM` | ✔️ Using full voltage capacity (speed) of the motor
✔️ Easy to understand | ❌ The choice of 2/4 PWM stepper driver is very limited +`HybridStepperMotor` | `BLDCDriver3PWM`
`BLDCDriver6PWM` | ✔️ Can use any regular BLDC driver | ❌ Reduced voltage capacity (speed) of the motor (max 70%)
❌ A bit more complex to understand + +Both classes implement the FOC algorithm and motion control loops, as well as the current sensing so the choice of the class depends on the hardware you have available. + + ## Step 1. Creating the instance of the stepper motor To create a stepper motor instance you need to specify the number of `pole pairs` of the motor. + + +StepperMotor +HybridStepperMotor + + +
```cpp -// StepperMotor( int pp, (optional R, KV)) -// - pp - pole pair number -// - R - phase resistance value - optional -// - KV - motor KV rating [rpm/V] - optional -StepperMotor motor = StepperMotor(50, 1.5, 20.6); +// StepperMotor( int pp, (optional R, KV, L)) +// - pp - pole pair number +// - R - motor phase resistance - optional +// - KV - motor kv rating (rmp/v) - optional +// - L - motor phase inductance [H] - optional +StepperMotor motor = StepperMotor(50, 1.5, 20.6, 0.01); ``` +
+ +
+```cpp +// HybridStepperMotor( int pp, (optional R, KV, L)) +// - pp - pole pair number +// - R - motor phase resistance - optional +// - KV - motor kv rating (rmp/v) - optional +// - L - motor phase inductance [H] - optional +HybridStepperMotor motor = HybridStepperMotor(50, 1.5, 20.6, 0.01); +``` +
+

Pole pair number

Most of the stepper motors are 200 step per rotation motors making them 50 pole pair motors. In practice you can know the pole_pairs number by dividing the number of steps per rotation by 4.

If you are not sure what your pole_pairs number is. The library provides you an example code to estimate your pole_pairs number in the examples examples/utils/calibration/find_pole_pairs_number.ino. @@ -84,7 +115,12 @@ Once when you have the `motor` defined and the driver initialized you need to li motor.linkDriver(&driver); ``` -The `StepperMotor` class expect to receive a `StepperDriver` class instance, implemented by default with the `StepperDriver4PWM` class. The `driver` deals with all the hardware specific operations related to specific microcontroller architecture and driver hardware. See the [stepper driver docs](stepperdriver) for more info! +The `StepperMotor` class expect to receive a `StepperDriver` class instance, while `HybridStepperMotor` can expects the `BLDCDriver` instance. The `driver` deals with all the hardware specific operations related to specific microcontroller architecture and driver hardware. See the [stepper driver docs](stepperdriver) for more info! + +Class | Driver types +---- | ---- +`StepperMotor` | `StepperDriver4PWM`
`StepperDriver2PWM` +`HybridStepperMotor` | `BLDCDriver3PWM`
`BLDCDriver6PWM` ## Step 4. Configuration @@ -99,7 +135,12 @@ You can set them by changing the `motor.foc_modulation` variable: // FOCModulationType::SinePWM; motor.foc_modulation = FOCModulationType::SinePWM; ``` -`StepperMotor` class has only Sinusoidal PWM modulation implemented for the moment current version. +`StepperMotor` class has only Sinusoidal PWM modulation implemented for the moment current version, while the `HybridStepperMotor` class supports both Sinusoidal PWM and Space Vector PWM modulation, where the Space Vector PWM is more significantly more efficient and can provide better performance. + +Class | FOC Modulation types +---- | ---- +`StepperMotor` | `FOCModulationType::SinePWM` +`HybridStepperMotor` | `FOCModulationType::SinePWM`
`FOCModulationType::SpaceVectorPWM` (recommended) For more information about the theory of these approaches please and source code implementation check the [FOC implementation docs](foc_implementation) or visit the [digging deeper section](digging_deeper). @@ -316,7 +357,16 @@ And that is it, you have your complete Field Oriented Controlled BLDC motor with For more theoretical explanations and source code implementations of the FOC algorithm and the motion control approaches check out the [digging deeper section](digging_deeper). ## Example code + + A simple stepper motor torque control using voltage based on the FOC algorithm. + +StepperMotor +HybridStepperMotor + + +
+ ```cpp /** * Torque control example using voltage control loop. @@ -367,3 +417,61 @@ void loop() { motor.move(); } ``` +
+ +
+ +```cpp +/** + * Torque control example using voltage control loop. + */ +#include + +// Stepper motor instance +HybridStepperMotor motor = HybridStepperMotor( 50 ); +// BLDC driver instance +BLDCDriver3PWM driver = BLDCDriver3PWM(9, 10, 5, 8); +// sensor instance +MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C); + +void setup() { + + // initialize encoder sensor hardware + sensor.init(); + // link the motor to the sensor + motor.linkSensor(&sensor); + + // much more efficient than SinePWM + motor.foc_modulation = FOCModulationType::SpaceVectorPWM; + + // driver config + // power supply voltage [V] + driver.voltage_power_supply = 12; + driver.init(); + // link driver + motor.linkDriver(&driver); + + // set motion control loop to be used + motor.controller = MotionControlType::torque; + + // initialize motor + motor.init(); + // align sensor and start FOC + motor.initFOC(); + + // setting target voltage + motor.target = 2; + + _delay(1000); +} + +void loop() { + + // main FOC algorithm function + motor.loopFOC(); + + // Motion control function + motor.move(); +} +``` +
\ No newline at end of file diff --git a/docs/simplefoc_library/examples/index.md b/docs/simplefoc_library/examples/index.md index 363218b..6e1dec5 100644 --- a/docs/simplefoc_library/examples/index.md +++ b/docs/simplefoc_library/examples/index.md @@ -74,4 +74,16 @@ There are many different projects SimpleF - \ No newline at end of file + + + diff --git a/docs/simplefoc_library/examples/sensorless_example_nucleo.md b/docs/simplefoc_library/examples/sensorless_example_nucleo.md new file mode 100644 index 0000000..6b3262c --- /dev/null +++ b/docs/simplefoc_library/examples/sensorless_example_nucleo.md @@ -0,0 +1,264 @@ +--- +layout: default +title: Sensorless FOC +parent: Example projects +description: "Arduino Simple Field Oriented Control (FOC) library ." +nav_order: 12 +permalink: /sensorless_foc_nucleo_example +grand_parent: Arduino SimpleFOClibrary +toc: true +--- + + + +# Sensorless FOC example
using SimpleFOCShield and Stm32 Nucleo-64 +For this example of the Sensorless FOC control we are going to be using this hardware: + +[Stm32 Nucleo-64](https://www.mouser.fr/ProductDetail/STMicroelectronics/NUCLEO-F446RE?qs=%2Fha2pyFaduj0LE%252BzmDN2WNd7nDNNMR7%2Fr%2FThuKnpWrd0IvwHkOHrpg%3D%3D) | [Arduino SimpleFOCShield](arduino_simplefoc_shield_showcase) |[GBM3506-120T](https://iflight-rc.eu/en-ch/products/ipower-gm3506-gimbal-motor-with-encoder) +--- | --- | --- + | | + + +This is just an example of how to use the SimpleFOClibrary to control a motor without any sensors. You can use any other motor (BLDC, stepper or hybrid stepper) and any other driver or microcontroller. As long as the driver has enough current capacity to drive the motor and the microcontroller has enough processing power to run the FOC algorithm, you can use it. The only real constraint is that you need to be able to measure the phase current of the motor. This is because the sensorless observer uses the phase current to estimate the rotor position and velocity. + + +# Connecting everything together +For a bit more in depth explanation of how to connect Nucleo board and SimpleFOCShield connection please check the [connection examples](nucleo_connection). +

+ +For more information about the SimpleFOCShield check the [docs](arduino_simplefoc_shield_showcase). + +## Motor +- Motor phases `a`, `b` and `c` are connected directly the motor terminal connector `TB_M1` + + +## SimpleFOCShield connections + +

+ +Signal | Pwm A | Pwm B | Pwm C | Enable +--- | - | - | - | - +Pin | `6` | `10` | `5` | `8` + + +# Arduino code + +First thing you need to do is include the `SimpleFOC` library: + +```cpp +#include +``` +Make sure you have the library installed. If you still don't have it please check the [get started page](installation) + +Then import the drivers library and the Sensorless observer: +```cpp +#include +#include "encoders/MXLEMMING_observer/MXLEMMINGObserverSensor.h" +``` + +## Motor and driver +Next we need to define the BLDC motor and driver classes. The motor class is used to control the motor and the driver class is used to control the power electronics. + +```cpp +// define BLDC motor +// - 11 is the number of pole pairs +// - 5.9 is the resistance of the motor [Ohms] +// - 100 is the KV rating of the motor in [RPM per Volt] +// - 0.0005 is the phase inductance [H] +// These parameters are specific to the motor you are using, please check the motor datasheet +// I'm using GBM3506-120T +BLDCMotor motor = BLDCMotor(11, 5.94, 100, 0.0005); + +// define BLDC driver +BLDCDriver3PWM driver = BLDCDriver3PWM(6, 10, 5, 8); +``` + +
+

Note: Correct motor parameters are crucial!

+Having the correct motor parameters is crucial for the motor to work properly. +
+ +
+

KV rating

+Motor's KV rating is usually easy to find in the datasheets. If the datasheet does not specify the KV rating, they often specify some rated voltage and speed. In that case you can calculate the KV by dividing the motor's RPM by the voltage applied to it. You can also use the `examples/utils/calibration/find_kv_rating.ino` example to find it out. +
+ +
+

Phase resistance and inductance

+If you are not sure what your motor resistance and inductance are, you can use this code to measure them: + +```cpp +#include + +// Stepper motor & BLDC driver instance +BLDCMotor motor = BLDCMotor(11); +// SimpleFOCShield +BLDCDriver3PWM driver = BLDCDriver3PWM(6, 10, 5, 8); + +// inline current sensor instance +// ACS712-05B has the resolution of 0.185mV per Amp +LowsideCurrentSense current_sense = LowsideCurrentSense(185.0f, A0, A2); + + +void setup() { + + // use monitoring with serial + Serial.begin(115200); + // enable more verbose output for debugging + // comment out if not needed + SimpleFOCDebug::enable(&Serial); + + // driver config + // power supply voltage [V] + driver.voltage_power_supply = 20; + driver.init(); + // link driver + motor.linkDriver(&driver); + // link current sense and the driver + current_sense.linkDriver(&driver); + + // current sense init and linking + current_sense.init(); + motor.linkCurrentSense(¤t_sense); + + // initialise motor + motor.init(); + + // find the motor parameters + motor.characteriseMotor(3.5f); + + + _delay(1000); +} + + +void loop() { + // do nothing + _delay(1000); +} +``` +The code output will look like this: + +``` +MOT: Init +MOT: Enable driver. +MOT: Measuring phase to phase resistance, keep motor still... +MOT: Estimated phase to phase resistance: 5.94 +MOT: Measuring inductance, keep motor still... +MOT: Inductance measurement complete! +MOT: Measured D-inductance in mH: 0.50 +MOT: Measured Q-inductance in mH: 0.59 +``` + +So then you can use the measured values to define the motor: +```cpp +// define BLDC motor +// - 11 is the number of pole pairs +// - 5.94 is the resistance of the motor [Ohms] +// - 100 is the KV rating of the motor in [RPM per Volt] +// - 0.0005 is the phase inductance [H] +BLDCMotor motor = BLDCMotor(11, 5.94, 100, 0.0005); +``` + +
+ + +## Sensorless observer +Next we need to define the sensorless observer class. The observer is used to estimate the rotor position and velocity without using any sensors. The observer is based on the [MXLEMMING_observer](https://github.com/simplefoc/Arduino-FOC-drivers/tree/dev/src/encoders/MXLEMMING_observer) + +```cpp +// define sensorless observer +MXLEMMINGObserverSensor observer = MXLEMMINGObserverSensor(motor); +``` + +And you're more or less set, the rest of the code is the same as usual. + +## Full Arduino code + +The full code for the sensorless FOC example is as follows: + +```cpp +#include +#include + +#include "encoders/MXLEMMING_observer/MXLEMMINGObserverSensor.h" + +// Stepper motor & BLDC driver instance +BLDCMotor motor = BLDCMotor(11, 5.94, 100, 0.0005); +// SimpleFOCShield +BLDCDriver3PWM driver = BLDCDriver3PWM(6, 10, 5, 8); + +// MXLEMMING observer sensor instance +MXLEMMINGObserverSensor observer = MXLEMMINGObserverSensor(motor); + +// inline current sensor instance +// ACS712-05B has the resolution of 0.185mV per Amp +LowsideCurrentSense current_sense = LowsideCurrentSense(185.0f, A0, A2); + +// commander communication instance +Commander command = Commander(Serial); +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); + + // link the motor to the sensor + motor.linkSensor(&observer); + + // driver config + // power supply voltage [V] + driver.voltage_power_supply = 20; + 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::torque; + motor.torque_controller = TorqueControlType::foc_current; + + // current sense init and linking + current_sense.init(); + motor.linkCurrentSense(¤t_sense); + + // initialise motor + motor.init(); + // skip the sensor alignment + motor.sensor_direction= Direction::CW; + motor.zero_electric_angle = 0; + motor.initFOC(); + + + // subscribe motor to the commander + command.add('M', doMotor, "motor"); + + // Run user commands to configure and the motor (find the full command list in docs.simplefoc.com) + Serial.println("Motor ready."); + + _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(); +} +``` + + +And you can interact with the motor using the commander. For example, you can set the target torque by sending the command `M0.5` to set the target torque to 0.5Amps. You can also use other commands to control the motor, like `M0` to stop the motor, `M1` to set the target torque to 1Amp, etc. You can find the full command list in the [docs](commander_interface). \ No newline at end of file diff --git a/docs/simplefoc_library/examples/stepper_control_shield.md b/docs/simplefoc_library/examples/stepper_control_shield.md new file mode 100644 index 0000000..8c45ee6 --- /dev/null +++ b/docs/simplefoc_library/examples/stepper_control_shield.md @@ -0,0 +1,194 @@ +--- +layout: default +title: Stepper Motor Control with SimpleFOCShield +parent: Example projects +description: "Arduino Simple Field Oriented Control (FOC) library ." +nav_order: 11 +permalink: /stepper_control_shield +grand_parent: Arduino SimpleFOClibrary +toc: true +--- + + + +# Stepper motor control example
using the SimpleFOCShield and Stm32 Nucleo-64 +For this stepper motor control example we are going to be using this hardware: + +[Stm32 Nucleo-64](https://www.mouser.fr/ProductDetail/STMicroelectronics/NUCLEO-F446RE?qs=%2Fha2pyFaduj0LE%252BzmDN2WNd7nDNNMR7%2Fr%2FThuKnpWrd0IvwHkOHrpg%3D%3D) | [Arduino SimpleFOCShield](arduino_simplefoc_shield_showcase) | [AMT 103 encoder](https://www.mouser.fr/ProductDetail/CUI-Devices/AMT103-V?qs=%2Fha2pyFaduiAsBlScvLoAWHUnKz39jAIpNPVt58AQ0PVb84dpbt53g%3D%3D) | [NEMA 17](https://www.ebay.com/itm/Nema-17-Stepper-Motor-Bipolar-2A-59Ncm-83-6oz-in-48mm-Body-4-lead-3D-Printer-CNC/282285186801?hash=item41b9821ef1:g:7dUAAOSwEzxYSl25) +--- | --- | --- | --- + | | | + +Download the STL file as well as STEP and solidworks project of the amt103 mount on the nema17 used in the images and the Youtube video [here](extras/nema17_encoder_mount.zip). + +# Connecting everything together + +Here is an example of the connection scheme using the SimpleFOCShield and Nucleo-64: + +

+ + +## Nema 17 stepper motor connection using 3 phases +As nema 17 steppers have 2 phases and 4 wires, we need to transform them to 3 phases to connect them to the SimpleFOCShiled. So we will connect one wire from each phase to the shield spearately and the third wire of each phase will be connected together to the common phase. + +Pin | Nema 17 wire | Shield phase +--- | --- | --- +1 | `A+` | `A` +2 | `B-`, `A-` | `B` +3 | `B+` | `C` + +

+ +- Motor phases `A`, `B` and common are connected directly the motor terminal connector `TB_M1` + +
+It is not too important which of the two wires `+` or `-` you connect to which pin as long as the common pin `2` has the wires of both phases connected to it. If it does not the motor will not work. +
+ +## SimpleFOCShield connections + +

+ +Signal | Pwm A | Pwm B | Pwm C | Enable | Encoder A | Encoder B | Encoder I | Current A | Current B +--- | - | - | - | - | - | - | - | - | - +Pin | `6` | `10` | `5` | `8` | `3` | `2`| `4`|`A0` | `A2` + +## Encoder +- Channels `A` and `B` are connected to the encoder connector `P_ENC`, terminals `A` and `B`. +- Index channel you can connect directly to the `P_ENC` as well to the terminal `I` + + + +# Arduino code + + +There are just a couple of things to note when using stepper motors in the hybrid configuration with the SimpleFOClibrary: +- The motor is configured as a `HybridStepperMotor` and not a `StepperMotor` + +```cpp +HybridStepperMotor motor = HybridStepperMotor(50); +``` + +- The driver pins order is important, it should be: + 1. `A` phase + 2. `B` phase + 3. common pin + In this example we are using the `BLDCDriver3PWM` driver + +```cpp +// IMPORTANT: the order of the pins is important, it should be: +// 1. Stepper A phase (shield pin A) +// 2. Stepper B phase (shield pin C) +// 3. common pin (shield pin B) +BLDCDriver3PWM driver = BLDCDriver3PWM(6, 5, 10, 8); +``` + +Here is the full code example for the stepper motor control using the SimpleFOCShield and Stm32 Nucleo-64: + +```cpp +#include + +// Stepper motor +HybridStepperMotor motor = HybridStepperMotor(50); + +// BLDC driver instance +// SimpleFOCShield +BLDCDriver3PWM driver = BLDCDriver3PWM(6, 5, 10, 8); + +// encoder instance +Encoder encoder = Encoder(2, 3, 2048); +// 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 +// NOTE: LowsideCurrentSense sense is used because its faster than InlineCurrentSense class +LowsideCurrentSense current_sense = LowsideCurrentSense(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); + + // driver config + // power supply voltage [V] + driver.voltage_power_supply = 20; + 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::torque; + motor.torque_controller = TorqueControlType::foc_current; + + // SVPWM modulation type is much more efficient for hybrid stepper motors + motor.foc_modulation = FOCModulationType::SpaceVectorPWM; + + + // controller configuration based on the control type + motor.PID_velocity.P = 0.05f; + motor.PID_velocity.I = 1; + motor.PID_velocity.D = 0; + // default voltage_power_supply + motor.voltage_limit = 12; + + // velocity low pass filtering time constant + motor.LPF_velocity.Tf = 0.01f; + + // angle loop controller + motor.P_angle.P = 20; + // angle loop velocity limit + motor.velocity_limit = 20; + + // comment out if not needed + motor.useMonitoring(Serial); + + // current sense init and linking + current_sense.init(); + motor.linkCurrentSense(¤t_sense); + + // initialise motor + motor.init(); + // align encoder and start FOC + motor.initFOC(); + + // subscribe motor to the commander + command.add('M', doMotor, "motor"); + + // Run user commands to configure and the motor (find the full command list in docs.simplefoc.com) + Serial.println("Motor ready."); + + _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(); +} +``` \ No newline at end of file diff --git a/docs/simplefoc_library/hardware/drivers/index.md b/docs/simplefoc_library/hardware/drivers/index.md index 58a4e0c..bae083d 100644 --- a/docs/simplefoc_library/hardware/drivers/index.md +++ b/docs/simplefoc_library/hardware/drivers/index.md @@ -24,6 +24,7 @@ Arduino SimpleFOClibrary ha - gimbal motor drivers or high-performance boards - [Stepper drivers ](stepper_drivers) - **4 PWM signals** ( 2 phase ) + - **2 PWM signals + 2 direction signals** ( 2 phase ) - Stepper drivers or double DC motor drivers ## 📢 Make sure to read this before settling for a driver! diff --git a/docs/simplefoc_library/hardware/drivers/stepper_drivers.md b/docs/simplefoc_library/hardware/drivers/stepper_drivers.md index 09f73e6..331b7bb 100644 --- a/docs/simplefoc_library/hardware/drivers/stepper_drivers.md +++ b/docs/simplefoc_library/hardware/drivers/stepper_drivers.md @@ -10,7 +10,10 @@ grand_grand_parent: Arduino SimpleFOC MC33926](https://www.nxp.com/docs/en/data-sheet/MC33926.pdf), [ L298](https://www.st.com/resource/en/datasheet/l298.pdf), [ L293](http://www.ti.com/lit/ds/symlink/l293.pdf) and many more. **In order for the driver board to work with the library it needs to be controllable using 4 pwm signals.** +This library will be compatible with most of the 2 phase stepper motor driver boards that feature 2 full H-bridges or 4 half-bridges such as [ MC33926](https://www.nxp.com/docs/en/data-sheet/MC33926.pdf), [ L298](https://www.st.com/resource/en/datasheet/l298.pdf), [ L293](http://www.ti.com/lit/ds/symlink/l293.pdf) and many more. In order for the driver board to work with the library it needs to be controllable either using + + - 4 pwm signals or + - 2 pwm signals + 2 direction signals.

⚠️ DIR/STEP stepper drivers not supported!

This library does not support stepper drivers with DIR+STEP (step and direction) interface such as A4988, DRV8825, TB6600, TB6560 and similar. diff --git a/docs/simplefoc_library/hardware/mcus/index.md b/docs/simplefoc_library/hardware/mcus/index.md index e23603c..0eeafe0 100644 --- a/docs/simplefoc_library/hardware/mcus/index.md +++ b/docs/simplefoc_library/hardware/mcus/index.md @@ -82,7 +82,8 @@ stm32f1 family | ✔️ | ✔️ (one motor) | ❌ stm32f4 family | ✔️ | ✔️ (one motor) | ❌ stm32g4 family | ✔️ | ✔️ (one motor) | ❌ stm32l4 family | ✔️ | ✔️ (one motor) | ❌ -stm32f7 family | ✔️ | ✔️ (initial) | ❌ +stm32f7 family | ✔️ | ✔️ (one motor) | ❌ +stm32h7 family | ✔️ | ✔️ (one motor) | ❌ stm32 B_G431B_ESC1 | ❌ | ✔️ (one motor) | ❌ esp32/esp32s3 | ✔️ | ✔️ | ❌ esp32s2/esp32c3 | ✔️ | ❌ | ❌ diff --git a/docs/simplefoc_library/hardware/mcus/stm32.md b/docs/simplefoc_library/hardware/mcus/stm32.md index 4ee4010..1aa3a7c 100644 --- a/docs/simplefoc_library/hardware/mcus/stm32.md +++ b/docs/simplefoc_library/hardware/mcus/stm32.md @@ -27,7 +27,8 @@ stm32f1 family | ✔️ | ✔️ (one motor) | ❌ stm32f4 family | ✔️ | ✔️ (one motor) | ❌ stm32g4 family | ✔️ | ✔️ (one motor) | ❌ stm32l4 family | ✔️ | ✔️ (one motor) | ❌ -stm32f7 family | ✔️ | ✔️ (initial) | ❌ +stm32f7 family | ✔️ | ✔️ (one motor) | ❌ +stm32h7 family | ✔️ | ✔️ (one motor) | ❌ stm32 B_G431B_ESC1 | ❌ | ✔️ (one motor) | ❌ Stm32 devices have full compatibility using the SimpleFOClibrary and will work with all driver types. diff --git a/docs/simplefoc_library/index.md b/docs/simplefoc_library/index.md index 1021e3d..625133e 100644 --- a/docs/simplefoc_library/index.md +++ b/docs/simplefoc_library/index.md @@ -14,7 +14,7 @@ toc: true # Arduino SimpleFOClibrary ![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg) -![arduino-library-badge](https://ardubadge.simplefoc.com?lib=Simple%20FOC) +![arduino-library-badge](https://www.ardu-badge.com/badge/Simple%20FOC.svg) ![PlatformIO Registry](https://badges.registry.platformio.org/packages/askuric/library/Simple%20FOC.svg) [![status](https://joss.theoj.org/papers/4382445f249e064e9f0a7f6c1bb06b1d/status.svg)](https://joss.theoj.org/papers/4382445f249e064e9f0a7f6c1bb06b1d) diff --git a/docs/simplefoc_library/practical/choosing_pins.md b/docs/simplefoc_library/practical/choosing_pins.md index 34f8574..45be6ae 100644 --- a/docs/simplefoc_library/practical/choosing_pins.md +++ b/docs/simplefoc_library/practical/choosing_pins.md @@ -32,7 +32,7 @@ stm32 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ esp32 MCPWM | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ esp32 LEDC | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ esp8266 | ✔️ | ✔️ | ✔️ | ❌ | ✔️ | ❌ | ❌ -samd21/51 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ (2/3/4PWM)
✔️ (6PWM) | ❌ +samd21/51 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ (2/3/4PWM)
✔️ (6PWM) | ✔️ (samd21 only - Synced with the 1st Timer )
❌(samd51) teensy3 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ (2/3/4PWM)
✔️ (6PWM) | ❌ teensy4 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌(2/3/4PWM)
✔️ (6PWM)
✔️(3PWM forced) | ❌(2/3/4PWM)
✔️(6PWM)
✔️(3PWM aligned) Raspberry Pi Pico | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ (2/3/4PWM)
✔️ (6PWM) | ❌ @@ -122,12 +122,14 @@ So when using esp32 boards that have `MCPWM` module (ex. `esp32` and `esp32s3`) This association of the appropriate timer and chanel for your applications will be done automatically by the SimpleFOC. -ESP32 SoC | has `MCPWM` +ESP32 SoC | has `MCPWM` --- | --- ESP32 | ✔️ ESP32-S2| ❌ +ESP32-C2 | ❌ ESP32-S3| ✔️ ESP32-C3 | ❌ +ESP32-C6 | ✔️