1+ /* *
2+  * This is an example code for visual aligning current sense and the driver phases as well  
3+  * it is used to test the current sense implementation. 
4+  *  
5+  * In this example it uses the BLDCMotor and BLDCDriver3PWM classes to control a BLDC motor 
6+  * and the InlineCurrentSense class to read the phase currents. 
7+  * > In your application you can use any other motor, driver and current sense implementation. 
8+  * > The rest of the code will stay the same 
9+  *  
10+  * The example uses the teleplot (https://teleplot.fr) service to visualize the phase currents and voltages. 
11+  * Its really awesome tool and you can use it to visualize any data you want.   
12+  */  
13+ #include  < SimpleFOC.h> 
14+ 
15+ //  BLDC motor & driver instance
16+ //  NOTE: replace with your motor and driver configuration
17+ BLDCMotor motor = BLDCMotor(11 );
18+ BLDCDriver3PWM driver = BLDCDriver3PWM(6 , 10 , 5 , 8 );
19+ 
20+ //  Current sense instance 
21+ //  NOTE: replace with your current sense configuration
22+ //  inline current sensor instance
23+ //  ACS712-05B has the resolution of 0.185mV per Amp
24+ InlineCurrentSense current_sense = InlineCurrentSense(185 .0f , A0, A2);
25+ //  or some other current sense
26+ //  LowsideCurrentSense current_sense = LowsideCurrentSense(185.0f, A0, A2); // ex. lowside current sense
27+ 
28+ //  commander communication instance
29+ Commander command = Commander(Serial);
30+ 
31+ 
32+ bool  start = false ; //  flag to start printing phase currents and voltages
33+ float  frequency = 10000 ; //  frequency of printing phase currents and voltages
34+ 
35+ void  doStart (char * cmd){
36+   //  toggle the start flag
37+   start = !start;
38+   if (start){
39+     SIMPLEFOC_DEBUG (" Start printing phase currents and voltages"  );
40+   } else  {
41+     SIMPLEFOC_DEBUG (" Stop printing phase currents and voltages"  );
42+   }
43+ }
44+ 
45+ void  doCurrentA (char * cmd){ 
46+     SIMPLEFOC_DEBUG (" Inverted cs A gain"  ); 
47+     current_sense.gain_a  = -current_sense.gain_a ; 
48+     SIMPLEFOC_DEBUG (" New gain A: "  , current_sense.gain_a );
49+ }
50+ void  doCurrentB (char * cmd){ 
51+     SIMPLEFOC_DEBUG (" Inverted cs B gain"  ); 
52+     current_sense.gain_b  = -current_sense.gain_b ; 
53+     SIMPLEFOC_DEBUG (" New gain B: "  , current_sense.gain_b );
54+ }
55+ void  doCurrentC (char * cmd){ 
56+     SIMPLEFOC_DEBUG (" Inverted cs C gain"  ); 
57+     current_sense.gain_c  = -current_sense.gain_c ; 
58+     SIMPLEFOC_DEBUG (" New gain C: "  , current_sense.gain_c );
59+ }
60+ 
61+ void  doMotorLimit (char * cmd){
62+   //  set the voltage limit for the motor
63+   command.scalar (&motor.voltage_limit , cmd);
64+ }
65+ 
66+ void  doTarget (char * cmd){
67+   //  set the target value for the motor
68+   command.scalar (&motor.target , cmd);
69+ }
70+ 
71+ void  doFrequency (char * cmd){
72+   //  set the frequency of printing phase currents and voltages
73+   command.scalar (&frequency, cmd);
74+ }
75+ 
76+ void  setup () {
77+ 
78+   //  use monitoring with serial 
79+   Serial.begin (115200 );
80+   //  enable more verbose output for debugging
81+   //  comment out if not needed
82+   SimpleFOCDebug::enable (&Serial);
83+ 
84+   //  driver config
85+   //  power supply voltage [V]
86+   driver.voltage_power_supply  = 20 ;
87+   driver.init ();
88+   //  link driver
89+   motor.linkDriver (&driver);
90+   //  link current sense and the driver
91+   current_sense.linkDriver (&driver);
92+ 
93+   //  set control loop type to be used
94+   motor.controller  = MotionControlType::velocity_openloop;
95+ 
96+   motor.voltage_limit  = 1 ; //  voltage limit for the motor
97+ 
98+   //  initialise motor
99+   motor.init ();
100+ 
101+   //  current sense init and linking
102+   current_sense.init ();
103+   motor.linkCurrentSense (¤t_sense);
104+ 
105+   //  align encoder and start FOC
106+   motor.initFOC ();
107+ 
108+   //  set the inital target value
109+   motor.target  = 0.5 ;
110+ 
111+ 
112+   //  subscribe motor to the commander
113+   // command.add('T', doMotion, "motion control");
114+   command.add (' A'  , doCurrentA, " Invert cs A gain"  );
115+   command.add (' B'  , doCurrentB, " Invert cs B gain"  );
116+   command.add (' C'  , doCurrentC, " Invert cs C gain"  );
117+   command.add (' L'  , doMotorLimit, " Set motor voltage limit"  );
118+   command.add (' T'  , doTarget, " Set motor target"  );
119+   command.add (' S'  , doStart, " Start/Stop printing phase currents and voltages"  );
120+   command.add (' F'  , doFrequency, " Set frequency of printing phase currents and voltages"  );
121+   
122+   SIMPLEFOC_DEBUG (" To use this example:"  );
123+   SIMPLEFOC_DEBUG ("  - use 'L' to control the motor voltage limit"  );
124+   SIMPLEFOC_DEBUG ("  - use 'T' to set the motor target"  );
125+   SIMPLEFOC_DEBUG ("  - use 'A', 'B', 'C' to invert current sense gains"  );
126+   SIMPLEFOC_DEBUG ("  - use 'F' to set frequency of printing phase currents and voltages (100Hz by default)"  );
127+   SIMPLEFOC_DEBUG ("  - use 'S' to start/stop printing phase currents and voltages"  );
128+   SIMPLEFOC_DEBUG (" IMPORTANT: Use teleplot to visualize the phase currents and voltages: https://teleplot.fr/"  );
129+ 
130+   _delay (1000 );
131+ 
132+ }
133+ 
134+ float  normalize_voltage (float  v){
135+   return  (v - driver.voltage_power_supply /2.0 )/motor.voltage_limit ;
136+ }
137+ 
138+ float  max_current = 0 .0f ; //  max current for normalization
139+ LowPassFilter lp_filter_maxc (0 .3f ); //  low pass filter for current normalization
140+ void  normalize_currents (PhaseCurrent_s& c, float & max_current){
141+   static  unsigned  long  timestamp = _micros ();
142+   //  normalize current to the max current
143+    
144+   float  m_current = 0 .0f ;
145+   if (fabs (c.a ) > m_current) m_current = fabs (c.a );
146+   if (fabs (c.b ) > m_current) m_current = fabs (c.b );
147+   if (fabs (c.c ) > m_current) m_current = fabs (c.c );
148+   //  filter the max current 
149+   max_current = lp_filter_maxc (m_current);
150+ 
151+   c.a  = c.a  / max_current;
152+   c.b  = c.b  / max_current;
153+   c.c  = c.c  / max_current;
154+ }
155+ 
156+ unsigned  long  t = _micros();
157+ 
158+ void  loop () {
159+   motor.loopFOC ();
160+   motor.move ();
161+ 
162+   //  print each 
163+   if ( start & (_micros () - t > (1.0 /frequency * 1e6 ))){
164+     //  read phase currents
165+     PhaseCurrent_s currents = current_sense.getPhaseCurrents ();
166+     //  normalize currents
167+     normalize_currents (currents, max_current);
168+     //  print phase currents
169+     SIMPLEFOC_DEBUG (" >c.a:"  ,currents.a );
170+     SIMPLEFOC_DEBUG (" >c.b:"  ,currents.b );
171+     SIMPLEFOC_DEBUG (" >c.c:"  ,currents.c );
172+     //  print phase voltages
173+     SIMPLEFOC_DEBUG (" >v.a:"  ,normalize_voltage (motor.Ua ));
174+     SIMPLEFOC_DEBUG (" >v.b:"  ,normalize_voltage (motor.Ub ));
175+     SIMPLEFOC_DEBUG (" >v.c:"  ,normalize_voltage (motor.Uc ));
176+     t = _micros ();
177+   }
178+ 
179+   //  user communication
180+   command.run ();
181+ }
0 commit comments