flyingtux Posted December 28, 2021 Posted December 28, 2021 (edited) On 10/10/2021 at 10:15 AM, propeler said: It is finished, it is working. No they don't. All components are conected. Hi, Can somebody explain me the process to order the @propeler / olukelo premount PCB for this FFB joystick? I tried via EasyEDA for JLPCB but the bridge between the two websites seems to be broken. After that which BOM should I buy (for composant not mounted by EasyEDA) ? Thanks Edited December 28, 2021 by flyingtux
theperson Posted January 1, 2022 Posted January 1, 2022 Between adding always-active damping and dropping odrv0.axis0.motor.config.current_control_bandwidth from the default of 2000 down to 100 it seems like I solved my out of control oscillation problems at higher torques. Motors are nice and quiet too. Now the limiting factor really is the strength of the printed gimbal joint, and all that vibration has put that "clunk" back in to the roll axis, even with re-tightening everything down 1
TomVR Posted February 7, 2022 Posted February 7, 2022 Started playing around with this project again, I've narrowed down my pitch clunk seems to be related to the M5x50 screw going up into the 20x20 base. Any ideas how to reduce the slop in it? Also on a whim I made an adapter for the Authentikit Spade grip to put onto the extrusion. anglebracket_mod.stl 1
Alterscape Posted February 9, 2022 Posted February 9, 2022 On 2/7/2022 at 10:02 AM, TomVR said: Any ideas how to reduce the slop in it? In precision machining (in metal), screws are avoided for positioning. Instead you'll usually find pins indexing the position of components (in reamed holes, so the diameters have specific fit tolerances), and screws holding the parts together. Given that we're 3d printing everything, I'm not sure we can get enough precision for pins to be relevant, but if we could, that's where I'd start. In 3d printing I tend to just torque things down but you can only go so far before you start to crack things.
TomVR Posted February 9, 2022 Posted February 9, 2022 (edited) 3 hours ago, Alterscape said: In precision machining (in metal), screws are avoided for positioning. Instead you'll usually find pins indexing the position of components (in reamed holes, so the diameters have specific fit tolerances), and screws holding the parts together. Given that we're 3d printing everything, I'm not sure we can get enough precision for pins to be relevant, but if we could, that's where I'd start. In 3d printing I tend to just torque things down but you can only go so far before you start to crack things. I wonder if then instead running a shoulder bolt from the top and putting a nut on the bottom would work better https://www.amazon.ca/uxcell5pcs-Stainless-Socket-Shoulder-Length/dp/B077GWSV23/ref=sr_1_47?crid=1ZYZRE2FM43G1&keywords=5mm+shoulder+bolt&qid=1644431485&sprefix=5mm+shoulder+bolt%2Caps%2C60&sr=8-47 Edited February 9, 2022 by TomVR
theperson Posted February 10, 2022 Posted February 10, 2022 12 hours ago, TomVR said: I wonder if then instead running a shoulder bolt from the top and putting a nut on the bottom would work better https://www.amazon.ca/uxcell5pcs-Stainless-Socket-Shoulder-Length/dp/B077GWSV23/ref=sr_1_47?crid=1ZYZRE2FM43G1&keywords=5mm+shoulder+bolt&qid=1644431485&sprefix=5mm+shoulder+bolt%2Caps%2C60&sr=8-47 I cut the head off a m5x50 shoulder bolt, put it in the existing hole with a flange nut on the bottom and a shaft collar at the top.
slimheli Posted February 19, 2022 Posted February 19, 2022 I just ordered the bolts that @TomVR suggested. I haven't started any final assembly, so I'll post how it goes. I printed almost everything in PETG witih 100% infill. So I think it'll be pretty strong. My intention is to take this beyond just FFB. I'd like to be able to program a helicopter autopilot that can be fed with DCS, X-Plane, or maybe even MSFS.
theperson Posted February 20, 2022 Posted February 20, 2022 (edited) I was having issues with stability where the joystick would randomly stop working and need to be reset, once every couple of days/sessions, so I did a couple of things that seem to have cured it. Firstly, I replaced the chinese pro micro clone with a genuine sparkfun one, and installed their drivers for it. Second, I changed my code to use my own odrive->arduino comms instead of using the ODriveArduino library. This avoids the use of arduino Strings to try and eliminate possible memory issues, clears the serial buffer before reading/writing on it, and overall reduces the number of characters being written on the serial port which makes things faster. I also made sure to give the arduino some "idle" time instead of trying to get as many position updates as possible. I also realized that my settings for the motors and torque commands meant I was saturating my set current limit and was clipping the feedback. You should set the odrive's motor torque constant parameter correctly, and send the commands in units of torque instead of units of current. Here's the updated code. Be warned that it's still pretty confusing and mostly hacked together bull<profanity>. If you've got a question I'd be happy to try and explain. Replace the files in the Fino project with the contents here: Fino.ino: #include "src/Joystick.h" #include "config.h" #include <HardwareSerial.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 //periodicGain sets the gains for everything that isnt a spring, friction, or damping force const float periodicGain = 0.5; const float extraDampingGain = 0.01; int dampingEnabled = 0; bool is_connected = false; bool forces_requested = false; bool pos_updated = false; bool newData = false; const byte numChars = 32; char receivedChars[numChars]; char tempChars[numChars]; // temporary array for use when parsing float rcvdPos[2]; //uses odrive notation for motors float rcvdVel[2]; //uses odrive notation for motors int16_t pos[2] = {0, 0}; int lastX; int lastY; int lastVelX; int lastVelY; int lastAccelX; int lastAccelY; float scaleFactorX; float scaleFactorY; //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 const float maxXRot = 0.13; const float minXRot = -0.11; const float maxYRot = -0.23; const float minYRot = 0.17; const float centerXRot = 0.02; const float centerYRot = -0.03; 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 may get flooded //hit the reset pin as it finishes compiling delay(1000); setupJoystick(); // setup timing and run them as soon as possible lastEffectsUpdate = 0; nextJoystickMillis = 0; nextEffectsMillis = 0; dampingEnabled = 0; } void loop(){ //i setup my odrive as motor 1 is x, 0 is y :bigbrain: unsigned long currentMillis; currentMillis = millis(); //wait 2 seconds for encoder signal to calm down and make sure theres no velX funny business if(currentMillis > 2000){ dampingEnabled = 1; } // do not run more frequently than these many milliseconds if (currentMillis >= nextJoystickMillis) { getFeedback(1); getFeedback(0); pos[0] = (int)((rcvdPos[1]-centerXRot)*scaleFactorX); pos[1] = (int)((rcvdPos[0]-centerYRot)*scaleFactorY); updateJoystickPos(); nextJoystickMillis = currentMillis + 8; // we calculate condition forces every 50ms or more frequently if we get position updates if (currentMillis >= nextEffectsMillis || pos_updated) { updateEffects(true); nextEffectsMillis = currentMillis + 50; 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); } setTorque(1,(forces[0]*(0.1378*7.5/10000.0))+(effects[0].damperVelocity*-extraDampingGain*dampingEnabled)); setTorque(0,(-forces[1]*(0.1378*10/10000.0))+(effects[1].damperVelocity*extraDampingGain*dampingEnabled*2)); } } com.ino: void setOdriveState(int axis, int requested_state) { Serial1 << "w axis" << axis << ".requested_state " << requested_state << '\n'; } void setTorque(int axis, float torque) { Serial1 << "c " << axis << " " << torque << "\n"; } void getFeedback(int motor_number){ //use odrive numbers for motors //clear the input buffer while(Serial1.available()>0){ Serial1.read(); } Serial1 << "f " << motor_number << "\n"; recvFeedback(motor_number); } void recvFeedback(int motor_number) { static byte ndx = 0; char endMarker = '\n'; char rc; static const unsigned long timeout = 10; unsigned long timeout_start = millis(); bool not_timed_out = true; while (newData == false && not_timed_out) { if (Serial1.available() > 0) { rc = Serial1.read(); if (rc != endMarker) { receivedChars[ndx] = rc; ndx++; if (ndx >= numChars) { ndx = numChars - 1; } } else { receivedChars[ndx] = '\0'; // terminate the string ndx = 0; newData = true; } } else if (millis() - timeout_start >= timeout) { not_timed_out = false; //taking too long, abort } } if(newData){ //we must have timed out, so don't copy in new data strcpy(tempChars, receivedChars); char * strtokIndx; // this is used by strtok() as an index strtokIndx = strtok(tempChars, " "); // get the first part - the string rcvdPos[motor_number] = atof(strtokIndx); strtokIndx = strtok(NULL, ","); // this continues where the previous call left off rcvdVel[motor_number] = atof(strtokIndx); // convert this part to a float newData = false; //reset for next read pos_updated = true; } } joystick.ino: void setupJoystick() { 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 = 1.0; gains[1].springGain = 1.0; 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; gains[0].damperGain = 0; //added always-active damping elsewhere gains[1].damperGain = 0; Joystick.setGains(gains); Serial1.begin(500000); delay(100); //clear the input buffer while(Serial1.available()>0){ Serial1.read(); } setOdriveState(0, 8); //AXIS_STATE_CLOSED_LOOP_CONTROL = 8 delay(100); setOdriveState(1, 8); delay(100); } void updateJoystickPos() { Joystick.setXAxis(pos[0]); Joystick.setYAxis(pos[1]); } void updateEffects(bool recalculate){ for (int i =0; i < 2; i++) { effects[i].frictionMaxPositionChange = 15; // TODO: find proper values for these automatically effects[i].inertiaMaxAcceleration = 5; effects[i].damperMaxVelocity = 50; } 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; 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); } Eventually I'd like to speed things up even further by just reading the position in as an int and avoid all the float math. Edited February 20, 2022 by theperson 1 1
98abaile Posted March 9, 2022 Posted March 9, 2022 Just noticed the project has been removed from propeller's github.
-Dagger- Posted March 12, 2022 Posted March 12, 2022 (edited) On 3/9/2022 at 1:41 AM, 98abaile said: Just noticed the project has been removed from propeller's github. You still have the forks. Ex: https://github.com/dmtrkun/bldc-ffb-joystick-base Edited March 12, 2022 by -Dagger- 1
98abaile Posted March 15, 2022 Posted March 15, 2022 (edited) On 10/5/2021 at 9:33 PM, TomVR said: Travelling again for work so don't have a chance to actually open up my MSFFB and see what the as designed gear reduction is, reading conflicting posts that its either 25:1 or 16:1 I've been going back through the thread, planning things when I noticed this comment. In the past I've been looking for this ratio as well but could never find a decent answer. For the record, the reduction ratio of the MSFFB is 19.05:1 (basically 19:1). I was looking at my MSFFB trying to figure out if there was anything I could do to it to swap the gears for belts and make it more compact and mountable to a VPC desk mount. Part of this was taking the gear train apart and actually counting the teeth. Gear 1 is 30 teeth, gear 2 is 100 teeth on the large gear and 21 teeth on the small gear. Gear 3 (the partial gear) is 20 teeth in a 60 degree arc (120 teeth for a full 70mm gear). Edited March 15, 2022 by 98abaile
01G8R Posted March 24, 2022 Posted March 24, 2022 On 9/30/2021 at 7:15 AM, walmis said: Hey guys, an update on my FFB development. Ordered FFB controller boards and boards for the motor control, redesigned the gimbal from scratch, so not to be bound by copyrights. Also spent some time on optimizing the design, so it could be built rather quickly. Finding sources of parts is also a challenge during these times of various shortages. I'm hoping I will be able to start selling these electronics kits for anyone that wants to build own FFB joysticks. And later some finished builds, similarily how Prusa started with 3D printers Added some prototype photos @walmis I'm sorry if I missed it, but can you share more info about this GUI for adjusting the forces? I have a Odrive, some motors, encoders and power supply. I want to use them to make a cyclic for helicopter sim. Possibly add FFB in the future, but I'm more interested in friction, damping and trim adjustment for the cyclic than full FFB. I have been through the mechanical dampers, springs, etc in cyclic design and never been happy with the results (homebuilt and commercial options on the market). The mechanical aspect of building it is not an issue for me. I have a VMC to make parts, but I need programming help.
Roller25 Posted March 28, 2022 Posted March 28, 2022 With the release of the Apache I can't believe this thread isn't more active... Anyone currently doing a build?
walmis Posted March 28, 2022 Posted March 28, 2022 Been super busy last few months developing hardware/firmware/software for my FFB system. Pleased to say it's nearing release. I'm also building a small batch of fully plug and play FFB units and drive kits. Gonna do a photo shoot this week so will have more media to share If anyone's interested in buying a DYI motor/controller kit contact me via PM, I'll need to gauge how many components I'll need to preorder in advance. Here's a sneak peek of the software side state: This is the system diagram of connections for the DYI kit. And the assembled motor unit itself: 5
bpremus Posted March 28, 2022 Posted March 28, 2022 (edited) Hello, sorry if i have missed it in the thread, but has anyone yet compared it side to side to an unmodified Force Feedback 2 in the terms of latency, variety of forces etc? I was modifying my FF2 with custom grip (3d printed) while keeping the twist handle and hand hold sensor, unfortunately mbo died before project was finished. It used an arduino leonardo for custom components. Perhaps this project would be a good starting project to revive my FF, has anyone investigated maybe what could be reused from stock FFB? Edit: I was able to repair the FF2 MBO, however once winwing grip arrive will give it a shot to make a FF base. Edited March 30, 2022 by bpremus 2 AMD FX 8350 4.0Ghz, 16gb DDR3, MSI R9 390, MS FF2 & CH Throttle PRO, track IR 4 & Lenovo Explorer VMR
98abaile Posted March 28, 2022 Posted March 28, 2022 10 hours ago, Roller25 said: With the release of the Apache I can't believe this thread isn't more active... Anyone currently doing a build? I've got parts on order from aliexpress; I'm going to 3D print the base.
slimheli Posted March 30, 2022 Posted March 30, 2022 (edited) I've been busy! Need to order some pulleys and belts. Looking forward to actually firing this thing up. Edited March 30, 2022 by slimheli 3
98abaile Posted April 2, 2022 Posted April 2, 2022 On 3/30/2022 at 5:40 PM, slimheli said: I've been busy! Need to order some pulleys and belts. Looking forward to actually firing this thing up. Tell us about your print settings. I just started printing all the needed parts but didn't know how strong to make it. Currently I'm using PLA+ (stiffer than PETG) with 10 perimeters, 10 top and bottom layers and 10% gyroid infill.
RoyMi6 Posted April 4, 2022 Posted April 4, 2022 On 3/28/2022 at 7:42 AM, walmis said: Been super busy last few months developing hardware/firmware/software for my FFB system. Pleased to say it's nearing release. I'm also building a small batch of fully plug and play FFB units and drive kits. Gonna do a photo shoot this week so will have more media to share If anyone's interested in buying a DYI motor/controller kit contact me via PM, I'll need to gauge how many components I'll need to preorder in advance. Here's a sneak peek of the software side state: This is the system diagram of connections for the DYI kit. And the assembled motor unit itself: I need this soooo badly I know you're trying to make the kits as flexible as possible, but any chance of creating an accompanying design that creates a completed kit that we can cut/print ourselves? 1
98abaile Posted April 4, 2022 Posted April 4, 2022 4 hours ago, RoyMi6 said: I need this soooo badly I know you're trying to make the kits as flexible as possible, but any chance of creating an accompanying design that creates a completed kit that we can cut/print ourselves? Read through the thread. TomVR posted his github with a 3D printable version of the base. 2
Bard_the_Bowman Posted April 6, 2022 Posted April 6, 2022 (edited) On 3/28/2022 at 4:18 AM, bpremus said: has anyone investigated maybe what could be reused from stock FFB? Most of the parts are useless if you're going for anything with much torque. There's all kinds of builds out there that re-use the FFB2 gimbal (often combining 2 into one unit), but IMHO none of those are adequate for a real, quality stick with good force. However, the board itself is another story. If you're like me and you're handier with a soldering iron than you are with a code editor, then the board itself is a fantastic resource for building your own stick. If you look farther up this thread you'll see some posts of mine regarding my FFB2 build. I think I've pushed the FFB2 board probably farther than anyone else has in terms of current, at least farther than anyone I'm aware of. And you could push it even farther with a breakout board and discrete P and N mosfets instead of the little P/N mosfet pairs it uses. I do know that there is one other guy who has actually done a breakout board like that, although I think my build pushes more current than his. Anyway, the FFB2 board is a very good piece of hardware that can withstand some severe modifications. Here's a link to a Reddit post I made with some photos and description of the build. https://www.reddit.com/r/hoggit/comments/py7525/ive_seen_some_love_for_the_microsoft_sidewinder/ And I've got various posts up above about it. If you are interested in doing an FFB2 build I would be happy to get you a parts list and help with any questions you might have. I have spent many many hours learning about modifications to the FFB2. I keep meaning to make a dedicated thread to function as an easy "FFB2 Reference Guide," with the details of my own build and with links to many other good builds I have seen. But have not got around to it yet. But I'm happy to answer questions. Edited April 6, 2022 by Bard_the_Bowman 1
Joerg Posted April 6, 2022 Posted April 6, 2022 vor 5 Stunden schrieb Bard_the_Bowman: Most of the parts are useless if you're going for anything with much torque. There's all kinds of builds out there that re-use the FFB2 gimbal (often combining 2 into one unit), but IMHO none of those are adequate for a real, quality stick with good force. However, the board itself is another story. If you're like me and you're handier with a soldering iron than you are with a code editor, then the board itself is a fantastic resource for building your own stick. If you look farther up this thread you'll see some posts of mine regarding my FFB2 build. I think I've pushed the FFB2 board probably farther than anyone else has in terms of current, at least farther than anyone I'm aware of. And you could push it even farther with a breakout board and discrete P and N mosfets instead of the little P/N mosfet pairs it uses. I do know that there is one other guy who has actually done a breakout board like that, although I think my build pushes more current than his. Anyway, the FFB2 board is a very good piece of hardware that can withstand some severe modifications. Here's a link to a Reddit post I made with some photos and description of the build. https://www.reddit.com/r/hoggit/comments/py7525/ive_seen_some_love_for_the_microsoft_sidewinder/ And I've got various posts up above about it. If you are interested in doing an FFB2 build I would be happy to get you a parts list and help with any questions you might have. I have spent many many hours learning about modifications to the FFB2. I keep meaning to make a dedicated thread to function as an easy "FFB2 Reference Guide," with the details of my own build and with links to many other good builds I have seen. But have not got around to it yet. But I'm happy to answer questions. Do you think that there is a way to control an odrive from a FFB2 board? Maybe converting the signals that steer the mosfets to something an odrive can understand (RC PWM or step/dir)? Its so hard to find inexpensive DC motors with a skewed rotor to improve the torque smoothness. A "FFB2 Reference Guide" is highly welcome. It would be very nice to have all the information in one place and not scatterd all over the internet. 1
walmis Posted April 6, 2022 Posted April 6, 2022 First release of device maintenance page for my FFB controller is ready! The controllers firmware will be upgrade'able over WebUSB. I'll probably move away from desktop app in the future to full configuration over the web. You can find it here: https://vpforcecontrols.com/usb/rhino/ Supporting stuff is now done, now I finally can start prepping the DYI kits for shipping 6 1
RealDCSpilot Posted April 6, 2022 Posted April 6, 2022 I really like the name "Rhino FFB"! 1 1 i9 13900K @5.5GHz, Z790 Gigabyte Aorus Master, RTX4090 Waterforce, 64 GB DDR5 @5600, PSVR2, Pico 4 Ultra, HOTAS & Rudder: all Virpil with Rhino FFB base made by VPforce, DCS: all modules
Recommended Posts