Post

SimpleFOC Integrated Board from Zero to One - Part 4

SimpleFOC Integrated Board from Zero to One - Part 4

SimpleFOC Integrated Board Hardware Practice: From Zero to One (4) – Interpreting the Code and add heartbeat function

Interpreting the Code

This article mainly explains the code.
The example is based on the official SimpleFOC example: full_control_serial.ino.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <SimpleFOC.h>
//#define USE_HSI
// magnetic sensor instance - SPI
//MagneticSensorSPI sensor = MagneticSensorSPI(AS5147_SPI, 10);
// magnetic sensor instance - MagneticSensorI2C
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
//MagneticSensorI2C sensor = MagneticSensorI2C(0x36, 12, 0X0C, 4);
// magnetic senso    r instance - analog output
// MagneticSensorAnalog sensor = MagneticSensorAnalog(A1, 14, 1020);

// BLDC motor & driver instance
//BLDCMotor motor = BLDCMotor(11);
BLDCMotor motor = BLDCMotor(7);   //your brushless motor
//BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);
BLDCDriver3PWM driver = BLDCDriver3PWM(PB0, PB1, PB4, PA6);
// Stepper motor & driver instance
//StepperMotor motor = StepperMotor(50);
//StepperDriver4PWM driver = StepperDriver4PWM(9, 5, 10, 6,  8);

//LED
int ledState = LOW;             // used to set the LED state
unsigned long previousMillis = 0;  //will store last time LED was blinked
const long period = 400;         // period at which to blink in ms
#define ledPin PB3

// commander interface
Commander command = Commander(Serial);
void onMotor(char* cmd) {
  command.motor(&motor, cmd);
}


void setup() {

  pinMode(PB3, OUTPUT);

  // initialise magnetic sensor hardware
  sensor.init();
  // link the motor to the sensor
  motor.linkSensor(&sensor);

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

  // choose FOC modulation
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

  // set control loop type to be used
  // set motion control loop to be used
  // MotionControlType::torque
  // MotionControlType::velocity
  // MotionControlType::angle
//  motor.controller = MotionControlType::angle;
  //bi4wms add bellow comment above
  motor.controller = MotionControlType::torque;
  
  // contoller configuration based on the control type
/*
  motor.PID_velocity.P = 0.2f;
  motor.PID_velocity.I = 20;
  motor.PID_velocity.D = 0;
*/
//bi4wms comment above add bellow
    motor.PID_velocity.P = 0.1f;
  motor.PID_velocity.I = 10;
  motor.PID_velocity.D = 0;
  
  // default voltage_power_supply
 // motor.voltage_limit = 12;
    motor.voltage_limit = 0.5; //bi4wms

  // 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 = 50;
*/
//bi4wms comment above add bellow
  // angle loop controller
  motor.P_angle.P = 10;
  // angle loop velocity limit
  motor.velocity_limit = 20;

  // use monitoring with serial for motor init
  // monitoring port
  Serial.begin(115200);
  // comment out if not needed
  motor.useMonitoring(Serial);

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

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

  // define the motor id
  command.add('M', onMotor, "motor");

  // Run user commands to configure and the motor (find the full command list in docs.simplefoc.com)
  Serial.println(F("Motor commands sketch | Initial motion control > torque/voltage : target 2V."));
  Serial.println(F("====bi4wms SETUP SUCESS====."));
}


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

  // iterative function setting the outter loop target
  // velocity, position or voltage
  // if tatget not set in parameter uses motor.target variable
  motor.move();

  // user communication
  command.run();

    LEDblink();
}



void LEDblink()
{
  unsigned long currentMillis = millis(); // store the current time
  if (currentMillis - previousMillis >= period) { // check if 1000ms passed
    previousMillis = currentMillis;   // save the last time you blinked the LED
    if (ledState == LOW) { // if the LED is off turn it on and vice-versa
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(ledPin, ledState);//set LED with ledState to blink again
  }
}

Main Modifications

  1. Power supply
  2. DRV8313 driver chip control pins
  3. Motor pole pair parameters (different brushless motors have different numbers of pole pairs)
  4. Magnetic encoder related settings

After completing the modifications, upload the code and test it using serial commands.


Adding a Heartbeat Indicator

When designing hardware circuits, in addition to the power supply indicator LED, a heartbeat indicator LED is typically added to indicate that the software system is running normally. This design is no exception. image

Most beginner Arduino projects use delay() to blink an LED. However, when using the FOC (Field Oriented Control) vector control algorithm for the motor, using delay() becomes very inappropriate. Using Arduino’s FreeRTOS would also consume too many system resources.

After research, the millis() function can be used to achieve a non-blocking heartbeat LED. The key code is as follows:

Variable and function declarations for the heartbeat:

1
2
3
4
5
6
//LED
int ledState = LOW;             // used to set the LED state
unsigned long previousMillis = 0;  //will store last time LED was blinked
const long period = 1000;         // period at which to blink in ms
#define ledPin PB3
void LEDblink();

** Heartbeat function:**

1
2
3
4
5
6
7
8
9
10
11
12
13
void LEDblink()
{
  unsigned long currentMillis = millis(); // store the current time
  if (currentMillis - previousMillis >= period) { // check if 1000ms passed
    previousMillis = currentMillis;   // save the last time you blinked the LED
    if (ledState == LOW) { // if the LED is off turn it on and vice-versa
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(ledPin, ledState);//set LED with ledState to blink again
  }
}

** Add heartbeat function to loop():**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void loop() {
  // iterative setting FOC phase voltage
  motor.loopFOC();

  // iterative function setting the outter loop target
  // velocity, position or voltage
  // if tatget not set in parameter uses motor.target variable
  motor.move();

  // user communication
  command.run();

  LEDblink();
}
This post is licensed under CC BY 4.0 by the author.