diff --git a/CHANGELOG.md b/CHANGELOG.md index 33c030e3..a85a4fad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ### Changes this version: -- Added independend friction and inertia effects to axis -- ODrive class can save encoder position offset -- Reverted the forza fix for 2 axis setups. - - TODO: test and report if behaviour works for all games with the angle always being used for 1 axis modes (Games must send 90° on X axis effects instead of 0°). \ No newline at end of file +- Fixed BISS-C encoder sometimes overflowing one rotation at startup +- Added BISS-C direction inversion function (Default true). Most BISS-C encoders count CW while most others and TMC count CCW. +- Standardized encoder counting direction counting up in CCW direction as a more common industrial standard +- Fixed idle spring effect not working before first save +- Retuned speed limiter function. Removed averaging. Should be more stable for high resolution encoders if high bandwidth speed filter preset is selected +- Force ramps up slowly on potential sharp position changes such as recentering +- FFB led now shows FFB state. On when FFB actuators enabled. Still blinks on clipping \ No newline at end of file diff --git a/Firmware/FFBoard/Inc/AnalogSource.h b/Firmware/FFBoard/Inc/AnalogSource.h index 919f2c20..e26c2c7a 100644 --- a/Firmware/FFBoard/Inc/AnalogSource.h +++ b/Firmware/FFBoard/Inc/AnalogSource.h @@ -30,7 +30,7 @@ class AnalogSource : public ChoosableClass, public PersistentStorage{ virtual std::vector* getAxes(); std::vector buf; - + static const std::vector> all_analogsources; private: diff --git a/Firmware/FFBoard/Inc/Axis.h b/Firmware/FFBoard/Inc/Axis.h index 82bce6b1..18d6c177 100644 --- a/Firmware/FFBoard/Inc/Axis.h +++ b/Firmware/FFBoard/Inc/Axis.h @@ -23,11 +23,16 @@ #include "ClassChooser.h" #include "ExtiHandler.h" #include "EffectsCalculator.h" -#include "FastAvg.h" #define INTERNAL_AXIS_DAMPER_SCALER 0.7 #define INTERNAL_AXIS_FRICTION_SCALER 0.7 #define INTERNAL_AXIS_INERTIA_SCALER 0.7 +#ifndef AXIS_SPEEDLIMITER_P +#define AXIS_SPEEDLIMITER_P 0.3 +#endif +#ifndef AXIS_SPEEDLIMITER_I +#define AXIS_SPEEDLIMITER_I 0.03 +#endif struct Control_t { @@ -154,6 +159,8 @@ class Axis : public PersistentStorage, public CommandHandler, public ErrorHandle int32_t getTorque(); // current torque scaled as a 32 bit signed value int16_t updateEndstop(); + void startForceFadeIn(float start = 0,float fadeTime = 0.5); + metric_t* getMetrics(); void setEffectTorque(int32_t torque); @@ -185,6 +192,9 @@ class Axis : public PersistentStorage, public CommandHandler, public ErrorHandle const Error outOfBoundsError = Error(ErrorCode::axisOutOfRange,ErrorType::warning,"Axis out of bounds"); + float forceFadeTime = 1.0; + float forceFadeCurMult = 1.0; + #ifdef TMC4671DRIVER TMC4671Limits tmclimits = TMC4671Limits({.pid_torque_flux_ddt = 32767, .pid_uq_ud = 30000, @@ -221,7 +231,8 @@ class Axis : public PersistentStorage, public CommandHandler, public ErrorHandle uint16_t maxSpeedDegS = 0; // Set to non zero to enable. example 1000. 8b * 10? //float maxAccelDegSS = 0; uint32_t maxTorqueRateMS = 0; // 8b * 128? - const float speedLimiterP = 0.2; + float speedLimiterP = AXIS_SPEEDLIMITER_P; + float speedLimiterI = AXIS_SPEEDLIMITER_I; float spdlimitreducerI = 0; //float acclimitreducerI = 0; @@ -244,7 +255,7 @@ class Axis : public PersistentStorage, public CommandHandler, public ErrorHandle uint16_t power = 5000; float torqueScaler = 0; // power * fx_ratio as a ratio between 0 & 1 float effect_margin_scaler = 0; - bool invertAxis = false; + bool invertAxis = true; // By default most motors and encoders count up CCW while gamepads are counting up CW. uint8_t endstopStrength = 127; // Sets how much extra torque per count above endstop is added. High = stiff endstop. Low = softer const float endstopGain = 25; // Overall max endstop intensity @@ -252,11 +263,11 @@ class Axis : public PersistentStorage, public CommandHandler, public ErrorHandle uint8_t idlespringstrength = 127; int16_t idlespringclip = 0; float idlespringscale = 0; - bool idle_center = false; + bool motorWasNotReady = true; // TODO tune these and check if it is really stable and beneficial to the FFB. index 4 placeholder - const biquad_constant_t filterSpeedCst[4] = {{ 30, 55 }, { 60, 55 }, { 120, 55 }, {120, 55}}; - const biquad_constant_t filterAccelCst[4] = {{ 40, 30 }, { 55, 30 }, { 70, 30 }, {120, 55}}; + const std::array filterSpeedCst = { {{ 40, 55 }, { 70, 55 }, { 120, 55 }, {180, 55}} }; + const std::array filterAccelCst = { {{ 40, 30 }, { 55, 30 }, { 70, 30 }, {120, 55}} }; const biquad_constant_t filterDamperCst = {60, 55}; const biquad_constant_t filterFrictionCst = {50, 20}; const biquad_constant_t filterInertiaCst = {20, 20}; @@ -264,7 +275,6 @@ class Axis : public PersistentStorage, public CommandHandler, public ErrorHandle const float filter_f = 1000; // 1khz const int32_t intFxClip = 20000; uint8_t damperIntensity = 30; - FastAvg spdlimiterAvg; uint8_t frictionIntensity = 0; uint8_t inertiaIntensity = 0; diff --git a/Firmware/FFBoard/Inc/ButtonSource.h b/Firmware/FFBoard/Inc/ButtonSource.h index 934f6b91..6e6fb417 100644 --- a/Firmware/FFBoard/Inc/ButtonSource.h +++ b/Firmware/FFBoard/Inc/ButtonSource.h @@ -11,7 +11,7 @@ #include "cppmain.h" #include "ChoosableClass.h" #include "PersistentStorage.h" - +#include "vector" /** * A button source can return up to 64 buttons @@ -32,6 +32,8 @@ class ButtonSource : public ChoosableClass,public PersistentStorage { static bool isCreatable() {return true;}; virtual const ClassType getClassType() {return ClassType::Buttonsource;}; + static const std::vector > all_buttonsources; + protected: uint16_t btnnum = 0; // Amount of active buttons (valid bitfield length) to report }; diff --git a/Firmware/FFBoard/Inc/Encoder.h b/Firmware/FFBoard/Inc/Encoder.h index 2033a707..765223e3 100644 --- a/Firmware/FFBoard/Inc/Encoder.h +++ b/Firmware/FFBoard/Inc/Encoder.h @@ -12,12 +12,10 @@ #include "ChoosableClass.h" /* - * Info about used ids: - * 0: none - * 1: tmc reserved - * 2: local/tmc1 - * 3: tmc3 - * 4: mt encoder + * Note: + * Encoders should count UP when turned counterclockwise + * This is not the default gamepad direction but matches most motors + * If direction is not fixed the encoder class should provide a reverse option */ /* diff --git a/Firmware/FFBoard/Inc/constants.h b/Firmware/FFBoard/Inc/constants.h index 27fb6115..4f323607 100644 --- a/Firmware/FFBoard/Inc/constants.h +++ b/Firmware/FFBoard/Inc/constants.h @@ -8,7 +8,7 @@ * For more settings see target_constants.h in a target specific folder */ -static const uint8_t SW_VERSION_INT[3] = {1,15,0}; // Version as array. 8 bit each! +static const uint8_t SW_VERSION_INT[3] = {1,15,1}; // Version as array. 8 bit each! #ifndef MAX_AXIS #define MAX_AXIS 2 // ONLY USE 2 for now else screws HID Reports #endif diff --git a/Firmware/FFBoard/Inc/ledEffects.h b/Firmware/FFBoard/Inc/ledEffects.h index b9169bc8..84023038 100644 --- a/Firmware/FFBoard/Inc/ledEffects.h +++ b/Firmware/FFBoard/Inc/ledEffects.h @@ -14,6 +14,7 @@ typedef struct Ledstruct{ int32_t blinks; GPIO_TypeDef* port; uint16_t pin; + uint8_t state; } Ledstruct_t; @@ -29,5 +30,10 @@ void blinkClipLed(uint16_t period,uint16_t blinks); void updateLed(Ledstruct_t* led); void updateLeds(); +void setLed(Ledstruct_t* led,uint8_t on); +void setClipLed(uint8_t on); +void setErrLed(uint8_t on); +void setSysLed(uint8_t on); + #endif /* LEDEFFECTS_H_ */ diff --git a/Firmware/FFBoard/Inc/voltagesense.h b/Firmware/FFBoard/Inc/voltagesense.h index 7434bf22..c2bd0574 100644 --- a/Firmware/FFBoard/Inc/voltagesense.h +++ b/Firmware/FFBoard/Inc/voltagesense.h @@ -9,8 +9,8 @@ #define VOLTAGESENSE_H_ #include "target_constants.h" -uint16_t getIntV(); -uint16_t getExtV(); +int32_t getIntV(); +int32_t getExtV(); void brakeCheck(); /* diff --git a/Firmware/FFBoard/Src/Axis.cpp b/Firmware/FFBoard/Src/Axis.cpp index e5899d2c..03b4deea 100644 --- a/Firmware/FFBoard/Src/Axis.cpp +++ b/Firmware/FFBoard/Src/Axis.cpp @@ -203,6 +203,8 @@ void Axis::restoreFlash(){ if(Flash_Read(flashAddrs.effects1, &effects)){ setIdleSpringStrength(effects & 0xff); setFxStrengthAndFilter((effects >> 8) & 0xff,damperIntensity,damperFilter); + }else{ + setIdleSpringStrength(idlespringstrength); // Use default } if(Flash_Read(flashAddrs.effects2, &effects)){ @@ -261,6 +263,7 @@ uint8_t Axis::getEncType(){ void Axis::setPos(uint16_t val) { + startForceFadeIn(0.25,0.5); if(this->drv != nullptr){ drv->getEncoder()->setPos(val); } @@ -318,6 +321,13 @@ void Axis::prepareForUpdate(){ //ErrorHandler::clearError(outOfBoundsError); } + // On first change to ready start a fade + if(motorWasNotReady && drv->motorReady()){ + motorWasNotReady = false; + startForceFadeIn(0, 1.0); + } + + this->updateMetrics(angle); } @@ -487,8 +497,10 @@ float Axis::getEncAngle(Encoder *enc){ */ void Axis::emergencyStop(bool reset){ drv->turn(0); // Send 0 torque first + if(reset){ + startForceFadeIn(); + } drv->emergencyStop(reset); - //drv->stopMotor(); control->emergency = !reset; } @@ -506,6 +518,7 @@ void Axis::usbSuspend(){ * Enables motor driver */ void Axis::usbResume(){ + startForceFadeIn(); if (drv != nullptr){ drv->startMotor(); } @@ -536,11 +549,6 @@ int32_t Axis::updateIdleSpringForce() { */ void Axis::setIdleSpringStrength(uint8_t spring){ idlespringstrength = spring; - if(spring == 0){ - idle_center = false; - }else{ - idle_center = true; - } idlespringclip = clip((int32_t)spring*35,0,10000); idlespringscale = 0.5f + ((float)spring * 0.01f); } @@ -653,7 +661,7 @@ float Axis::getTorqueScaler(){ int32_t Axis::getTorque() { return metric.current.torque; } bool Axis::isInverted() { - return invertAxis; // TODO store in flash + return invertAxis; } /** @@ -697,9 +705,9 @@ bool Axis::updateTorque(int32_t* totalTorque) { float torqueSign = torque > 0 ? 1 : -1; // Used to prevent metrics against the force to go into the limiter // Speed. Mostly tuned... - spdlimiterAvg.addValue(metric.current.speed); - float speedreducer = (float)((spdlimiterAvg.getAverage()*torqueSign) - (float)maxSpeedDegS) * ((float)0x7FFF / maxSpeedDegS); - spdlimitreducerI = clip( spdlimitreducerI + ((speedreducer * 0.015) * torqueScaler),0,power); + //spdlimiterAvg.addValue(metric.current.speed); + float speedreducer = (float)((metric.current.speed*torqueSign) - (float)maxSpeedDegS) * ((float)0x7FFF / maxSpeedDegS); + spdlimitreducerI = clip( spdlimitreducerI + ((speedreducer * speedLimiterI) * torqueScaler),0,power); // Accel limit. Not really useful. Maybe replace with torque slew rate limit? // float accreducer = (float)((metric.current.accel*torqueSign) - (float)maxAccelDegSS) * getAccelScalerNormalized(); @@ -725,6 +733,12 @@ bool Axis::updateTorque(int32_t* totalTorque) { torque = 0; } + // Fade in + if(forceFadeCurMult < 1){ + torque = torque * forceFadeCurMult; + forceFadeCurMult += forceFadeTime / this->filter_f; // Fade time + } + // Torque calculated. Now sending to driver torque = (invertAxis) ? -torque : torque; metric.current.torque = torque; @@ -740,6 +754,15 @@ bool Axis::updateTorque(int32_t* totalTorque) { return (torqueChanged); } +/** + * Starts fading in force from start to 1 over fadeTime + */ +void Axis::startForceFadeIn(float start,float fadeTime){ + this->forceFadeTime = fadeTime; + this->forceFadeCurMult = clip(start, 0, 1); +} + + /** * Changes gamepad range in degrees for effect scaling */ @@ -869,11 +892,12 @@ CommandStatus Axis::command(const ParsedCommand& cmd,std::vector& case Axis_commands::pos: if (cmd.type == CMDtype::get && this->drv->getEncoder() != nullptr) { - replies.emplace_back(this->drv->getEncoder()->getPos()); + int32_t pos = this->drv->getEncoder()->getPos(); + replies.emplace_back(isInverted() ? -pos : pos); } else if (cmd.type == CMDtype::set && this->drv->getEncoder() != nullptr) { - this->drv->getEncoder()->setPos(cmd.val); + this->drv->getEncoder()->setPos(isInverted() ? -cmd.val : cmd.val); } else { @@ -925,7 +949,7 @@ CommandStatus Axis::command(const ParsedCommand& cmd,std::vector& } else if (cmd.type == CMDtype::set) { - uint32_t value = clip(cmd.val, 0, 2); + uint32_t value = clip(cmd.val, 0, filterSpeedCst.size()-1); this->filterProfileId = value; speedFilter.setFc(filterSpeedCst[this->filterProfileId].freq / filter_f); speedFilter.setQ(filterSpeedCst[this->filterProfileId].q / 100.0); diff --git a/Firmware/FFBoard/Src/EffectsCalculator.cpp b/Firmware/FFBoard/Src/EffectsCalculator.cpp index 1c1d7cb0..1e3a5a2a 100644 --- a/Firmware/FFBoard/Src/EffectsCalculator.cpp +++ b/Firmware/FFBoard/Src/EffectsCalculator.cpp @@ -9,7 +9,7 @@ #include #include "EffectsCalculator.h" #include "Axis.h" - +#include "ledEffects.h" #define EFFECT_STATE_INACTIVE 0 @@ -71,6 +71,7 @@ void EffectsCalculator::setActive(bool active) effects_stats[i].current = {0}; // Reset active effect forces effects_statslast[i].current = {0}; } + setClipLed(active); } diff --git a/Firmware/FFBoard/Src/Encoder.cpp b/Firmware/FFBoard/Src/Encoder.cpp index d88b3011..15736330 100644 --- a/Firmware/FFBoard/Src/Encoder.cpp +++ b/Firmware/FFBoard/Src/Encoder.cpp @@ -7,30 +7,6 @@ #include "Encoder.h" #include "ClassChooser.h" -#include "EncoderLocal.h" -#include "MtEncoderSPI.h" -#include "EncoderBissC.h" -#include "EncoderSSI.h" -// 0-63 valid ids -std::vector> const Encoder::all_encoders = - { - add_class(0), - -#ifdef LOCALENCODER - add_class(2), -#endif - -#ifdef MTENCODERSPI - add_class(4), -#endif -#ifdef BISSENCODER - add_class(5), -#endif -#ifdef SSIENCODER - add_class(6), -#endif - -}; ClassIdentifier Encoder::info ={.name = "None" , .id=CLSID_ENCODER_NONE, .visibility = ClassVisibility::visible}; diff --git a/Firmware/FFBoard/Src/SerialFFB.cpp b/Firmware/FFBoard/Src/SerialFFB.cpp index 563270dc..a439850d 100644 --- a/Firmware/FFBoard/Src/SerialFFB.cpp +++ b/Firmware/FFBoard/Src/SerialFFB.cpp @@ -74,7 +74,7 @@ void SerialFFB::set_gain(uint8_t gain){ * Returns the index where the effect was created or -1 if it can not be created */ int32_t SerialFFB::newEffect(uint8_t effectType){ - uint32_t idx = this->effects_calc->find_free_effect(effectType); + int32_t idx = this->effects_calc->find_free_effect(effectType); if(idx >= 0){ // Allocate effect effects[idx].type = effectType; diff --git a/Firmware/FFBoard/Src/ledEffects.cpp b/Firmware/FFBoard/Src/ledEffects.cpp index 0a4688fb..58952951 100644 --- a/Firmware/FFBoard/Src/ledEffects.cpp +++ b/Firmware/FFBoard/Src/ledEffects.cpp @@ -8,13 +8,13 @@ #include "main.h" Ledstruct_t sysled{ - 0,0,0,LED_SYS_GPIO_Port,LED_SYS_Pin + 0,0,0,LED_SYS_GPIO_Port,LED_SYS_Pin,0 }; Ledstruct_t errled{ - 0,0,0,LED_ERR_GPIO_Port,LED_ERR_Pin + 0,0,0,LED_ERR_GPIO_Port,LED_ERR_Pin,0 }; Ledstruct_t clipled{ - 0,0,0,LED_CLIP_GPIO_Port,LED_CLIP_Pin + 0,0,0,LED_CLIP_GPIO_Port,LED_CLIP_Pin,0 }; /** @@ -27,12 +27,12 @@ void blinkLed(Ledstruct* led,uint16_t period,uint16_t blinks){ if(period == 0 && blinks == 0){ led->blinks = 0; led->period = 0; - HAL_GPIO_WritePin(led->port, led->pin, GPIO_PIN_RESET); + HAL_GPIO_WritePin(led->port, led->pin, led->state ? GPIO_PIN_SET : GPIO_PIN_RESET); }else{ led->blinks = (blinks * 2) -1; led->period = period; led->tick = HAL_GetTick(); - HAL_GPIO_WritePin(led->port, led->pin, GPIO_PIN_SET); + HAL_GPIO_WritePin(led->port, led->pin, led->state ? GPIO_PIN_RESET : GPIO_PIN_SET); } } @@ -62,12 +62,29 @@ void blinkClipLed(uint16_t period,uint16_t blinks){ blinkLed(&clipled, period, blinks); } +void setLed(Ledstruct_t* led,uint8_t on){ + led->state = on; + HAL_GPIO_WritePin(led->port, led->pin, led->state ? GPIO_PIN_SET : GPIO_PIN_RESET); +} + +void setClipLed(uint8_t on){ + setLed(&clipled,on); +} + +void setErrLed(uint8_t on){ + setLed(&errled,on); +} + +void setSysLed(uint8_t on){ + setLed(&sysled,on); +} + void updateLed(Ledstruct* led){ // If led has an effect (period != 0) and time is up do something if(led->period != 0 && HAL_GetTick() > led->tick+led->period){ if(led->blinks == 0){ // No blinks left. turn off - HAL_GPIO_WritePin(led->port, led->pin, GPIO_PIN_RESET); + HAL_GPIO_WritePin(led->port, led->pin, led->state ? GPIO_PIN_SET : GPIO_PIN_RESET); led->period = 0; }else{ led->tick = HAL_GetTick(); diff --git a/Firmware/FFBoard/Src/voltagesense.cpp b/Firmware/FFBoard/Src/voltagesense.cpp index 86395b43..0ecd62a4 100644 --- a/Firmware/FFBoard/Src/voltagesense.cpp +++ b/Firmware/FFBoard/Src/voltagesense.cpp @@ -41,11 +41,11 @@ void setupBrakePin(uint32_t vdiffAct,uint32_t vdiffDeact,uint32_t vMax){ voltageDiffDeactivate = vdiffDeact; } -uint16_t getIntV(){ +int32_t getIntV(){ return VSENSE_ADC_BUF[ADC_CHAN_VINT] * vSenseMult; } -uint16_t getExtV(){ +int32_t getExtV(){ return VSENSE_ADC_BUF[ADC_CHAN_VEXT] * vSenseMult; } @@ -53,8 +53,8 @@ void brakeCheck(){ if(maxVoltage == 0 || brake_failure){ return; } - uint16_t vint = getIntV(); - uint16_t vext = getExtV(); + int32_t vint = getIntV(); + int32_t vext = getExtV(); if(vint < minVoltage && vext < minVoltage){ return; // Do not enable if device is unpowered (just measuring usb leakage) diff --git a/Firmware/FFBoard/UserExtensions/Inc/EncoderBissC.h b/Firmware/FFBoard/UserExtensions/Inc/EncoderBissC.h index fb544cac..772bec66 100644 --- a/Firmware/FFBoard/UserExtensions/Inc/EncoderBissC.h +++ b/Firmware/FFBoard/UserExtensions/Inc/EncoderBissC.h @@ -42,7 +42,7 @@ class EncoderBissC: public Encoder, public SPIDevice , public CommandHandler,cpp void Run(); - enum class EncoderBissC_commands {bits,cs,speed,errors}; + enum class EncoderBissC_commands {bits,cs,speed,errors,direction}; CommandStatus command(const ParsedCommand& cmd,std::vector& replies); @@ -59,6 +59,7 @@ class EncoderBissC: public Encoder, public SPIDevice , public CommandHandler,cpp int lenghtDataBit = 22; int spiSpeed = 3; bool waitData = false; + bool invertDirection = true; // Most biss-c encoders count UP clockwise while standard motor direction is usually CCW uint32_t lastUpdateTick = 0; diff --git a/Firmware/FFBoard/UserExtensions/Inc/TMC4671.h b/Firmware/FFBoard/UserExtensions/Inc/TMC4671.h index 1980de97..d35fa863 100644 --- a/Firmware/FFBoard/UserExtensions/Inc/TMC4671.h +++ b/Firmware/FFBoard/UserExtensions/Inc/TMC4671.h @@ -458,6 +458,8 @@ friend class TMCDebugBridge; int32_t getActualFlux(); int32_t getActualTorque(); + void rampFlux(uint16_t target,uint16_t time_ms); + bool checkAdc(); float getTemp(); diff --git a/Firmware/FFBoard/UserExtensions/Src/AnalogSources.cpp b/Firmware/FFBoard/UserExtensions/Src/AnalogSources.cpp new file mode 100644 index 00000000..52694dc5 --- /dev/null +++ b/Firmware/FFBoard/UserExtensions/Src/AnalogSources.cpp @@ -0,0 +1,27 @@ +/* + * AnalogSources.cpp + * + * Created on: Apr 18, 2024 + * Author: Yannick + */ + +#include "constants.h" +#include "LocalAnalog.h" +#include "CanAnalog.h" +#include "ADS111X.h" + +// Register possible analog sources (id 0-15) +#ifndef ANALOGSOURCES_DEFAULT_OVERRIDE +const std::vector> AnalogSource::all_analogsources = +{ +#ifdef ANALOGAXES + add_class(0), +#endif +#ifdef CANANALOG + add_class,AnalogSource>(1), +#endif +#ifdef ADS111XANALOG + add_class(2), +#endif +}; +#endif diff --git a/Firmware/FFBoard/UserExtensions/Src/ButtonSources.cpp b/Firmware/FFBoard/UserExtensions/Src/ButtonSources.cpp new file mode 100644 index 00000000..554560c7 --- /dev/null +++ b/Firmware/FFBoard/UserExtensions/Src/ButtonSources.cpp @@ -0,0 +1,37 @@ +/* + * ButtonSources.cpp + * + * Created on: Apr 18, 2024 + * Author: Yannick + */ +#include "constants.h" +#include "SPIButtons.h" +#include "CanButtons.h" +#include "LocalButtons.h" +#include +#include "PCF8574.h" + +#ifndef BUTTONSOURCES_DEFAULT_OVERRIDE +// Register possible button sources (id 0-15) +const std::vector> ButtonSource::all_buttonsources = +{ +#ifdef LOCALBUTTONS + add_class(0), +#endif +#ifdef SPIBUTTONS + add_class(1), +#endif +#ifdef SPIBUTTONS2 + add_class(2), +#endif +#ifdef SHIFTERBUTTONS + add_class(3), +#endif +#ifdef PCF8574BUTTONS + add_class(4), +#endif +#ifdef CANBUTTONS + add_class(5), +#endif +}; +#endif diff --git a/Firmware/FFBoard/UserExtensions/Src/EncoderBissC.cpp b/Firmware/FFBoard/UserExtensions/Src/EncoderBissC.cpp index bfae2357..218e3e03 100644 --- a/Firmware/FFBoard/UserExtensions/Src/EncoderBissC.cpp +++ b/Firmware/FFBoard/UserExtensions/Src/EncoderBissC.cpp @@ -49,15 +49,17 @@ void EncoderBissC::Run(){ this->WaitForNotification(); // Wait until DMA is finished if(updateFrame()){ + int32_t halfres = 1<<(lenghtDataBit-1); pos = newPos; if(first){ // Prevent immediate multiturn update - lastPos = pos; + lastPos = posOffset; first = false; + // If offset from current pos is more than half rotation add a multiturn count by setting previous position to the reloaded offset } //handle multiturn - if(pos-lastPos > 1<<(lenghtDataBit-1)){ + if(pos-lastPos > halfres){ mtpos--; - }else if(lastPos-pos > 1<<(lenghtDataBit-1)){ + }else if(lastPos-pos > halfres){ mtpos++; } @@ -79,16 +81,19 @@ void EncoderBissC::restoreFlash(){ if(Flash_Read(ADR_BISSENC_CONF1, &buf)){ this->lenghtDataBit = (buf & 0x1F)+1; // up to 32 bit. 5 bits this->spiSpeed = ((buf >> 5) & 0x3) +1; + this->invertDirection = ((buf >> 7) & 1); } - posOffset = Flash_ReadDefault(ADR_BISSENC_OFS, 0)<(restoredOffset) << std::max(0,(lenghtDataBit-16)); } void EncoderBissC::saveFlash(){ uint16_t buf = std::max((this->lenghtDataBit-1),0) & 0x1F; buf |= ((this->spiSpeed-1) & 0x3) << 5; + buf |= (this->invertDirection & 1) << 7; Flash_Write(ADR_BISSENC_CONF1, buf); - Flash_Write(ADR_BISSENC_OFS, posOffset >> std::max(0,(lenghtDataBit-16))); + int32_t scaledOfs = posOffset >> std::max(0,(lenghtDataBit-16)); + Flash_Write(ADR_BISSENC_OFS, (uint16_t)(scaledOfs) ); } void EncoderBissC::configSPI() { @@ -204,16 +209,27 @@ int32_t EncoderBissC::getPosAbs(){ if(useWaitSem && HAL_GetTick() - lastUpdateTick > waitThresh) waitForUpdateSem.Take(waitThresh); // Wait a bit } - return pos + mtpos * getCpr(); + int32_t curpos = pos + mtpos * getCpr(); + return invertDirection ? -curpos : curpos; } int32_t EncoderBissC::getPos(){ - return getPosAbs()-posOffset; + if(invertDirection){ + return getPosAbs()+posOffset; + }else{ + return getPosAbs()-posOffset; + } + } void EncoderBissC::setPos(int32_t newpos){ + if(invertDirection){ + newpos = -newpos; + } + int32_t diff = ( pos - newpos); + mtpos = newpos / getCpr(); // Multiturn should be reset - posOffset = pos - newpos; + posOffset = diff % getCpr(); // Always positive } @@ -227,6 +243,7 @@ void EncoderBissC::registerCommands(){ registerCommand("bits", EncoderBissC_commands::bits, "Bits of resolution",CMDFLAG_GET|CMDFLAG_SET); registerCommand("speed", EncoderBissC_commands::speed, "SPI speed preset 1-3",CMDFLAG_GET|CMDFLAG_SET); registerCommand("errors", EncoderBissC_commands::errors, "CRC error count",CMDFLAG_GET); + registerCommand("dir", EncoderBissC_commands::direction, "Invert direction",CMDFLAG_GET|CMDFLAG_SET); } CommandStatus EncoderBissC::command(const ParsedCommand& cmd,std::vector& replies){ @@ -247,6 +264,10 @@ CommandStatus EncoderBissC::command(const ParsedCommand& cmd,std::vectorinvertDirection); + break; default: return CommandStatus::NOT_FOUND; } diff --git a/Firmware/FFBoard/UserExtensions/Src/EncoderSources.cpp b/Firmware/FFBoard/UserExtensions/Src/EncoderSources.cpp new file mode 100644 index 00000000..068c8f61 --- /dev/null +++ b/Firmware/FFBoard/UserExtensions/Src/EncoderSources.cpp @@ -0,0 +1,33 @@ +/* + * EncoderSources.cpp + * + * Created on: Apr 18, 2024 + * Author: Yannick + */ + +#include "constants.h" +#include "EncoderLocal.h" +#include "MtEncoderSPI.h" +#include "EncoderBissC.h" +#include "EncoderSSI.h" +// 0-63 valid ids +#ifndef ENCODERSOURCES_DEFAULT_OVERRIDE +std::vector> const Encoder::all_encoders = + { + add_class(0), + +#ifdef LOCALENCODER + add_class(2), +#endif + +#ifdef MTENCODERSPI + add_class(4), +#endif +#ifdef BISSENCODER + add_class(5), +#endif +#ifdef SSIENCODER + add_class(6), +#endif +}; +#endif diff --git a/Firmware/FFBoard/UserExtensions/Src/FFBHIDMain.cpp b/Firmware/FFBoard/UserExtensions/Src/FFBHIDMain.cpp index ecd4e111..1ef11857 100644 --- a/Firmware/FFBoard/UserExtensions/Src/FFBHIDMain.cpp +++ b/Firmware/FFBoard/UserExtensions/Src/FFBHIDMain.cpp @@ -11,65 +11,18 @@ #include "tusb.h" #include "usb_hid_ffb_desc.h" -#include "SPIButtons.h" -#include "CanButtons.h" -#include "LocalButtons.h" -#include -#include "PCF8574.h" - -#include "LocalAnalog.h" -#include "CanAnalog.h" -#include "ADS111X.h" - #include "cmsis_os.h" extern osThreadId_t defaultTaskHandle; ////////////////////////////////////////////// -/* - * Sources for class choosers here - */ -// Register possible button sources (id 0-15) -const std::vector> button_sources = -{ -#ifdef LOCALBUTTONS - add_class(0), -#endif -#ifdef SPIBUTTONS - add_class(1), -#endif -#ifdef SPIBUTTONS2 - add_class(2), -#endif -#ifdef SHIFTERBUTTONS - add_class(3), -#endif -#ifdef PCF8574BUTTONS - add_class(4), -#endif -#ifdef CANBUTTONS - add_class(5), -#endif -}; -// Register possible analog sources (id 0-15) -const std::vector> analog_sources = -{ -#ifdef ANALOGAXES - add_class(0), -#endif -#ifdef CANANALOG - add_class,AnalogSource>(1), -#endif -#ifdef ADS111XANALOG - add_class(2), -#endif -}; /** * setFFBEffectsCalc must be called in constructor of derived class to finish the setup */ FFBHIDMain::FFBHIDMain(uint8_t axisCount) : - Thread("FFBMAIN", 256, 30),axisCount(axisCount),btn_chooser(button_sources),analog_chooser(analog_sources) + Thread("FFBMAIN", 256, 30),axisCount(axisCount), + btn_chooser(ButtonSource::all_buttonsources),analog_chooser(AnalogSource::all_analogsources) { restoreFlash(); // Load parameters diff --git a/Firmware/FFBoard/UserExtensions/Src/TMC4671.cpp b/Firmware/FFBoard/UserExtensions/Src/TMC4671.cpp index de75daef..b91bfe7f 100644 --- a/Firmware/FFBoard/UserExtensions/Src/TMC4671.cpp +++ b/Firmware/FFBoard/UserExtensions/Src/TMC4671.cpp @@ -186,7 +186,7 @@ void TMC4671::restoreFlash(){ } bool TMC4671::hasPower(){ - uint16_t intV = getIntV(); + int32_t intV = getIntV(); return (intV > 10000) && (getExtV() > 10000) && (intV < 78000); } @@ -839,16 +839,13 @@ bool TMC4671::findEncoderIndex(int32_t speed, uint16_t power,bool offsetPhiM,boo //uint32_t mposStart = readReg(0x2A); int32_t timeout = 1000; // 10s - for(int16_t flux = 0; flux <= power; flux+=10){ - setFluxTorque(flux, 0); - Delay(3); - } + rampFlux(power, 500); runOpenLoop(power, 0, speed, 10, true); while(!encoderIndexHitFlag && timeout-- > 0){ Delay(10); } //int32_t speed = 10; - + rampFlux(0, 100); runOpenLoop(0, 0, 0, 10, true); if(!encoderIndexHitFlag){ pulseErrLed(); @@ -987,10 +984,7 @@ void TMC4671::bangInitEnc(int16_t power){ setPhiE_ext(phiEpos); setPhiEtype(PhiE::ext); // Ramp up flux - for(int16_t flux = 0; flux <= power; flux+=10){ - setFluxTorque(flux, 0); - Delay(3); - } + rampFlux(power, 1000); int16_t phiE_enc = getPhiE_Enc(); Delay(50); @@ -1011,7 +1005,7 @@ void TMC4671::bangInitEnc(int16_t power){ //phiE_enc=readReg(phiEreg)>>16; Delay(10); } - setFluxTorque(0, 0); + rampFlux(0, 100); //Write offset //int16_t phiE_abn = readReg(0x2A)>>16; @@ -1062,10 +1056,7 @@ void TMC4671::calibrateAenc(){ setMotionMode(MotionMode::torque,true); if(this->conf.motconf.motor_type == MotorType::STEPPER || this->conf.motconf.motor_type == MotorType::BLDC){ - for(int16_t flux = 0; flux <= bangInitPower; flux+=10){ - setFluxTorque(flux, 0); - Delay(5); - } + rampFlux(bangInitPower, 250); } uint32_t minVal_0 = 0xffff, minVal_1 = 0xffff, minVal_2 = 0xffff; uint32_t maxVal_0 = 0, maxVal_1 = 0, maxVal_2 = 0; @@ -1099,6 +1090,7 @@ void TMC4671::calibrateAenc(){ aencconf.AENC2_scale = 0xF6FF00 / (maxVal_2 - minVal_2); aencconf.rdir = false; setup_AENC(aencconf); + rampFlux(0, 100); runOpenLoop(0, 0, 0, 1000,true); Delay(250); // Zero aenc @@ -1108,6 +1100,7 @@ void TMC4671::calibrateAenc(){ stage = 2; }else if(getPos() > 0 && stage == 2){ stage = 3; + rampFlux(0, 100); runOpenLoop(0, 0, 0, 1000,true); } @@ -1188,10 +1181,8 @@ bool TMC4671::checkEncoder(){ setPhiE_ext(startAngle); // Ramp up flux - for(int16_t flux = 0; flux <= 2*bangInitPower/3; flux+=20){ - setFluxTorque(flux, 0); - Delay(2); - } + rampFlux(2*bangInitPower/3, 250); + //Forward int16_t phiE_enc = 0; uint16_t failcount = 0; @@ -1279,7 +1270,7 @@ bool TMC4671::checkEncoder(){ ErrorHandler::addError(Error(ErrorCode::encoderReversed,ErrorType::warning,"Encoder direction reversed during check")); } - setFluxTorque(0, 0); + rampFlux(0, 100); setPhiE_ext(0); setPhiEtype(lastphie); setMotionMode(lastmode,true); @@ -2063,6 +2054,22 @@ void TMC4671::setFluxTorqueFF(int16_t flux, int16_t torque){ writeReg(0x65, (flux & 0xffff) | (torque << 16)); } +/** + * Ramps flux from current value to a target value over a specified duration + */ +void TMC4671::rampFlux(uint16_t target,uint16_t time_ms){ + uint16_t startFlux = readReg(0x64) & 0xffff; + int32_t stepsize = (target - startFlux) / std::max(1, time_ms/2); + if(stepsize == 0){ + stepsize = startFlux < target ? 1 : -1; + } + uint16_t flux = startFlux; + while(abs(target - flux) >= abs(stepsize)){ + flux+=stepsize; + setFluxTorque(std::max(0,flux), 0); + Delay(2); + } +} void TMC4671::setPids(TMC4671PIDConf pids){ curPids = pids; @@ -2272,10 +2279,7 @@ void TMC4671::estimateABNparams(){ setPhiEtype(PhiE::ext); setFluxTorque(0, 0); setMotionMode(MotionMode::torque,true); - for(int16_t flux = 0; flux <= bangInitPower; flux+=10){ - setFluxTorque(flux, 0); - Delay(5); - } + rampFlux(bangInitPower, 1000); int16_t phiE_abn = readReg(0x2A)>>16; int16_t phiE_abn_old = 0; @@ -2299,7 +2303,7 @@ void TMC4671::estimateABNparams(){ } setTmcPos(pos+getPos()); - setFluxTorque(0, 0); + rampFlux(0, 100); setPhiEtype(lastphie); setMotionMode(lastmode,true); @@ -2327,10 +2331,7 @@ void TMC4671::estimateExtEnc(){ setPhiEtype(PhiE::ext); setFluxTorque(0, 0); setMotionMode(MotionMode::torque,true); - for(int16_t flux = 0; flux <= bangInitPower; flux+=10){ - setFluxTorque(flux, 0); - Delay(5); - } + rampFlux(bangInitPower, 1000); int16_t phiE_enc = getPhiEfromExternalEncoder(); int16_t phiE_enc_old = 0; int16_t rcount=0,c = 0; // Count how often direction was in reverse @@ -2348,7 +2349,7 @@ void TMC4671::estimateExtEnc(){ } } - setFluxTorque(0, 0); + rampFlux(0, 100); setPhiEtype(lastphie); setMotionMode(lastmode,true); diff --git a/Firmware/FFBoard/UserExtensions/Src/mainclass_chooser.cpp b/Firmware/FFBoard/UserExtensions/Src/mainclass_chooser.cpp index 4f9f5998..3730a256 100644 --- a/Firmware/FFBoard/UserExtensions/Src/mainclass_chooser.cpp +++ b/Firmware/FFBoard/UserExtensions/Src/mainclass_chooser.cpp @@ -30,6 +30,7 @@ #endif // Add all classes here +#ifndef CLASSREGISTRY_OVERRIDE const std::vector> class_registry = { add_class(0), @@ -60,5 +61,6 @@ const std::vector> class_registry = add_class() }; +#endif