Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v1.15.1 #116

Merged
merged 16 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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°).
- 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
2 changes: 1 addition & 1 deletion Firmware/FFBoard/Inc/AnalogSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class AnalogSource : public ChoosableClass, public PersistentStorage{
virtual std::vector<int32_t>* getAxes();
std::vector<int32_t> buf;


static const std::vector<class_entry<AnalogSource>> all_analogsources;

private:

Expand Down
24 changes: 17 additions & 7 deletions Firmware/FFBoard/Inc/Axis.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand All @@ -244,27 +255,26 @@ 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


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<biquad_constant_t,4> filterSpeedCst = { {{ 40, 55 }, { 70, 55 }, { 120, 55 }, {180, 55}} };
const std::array<biquad_constant_t,4> 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};
uint8_t filterProfileId = 1; // Default medium (1) as this is the most common encoder resolution and users can go lower or higher if required.
const float filter_f = 1000; // 1khz
const int32_t intFxClip = 20000;
uint8_t damperIntensity = 30;
FastAvg<float,5> spdlimiterAvg;

uint8_t frictionIntensity = 0;
uint8_t inertiaIntensity = 0;
Expand Down
4 changes: 3 additions & 1 deletion Firmware/FFBoard/Inc/ButtonSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include "cppmain.h"
#include "ChoosableClass.h"
#include "PersistentStorage.h"

#include "vector"

/**
* A button source can return up to 64 buttons
Expand All @@ -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<class_entry<ButtonSource> > all_buttonsources;

protected:
uint16_t btnnum = 0; // Amount of active buttons (valid bitfield length) to report
};
Expand Down
10 changes: 4 additions & 6 deletions Firmware/FFBoard/Inc/Encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/

/*
Expand Down
2 changes: 1 addition & 1 deletion Firmware/FFBoard/Inc/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions Firmware/FFBoard/Inc/ledEffects.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ typedef struct Ledstruct{
int32_t blinks;
GPIO_TypeDef* port;
uint16_t pin;
uint8_t state;
} Ledstruct_t;


Expand All @@ -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_ */
4 changes: 2 additions & 2 deletions Firmware/FFBoard/Inc/voltagesense.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

/*
Expand Down
50 changes: 37 additions & 13 deletions Firmware/FFBoard/Src/Axis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)){
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);

}
Expand Down Expand Up @@ -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;
}

Expand All @@ -506,6 +518,7 @@ void Axis::usbSuspend(){
* Enables motor driver
*/
void Axis::usbResume(){
startForceFadeIn();
if (drv != nullptr){
drv->startMotor();
}
Expand Down Expand Up @@ -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,int32_t>((int32_t)spring*35,0,10000);
idlespringscale = 0.5f + ((float)spring * 0.01f);
}
Expand Down Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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<float,int32_t>( 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<float,int32_t>( 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();
Expand All @@ -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;
Expand All @@ -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<float>(start, 0, 1);
}


/**
* Changes gamepad range in degrees for effect scaling
*/
Expand Down Expand Up @@ -869,11 +892,12 @@ CommandStatus Axis::command(const ParsedCommand& cmd,std::vector<CommandReply>&
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
{
Expand Down Expand Up @@ -925,7 +949,7 @@ CommandStatus Axis::command(const ParsedCommand& cmd,std::vector<CommandReply>&
}
else if (cmd.type == CMDtype::set)
{
uint32_t value = clip<uint32_t, uint32_t>(cmd.val, 0, 2);
uint32_t value = clip<uint32_t, uint32_t>(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);
Expand Down
3 changes: 2 additions & 1 deletion Firmware/FFBoard/Src/EffectsCalculator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <math.h>
#include "EffectsCalculator.h"
#include "Axis.h"

#include "ledEffects.h"


#define EFFECT_STATE_INACTIVE 0
Expand Down Expand Up @@ -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);
}


Expand Down
24 changes: 0 additions & 24 deletions Firmware/FFBoard/Src/Encoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<class_entry<Encoder>> const Encoder::all_encoders =
{
add_class<Encoder, Encoder>(0),

#ifdef LOCALENCODER
add_class<EncoderLocal, Encoder>(2),
#endif

#ifdef MTENCODERSPI
add_class<MtEncoderSPI, Encoder>(4),
#endif
#ifdef BISSENCODER
add_class<EncoderBissC, Encoder>(5),
#endif
#ifdef SSIENCODER
add_class<EncoderSSI, Encoder>(6),
#endif

};

ClassIdentifier Encoder::info ={.name = "None" , .id=CLSID_ENCODER_NONE, .visibility = ClassVisibility::visible};

Expand Down
2 changes: 1 addition & 1 deletion Firmware/FFBoard/Src/SerialFFB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading
Loading