@@ -95,22 +95,22 @@ Axis::Axis(char axis,volatile Control_t* control) :CommandHandler("axis", CLSID_
9595 setInstance (0 );
9696 this ->flashAddrs = AxisFlashAddrs ({ADR_AXIS1_CONFIG, ADR_AXIS1_MAX_SPEED, ADR_AXIS1_MAX_ACCEL,
9797 ADR_AXIS1_ENDSTOP, ADR_AXIS1_POWER, ADR_AXIS1_DEGREES,ADR_AXIS1_EFFECTS1,ADR_AXIS1_EFFECTS2,ADR_AXIS1_ENC_RATIO,
98- ADR_AXIS1_SPEEDACCEL_FILTER});
98+ ADR_AXIS1_SPEEDACCEL_FILTER,ADR_AXIS1_POSTPROCESS1 });
9999 }
100100 else if (axis == ' Y' )
101101 {
102102 drv_chooser = ClassChooser<MotorDriver>(axis2_drivers);
103103 setInstance (1 );
104104 this ->flashAddrs = AxisFlashAddrs ({ADR_AXIS2_CONFIG, ADR_AXIS2_MAX_SPEED, ADR_AXIS2_MAX_ACCEL,
105105 ADR_AXIS2_ENDSTOP, ADR_AXIS2_POWER, ADR_AXIS2_DEGREES,ADR_AXIS2_EFFECTS1,ADR_AXIS2_EFFECTS2, ADR_AXIS2_ENC_RATIO,
106- ADR_AXIS2_SPEEDACCEL_FILTER});
106+ ADR_AXIS2_SPEEDACCEL_FILTER,ADR_AXIS2_POSTPROCESS1 });
107107 }
108108 else if (axis == ' Z' )
109109 {
110110 setInstance (2 );
111111 this ->flashAddrs = AxisFlashAddrs ({ADR_AXIS3_CONFIG, ADR_AXIS3_MAX_SPEED, ADR_AXIS3_MAX_ACCEL,
112112 ADR_AXIS3_ENDSTOP, ADR_AXIS3_POWER, ADR_AXIS3_DEGREES,ADR_AXIS3_EFFECTS1,ADR_AXIS3_EFFECTS2,ADR_AXIS3_ENC_RATIO,
113- ADR_AXIS3_SPEEDACCEL_FILTER});
113+ ADR_AXIS3_SPEEDACCEL_FILTER,ADR_AXIS3_POSTPROCESS1 });
114114 }
115115
116116
@@ -157,6 +157,8 @@ void Axis::registerCommands(){
157157 registerCommand (" filterAccel" , Axis_commands::filterAccel, " Biquad filter freq and q*100 for accel" , CMDFLAG_GET);
158158
159159 registerCommand (" cpr" , Axis_commands::cpr, " Reported encoder CPR" ,CMDFLAG_GET);
160+ registerCommand (" expo" , Axis_commands::expo, " Exponential curve correction (x^(val/exposcale)+1)" , CMDFLAG_GET | CMDFLAG_SET);
161+ registerCommand (" exposcale" , Axis_commands::exposcale, " Scaler constant for expo" , CMDFLAG_GET);
160162}
161163
162164/*
@@ -235,6 +237,11 @@ void Axis::restoreFlash(){
235237 accelFilter.setQ (filterAccelCst[this ->filterProfileId ].q / 100.0 );
236238 }
237239
240+ uint16_t pp1;
241+ if (Flash_Read (flashAddrs.postprocess1 , &pp1)){
242+ setExpo (pp1 & 0xff );
243+ }
244+
238245}
239246// Saves parameters to flash.
240247void Axis::saveFlash (){
@@ -253,6 +260,10 @@ void Axis::saveFlash(){
253260 // save CF biquad
254261 uint16_t filterStorage = (uint16_t )this ->filterProfileId & 0xFF ;
255262 Flash_Write (flashAddrs.speedAccelFilter , filterStorage);
263+
264+ // Postprocessing
265+ Flash_Write (flashAddrs.postprocess1 , expoValInt & 0xff );
266+
256267}
257268
258269
@@ -598,7 +609,7 @@ void Axis::calculateAxisEffects(bool ffb_on){
598609 float speed = metric.current .speed * INTERNAL_SCALER_FRICTION;
599610 float speedRampupCeil = 4096 ;
600611 float rampupFactor = 1.0 ;
601- if (fabs (speed) < speedRampupCeil) { // if speed in the range to rampup we apply a sinus curbe to ramup
612+ if (fabs (speed) < speedRampupCeil) { // if speed in the range to rampup we apply a sine curve
602613 float phaseRad = M_PI * ((fabs (speed) / speedRampupCeil) - 0.5 );// we start to compute the normalized angle (speed / normalizedSpeed@5%) and translate it of -1/2PI to translate sin on 1/2 periode
603614 rampupFactor = ( 1 + sin (phaseRad ) ) / 2 ; // sin value is -1..1 range, we translate it to 0..2 and we scale it by 2
604615 }
@@ -655,6 +666,18 @@ uint16_t Axis::getPower(){
655666 return power;
656667}
657668
669+ /* *
670+ * Calculates an exponential torque correction curve
671+ */
672+ int32_t Axis::calculateExpoTorque (int32_t torque){
673+ float torquef = (float )torque / (float )0x7fff ; // This down and upscaling may introduce float artifacts. Do this before scaling down.
674+ if (torquef < 0 ){
675+ return -powf (-torquef,expo) * 0x7fff ;
676+ }else {
677+ return powf (torquef,expo) * 0x7fff ;
678+ }
679+ }
680+
658681void Axis::updateTorqueScaler () {
659682 effect_margin_scaler = ((float )fx_ratio_i/255.0 );
660683 torqueScaler = ((float )power / (float )0x7fff );
@@ -702,11 +725,15 @@ bool Axis::updateTorque(int32_t* totalTorque) {
702725
703726 // Scale effect torque
704727 int32_t torque = effectTorque; // Game effects
728+ if (expo != 1 ){
729+ torque = calculateExpoTorque (torque);
730+ }
705731 torque *= effect_margin_scaler;
706732 torque += axisEffectTorque; // Independent effects
707733 torque += updateEndstop ();
708734 torque *= torqueScaler; // Scale to power
709735
736+
710737 // TODO speed and accel limiters
711738 if (maxSpeedDegS > 0 ){
712739
@@ -785,6 +812,21 @@ void Axis::setDegrees(uint16_t degrees){
785812}
786813
787814
815+ void Axis::setExpo (int val){
816+ val = clip (val, -127 , 127 );
817+ expoValInt = val;
818+ if (val == 0 ){
819+ expo = 1 ; // Explicitly force expo off
820+ return ;
821+ }
822+ float valF = abs ((float )val / expoScaler);
823+ if (val < 0 ){
824+ expo = 1 .0f /(1 .0f +valF);
825+ }else {
826+ expo = 1 +valF;
827+ }
828+ }
829+
788830CommandStatus Axis::command (const ParsedCommand& cmd,std::vector<CommandReply>& replies){
789831
790832 switch (static_cast <Axis_commands>(cmd.cmdId )){
@@ -998,6 +1040,14 @@ CommandStatus Axis::command(const ParsedCommand& cmd,std::vector<CommandReply>&
9981040 }
9991041 break ;
10001042
1043+ case Axis_commands::expo:
1044+ handleGetSetFunc (cmd, replies, expoValInt, &Axis::setExpo, this ); // need to also provide the expoScaler constant
1045+ break ;
1046+
1047+ case Axis_commands::exposcale:
1048+ handleGetSet (cmd, replies, expoScaler); // need to also provide the expoScaler constant
1049+ break ;
1050+
10011051 default :
10021052 return CommandStatus::NOT_FOUND;
10031053 }
0 commit comments