@@ -117,7 +117,7 @@ Axis::Axis(char axis,volatile Control_t* control) :CommandHandler("axis", CLSID_
117117 {
118118 driverChooser = ClassChooser<MotorDriver>(axis1_drivers);
119119 setInstance (0 );
120- this ->flashAddresses = AxisFlashAddresses ({ADR_AXIS1_CONFIG, ADR_AXIS1_MAX_SPEED, ADR_AXIS1_MAX_ACCEL,
120+ this ->flashAddresses = AxisFlashAddresses ({ADR_AXIS1_CONFIG, ADR_AXIS1_MAX_SPEED, ADR_AXIS1_MAX_ACCEL, ADR_AXIS1_MAX_SLEWRATE_DRV,
121121 ADR_AXIS1_ENDSTOP, ADR_AXIS1_POWER, ADR_AXIS1_DEGREES,ADR_AXIS1_EFFECTS1,ADR_AXIS1_EFFECTS2,ADR_AXIS1_ENC_RATIO,
122122 ADR_AXIS1_SPEEDACCEL_FILTER,ADR_AXIS1_POSTPROCESS1,
123123 ADR_AXIS1_EQ1,ADR_AXIS1_EQ2,ADR_AXIS1_EQ3,
@@ -128,7 +128,7 @@ Axis::Axis(char axis,volatile Control_t* control) :CommandHandler("axis", CLSID_
128128 {
129129 driverChooser = ClassChooser<MotorDriver>(axis2_drivers);
130130 setInstance (1 );
131- this ->flashAddresses = AxisFlashAddresses ({ADR_AXIS2_CONFIG, ADR_AXIS2_MAX_SPEED, ADR_AXIS2_MAX_ACCEL,
131+ this ->flashAddresses = AxisFlashAddresses ({ADR_AXIS2_CONFIG, ADR_AXIS2_MAX_SPEED, ADR_AXIS2_MAX_ACCEL, ADR_AXIS2_MAX_SLEWRATE_DRV,
132132 ADR_AXIS2_ENDSTOP, ADR_AXIS2_POWER, ADR_AXIS2_DEGREES,ADR_AXIS2_EFFECTS1,ADR_AXIS2_EFFECTS2, ADR_AXIS2_ENC_RATIO,
133133 ADR_AXIS2_SPEEDACCEL_FILTER,ADR_AXIS2_POSTPROCESS1,
134134 ADR_AXIS2_EQ1,ADR_AXIS2_EQ2,ADR_AXIS2_EQ3,
@@ -138,7 +138,7 @@ Axis::Axis(char axis,volatile Control_t* control) :CommandHandler("axis", CLSID_
138138 else if (axis == ' Z' )
139139 {
140140 setInstance (2 );
141- this ->flashAddresses = AxisFlashAddresses ({ADR_AXIS3_CONFIG, ADR_AXIS3_MAX_SPEED, ADR_AXIS3_MAX_ACCEL,
141+ this ->flashAddresses = AxisFlashAddresses ({ADR_AXIS3_CONFIG, ADR_AXIS3_MAX_SPEED, ADR_AXIS3_MAX_ACCEL, ADR_AXIS3_MAX_SLEWRATE_DRV,
142142 ADR_AXIS3_ENDSTOP, ADR_AXIS3_POWER, ADR_AXIS3_DEGREES,ADR_AXIS3_EFFECTS1,ADR_AXIS3_EFFECTS2,ADR_AXIS3_ENC_RATIO,
143143 ADR_AXIS3_SPEEDACCEL_FILTER,ADR_AXIS3_POSTPROCESS1,
144144 ADR_AXIS3_EQ1,ADR_AXIS3_EQ2,ADR_AXIS3_EQ3,
@@ -207,6 +207,9 @@ void Axis::registerCommands(){
207207 registerCommand (" handsoff" , Axis_commands::handsoff, " Hands-off enable" , CMDFLAG_GET | CMDFLAG_SET);
208208 registerCommand (" handsoff_speed" , Axis_commands::handsoff_speed, " Hoff speed thrld (deg/s)" , CMDFLAG_GET | CMDFLAG_SET);
209209 registerCommand (" handsoff_accel" , Axis_commands::handsoff_accel, " Hoff accel std dev thrld (float, val/1000)" , CMDFLAG_GET | CMDFLAG_SET);
210+
211+ registerCommand (" maxSlewRateDrv" , Axis_commands::maxSlewRateDrv, " Max driver torque in counts/ms" ,CMDFLAG_GET);
212+ registerCommand (" calibrate_maxSlewRateDrv" , Axis_commands::calibrate_maxSlewRateDrv, " Start driver slewRate calib" , CMDFLAG_GET);
210213}
211214
212215/*
@@ -238,6 +241,13 @@ void Axis::restoreFlash(){
238241 pulseErrLed ();
239242 }
240243
244+ // save the max torque for the slew rate
245+ if (Flash_Read (flashAddresses.maxSlewRateDrv , &value)){
246+ this ->maxSlewRate_Driver = value;
247+ }else {
248+ pulseErrLed ();
249+ }
250+
241251
242252 uint16_t endstopRawValue, power;
243253 if (Flash_Read (flashAddresses.endstop , &endstopRawValue)) {
@@ -322,6 +332,7 @@ void Axis::saveFlash(){
322332 Flash_Write (flashAddresses.config , Axis::encodeConfToInt (this ->conf ));
323333 Flash_Write (flashAddresses.maxSpeed , this ->maxSpeedDegS );
324334 Flash_Write (flashAddresses.maxAccel , (uint16_t )(this ->maxTorqueRateMS ));
335+ Flash_Write (flashAddresses.maxSlewRateDrv , (uint16_t )(this ->maxSlewRate_Driver ));
325336
326337 Flash_Write (flashAddresses.endstop , effectRatio | (endstopStrength << 8 ));
327338 Flash_Write (flashAddresses.power , power);
@@ -435,6 +446,29 @@ void Axis::prepareForUpdate(){
435446 startForceFadeIn (0 , 1.0 );
436447 }
437448
449+ // Check for pending slew rate calibration result
450+ if (this ->awaitingSlewCalibration ){
451+ // If driver reports calibration finished, retrieve measured value and persist
452+ if (!drv->isSlewRateCalibrationInProgress ()){
453+ // Get value from drv
454+ this ->maxSlewRate_Driver = drv->getDrvSlewRate ();
455+
456+ // If the driver's max slew rate is lowest thant current max flew rate, cap the value and send the new value to the UI
457+ if (this ->maxSlewRate_Driver < this ->maxTorqueRateMS ) {
458+ this ->maxTorqueRateMS = this ->maxSlewRate_Driver ;
459+ CommandHandler::broadcastCommandReply (CommandReply (this ->maxTorqueRateMS ), (uint32_t )Axis_commands::slewrate, CMDtype::get);
460+ }
461+
462+ // Broadcast a friendly completion message and the numeric value
463+ CommandHandler::broadcastCommandReply (CommandReply (" Slew rate calibration complete" ,0 ), (uint32_t )Axis_commands::calibrate_maxSlewRateDrv, CMDtype::get);
464+ CommandHandler::broadcastCommandReply (CommandReply (this ->maxSlewRate_Driver ), (uint32_t )Axis_commands::maxSlewRateDrv, CMDtype::get);
465+
466+
467+ this ->awaitingSlewCalibration = false ;
468+ }
469+ }
470+
471+
438472 this ->updateMetrics (angle);
439473 this ->updateHandsOffState ();
440474
@@ -499,6 +533,7 @@ void Axis::setDrvType(uint8_t drvtype)
499533 old_drv_ptr = this ->drv .release (); // Detach the old driver safely
500534 this ->drv .reset (drv_new); // Attach the new driver
501535 this ->conf .drvtype = drvtype;
536+ this ->maxTorqueRateMS = drv_new->getDrvSlewRate ();
502537 cpp_freertos::CriticalSection::Exit ();
503538
504539 // Delete the old driver outside of the critical section to avoid blocking destructors or FreeRTOS issues
@@ -671,13 +706,13 @@ void Axis::calculateMechanicalEffects(bool ffb_on){
671706 // Always active damper
672707 if (damperIntensity != 0 ){
673708 float speedFiltered = (metric.current .speed ) * (float )damperIntensity * AXIS_DAMPER_RATIO;
674- mechanicalEffectTorque -= damperFilter.process (clip<float , int32_t >(speedFiltered, -INTERNAL_FX_CLIP, INTERNAL_FX_CLIP ));
709+ mechanicalEffectTorque -= damperFilter.process (clip<float , int32_t >(speedFiltered, -internalFxClip, internalFxClip ));
675710 }
676711
677712 // Always active inertia
678713 if (inertiaIntensity != 0 ){
679714 float accelFiltered = metric.current .accel * (float )inertiaIntensity * AXIS_INERTIA_RATIO;
680- mechanicalEffectTorque -= inertiaFilter.process (clip<float , int32_t >(accelFiltered, -INTERNAL_FX_CLIP, INTERNAL_FX_CLIP ));
715+ mechanicalEffectTorque -= inertiaFilter.process (clip<float , int32_t >(accelFiltered, -internalFxClip, internalFxClip ));
681716 }
682717
683718 // Always active friction. Based on effectsCalculator implementation
@@ -696,7 +731,7 @@ void Axis::calculateMechanicalEffects(bool ffb_on){
696731 }
697732 int8_t sign = speed >= 0 ? 1 : -1 ;
698733 float force = (float )frictionIntensity * rampupFactor * sign * INTERNAL_AXIS_FRICTION_SCALER * 32 ;
699- mechanicalEffectTorque -= frictionFilter.process (clip<float , int32_t >(force, -INTERNAL_FX_CLIP, INTERNAL_FX_CLIP ));
734+ mechanicalEffectTorque -= frictionFilter.process (clip<float , int32_t >(force, -internalFxClip, internalFxClip ));
700735 }
701736
702737}
@@ -805,7 +840,7 @@ int32_t Axis::calculateEndstopTorque(){
805840 return 0 ;
806841 }
807842 float endstopTorque = clipDirection*metric.current .posDegrees - (float )this ->degreesOfRotation /2.0 ; // degress of rotation counts total range so multiply by 2
808- endstopTorque *= (float )endstopStrength * ENDSTOP_GAIN ; // Apply endstop gain for stiffness.
843+ endstopTorque *= (float )endstopStrength * endstopGain ; // Apply endstop gain for stiffness.
809844 endstopTorque *= -clipDirection;
810845
811846 return clip<int32_t ,int32_t >(endstopTorque,-0x7fff ,0x7fff );
@@ -1132,13 +1167,38 @@ CommandStatus Axis::command(const ParsedCommand& cmd,std::vector<CommandReply>&
11321167 case Axis_commands::slewrate:
11331168 {
11341169 if (cmd.type == CMDtype::get){
1170+ // If driver has a more restrictive calibrated value, update the axis limit
1171+ if (maxSlewRate_Driver < this ->maxTorqueRateMS ) {
1172+ this ->maxTorqueRateMS = maxSlewRate_Driver;
1173+ }
11351174 replies.emplace_back (this ->maxTorqueRateMS );
11361175 }else if (cmd.type == CMDtype::set){
1137- this ->maxTorqueRateMS = cmd.val ;
1176+ this ->maxTorqueRateMS = clip< uint32_t , uint32_t >( cmd.val , 0 , maxSlewRate_Driver) ;
11381177 }
11391178 }
11401179 break ;
11411180
1181+ case Axis_commands::calibrate_maxSlewRateDrv:
1182+ {
1183+ if (cmd.type == CMDtype::get){
1184+ // Start calibration on driver and set awaiting flag if start is OK
1185+ if (drv->startSlewRateCalibration ()) {
1186+ this ->awaitingSlewCalibration = true ;
1187+ } else {
1188+ // Inform user that calibration can't started
1189+ CommandHandler::broadcastCommandReply (CommandReply (" Slew rate calibration unsupported" ,1 ), (uint32_t )Axis_commands::calibrate_maxSlewRateDrv, CMDtype::get);
1190+ }
1191+ replies.emplace_back (1 ); // ack
1192+ }
1193+ break ;
1194+ }
1195+
1196+ case Axis_commands::maxSlewRateDrv:
1197+ if (cmd.type == CMDtype::get) {
1198+ replies.emplace_back (maxSlewRate_Driver);
1199+ }
1200+ break ;
1201+
11421202 case Axis_commands::fxratio:
11431203 if (cmd.type == CMDtype::get){
11441204 replies.emplace_back (this ->effectRatio );
@@ -1200,6 +1260,14 @@ CommandStatus Axis::command(const ParsedCommand& cmd,std::vector<CommandReply>&
12001260 if (this ->getEncoder () != nullptr ){
12011261 cpr = this ->getEncoder ()->getCpr ();
12021262 }
1263+ // TODO: For TMC4671 drivers, CPR reporting might be inconsistent. Investigate if a prescale is needed or if the UI should handle the readout correction.
1264+ // #ifdef TMC4671DRIVER // CPR should be consistent with position. Maybe change TMC to prescale to encoder count or correct readout in UI
1265+ // TMC4671 *tmcdrv = dynamic_cast<TMC4671 *>(this->drv.get()); // Special case for TMC. Get the actual encoder resolution
1266+ // if (tmcdrv && tmcdrv->hasIntegratedEncoder())
1267+ // {
1268+ // cpr = tmcdrv->getEncCpr();
1269+ // }
1270+ // #endif
12031271 replies.emplace_back (cpr);
12041272 }else {
12051273 return CommandStatus::ERR;
0 commit comments