Logitech G25, G27, G29, G920 load cell DIY project

Seeing that I haven’t completed the work, allow me to showcase the work of others in my place, as this is starting to become more of a repository of ideas on the topic.

RD member GeekyDeaks showcases a bathroom scale based load-cell project on his github
- More details about bathroom scale based loadcells

RD member Grezson built one by using a 20kg straight Bar load-cell (which are very cheap btw)
- More details about straight bar based loadcells not specific to logitech

- More general information about load-cells
- Some older research completed that is still relevant

- RD member Panicpete has also shared a lot of detail about his own project that can be found on this thread

Provided in the spoiler below is all the most pertinent information I’ve dug up on building a button load-cell for the Logitech brake pedal. Very similar in design to that of Richmotech’s model. The total cost for this project would come around $60 to $70 on the low end roughly. Be advised, I’ve not actually completed this project and ended up installing the AXC Sim brake mod in it’s place, which comes at the same cost it would take to build a button load-cell mod.
Parts list:

Steel Spring:

30mm Outer Diameter (This is wrong, I will updated the O.D. and I.D. later)
2.0mm Wire Diameter
50mm length
A length of 50mm is overshooting it, so the spring would need to be shorten to length with a dremel. A dual rated spring such as what is used with the nixim and gteye mod might also work, but I presume that having a combination of the spring, rubber and the load cell should provide for enough change in pressure. I've also read of some success by using a product called Real Pedal that can be found on ebay, which comes with a spring and sponge, but a bit over priced again at $30. So best to DIY this imo.


3123_0.jpg

Load Cell
The load cell should have an Outer Diameter or 25mm and not likely much larger, but definitely not greater than 28mm. The Logitech housing that holds the spring assembly has an inside diameter of 30mm, so it needs to be a bit less than that. The actual rating of the load cell should be around 45kb (100lbf) and a 3 wire system that can be supplied with up to 5V.

Example load cell:
Button Load Cell (50kg) - CZL204E
FC22 Compression Load Cell (45kg)
note: This particular model would need to have the mounting brackets edged off with something like a dremel.


Amplifier:
An amplifier might not actually be needed if the supplied voltage is maintained, but they are pretty cheap and might be a good fail safe to have. An affordable standalone load cell amplifier by Leo Bodnar or maybe something like a SparkFun Load Cell Amplifier - HX711. Can't really say for sure what the best option is just yet.

OR build your own:

Rubber fuel line:
This should have an outsider diameter that doesn't exceed the insider diameter of the steel spring (possibly a hair shorter to be on the safe side) and then just trim it up to fit inside the spring.

Felt or Foam:
To wrap around the load cell so as to make a more snug fit.

For assembly, simply refer to any Ricmotech style information, such as,
Sim Racing Garage review
Ricmotech assembly manual
 
Last edited:
@GeekyDeaks this is the sketch I can get a reading in serial monitor with,

#include "HX711.h"

// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = 2;
const int LOADCELL_SCK_PIN = 3;

HX711 scale;

void setup() {
Serial.begin(57600);
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
}

void loop() {

if (scale.is_ready()) {
long reading = scale.read();
Serial.print("HX711 reading: ");
Serial.println(reading);
} else {
Serial.println("HX711 not found.");
}

delay(1000);

}

I tested everything else I wanted to connect the other day and the only parts that will work are the buttons and not very well. I think I will have to start from scratch as I wont be using the buttons.

I used this sketch to get the pots working,

// Analog eBrake-Handbrake
// PIN A0 to 10k pot output - Throttle Axis
// Use with Arduino ProMicro.
// Tested and working in DiRT RALLY + ASSETTO CORSA
// by AMSTUDIO
// 20.1.2017

#include <Joystick.h>

void setup()

{pinMode(A0, INPUT);
Joystick.begin();}

const int pinToButtonMap = A0;

void loop()

{int pot = analogRead(A0);
int mapped = map(pot,0,1023,0,255);
{Joystick.setThrottle(mapped);}}

Now just to combine them. I believe the analogue eBrake uses a different joystick library to the others.

I haven't had a chance to look into this myself since I was last on here, family emergency, so will see what I can come up with this week.

Thanks for your assistance guys. Will post details when I can.
 
Last edited:
Upvote 0
Hi @RustyNaki

Try something like the following:

C++:
#include "HX711.h"
#include <Joystick.h>

// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = 2;
const int LOADCELL_SCK_PIN = 3;

HX711 scale;
Joystick_ Joystick;

void setup() {
    Serial.begin(57600);
    scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);

    pinMode(A0, INPUT);
    Joystick.begin();
}

void loop() {

    if (scale.is_ready()) {
        long reading = scale.read();
        Joystick.setBrake(reading);
    }

    int throttle = analogRead(A0);
    Joystick.setThrottle(throttle);

}

You shouldn't need to map the value from the pin attached to the pot to 0-255 since Joystick.h accepts values from 0-1023 for all the axis, so I removed the map()

EDIT: I forgot to mention, but the above code is completely dumb and simply sends values as fast as it can. Ideally you would want to make it a little smarter and kinder to the USB bus by sending the brake and throttle values in one update (Joystick.sendState()) and only updating the state if any of the measurements changed (i.e. store the previous values of each axis/button and compare to the new reading).
 
Last edited:
Upvote 0
Hi @GeekyDeaks ,

I have just tried this,


#include "HX711.h"
#include <Joystick.h>

// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = 2;
const int LOADCELL_SCK_PIN = 3;

HX711 scale;
Joystick_ Joystick;

void setup() {
Serial.begin(57600);
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);

pinMode(A0, INPUT);
Joystick.begin();

}

void loop() {

if (scale.is_ready()) {
long reading = scale.read();
Joystick.setBrake(reading);
}

int throttle = analogRead(A0);
Joystick.setThrottle(throttle);

Joystick.sendState();
}

Could only get a reading for the pot not the load cell. I have tried adding an axis for clutch but no matter what I tried it would merge with the throttle. I'll have a play with the load cell today and see what I come up with.

Thank you for your assistance.
 
Upvote 0
@GeekyDeaks ,

Just tried this for load cell only and it worked

#include <HX711.h>
#include <Joystick.h>
#define calibration_factor 0 // Change this value to give accurate reading with your known mass.
#define DOUT 2
#define CLK 3
HX711 scale;
/*
Please check out our YouTube video series, Make your own loadcell pedals for sim racing

www.gpsimrigs.com

www.facebook.com/gpracesim
*/
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,
JOYSTICK_TYPE_MULTI_AXIS, 4, 3,
false, false, true, false, false, false,
false, true, true, true, false);



int brake = 0;
int lastBrakeValue = 0;

void setup() {
// Ranges are 1023 by default
Joystick.setBrakeRange(0, 1023);


Joystick.begin();
Serial.begin(38400);

scale.begin(DOUT, CLK);
scale.set_scale(calibration_factor);
scale.tare();
}
void loop() {

//Displays reading in Serial Monitor

Serial.println (brake);
brake = scale.get_units(); // if the value is inverted put a - sign in front like -scale.get

if (brake < 0 or brake < 1) {
brake = 0;
}

if (lastBrakeValue != brake) {
Joystick.setBrake(brake);
lastBrakeValue = brake;
}
}

Cheers
 
Upvote 0
ok, I don't understand how your second example is working from looking at the source code for the HX711 library.

You have the following:

Code:
#define calibration_factor 0 // Change this value to give accurate reading with your known mass.

Then you use this in setup() as follows:

Code:
scale.set_scale(calibration_factor);

The problem is that this sets the scale to 0 and in the HX711 library (https://github.com/bogde/HX711) it gets used as follows:

Code:
float HX711::get_units(byte times) {
    return get_value(times) / SCALE;
}

So you will be trying to divide by 0.

I'm not sure you are using the same library. Can you let me know which one you are using?
 
Last edited:
Upvote 0
Sorry was calibrating when I copied and pasted, working for me with 28000
Ah, ok that explains it :D

I guess the next thing I would do is try and add in the pot code to your second working example with the load cell.

You will need to first tell the arduino to use the pin for INPUT in the setup() section:

C++:
pinMode(A0, INPUT);

Then read and send the value via USB in the loop()

Code:
int throttle = analogRead(A0);
Joystick.setThrottle(throttle);

If that doesn't work, try using a different axis. It looks like you have enabled the Z axis on a joystick as well as the throttle, brake and steering, so I'd probably try the Z axis first as it'll be on a completely different section in the USB HID record
 
Upvote 0
Hi @GeekyDeaks,

Just finished messing with the hardware and tidying up the wiring a bit. I've printed an insert to go in the spring to try and use all the stock components where I can. Have it running with just the load cell at the moment but only getting very narrow readings once calibrated. About to try the new print setup and see if I get any better results. I do have different load cells on the way to try to as the ones I have are smaller and I had to make spacers to fit in your double holder. And they keep popping out lol. I can get readings in serial monitor of around 80kg but once its running as a controller it barley moves the bar. Fine tuning I guess. I'll get there by the end of the weekend I reckon.

Once again thank you for your help. I will try adding your suggestions and see how I get on.
 
Upvote 0
but only getting very narrow readings once calibrated
I think this might be because you are using such a high value for the scale. By default the library sets it to 1 and I notice you didn't seem to set it in the serial output test. Remember that all the scale is used for is to divide the actual value, so if it's set to 2, you are essentially halving the values from the HX711, at 28000 you are probably going to reduce them to a minuscule amount. I recommend looking at what the raw values are first and then you can correctly calculate the scale, otherwise you are just programming by coincidence and that generally tends to lead to frustration.
 
Upvote 0
@GeekyDeaks,

My accurate readings wanted 32000 calibration in the end but I get a much better feel with 3000. I think I will get there eventually. I've added what you suggested, haven't tested it yet though. I'll try and get some photos once its finished.
 
Upvote 0
long reading = scale.read();
I just noticed that you are calling read() in your serial output test, but get_units() in your second example:
brake = scale.get_units(); // if the value is inverted put a - sign in front like -scale.get

I recommend taking a look at the module source code so you can get a feel for what each one does. You should find that get_units() *eventually* calls read(). Also read() gives you the raw value (ignores the scale and offset), but get_units() will be scaled and offset.

read() vs get_units()
 
Upvote 0
Just used my soldering iron to plastic weld things it place. I'll look into that and get a better idea. I've thrown that together from modifying gpsimracings sketch. I'll try and lighten it up and test the pot soon. Then I'll add another pot and that should do for now.
IMG_20201029_232432.jpg
 

Attachments

  • IMG_20201029_232339.jpg
    IMG_20201029_232339.jpg
    1.1 MB · Views: 196
Upvote 0
some thing to bear in mind is that the dual cell design required that the top cell be able to move downwards as the lower one compressed. If you are welding them in, then only the top one is likely to change resistance under load. I don't think this will make a huge difference though, as it's electrically the same as the single cell design
 
Upvote 0
It's just around those outside edges to stop my spacers slipping out. The internal component should all still move/flex . Not sure if I have a big enough gap between them yet. Have some load cells like the ones you used on the way. It's working perfectly now. Still have to connect the pot and see if I got that right. That's a tomorrow job it's 1am here. If I get it all running tomorrow I'll post what I did.
 
Last edited:
Upvote 0
@GeekyDeaks ,

I now have a functioning load cell brake and pot throttle all looking nice and tidy go the logitech housing. Have found that I'll need to file the corners of the load cell housing to get the top cover to fit perfectly. I was just about to code the clutch and post the sketch I used but we have no power at the moment, very frustrating lol
 
Upvote 0
So with this I now haver a full set of operational pedals. there does seem to be a bit of a delay to is registering though.



#include <HX711.h>
#include <Joystick.h>
#define calibration_factor 2000 // Change this value to give accurate reading with your known mass.
#define DOUT 2
#define CLK 3
HX711 scale;
/*
Please check out our YouTube video series, Make your own loadcell pedals for sim racing

www.gpsimrigs.com

www.facebook.com/gpracesim
*/
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,
JOYSTICK_TYPE_MULTI_AXIS, 4, 3,
false, false, true, false, false, false,
false, true, true, true, false);



int brake = 0;
int lastBrakeValue = 0;

void setup() {
// Ranges are 1023 by default
Joystick.setBrakeRange(0, 1023);


Joystick.begin();
Serial.begin(38400);

scale.begin(DOUT, CLK);
scale.set_scale(calibration_factor);
scale.tare();

pinMode(A0, INPUT);
pinMode(A1, INPUT);
}
void loop() {

//Displays reading in Serial Monitor

Serial.println (brake);
brake = scale.get_units(); // if the value is inverted put a - sign in front like -scale.get

if (brake < 0 or brake < 1) {
brake = 0;

int throttle = analogRead(A0);
Joystick.setThrottle(throttle);
int zAxis = analogRead(A1);
Joystick.setZAxis(zAxis);
}

if (lastBrakeValue != brake) {
Joystick.setBrake(brake);
lastBrakeValue = brake;
}
}
 
Upvote 0
OK so pedals installed and running, have discovered a couple of small things. Sometimes there can be severe input lag, think it may be connected to issue 2. 2nd whatever position the throttle is in when you hit the brakes it stays there till you release the brake. The load cell/brake works perfectly and on its own would be awesome. I just wonder why the throttle would be doing what it is doing. Really happy with how this works and appreciate @GeekyDeaks help.
122996295_2798329437113507_4951296187787385992_n.jpg
 
Last edited:
Upvote 0
Hey @RustyNaki, glad you are having some success. I think the problem is pretty easy and due to the following piece of code:

C++:
if (brake < 0 or brake < 1) {
  brake = 0;

  int throttle = analogRead(A0);
  Joystick.setThrottle(throttle);
  int zAxis = analogRead(A1);
  Joystick.setZAxis(zAxis);
}

What that is doing is only reading and setting the throttle (and clutch?) when the brake is less than 1. You need to move those statements out of the if

If that solves your problem, then you might want to consider making a lastThrottleValue and lastClutchValue so you can Joystick.set them if they have changed and not every loop
 
Upvote 0
I've got the load cell working perfectly on its own. Connected along side the logitech pedals. I removed to serial monitor stuff and it sorted all the input lag but I haven't tried running the pots at all. I'll work on adding the pots another time. I now see why load cell brakes are so popular.
 
Upvote 0
I'll work on adding the pots another time
Did you try moving the statements outside the `if`? I think that is what is causing your 'sticky pedal' problem.

If you are happy with the setup you have then no worries for now, but maybe something to consider later. I can appreciate that sometimes the tinkering has to stop as you just want to race! :D
 
Upvote 0
Back
Top