YukMingLaw / ArduinoJoystickWithFFBLibrary

An Arduino Joystick Library With Force Feedback Feature
GNU Lesser General Public License v3.0
208 stars 55 forks source link

Gains #5

Open pkaser opened 4 years ago

pkaser commented 4 years ago

It appears gains should be set in setup() and not before as in your example.

YukMingLaw commented 4 years ago

In fact, this is not important, as long as it is called before getForce(), because these two interfaces are used to pass the array address, otherwise it will cause a null pointer exception.

pkaser commented 4 years ago

It is important because your example wont compile and gives and error. I posted this so that you could adjust your example so other people that aren't experienced programmers will be able to get their code to compile.

X spring forces also seem to always calculate out to 0. Y seems to work fine, but I am double checking my code to verify I havent made a typo.

YukMingLaw commented 4 years ago

The example code just shows the calling process, it is not compilable.

Check whether the effect params settings are correct and whether the X axis is used as the action axis in the game.

pkaser commented 4 years ago

I guess if you want to have examples that work or dont is up to you.

The effect params are set. the X and Y axis are reporting correct values. The X force is always 0. If I swap the effect params I still only get Y forces calculated. I am using ForceTest, not a game. It simulates a lot of the FFB variables.

YukMingLaw commented 4 years ago

Could you send me the ForceTset please?I will check it later.

YukMingLaw commented 4 years ago

as well as your code.

pkaser commented 4 years ago

Here is ForceTest.exe:

https://www.dirks-software.ca/downloads/ForceTest.exe

pkaser commented 4 years ago

Here is my current code. I havent figured out the effects yet, like damper, inertia, friction, etc setting yet so they may be all wrong the way I have them implemented. Same with almost everything in here. I'm new to Arduino. It is a joystick made from a Leonardo, a MotoShield, a 12v/2amp power supply, and an old Microsoft Sidewinder Pro Force Feedback V1 that has had all the electronics removed. I am using only the motors and the yoke and have 3D printed a temporary testing mounting bracket. 90% of it works great with XPForce with X-Plane 11.41.

I really appreciate how much you have done to make this happen, and I happily share my code for anyone else trying to do the same thing.

`#include "Joystick.h"

include "Encoder.h"

int32_t forces[2] = { 0 };

long posX; long posY;

int centerX; int centerY;

int lastX = 0; int lastY = 0;

// Motor int dirX = 12; int dirY = 13;

int brakeX = 9; // NIU int brakeY = 8; // NIU

int motorX = 3; // int motorY = 11; //

//current draw on motors int loadX = A0; int loadY = A1;

// joystick encoders int encoderX1 = 0; int encoderX2 = 1; int encoderY1 = 2; int encoderY2 = 4;

int xDirection = LOW; int yDirection = LOW; int centerFound = LOW;

int dur = 2; int strength = 100;

long oldX = -999; long oldY = -999;

const int loopDelay = 20;

int minX = 0; int maxX = 0; int minY = 0; int maxY = 0;

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_JOYSTICK, 0, 0, // Button Count, Hat Switch Count true, true, false, // X and Y, but no Z Axis false, false, false, // No Rx, Ry, or Rz false, false, // No rudder or throttle false, false, false); // No accelerator, brake, or steering

Gains gain[2]; EffectParams effects[2];

//

Encoder encoderX(encoderX1, encoderX2); Encoder encoderY(encoderY1, encoderY2);

void setup() { Serial.begin(9600); delay(2000); //Give the serial port time to catch up so we can debug Serial.println("Setting up..."); pinMode(dirX, OUTPUT); //Initiates Motor Channel X pin pinMode(dirY, OUTPUT); //Initiates Motor Channel Y pin

Joystick.begin(true); doSetGains(); }

void loop(){ if (centerFound == 0){ Serial.println("--Centering"); doFindCenter(); } doJoystickStuff(); doFFBStuff(); delay(loopDelay); }

void doFindCenter(){ int cDur = 80; int cStrength = 255; int tXDir; int tYDir; int tPosX; int tPosY;

doMoveX(cStrength,cDur,HIGH); maxX = stopXMove(); doMoveX(cStrength,cDur,LOW);
minX = stopXMove(); int centerX = (minX + maxX)/2; doMoveY(cStrength,cDur,HIGH); maxY = stopYMove(); doMoveY(cStrength,cDur,LOW);
minY = stopYMove(); int centerY = (minY + maxY)/2;

centerX = ((minX + maxX)/2)-2; centerY = ((minY + maxY)/2)-2;

Joystick.setXAxisRange(minX,maxX); Joystick.setYAxisRange(minY,maxY); tPosX = encoderX.read(); tPosY = encoderY.read(); do { //center X
if (centerX > tPosX){tXDir = HIGH;} else {tXDir = LOW;} doMoveX(255,2,tXDir); tPosX = stopXMove();

} 
while (tPosX != centerX);

do { //center Y
if (centerY > tPosY){tYDir = HIGH;} else {tYDir = LOW;} doMoveY(255,2,tYDir); tPosY = stopYMove();

} 
while (tPosY != centerY);
stopXMove();
stopYMove();
centerFound = 1;

}

int stopXMove(){ return doMoveX(0, 10, HIGH); }

int stopYMove(){ return doMoveY(0, 10, HIGH); }

int doMoveX(int tStrength, int tDuration, int tDirection){ digitalWrite(dirX, tDirection); //High=Forward / Low=Reverse analogWrite(motorX, tStrength); //Spins the motor on Channel A at full speed delay(tDuration); // analogWrite(motorX, 0); //Stops motor delay(2); return encoderX.read(); }

int doMoveY(int tStrength, int tDuration, int tDirection){ digitalWrite(dirY, tDirection); //High=Forward / Low=Reverse analogWrite(motorY, tStrength); //Spins the motor on Channel A at full speed delay(tDuration); // analogWrite(motorY, 0); //Stops motor delay(2); return encoderY.read(); }

void doFFBStuff(){ //}

}

void doJoystickStuff(){

posX = encoderX.read(); posY = encoderY.read();

Joystick.setXAxis(posX); Joystick.setYAxis(posY);

effects[0].springMaxPosition = maxX/2; effects[1].springMaxPosition = maxY/2; effects[0].frictionMaxPositionChange = lastX - posX; effects[1].frictionMaxPositionChange = maxY; effects[0].inertiaMaxAcceleration = maxX; effects[1].inertiaMaxAcceleration = 100; effects[0].damperMaxVelocity = 10; effects[1].damperMaxVelocity = 100;

effects[0].springPosition = posX; effects[1].springPosition = posY; effects[0].frictionPositionChange = lastX - posX; effects[1].frictionPositionChange = lastY - posY; effects[0].inertiaAcceleration = 100; effects[1].inertiaAcceleration = 100; effects[0].damperVelocity=100; effects[1].damperVelocity=100;

Joystick.setEffectParams(effects); Joystick.getForce(forces);

int xMoveDir = 0; int yMoveDir = 0; //Get Force [-255,255] you can set PWM with this value Serial.println(""); Serial.print(" - XF: "); Serial.print(forces[0]); Serial.print(" YF: "); Serial.print(forces[1]); //if (forces[0] != 0 || forces[1] != 0 ){ if (forces[0]<0){ xMoveDir = LOW; } else if (forces[0]>0){ xMoveDir = HIGH; } if (forces[1]<0){ yMoveDir = LOW; } else if (forces[1]>0){ yMoveDir = HIGH; } if (forces[0]!=0){ doMoveX(abs(forces[0]),dur,xMoveDir); } else { doMoveX(0,2,xMoveDir); }; if (forces[1]!=0) { doMoveY(abs(forces[1]),dur,yMoveDir); } else { doMoveY(0,2,yMoveDir); };

lastX = posX; lastY = posY;

}

void doSetGains(){ //set x axis gains gain[0].totalGain = 100; gain[0].constantGain = 100; gain[0].rampGain = 100; gain[0].squareGain = 100; gain[0].sineGain = 100; gain[0].triangleGain = 100; gain[0].sawtoothdownGain = 100; gain[0].sawtoothupGain = 100; gain[0].springGain = 100; gain[0].damperGain = 100; gain[0].inertiaGain = 100; gain[0].frictionGain = 100;

//set y axis gains gain[1].totalGain = 100; gain[1].constantGain = 100; gain[1].rampGain = 100; gain[1].squareGain = 100; gain[1].sineGain = 100; gain[1].triangleGain = 100; gain[1].sawtoothdownGain = 100; gain[1].sawtoothupGain = 100; gain[1].springGain = 100; gain[1].damperGain = 100; gain[1].inertiaGain = 100; gain[1].frictionGain = 100;

Joystick.setGains(gain);

} `

YukMingLaw commented 4 years ago

Hi,there is no wrong in your code. I Traced the USB report output which from ForceTest.It set the multi-axis ffb paramers in a different way,it may take me a few more days to figure this out.

ZockZock commented 3 years ago

Hello, fist thank you very much for your work. I try to build an Yoke with your library and i have following components in use: Arduino Leonardo and two BTS7960B H-Bridges. I used the Code from "pkaser" and have now the Problem, that the Y axis work great with all Effects in XPForce, but the X axis wont work in XPForce. In the TestForce tool, the X axis generate Force but no Effects. Has anybody an Idea, what the Problem is?

"#include "Joystick.h"

include "Encoder.h"

int32_t forces[2] = {0};

long posX; long posY;

int centerX; int centerY;

int lastX = 0; int lastY = 0;

// MotorX int motorXR = 5; // int motorXL = 6; //

// MotorY int motorYR = 10; // int motorYL = 11; //

// joystick encoders int encoderX1 = 0; int encoderX2 = 1; int encoderY1 = 2; int encoderY2 = 3;

int xDirection = LOW; int yDirection = LOW; int centerFound = LOW;

int dur = 2; int strength = 100;

long oldX = -999; long oldY = -999;

const int loopDelay = 5;

int minX = 0; int maxX = 0; int minY = 0; int maxY = 0;

//X-axis & Y-axis REQUIRED Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_JOYSTICK, 0, 0, // Button Count, Hat Switch Count true, true, false, // X and Y, but no Z Axis false, false, false, // No Rx, Ry, or Rz false, false, // No rudder or throttle false, false, false); // No accelerator, brake, or steering

Gains gain[2]; EffectParams effects[2];

//

Encoder encoderX(encoderX1, encoderX2); Encoder encoderY(encoderY1, encoderY2);

void setup() { Serial.begin(9600); delay(2000); //Give the serial port time to catch up so we can debug Serial.println("Setting up...");

Joystick.begin(true); doSetGains(); }

void loop() { if (centerFound == 0) { Serial.println("--Centering"); doFindCenter(); } doJoystickStuff(); doFFBStuff(); delay(loopDelay); }

void doFindCenter() { int cDur = 1000; int cStrength = 50; int tXDir; int tYDir; int tPosX; int tPosY;

doMoveX(cStrength, cDur, HIGH); maxX = stopXMove(); Serial.println(maxX); doMoveX(cStrength, cDur, LOW); minX = stopXMove(); int centerX = (minX + maxX) / 2; doMoveY(cStrength, cDur, HIGH); maxY = stopYMove(); Serial.println(maxY); doMoveY(cStrength, cDur, LOW); minY = stopYMove(); int centerY = (minY + maxY) / 2;

centerX = ((minX + maxX) / 2) - 2; centerY = ((minY + maxY) / 2) - 2;

Joystick.setXAxisRange(minX, maxX); Joystick.setYAxisRange(minY, maxY); tPosX = encoderX.read(); tPosY = encoderY.read(); do { //center X if (centerX < tPosX) { tXDir = HIGH; } else { tXDir = LOW; } doMoveX(155, 2, tXDir); tPosX = stopXMove();

} while (tPosX != centerX);

do { //center Y if (centerY < tPosY) { tYDir = HIGH; } else { tYDir = LOW; } doMoveY(155, 2, tYDir); tPosY = stopYMove();

} while (tPosY != centerY); // stopXMove(); //stopYMove(); centerFound = 1;

}

int stopXMove() { return doMoveX(0, 10, HIGH); }

int stopYMove() { return doMoveY(0, 10, HIGH); }

int doMoveX(int tStrength, int tDuration, int tDirection) { if (tDirection == HIGH) { analogWrite(motorXL, tStrength); //Spins the motor on Channel A at full speed } else { analogWrite(motorXR, tStrength); //Spins the motor on Channel A at full speed } delay(tDuration); analogWrite(motorXR, 0); //Stops motor analogWrite(motorXL, 0); //Stops motor delay(2); return encoderX.read(); }

int doMoveY(int tStrength, int tDuration, int tDirection) { if (tDirection == HIGH) { // Serial.print("High"); analogWrite(motorYR, tStrength); //Spins the motor on Channel A at full speed } else { analogWrite(motorYL, tStrength); //Spins the motor on Channel A at full speed } delay(tDuration); analogWrite(motorYR, 0); //Stops motor analogWrite(motorYL, 0); //Stops motor delay(2); return encoderY.read(); }

void doFFBStuff() { //}

}

void doJoystickStuff() {

posX = encoderX.read(); posY = encoderY.read();

Joystick.setXAxis(posX); Joystick.setYAxis(posY);

effects[0].springMaxPosition = maxX / 2; effects[1].springMaxPosition = maxY / 2; effects[0].frictionMaxPositionChange = maxX; effects[1].frictionMaxPositionChange = maxY; effects[0].inertiaMaxAcceleration = 100; effects[1].inertiaMaxAcceleration = 100; effects[0].damperMaxVelocity = 100; effects[1].damperMaxVelocity = 100;

effects[0].springPosition = posX; effects[1].springPosition = posY; effects[0].frictionPositionChange = lastX - posX; effects[1].frictionPositionChange = lastY - posY; effects[0].inertiaAcceleration = 100; effects[1].inertiaAcceleration = 100; effects[0].damperVelocity = 100; effects[1].damperVelocity = 100;

Joystick.setEffectParams(effects); Joystick.getForce(forces);

int xMoveDir = 0; int yMoveDir = 0; //Get Force [-255,255] you can set PWM with this value //Serial.println(""); //Serial.print(" - XF: "); //Serial.print(forces[0]); //Serial.print(" YF: "); //Serial.print(forces[1]); if (forces[0] > 0) { xMoveDir = LOW; } else if (forces[0] < 0) { xMoveDir = HIGH; } if (forces[1] < 0) { yMoveDir = LOW; } else if (forces[1] > 0) { yMoveDir = HIGH; } if (forces[0] != 0) { doMoveX(abs(forces[0]), dur, xMoveDir); } else { doMoveX(0, 2, xMoveDir); }; if (forces[1] != 0) { doMoveY(abs(forces[1]), dur, yMoveDir); } else { doMoveY(0, 2, yMoveDir); };

lastX = posX; lastY = posY;

}

void doSetGains() { //set x axis gains gain[0].totalGain = 100; gain[0].constantGain = 100; gain[0].rampGain = 100; gain[0].squareGain = 100; gain[0].sineGain = 100; gain[0].triangleGain = 100; gain[0].sawtoothdownGain = 100; gain[0].sawtoothupGain = 100; gain[0].springGain = 100; gain[0].damperGain = 100; gain[0].inertiaGain = 100; gain[0].frictionGain = 100;

//set y axis gains gain[1].totalGain = 100; gain[1].constantGain = 100; gain[1].rampGain = 100; gain[1].squareGain = 100; gain[1].sineGain = 100; gain[1].triangleGain = 100; gain[1].sawtoothdownGain = 100; gain[1].sawtoothupGain = 100; gain[1].springGain = 100; gain[1].damperGain = 100; gain[1].inertiaGain = 100; gain[1].frictionGain = 100;

Joystick.setGains(gain);

}"

billydragon commented 3 years ago

can you guy post encoder files for test. I can't found compatible library for this. Thank you

fcppenta commented 3 years ago

Can you post your doFFBStuff() function ?

Thank you

Cardoba commented 1 year ago

Here is my current code. I havent figured out the effects yet, like damper, inertia, friction, etc setting yet so they may be all wrong the way I have them implemented. Same with almost everything in here. I'm new to Arduino. It is a joystick made from a Leonardo, a MotoShield, a 12v/2amp power supply, and an old Microsoft Sidewinder Pro Force Feedback V1 that has had all the electronics removed. I am using only the motors and the yoke and have 3D printed a temporary testing mounting bracket. 90% of it works great with XPForce with X-Plane 11.41.

I really appreciate how much you have done to make this happen, and I happily share my code for anyone else trying to do the same thing.

`#include "Joystick.h" #include "Encoder.h"

int32_t forces[2] = { 0 };

long posX; long posY;

int centerX; int centerY;

int lastX = 0; int lastY = 0;

// Motor int dirX = 12; int dirY = 13;

int brakeX = 9; // NIU int brakeY = 8; // NIU

int motorX = 3; // int motorY = 11; //

//current draw on motors int loadX = A0; int loadY = A1;

// joystick encoders int encoderX1 = 0; int encoderX2 = 1; int encoderY1 = 2; int encoderY2 = 4;

int xDirection = LOW; int yDirection = LOW; int centerFound = LOW;

int dur = 2; int strength = 100;

long oldX = -999; long oldY = -999;

const int loopDelay = 20;

int minX = 0; int maxX = 0; int minY = 0; int maxY = 0;

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_JOYSTICK, 0, 0, // Button Count, Hat Switch Count true, true, false, // X and Y, but no Z Axis false, false, false, // No Rx, Ry, or Rz false, false, // No rudder or throttle false, false, false); // No accelerator, brake, or steering

Gains gain[2]; EffectParams effects[2];

//

Encoder encoderX(encoderX1, encoderX2); Encoder encoderY(encoderY1, encoderY2);

void setup() { Serial.begin(9600); delay(2000); //Give the serial port time to catch up so we can debug Serial.println("Setting up..."); pinMode(dirX, OUTPUT); //Initiates Motor Channel X pin pinMode(dirY, OUTPUT); //Initiates Motor Channel Y pin

Joystick.begin(true); doSetGains(); }

void loop(){ if (centerFound == 0){ Serial.println("--Centering"); doFindCenter(); } doJoystickStuff(); doFFBStuff(); delay(loopDelay); }

void doFindCenter(){ int cDur = 80; int cStrength = 255; int tXDir; int tYDir; int tPosX; int tPosY;

doMoveX(cStrength,cDur,HIGH); maxX = stopXMove(); doMoveX(cStrength,cDur,LOW); minX = stopXMove(); int centerX = (minX + maxX)/2; doMoveY(cStrength,cDur,HIGH); maxY = stopYMove(); doMoveY(cStrength,cDur,LOW); minY = stopYMove(); int centerY = (minY + maxY)/2;

centerX = ((minX + maxX)/2)-2; centerY = ((minY + maxY)/2)-2;

Joystick.setXAxisRange(minX,maxX); Joystick.setYAxisRange(minY,maxY); tPosX = encoderX.read(); tPosY = encoderY.read(); do { //center X if (centerX > tPosX){tXDir = HIGH;} else {tXDir = LOW;} doMoveX(255,2,tXDir); tPosX = stopXMove();

} 
while (tPosX != centerX);

do { //center Y if (centerY > tPosY){tYDir = HIGH;} else {tYDir = LOW;} doMoveY(255,2,tYDir); tPosY = stopYMove();

} 
while (tPosY != centerY);
stopXMove();
stopYMove();
centerFound = 1;

}

int stopXMove(){ return doMoveX(0, 10, HIGH); }

int stopYMove(){ return doMoveY(0, 10, HIGH); }

int doMoveX(int tStrength, int tDuration, int tDirection){ digitalWrite(dirX, tDirection); //High=Forward / Low=Reverse analogWrite(motorX, tStrength); //Spins the motor on Channel A at full speed delay(tDuration); // analogWrite(motorX, 0); //Stops motor delay(2); return encoderX.read(); }

int doMoveY(int tStrength, int tDuration, int tDirection){ digitalWrite(dirY, tDirection); //High=Forward / Low=Reverse analogWrite(motorY, tStrength); //Spins the motor on Channel A at full speed delay(tDuration); // analogWrite(motorY, 0); //Stops motor delay(2); return encoderY.read(); }

void doFFBStuff(){ //}

}

void doJoystickStuff(){

posX = encoderX.read(); posY = encoderY.read();

Joystick.setXAxis(posX); Joystick.setYAxis(posY);

effects[0].springMaxPosition = maxX/2; effects[1].springMaxPosition = maxY/2; effects[0].frictionMaxPositionChange = lastX - posX; effects[1].frictionMaxPositionChange = maxY; effects[0].inertiaMaxAcceleration = maxX; effects[1].inertiaMaxAcceleration = 100; effects[0].damperMaxVelocity = 10; effects[1].damperMaxVelocity = 100;

effects[0].springPosition = posX; effects[1].springPosition = posY; effects[0].frictionPositionChange = lastX - posX; effects[1].frictionPositionChange = lastY - posY; effects[0].inertiaAcceleration = 100; effects[1].inertiaAcceleration = 100; effects[0].damperVelocity=100; effects[1].damperVelocity=100;

Joystick.setEffectParams(effects); Joystick.getForce(forces);

int xMoveDir = 0; int yMoveDir = 0; //Get Force [-255,255] you can set PWM with this value Serial.println(""); Serial.print(" - XF: "); Serial.print(forces[0]); Serial.print(" YF: "); Serial.print(forces[1]); //if (forces[0] != 0 || forces[1] != 0 ){ if (forces[0]<0){ xMoveDir = LOW; } else if (forces[0]>0){ xMoveDir = HIGH; } if (forces[1]<0){ yMoveDir = LOW; } else if (forces[1]>0){ yMoveDir = HIGH; } if (forces[0]!=0){ doMoveX(abs(forces[0]),dur,xMoveDir); } else { doMoveX(0,2,xMoveDir); }; if (forces[1]!=0) { doMoveY(abs(forces[1]),dur,yMoveDir); } else { doMoveY(0,2,yMoveDir); };

lastX = posX; lastY = posY;

}

void doSetGains(){ //set x axis gains gain[0].totalGain = 100; gain[0].constantGain = 100; gain[0].rampGain = 100; gain[0].squareGain = 100; gain[0].sineGain = 100; gain[0].triangleGain = 100; gain[0].sawtoothdownGain = 100; gain[0].sawtoothupGain = 100; gain[0].springGain = 100; gain[0].damperGain = 100; gain[0].inertiaGain = 100; gain[0].frictionGain = 100;

//set y axis gains gain[1].totalGain = 100; gain[1].constantGain = 100; gain[1].rampGain = 100; gain[1].squareGain = 100; gain[1].sineGain = 100; gain[1].triangleGain = 100; gain[1].sawtoothdownGain = 100; gain[1].sawtoothupGain = 100; gain[1].springGain = 100; gain[1].damperGain = 100; gain[1].inertiaGain = 100; gain[1].frictionGain = 100;

Joystick.setGains(gain);

} `

Hello Pkaser did you find a solution and got it to work perfectly?