Jump to content

Recommended Posts

Posted
3 hours ago, slimheli said:

Wow. This looks amazing! What material and thickness did you specify for the metal bits?

I followed propeler's design specs so I wouldn't have to recalculate bend radii. Cheap and cheerful A36 mild steel @ 3mm. With the slots there's some wiggle room, but my holes are lined up basically in the middle of the slots.

Eventually I may need to add some sort of rust preventative though.

 

The thickness is needed for the tapped holes mounting the main gimbal frame bearings. As designed there's no space for hex nuts there. If you lengthened the shoulder on the arm frames and spaced out the sheet metal plates and mounting holes accordingly you could get away with using thinner steel that you could bend in your garage.

 

Arduino -> oDrive serial connection keeps dropping due to noise, and Amazon has lost two separate ferrite ring orders. Why did I have to forget those on my digikey order? I've been mourning the loss of Radioshack and Fry's recently.

Posted

@theperson which encoders did you end up using? The as5048a? I have previously used the odrive board with the AMT102 and would like to keep using these if possible, would they work? When you finish the wiring for your setup would you mind posting the final arduino code you use and a quick schematic for which pins on the odrive and arduino you are using for the connection.

Keep up the great work

Posted (edited)
30 minutes ago, robjos1 said:

@theperson which encoders did you end up using? The as5048a? I have previously used the odrive board with the AMT102 and would like to keep using these if possible, would they work? When you finish the wiring for your setup would you mind posting the final arduino code you use and a quick schematic for which pins on the odrive and arduino you are using for the connection.

Keep up the great work

Correct, I'm using the as5048a's. While using incremental encoders is probably do-able, its a lot simpler to have the odrive already know where it is at startup without needing to do an index search. Remember that the joystick has limited travel and the motors can't make a full rotation. With the designed gear ratio the motors have a lock-to-lock range of ~half a rotation total (+/- 0.25 rotations each side). With a stick extension I'm only going to be using about half of that available travel on the roll axis, so the 2048ppr resolution of the amt102's might start becoming noticeable.

Edited by theperson
Posted
7 hours ago, slimheli said:

Hey @TomVR, did you see my question regarding the f3d file you posted? It doesn't seem to want to open in Fusion. Any idea what was causing that? I'd like to try printing your case, and maybe adapt it for the ODrive motors I have.

are you cloning the entire repo? If you right click and save as on github it just downloads an html which contains a bunch of useless binary text. You have to either use a git client or download the entire repo 

Posted (edited)

In the gimbal design, has anyone had a problem with a clunk on the pitch axis? Feels like the "GIMBAL_CORE_JOINT.STL" part is shifting back and forth while crossing the center on the pitch, making a popping noise and a felt clunk. Only happens when there is an external load on the axis from the gear teeth (or my cam springs)

recorded a video of it happening.

https://imgur.com/a/QQP1L1s

Edited by TomVR
Posted
9 hours ago, robjos1 said:

@theperson Out of interest which magnets did you fix to the end of the motor to control the AS5048A?

I'm using the development boards, which each came with a small round magnet (AS5000-MD6H-2 diametric magnet). I printed the encoder mounts such that the surface of the chip would be 1.5mm away from the magnet, since the datasheet recommends a 0.5-2.5mm range.

 

No luck with shielding and ferrite rings fixing my odrive->arduino communication problem. Posting about it here in the odrive forums.

 

@propeler let me know if you need any testers for the odrive firmware 😉

Posted

Downgrading the odrive firmware to 0.5.1 fixed all my serial dropout problems.

I kludged together some code using this library on an arduino pro micro

protip: spring effects in that library expect you to set your joystick range as (-min,max), not (0,max) like it shows in the example [at least to make effects in DCS work]

 

I've spent about 30 minutes just making sure it works right and getting gains in the right neighborhood to where they won't break the gimbal.

I'll get my setup mounted properly and clean up the code in the next couple days and post some more.

its_working_star_wars.gif

  • Like 2
Posted

Brilliant news, well done there! If you could post up your code and pertinent odrive settings with a quick list of which pins you used to hook it all up that would be amazing!

Thanks again for all your efforts

  • Like 1
Posted
On 12/15/2021 at 9:58 AM, theperson said:

I kludged together some code using this library on an arduino pro micro

Would you mind sharing your code? I just finished my mechanics and am about to tackle exactly this. I was actually looking at fino, but it seems it does not really matter which library to use 😅

I'm going direct drive with hoverboard motors by the way, landed a nice deal on a used hoverboard without charger for 30€. I was lucky the seller did not check used prices on those boards, a charger would have only been 15€ on amazon ...

Posted (edited)
On 12/16/2021 at 8:41 AM, 0xDEADBEEF said:

Would you mind sharing your code? I just finished my mechanics and am about to tackle exactly this. I was actually looking at fino, but it seems it does not really matter which library to use 😅

I'm going direct drive with hoverboard motors by the way, landed a nice deal on a used hoverboard without charger for 30€. I was lucky the seller did not check used prices on those boards, a charger would have only been 15€ on amazon ...

Be warned, it's still very much in the kludged-together state. I'm thinking of trying out the Fino library instead, since he's got nice rate control and the friction position change/velocity calculations set up already.

It's a bit jittery in DCS, and I'm not sure quite sure how much of that is forcefeedback vibration or jittery encoder vibration.

My problems with the Odrive UART not responding to the GetPosition() calls were solved by flashing the older 0.5.1 firmware. I also downgraded the odrivetool command line to keep things compatible.

BAD CODE USED TO BE HERE,
REMOVED TO SAVE THE WORLD FROM MY INEPTITUDE
LOOK AT A LATER POST BELOW FOR BETTER CODE

I included the Ewma library for input filtering, which is available to install through the arduino library manager window. For the ArduinoJoystickWithFFBLibrary and the OdriveArduino library you'll have to download them separately and move them into your ~/Documents/Arduino/libraries folder.

And these are the commands for setting up the odrive parameters with the as5048a encoders:

//Initial Setup
odrv0.axis0.motor.config.resistance_calib_max_voltage = 4
odrv0.axis0.encoder.config.abs_spi_cs_gpio_pin = 6
odrv0.axis0.encoder.config.mode = ENCODER_MODE_SPI_ABS_AMS
odrv0.axis0.encoder.config.cpr = 2**14
odrv0.axis1.motor.config.resistance_calib_max_voltage = 4
odrv0.axis1.encoder.config.abs_spi_cs_gpio_pin = 7
odrv0.axis1.encoder.config.mode = ENCODER_MODE_SPI_ABS_AMS
odrv0.axis1.encoder.config.cpr = 2**14
odrv0.config.uart_baudrate = 500000
...with the 0.5.1 firmware the brake resistor is just assumed to be connected
...for the newer firmwares you'll need to configure it
odrv0.config.enable_brake_resistor = True
...I set the current limits to 6, I dont really need more with my motors
odrv0.axis0.motor.config.current_lim = 6
odrv0.axis1.motor.config.current_lim = 6
...raise the velocity limits to 6rev/s, you can pretty easily hit the 2rev/s default
odrv0.axis0.controller.config.vel_limit = 6
odrv0.axis1.controller.config.vel_limit = 6
odrv0.save_configuration()
odrv0.reboot()

//Motor and Encoder Calibration
//do these with the motors free to spin, not hooked up to the gimbal
odrv0.axis0.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE
odrv0.axis0.motor.config.pre_calibrated = True
odrv0.axis0.encoder.config.pre_calibrated = True
odrv0.axis1.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE
odrv0.axis1.motor.config.pre_calibrated = True
odrv0.axis1.encoder.config.pre_calibrated = True
odrv0.save_configuration()
odrv0.reboot()

odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis1.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
...this should turn on the motors and have them hold position where they are
...try turning the motors by hand and see if they push back
...if motors aren't on check for errors by running:
dump_errors(odrv0)
...you can follow the Tuning section to tune the gains: https://docs.odriverobotics.com/control.html
...but it might be better to do that with the belts connected

//Anticogging Calibration
//do these with the motors free to spin, not hooked up to the gimbal
odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis0.controller.start_anticogging_calibration()
odrv0.axis1.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis1.controller.start_anticogging_calibration()
...wait for anticogging to finish, it can take a while like 10 minutes
...you can increase pos_gain and vel_integrator_gain by a factor of 10 to speed it up, but remember to set them back
...you can check if anticogging calibration is finished by running:
odrv0.axis0.controller.config.anticogging.calib_anticogging
...and if it returns True, calibration is still running, it will return False when its complete
odrv0.axis0.controller.config.anticogging.anticogging_enabled = True
odrv0.axis1.controller.config.anticogging.anticogging_enabled = True
odrv0.save_configuration()
odrv0.reboot()

 

 

odrive wiring diagram.png

Edited by theperson
  • Like 3
  • Thanks 1
Posted

Very nice, thank you! I had no clue there was an odrive library for arduino 😆 This alone will save me hours!

I had the original MS FFB Pro in the 90s, I think it's still in my basement. Can't wait to finally fly with force feedback again with a proper grip and more torque 🚀

thank you guys! What a fun project!! 👏

Posted

@theperson Nice work!

You said that downgrading the firmware helped with SPI issues? These have plagued my setup throughout, to the point that I've ordered two separate single-axis ODrive clones to get around the issue - Axis1 seemed to have SPI_COM_FAIL errors on calibration every time while Axis0 stayed ok.

I tried with tri-state buffers but these didn't seem to help with the dropouts, though they seemed to work as the data was still being passed on when checking SHADOW_COUNT.

At the moment I've got some jitter on both encoders, where it wasn't present when I was building a few months ago - I suspect I might have some alignment issues on the magnet/motor, so I'll have a bit of a re-think of the encoder enclosures as they were a bit... hastily built, shall we say.

Right now I have it all set up as a simple "return to center" stick, pedals and throttle all ready, so I just need to add the Arduino Due (which has enough com lines to speak to two ODrives simultaneously) and bodge together some FINO/ODrive Arduino example code - all the code you've posted is going to come in *VERY* handy for that, and I thank you greatly for providing it.

I've also given up on the 4-motor configuration I was hoping for - two hoverboard motors is absolutely enough. I'm not sure what the strength of the motors is currently running at, but I've dialled it down a lot, and the grip mount (VKB Gunfighter MKIII) and stick seem a little bit flexy when pushed to the far diagonals - not really enough to worry about, but enought to make me think I'd really like a solid metal grip...

Posted (edited)
3 hours ago, SquidgyB said:

@theperson Nice work!

You said that downgrading the firmware helped with SPI issues? These have plagued my setup throughout, to the point that I've ordered two separate single-axis ODrive clones to get around the issue - Axis1 seemed to have SPI_COM_FAIL errors on calibration every time while Axis0 stayed ok.

I tried with tri-state buffers but these didn't seem to help with the dropouts, though they seemed to work as the data was still being passed on when checking SHADOW_COUNT.

Sorry, but the comms issues I was having was just with the serial output to the arduino. My SPI comms seem to be solid. With the motors turned on the odrive would just stop responding to GetPosition() calls after a couple seconds. It would take longer at slower baudrates but it would eventually happen. The strange thing was the SetPosition() commands going the other way would get through just fine, even when the odrive stopped responding to position requests.

Do you have ferrite toroids on the motor leads, shielding wrap on your motor wires and encoder wires, grounding said shielding wrap to the V- input pad? Also just routing the encoder cables away from the motors and motor leads.

A word of warning on the Due - the ArduinoJoystickWithFFBLibrary and Fino are built around the usb comms of an ATmega32u4 chip. I spent a little while trying to see if I could run it on a SAMD51 chip, and couldn't figure it out.

I've determined that the jitter is the encoder data, definitely not a commanded vibration input. With friction turned on it gets pretty horrible with how it's trying to apply friction forces to the constantly changing position.

I'm going to take a look at redoing my encoder/magnet mounts to see if I can reduce some jitter that wayWith how much I've turned down my motors I could probably eliminate the belts and just direct-drive the gimbal, so I'll figure out how best to mount everything for that. I figure the loss of encoder resolution will be worth it.

Edited by theperson
  • Like 1
Posted
3 hours ago, theperson said:

Sorry, but the comms issues I was having was just with the serial output to the arduino. My SPI comms seem to be solid. With the motors turned on the odrive would just stop responding to GetPosition() calls after a couple seconds. It would take longer at slower baudrates but it would eventually happen. The strange thing was the SetPosition() commands going the other way would get through just fine, even when the odrive stopped responding to position requests.

Do you have ferrite toroids on the motor leads, shielding wrap on your motor wires and encoder wires, grounding said shielding wrap to the V- input pad? Also just routing the encoder cables away from the motors and motor leads.

A word of warning on the Due - the ArduinoJoystickWithFFBLibrary and Fino are built around the usb comms of an ATmega32u4 chip. I spent a little while trying to see if I could run it on a SAMD51 chip, and couldn't figure it out.

I've determined that the jitter is the encoder data, definitely not a commanded vibration input. With friction turned on it gets pretty horrible with how it's trying to apply friction forces to the constantly changing position.

I'm going to take a look at redoing my encoder/magnet mounts to see if I can reduce some jitter that wayWith how much I've turned down my motors I could probably eliminate the belts and just direct-drive the gimbal, so I'll figure out how best to mount everything for that. I figure the loss of encoder resolution will be worth it.

 

Ah, I see. Yep, I've worked through a lot of variations to get where it is now and never quite figured out what was wrong, the only way to work around it I've found that consistently works is just to not use the second axis! I've got RJ45 breakouts with each signal wire paired with a ground wire, shielded enclosures, toroids on the motor cables routing cables as best I can away from each other...

As for the Due, FINO does have an "experimental" branch for the Due, I haven't fully tested it but it can be flashed and shows up in Windows as a joystick - but I have a plethora of Arduino, RPi and teensy controllers, so one way or another I'll make it work hehe!

  • Like 1
Posted (edited)

My previous arduino code is garbage and I am deleting it out of shame.

Here is the much much better Fino implementation.

Download the Fino library, put it in your ~/Documents/Arduino/libraries folder and replace the Fino.ino and joystick.ino files with the code below.

I'm also filtering the input encoder position with a simple MovingAverage library - available through the library manager as MovingAverager by Ian Carey

 

I have my DCS controls FF_Tune menu set as follows:

Trimmer Force = 75
Shake Force = 5
Swap Axis = unchecked
Invert X = unchecked
Invert Y = unchecked

 

Fino.ino

#define DEBUGNO
// the digits mean Mmmmrrr (M=Major,m=minor,r=revision)
#define SKETCH_VERSION 3000001

#include "src/Joystick.h"
#include "config.h"
#include "order.h"
#include <ODriveArduino.h>
#include <ODriveEnums.h>
#include <HardwareSerial.h>
#include <MovingAverage.h>

// Printing with stream operator helper functions
template<class T> inline Print& operator <<(Print &obj,     T arg) {
  obj.print(arg);
  return obj;
}
template<>        inline Print& operator <<(Print &obj, float arg) {
  obj.print(arg, 4);
  return obj;
}
// -------------------------
// Various global variables
// -------------------------
unsigned long lastEffectsUpdate;
unsigned long nextJoystickMillis;
unsigned long nextEffectsMillis;

// --------------------------
// Joystick related variables
// --------------------------
#define minX -10000
#define maxX 10000
#define minY -10000
#define maxY 10000

//forces[] has a range of +/-10000, so this sets a safe motor amperage
float motorAmps = 1;
float forceToAmps;

//sets the values of all the periodic function gains
float periodicGain = 0.05;

bool is_connected = false;
bool forces_requested = false;
bool pos_updated = false;

int16_t pos[2] = {0, 0};
int lastX;
int lastY;
int lastVelX;
int lastVelY;
int lastAccelX;
int lastAccelY;

float scaleFactorX;
float scaleFactorY;

//Input filters - the number is the # of readings its averageing, higher number more stable but slower, lower number less filtered but faster response
int readX;
MovingAverage filterX(4);
int readY;
MovingAverage filterY(4);

//because odrive reports in motor rotations we have to do some converting
//these are the limits and center for my joystick in odrive-reported-rotations
//maxX is joystick to the right, maxY is joystick pushed away from you
float maxXRot = 0.13;
float minXRot = -0.11;
float maxYRot = -0.23;
float minYRot = 0.17;
float centerXRot = 0.02;
float centerYRot = -0.03;


//Hardware serial port
HardwareSerial& odrive_serial = Serial1;

// ODrive object
ODriveArduino odrive(odrive_serial);

EffectParams effects[2];
int32_t forces[2] = {0, 0};

Joystick_ Joystick(
    JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_JOYSTICK,
    0, 0, // Button Count, Hat Switch Count
    true, true, false, // X, Y, Z
    false, false, false, // Rx, Ry, Rz
    false, false); // rudder, throttle

void setup() {
    //Makes uploading the new sketch easier, because serial can get flooded
    //if you have trouble hit the reset pin as it finishes compiling
    delay(2000);
    setupJoystick();

    // setup communication
    Serial.begin(SERIAL_BAUD);
    // setup timing and run them as soon as possible
    lastEffectsUpdate = 0;
    nextJoystickMillis = 0;
    nextEffectsMillis = 0;
}

void loop(){
    //get_messages_from_serial();
    //i setup my odrive as motor 1 is x, 0 is y :bigbrain:
    readX = (int)((odrive.GetPosition(1)-centerXRot)*scaleFactorX);
    readY = (int)((odrive.GetPosition(0)-centerYRot)*scaleFactorY);
    //I'm sure this wont cause any issues in the future
    pos_updated = true;
    pos[0] = filterX.addSample(readX);
    pos[1] = filterY.addSample(readY);
    //Serial << "x" << pos[0] << ", y" << pos[1] << "\n";
    unsigned long currentMillis;
    currentMillis = millis();
    // do not run more frequently than these many milliseconds
    if (currentMillis >= nextJoystickMillis) {
        updateJoystickPos();
        nextJoystickMillis = currentMillis + 2;

        // we calculate condition forces every 100ms or more frequently if we get position updates
        if (currentMillis >= nextEffectsMillis || pos_updated) {
            updateEffects(true);
            nextEffectsMillis = currentMillis + 100;
            pos_updated = false;
        } else {
            // calculate forces without recalculating condition forces
            // this helps having smoother spring/damper/friction
            // if our update rate matches our input device
            updateEffects(false);
        }
        //Again, i have mine set up as X axis is motor 1, Y axis is motor 0
        odrive.SetCurrent(1,(float)forces[0]*forceToAmps);
        odrive.SetCurrent(0,(float)-forces[1]*forceToAmps);
        //Serial << "fx" << (forces[0]*forceToAmps) << ", fy" << (forces[1]*forceToAmps) << "\n";
    }
}

 

joystick.ino

void setupJoystick() {
    forceToAmps = motorAmps/10000;
    scaleFactorX = (2*maxX) / (maxXRot - minXRot);
    scaleFactorY = (2*maxY) / (maxYRot - minYRot);
    Joystick.setXAxisRange(minX, maxX);
    Joystick.setYAxisRange(minY, maxY);
    Joystick.begin();
    Gains gains[FFB_AXIS_COUNT];
    gains[0].springGain = 0.7;
    gains[1].springGain = 0.7;
    gains[0].frictionGain = 0.25;
    gains[1].frictionGain = 0.25;
    gains[0].squareGain = periodicGain;
    gains[1].squareGain = periodicGain;
    gains[0].sineGain = periodicGain;
    gains[1].sineGain = periodicGain;
    gains[0].triangleGain = periodicGain;
    gains[1].triangleGain = periodicGain;
    gains[0].sawtoothupGain = periodicGain;
    gains[1].sawtoothupGain = periodicGain;
    gains[0].sawtoothdownGain = periodicGain;
    gains[1].sawtoothdownGain = periodicGain;
    
    Joystick.setGains(gains);
    odrive_serial.begin(500000);
    //Serial.println("requesting torque control");
    //sometimes it fails to turn on axis 0, so i dunno, try it twice?
    odrive.run_state(0, AXIS_STATE_CLOSED_LOOP_CONTROL, false);
    delay(100);
    odrive.run_state(1, AXIS_STATE_CLOSED_LOOP_CONTROL, false);
    delay(50);
    odrive.run_state(0, AXIS_STATE_CLOSED_LOOP_CONTROL, false);
}

void updateJoystickPos() {
    Joystick.setXAxis(pos[0]);
    Joystick.setYAxis(pos[1]);
}

void updateEffects(bool recalculate){
    for (int i =0; i < 2; i++) {
        effects[i].frictionMaxPositionChange = 25; // TODO: find proper values for these automatically
        effects[i].inertiaMaxAcceleration = 10;
        effects[i].damperMaxVelocity = 40;
    }

    effects[0].springMaxPosition = maxX;
    effects[1].springMaxPosition = maxY;
    effects[0].springPosition = pos[0];
    effects[1].springPosition = pos[1];

    unsigned long currentMillis;
    currentMillis = millis();
    int16_t diffTime = currentMillis - lastEffectsUpdate;

    if (diffTime > 0 && recalculate) {
        lastEffectsUpdate = currentMillis;
        int16_t positionChangeX = pos[0] - lastX;
        int16_t positionChangeY = pos[1] - lastY;
        int16_t velX = positionChangeX / diffTime;
        int16_t velY = positionChangeY / diffTime;
        int16_t accelX = ((velX - lastVelX) * 10) / diffTime;
        int16_t accelY = ((velY - lastVelY) * 10) / diffTime;
    
        effects[0].frictionPositionChange = velX;
        effects[1].frictionPositionChange = velY;
        effects[0].inertiaAcceleration = accelX;
        effects[1].inertiaAcceleration = accelY;
        effects[0].damperVelocity = velX;
        effects[1].damperVelocity = velY;

        #ifdef DEBUG
        write_order(LOG);
        Serial.print(currentMillis);
        Serial.print("X");
        Serial.print(pos[0]);
        Serial.print("Y");
        Serial.print(pos[1]);
        Serial.print("C");
        Serial.print(positionChangeX);
        Serial.print(",");
        Serial.print(positionChangeY);
        Serial.print("V");
        Serial.print(velX);
        Serial.print(",");
        Serial.print(velY);
        Serial.print("A");
        Serial.print(accelX);
        Serial.print(",");
        Serial.print(accelY);
        #endif

        lastX = pos[0];
        lastY = pos[1];
        lastVelX = velX;
        lastVelY = velY;
        lastAccelX = accelX;
        lastAccelY = accelY;
    } else {
        effects[0].frictionPositionChange = lastVelX;
        effects[1].frictionPositionChange = lastVelY;
        effects[0].inertiaAcceleration = lastAccelX;
        effects[1].inertiaAcceleration = lastAccelY;
        effects[0].damperVelocity = lastVelX;
        effects[1].damperVelocity = lastVelY;
    }

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

    #ifdef DEBUG
    if (diffTime > 0 && recalculate) {
        Serial.print("F");
        Serial.print(forces[0]);
        Serial.print(",");
        Serial.println(forces[1]);
    }
    #endif
}

 

If I turn the gains up too high it'll start oscillating something fierce, but these seem alright for my setup. Maybe direct-driving the gimbals would take out that small springiness of the belt and allow for higher gains?

Edited by theperson
  • Thanks 1
Posted (edited)
On 12/9/2021 at 10:38 AM, TomVR said:

So i've had to put my plans for the project on hold for awhile as the costs of motors + odrive I keep putting into regular life/house stuff instead of this hobby, but just had a really dumb idea of remixing the object-77b cams and cheap skateboard bearings.

https://imgur.com/a/DeUFvlK

The roller at the bottom and the piece that holds it flexes too much so I'm either going to have to make that part from metal or cantilever it with a strap going over the top of the cams to pull it back straight.

Using the miss's hairbands as temp springs.

I actually wonder if having a cam spring, even with the motors engaged could be balanced to "neutralize" the weight of the grip over the long extension. On Cinema camera heads we use a similar system of counterbalance springs to make a 60lb+ camera be able to tilt up and down without being difficult to operate. My thought is having a light cam centering system tuned to keep the grip balanced might help a lot with the motors having to work much less to keep the stick centered.

For now I'm just gonna use it so I get get a working stick and get around to adding the motors much later.

Image from iOS (14).jpg

edit: also in reality it would just be way way easier to take the entire object-77b gimbal and scale it up but damn it I'm too far along now!

 

My concern with using centering springs to “help” the motors would be trimming.  Depending how your aircraft is trimmed the motors may end up fighting the springs.  Also, it would make the stick not work very well for helicopters at all for much the same reason.

On 12/2/2021 at 9:45 PM, Thadiun Okona said:

I love all the creative ideas but still can't fathom why not just let the roll motor/pulley for for a ride as you move the stick in pitch. It's easy to counterbalance the mass and you never saw on the stick in pitch in any form of flying though you might vigorously slam the ailerons from stop to stop.  Even aerobatics pitch inputs are relatively tame but most types of flying you hold steady pitch for long periods and do minute adjustments.

I mean, I understand why it was done on the MSFF II, it makes a smaller/more marketable base that follow domestic joystick expectations but anyone making one of these at this caliber here are not constrained by that yet the trend seems to be towards increasingly large and complex workarounds.  Keeping both motors stationary on the base seems like a solution looking for a problem.

I agree with all this.  Having a very large metal gimbal that the roll axis rides on is the way to go imo.  If I ever replace my propeler-gimbal ffb2 frankenstick, I’m probably going to use this method, possibly direct drive.

Edited by Bard_the_Bowman
Posted
On 12/12/2021 at 5:07 PM, TomVR said:

In the gimbal design, has anyone had a problem with a clunk on the pitch axis? Feels like the "GIMBAL_CORE_JOINT.STL" part is shifting back and forth while crossing the center on the pitch, making a popping noise and a felt clunk. Only happens when there is an external load on the axis from the gear teeth (or my cam springs)

recorded a video of it happening.

https://imgur.com/a/QQP1L1s

 

It may be an alignment issue.  the two gimbal arms have to be aligned almost perfectly to get smooth operation.  and even so I will get very minor "clunks" from time to time.  

Posted (edited)
22 hours ago, Bard_the_Bowman said:

It may be an alignment issue.  the two gimbal arms have to be aligned almost perfectly to get smooth operation.  and even so I will get very minor "clunks" from time to time.  

ended up reprinting the core joint and rotating the arm pillow blocks and that removed the clunk.

23 hours ago, Bard_the_Bowman said:

My concern with using centering springs to “help” the motors would be trimming.  Depending how your aircraft is trimmed the motors may end up fighting the springs.  Also, it would make the stick not work very well for helicopters at all for much the same reason.

 

Yeah my unique case is I'm trying to mount a GR tornado grip to the top of the gimbal which comes it at a staggering 1.7kilos for just the grip, so my hope was to tune the cams to try and keep the weight of the grip itself balanced.

What I've ended up finding though is the linkages from the gimbal are too complex and there are too many cantilevered parts in the design so it just flexes and breaks with strong enough springs. Such heavy cams need to be as close to the original "axis" of rotation as possible.

I might instead try just having a single spring that comes right out of the bottom of the core joint that goes to the bottom of the box as just a very basic "centering" force to see if that elevates the weight.

Edited by TomVR
Posted (edited)
On 12/12/2021 at 5:07 PM, TomVR said:

In the gimbal design, has anyone had a problem with a clunk on the pitch axis? Feels like the "GIMBAL_CORE_JOINT.STL" part is shifting back and forth while crossing the center on the pitch, making a popping noise and a felt clunk. Only happens when there is an external load on the axis from the gear teeth (or my cam springs)

recorded a video of it happening.

https://imgur.com/a/QQP1L1s

 

I had a similar "clunk" when going from one direction of force to the other. Noticed the frames were flexing and allowing the bearings to slide in and out on the joints. Fixed by tapping the holes on the joints and securing the bearings that way.

 

 

 

 

 

clunkfix.png

Edited by theperson
  • Like 1
Posted

yeah I ended up shimming the inside of the joint by expanding the width axis by 0.5% in my slicer settings, but that might be a good idea if things wear down overtime.

Posted
On 12/18/2021 at 6:23 AM, theperson said:

My previous arduino code is garbage and I am deleting it out of shame.

Here is the much much better Fino implementation.

Download the Fino library, put it in your ~/Documents/Arduino/libraries folder and replace the Fino.ino and joystick.ino files with the code below.

I'm also filtering the input encoder position with a simple MovingAverage library - available through the library manager as MovingAverager by Ian Carey

 

I have my DCS controls FF_Tune menu set as follows:

Trimmer Force = 75
Shake Force = 5
Swap Axis = unchecked
Invert X = unchecked
Invert Y = unchecked

 

...

If I turn the gains up too high it'll start oscillating something fierce, but these seem alright for my setup. Maybe direct-driving the gimbals would take out that small springiness of the belt and allow for higher gains?

 

Great job @theperson! When I created that Fino library I thought the most useful part would be the library but reusing the sketch that way is a great idea. I'll change it a bit so that it's easier to reuse but what you did is great.

Just one comment about when you wonder about the "pos_updated" variable. I just had to do that because the Brunner joystick refreshes the X and Y axes at different intervals and made recalculating inertia and friction really tricky, so I just calculate those at a lower frequency. Using the filter as you are doing is a very similar idea. I'll make some changes so it's easier to debug these.

Also, someone was kind enough to send me a Due which uses a SAM3X8E and everything but the USB communication is working. There's some issue there that I'm trying to find but it's quite tricky. I have read many messages online that the Arduino USB libraries are full of bugs but I don't know if that's still the case or I just have a lot to learn about all this. I hope to get this working during January

  • Thanks 3
Posted
10 hours ago, Chuls said:

Great job @theperson! When I created that Fino library I thought the most useful part would be the library but reusing the sketch that way is a great idea. I'll change it a bit so that it's easier to reuse but what you did is great.

Just one comment about when you wonder about the "pos_updated" variable. I just had to do that because the Brunner joystick refreshes the X and Y axes at different intervals and made recalculating inertia and friction really tricky, so I just calculate those at a lower frequency. Using the filter as you are doing is a very similar idea. I'll make some changes so it's easier to debug these.

Also, someone was kind enough to send me a Due which uses a SAM3X8E and everything but the USB communication is working. There's some issue there that I'm trying to find but it's quite tricky. I have read many messages online that the Arduino USB libraries are full of bugs but I don't know if that's still the case or I just have a lot to learn about all this. I hope to get this working during January

Thank you for making it available. You absolutely saved me a lot of headache getting it figured out.

I took a look at trying to run it on an SAME51 chip (basically an SAMD51 chip with a CAN bus - supposedly more reliable than the odrive serial uart) but the USB library stuff goes way over my head.

I think my next step is adding some switches to the arduino to turn on/off motors as well as adding some damping that isnt dependent on it being enabled in-game.

 

I also replaced the m5 bolt that runs up through the GIMBAL_CORE_JOINT with a proper 5mm shaft, since the bolt threads were slightly undersized for the bearing ID and caused a barely perceptible amount of slop.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...