@@ -108,12 +108,28 @@ int StepperMotor::initFOC() {
108108 // alignment necessary for encoders!
109109 // sensor and motor alignment - can be skipped
110110 // by setting motor.sensor_direction and motor.zero_electric_angle
111- _delay (500 );
112111 if (sensor){
113112 exit_flag *= alignSensor ();
114113 // added the shaft_angle update
115114 sensor->update ();
116- shaft_angle = sensor->getAngle ();
115+ shaft_angle = shaftAngle ();
116+
117+ // aligning the current sensor - can be skipped
118+ // checks if driver phases are the same as current sense phases
119+ // and checks the direction of measuremnt.
120+ if (exit_flag){
121+ if (current_sense){
122+ if (!current_sense->initialized ) {
123+ motor_status = FOCMotorStatus::motor_calib_failed;
124+ SIMPLEFOC_DEBUG (" MOT: Init FOC error, current sense not initialized" );
125+ exit_flag = 0 ;
126+ }else {
127+ exit_flag *= alignCurrentSense ();
128+ }
129+ }
130+ else { SIMPLEFOC_DEBUG (" MOT: No current sense." ); }
131+ }
132+
117133 } else {
118134 SIMPLEFOC_DEBUG (" MOT: No sensor." );
119135 if ((controller == MotionControlType::angle_openloop || controller == MotionControlType::velocity_openloop)){
@@ -136,6 +152,26 @@ int StepperMotor::initFOC() {
136152 return exit_flag;
137153}
138154
155+ // Calibrate the motor and current sense phases
156+ int StepperMotor::alignCurrentSense () {
157+ int exit_flag = 1 ; // success
158+
159+ SIMPLEFOC_DEBUG (" MOT: Align current sense." );
160+
161+ // align current sense and the driver
162+ exit_flag = current_sense->driverAlign (voltage_sensor_align);
163+ if (!exit_flag){
164+ // error in current sense - phase either not measured or bad connection
165+ SIMPLEFOC_DEBUG (" MOT: Align error!" );
166+ exit_flag = 0 ;
167+ }else {
168+ // output the alignment status flag
169+ SIMPLEFOC_DEBUG (" MOT: Success: " , exit_flag);
170+ }
171+
172+ return exit_flag > 0 ;
173+ }
174+
139175// Encoder alignment to electrical 0 angle
140176int StepperMotor::alignSensor () {
141177 int exit_flag = 1 ; // success
@@ -261,8 +297,6 @@ void StepperMotor::loopFOC() {
261297
262298 // if open-loop do nothing
263299 if ( controller==MotionControlType::angle_openloop || controller==MotionControlType::velocity_openloop ) return ;
264- // shaft angle
265- shaft_angle = shaftAngle ();
266300
267301 // if disabled do nothing
268302 if (!enabled) return ;
@@ -272,6 +306,44 @@ void StepperMotor::loopFOC() {
272306 // which is in range 0-2PI
273307 electrical_angle = electricalAngle ();
274308
309+ // Needs the update() to be called first
310+ // This function will not have numerical issues because it uses Sensor::getMechanicalAngle()
311+ // which is in range 0-2PI
312+ electrical_angle = electricalAngle ();
313+ switch (torque_controller) {
314+ case TorqueControlType::voltage:
315+ // no need to do anything really
316+ break ;
317+ case TorqueControlType::dc_current:
318+ if (!current_sense) return ;
319+ // read overall current magnitude
320+ current.q = current_sense->getDCCurrent (electrical_angle);
321+ // filter the value values
322+ current.q = LPF_current_q (current.q );
323+ // calculate the phase voltage
324+ voltage.q = PID_current_q (current_sp - current.q );
325+ // d voltage - lag compensation
326+ if (_isset (phase_inductance)) voltage.d = _constrain ( -current_sp*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
327+ else voltage.d = 0 ;
328+ break ;
329+ case TorqueControlType::foc_current:
330+ if (!current_sense) return ;
331+ // read dq currents
332+ current = current_sense->getFOCCurrents (electrical_angle);
333+ // filter values
334+ current.q = LPF_current_q (current.q );
335+ current.d = LPF_current_d (current.d );
336+ // calculate the phase voltages
337+ voltage.q = PID_current_q (current_sp - current.q );
338+ voltage.d = PID_current_d (-current.d );
339+ // d voltage - lag compensation - TODO verify
340+ // if(_isset(phase_inductance)) voltage.d = _constrain( voltage.d - current_sp*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
341+ break ;
342+ default :
343+ // no torque control selected
344+ SIMPLEFOC_DEBUG (" MOT: no torque control selected!" );
345+ break ;
346+ }
275347 // set the phase voltage - FOC heart function :)
276348 setPhaseVoltage (voltage.q , voltage.d , electrical_angle);
277349}
@@ -309,56 +381,70 @@ void StepperMotor::move(float new_target) {
309381 // estimate the motor current if phase reistance available and current_sense not available
310382 if (!current_sense && _isset (phase_resistance)) current.q = (voltage.q - voltage_bemf)/phase_resistance;
311383
312- // choose control loop
384+ // upgrade the current based voltage limit
313385 switch (controller) {
314386 case MotionControlType::torque:
315- if (!_isset (phase_resistance)) voltage.q = target; // if voltage torque control
316- else voltage.q = target*phase_resistance + voltage_bemf;
317- voltage.q = _constrain (voltage.q , -voltage_limit, voltage_limit);
318- // set d-component (lag compensation if known inductance)
319- if (!_isset (phase_inductance)) voltage.d = 0 ;
320- else voltage.d = _constrain ( -target*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
387+ if (torque_controller == TorqueControlType::voltage){ // if voltage torque control
388+ if (!_isset (phase_resistance)) voltage.q = target;
389+ else voltage.q = target*phase_resistance + voltage_bemf;
390+ voltage.q = _constrain (voltage.q , -voltage_limit, voltage_limit);
391+ // set d-component (lag compensation if known inductance)
392+ if (!_isset (phase_inductance)) voltage.d = 0 ;
393+ else voltage.d = _constrain ( -target*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
394+ }else {
395+ current_sp = target; // if current/foc_current torque control
396+ }
321397 break ;
322398 case MotionControlType::angle:
399+ // TODO sensor precision: this calculation is not numerically precise. The target value cannot express precise positions when
400+ // the angles are large. This results in not being able to command small changes at high position values.
401+ // to solve this, the delta-angle has to be calculated in a numerically precise way.
323402 // angle set point
324403 shaft_angle_sp = target;
325404 // calculate velocity set point
326405 shaft_velocity_sp = feed_forward_velocity + P_angle ( shaft_angle_sp - shaft_angle );
327- shaft_velocity_sp = _constrain (shaft_velocity_sp, -velocity_limit, velocity_limit);
328- // calculate the torque command
406+ shaft_velocity_sp = _constrain (shaft_velocity_sp,-velocity_limit, velocity_limit);
407+ // calculate the torque command - sensor precision: this calculation is ok, but based on bad value from previous calculation
329408 current_sp = PID_velocity (shaft_velocity_sp - shaft_velocity); // if voltage torque control
330409 // if torque controlled through voltage
331- // use voltage if phase-resistance not provided
332- if (!_isset (phase_resistance)) voltage.q = current_sp;
333- else voltage.q = _constrain ( current_sp*phase_resistance + voltage_bemf , -voltage_limit, voltage_limit);
334- // set d-component (lag compensation if known inductance)
335- if (!_isset (phase_inductance)) voltage.d = 0 ;
336- else voltage.d = _constrain ( -current_sp*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
410+ if (torque_controller == TorqueControlType::voltage){
411+ // use voltage if phase-resistance not provided
412+ if (!_isset (phase_resistance)) voltage.q = current_sp;
413+ else voltage.q = _constrain ( current_sp*phase_resistance + voltage_bemf , -voltage_limit, voltage_limit);
414+ // set d-component (lag compensation if known inductance)
415+ if (!_isset (phase_inductance)) voltage.d = 0 ;
416+ else voltage.d = _constrain ( -current_sp*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
417+ }
337418 break ;
338419 case MotionControlType::velocity:
339- // velocity set point
420+ // velocity set point - sensor precision: this calculation is numerically precise.
340421 shaft_velocity_sp = target;
341422 // calculate the torque command
342423 current_sp = PID_velocity (shaft_velocity_sp - shaft_velocity); // if current/foc_current torque control
343424 // if torque controlled through voltage control
344- // use voltage if phase-resistance not provided
345- if (!_isset (phase_resistance)) voltage.q = current_sp;
346- else voltage.q = _constrain ( current_sp*phase_resistance + voltage_bemf , -voltage_limit, voltage_limit);
347- // set d-component (lag compensation if known inductance)
348- if (!_isset (phase_inductance)) voltage.d = 0 ;
349- else voltage.d = _constrain ( -current_sp*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
425+ if (torque_controller == TorqueControlType::voltage){
426+ // use voltage if phase-resistance not provided
427+ if (!_isset (phase_resistance)) voltage.q = current_sp;
428+ else voltage.q = _constrain ( current_sp*phase_resistance + voltage_bemf , -voltage_limit, voltage_limit);
429+ // set d-component (lag compensation if known inductance)
430+ if (!_isset (phase_inductance)) voltage.d = 0 ;
431+ else voltage.d = _constrain ( -current_sp*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
432+ }
350433 break ;
351434 case MotionControlType::velocity_openloop:
352- // velocity control in open loop
435+ // velocity control in open loop - sensor precision: this calculation is numerically precise.
353436 shaft_velocity_sp = target;
354437 voltage.q = velocityOpenloop (shaft_velocity_sp); // returns the voltage that is set to the motor
355- voltage.d = 0 ; // TODO d-component lag-compensation
438+ voltage.d = 0 ;
356439 break ;
357440 case MotionControlType::angle_openloop:
358- // angle control in open loop
441+ // angle control in open loop -
442+ // TODO sensor precision: this calculation NOT numerically precise, and subject
443+ // to the same problems in small set-point changes at high angles
444+ // as the closed loop version.
359445 shaft_angle_sp = target;
360446 voltage.q = angleOpenloop (shaft_angle_sp); // returns the voltage that is set to the motor
361- voltage.d = 0 ; // TODO d-component lag-compensation
447+ voltage.d = 0 ;
362448 break ;
363449 }
364450}
0 commit comments