Issue with load cell handbrake project on a sim rig

Hello everybody!

I am stuck on a load cell-driven handbrake project for a racing simulator rig and I need your help. In a nutshell, after I have done my setup, described below, pulling the brake lever does not result in any input into the mapped axis in the Game Controller screen.

I am using the following items:

  • Load cell + HX711 amplifier (which perhaps also is an analog to digital converter - this is yet to be clarified in this thread) -

  • Arduino ProMicro -

  • Micro USB cable

  • Handbrake body -

  • Piston-push and load cell mount platform I made myself with some mild steel parts, a grinder, a tig welder and a drill.

Before continuing further I would like to point out the following:

  • This is my first project in using a load cell + HX711

  • This is my first project in using an Arduino (I cannot even explain what an Arduino is to a kid, although I have already managed to successsfully upload some code to it)

  • I have absolutely zero knowledge in coding (for now I am limited to copy\pasting code)

  • This is my fist post on this forum

In other words - you are dealing with a noob. I will also be writing this post in a simplified, yet detailed way so that whenever other noobs like me read this, they will be able to capture all of the bits and pieces of knowledge they are missing in the whole equation.

I already referred to the following threads on this forum (and many other forums which I am not sure if I am allowed to provide the links to here)

Unfortunately I could not resolve my issue by referring to the above

This is what the project looks like at its current stage:



These were the major steps followed:

  1. Welding/grinding/drilling the piston-push and load cell mount and mounting the load cell on

  2. Soldering the load cell to the HX711 , then the amp to the Arduino according to the following diagram (later re-soldered DT and SCK to ports 2 and 3 on the Arduino respectively as the first attempts go get a proper output into Windows Game Controllers -> Arduino have failed)

  1. Installing the Arduino freeware

  2. Adding the following libraries

  • see attached files as message becomes longer than 9000 characters if I post the actual code
  1. Uploading the following code (I tried different code\library combinations) to the Arduino. Ultimately all uploaded code failed to deliver the expected result.
#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);}}

The issue:

The issue is that whatever amounts of pressure I put on the load cell, the throttle axis (pic below) remains unchanged, with only a single digit change from time to time, which assume to be just some electronic noise. I presume to have wrongly executed one or more of steps 2), 4) or 5) from the ones followed above.

The ask:

Please let me know what you think I have done wrong here – it has already been more than a month that I am trying to make this work after I come home from the office, not counting waiting for parts to arrive from China. You are my last hope.

Best regards,
Kris

Joystick.h (2.25 KB)

HX711.h (2.76 KB)

HX711_ADC.h (3.43 KB)

  1. Please put your code into code tags. (Read the how-to-use-this-forum post.)
  2. Please insert your images inline. (There's an image guide somewhere.)
  3. Please put URL tags on your links. Copy-pasting links is tedious on my phone, for some reason related to this phone.

Did you even glance at any HX711 examples? Did any of them use analogRead()?

Yes, the HX711 is an ADC and you need to read the digital data from it. Load up any of the simple HX711 library examples and get that working, showing some data changing as you pull the handle. That will check your wiring and mechanics.

Once you have some numbers, you can put that into a map() function and get a sensible output.

Hi MorganS,

Thank you for your feedback. Noted on points 1, 2 and 3 and amended in initial post.

OK, HX711 is an ADC - does that mean that I should not use the analog pins on the Arduino (A0-A0) but use the other numerated 2-15 pins instead?

When you suggest loading up an HX711 library examples and get it working - what would that mean essentially? Should I tailor-amend the existing code or use it straight as it is? Apologies for my ignorance here but this really is all new to me.

Below is the code for the three libraries I am attempting to incorporate - there is no analogRead() contained in it:

1) Joystick.h

#ifndef JOYSTICK_h
#define JOYSTICK_h

#include "HID.h"

#if ARDUINO < 10606
#error The Joystick library requires Arduino IDE 1.6.6 or greater. Please update your IDE.
#endif

#if !defined(USBCON)
#error The Joystick library can only be used with a USB MCU (e.g. Arduino Leonardo, Arduino Micro, etc.).
#endif

#if !defined(_USING_HID)

#warning "Using legacy HID core (non pluggable)"

#else

//================================================================================
//================================================================================
//  Joystick (Gamepad)

class Joystick_
{
private:
 bool     autoSendState;
 int8_t xAxis;
 int8_t yAxis;
 int8_t zAxis;
 int16_t xAxisRotation;
 int16_t yAxisRotation;
 int16_t zAxisRotation;
 uint32_t buttons;
 uint8_t  throttle;
 uint8_t  rudder;
 int16_t hatSwitch[2];

public:
 Joystick_();

 void begin(bool initAutoSendState = true);
 void end();

 void setXAxis(int8_t value);
 void setYAxis(int8_t value);
 void setZAxis(int8_t value);

 void setXAxisRotation(int16_t value);
 void setYAxisRotation(int16_t value);
 void setZAxisRotation(int16_t value);

 void setButton(uint8_t button, uint8_t value);
 void pressButton(uint8_t button);
 void releaseButton(uint8_t button);

 void setThrottle(uint8_t value);
 void setRudder(uint8_t value);

 void setHatSwitch(int8_t hatSwitch, int16_t value);

 void sendState();
};
extern Joystick_ Joystick;

#endif
#endif

2) HX711.h

#ifndef HX711_h
#define HX711_h

#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

class HX711
{
 private:
 byte PD_SCK; // Power Down and Serial Clock Input Pin
 byte DOUT; // Serial Data Output Pin
 byte GAIN; // amplification factor
 long OFFSET = 0; // used for tare weight
 float SCALE = 1; // used to return weight in grams, kg, ounces, whatever

 public:

 HX711();

 virtual ~HX711();

 // Initialize library with data output pin, clock input pin and gain factor.
 // Channel selection is made by passing the appropriate gain:
 // - With a gain factor of 64 or 128, channel A is selected
 // - With a gain factor of 32, channel B is selected
 // The library default is "128" (Channel A).
 void begin(byte dout, byte pd_sck, byte gain = 128);

 // Check if HX711 is ready
 // from the datasheet: When output data is not ready for retrieval, digital output pin DOUT is high. Serial clock
 // input PD_SCK should be low. When DOUT goes to low, it indicates data is ready for retrieval.
 bool is_ready();

 // Wait for the HX711 to become ready
 void wait_ready(unsigned long delay_ms = 0);
 bool wait_ready_retry(int retries = 3, unsigned long delay_ms = 0);
 bool wait_ready_timeout(unsigned long timeout = 1000, unsigned long delay_ms = 0);

 // set the gain factor; takes effect only after a call to read()
 // channel A can be set for a 128 or 64 gain; channel B has a fixed 32 gain
 // depending on the parameter, the channel is also set to either A or B
 void set_gain(byte gain = 128);

 // waits for the chip to be ready and returns a reading
 long read();

 // returns an average reading; times = how many times to read
 long read_average(byte times = 10);

 // returns (read_average() - OFFSET), that is the current value without the tare weight; times = how many readings to do
 double get_value(byte times = 1);

 // returns get_value() divided by SCALE, that is the raw value divided by a value obtained via calibration
 // times = how many readings to do
 float get_units(byte times = 1);

 // set the OFFSET value for tare weight; times = how many times to read the tare value
 void tare(byte times = 10);

 // set the SCALE value; this value is used to convert the raw data to "human readable" data (measure units)
 void set_scale(float scale = 1.f);

 // get the current SCALE
 float get_scale();

 // set OFFSET, the value that's subtracted from the actual reading (tare weight)
 void set_offset(long offset = 0);

 // get the current OFFSET
 long get_offset();

 // puts the chip into power down mode
 void power_down();

 // wakes up the chip after power down mode
 void power_up();
};

#endif /* HX711_h */

3) HX711_ADC.h (whatever ADC stands for)

#ifndef HX711_ADC_h
#define HX711_ADC_h

#include <Arduino.h>
#include "config.h"

/*
Note: HX711_ADC configuration values has been moved to file config.h
*/

#define DATA_SET SAMPLES + IGN_HIGH_SAMPLE + IGN_HIGH_SAMPLE // total samples in memory

#if (SAMPLES  != 4) & (SAMPLES  != 8) & (SAMPLES  != 16) & (SAMPLES  != 32) & (SAMPLES  != 64) & (SAMPLES  != 128)
 #error "number of SAMPLES not valid!"
#endif

#if (SAMPLES == 4)
#define DIVB 2
#elif  (SAMPLES == 8)
#define DIVB 3
#elif  (SAMPLES == 16)
#define DIVB 4
#elif  (SAMPLES == 32)
#define DIVB 5
#elif  (SAMPLES == 64)
#define DIVB 6
#elif  (SAMPLES == 128)
#define DIVB 7
#endif

class HX711_ADC
{ 
 
 public:
 HX711_ADC(uint8_t dout, uint8_t sck); //constructor
 void setGain(uint8_t gain = 128); //value should be 32, 64 or 128*
 void begin();
 void begin(uint8_t gain);
 int start(unsigned int t); // start and tare one HX711
 int startMultiple(unsigned int t); //start and tare multiple HX711 simultaniously
 void tare(); // zero the scale, wait for tare to finnish
 void tareNoDelay(); // zero the scale, do tare in loop without waiting for tare to finnish
 void setCalFactor(float cal); //calibration factor, raw data is divided by this value to convert to readable data
 float getCalFactor(); // returns the current calibration factor
 float getData(); // returns data from the moving average data set 
 float getSingleConversion(); //for testing and debugging
 long getSingleConversionRaw(); //for testing and debugging
 int getReadIndex(); //for testing and debugging
 float getConversionTime(); //for testing and debugging
 float getSPS(); //for testing and debugging
 bool getTareTimeoutFlag(); //for testing and debugging
 void disableTareTimeout(); //for testing and debugging
 long getSettlingTime(); //for testing and debugging
 void powerDown(); 
 void powerUp(); 
 bool getTareStatus(); // returns 1 if tareNoDelay() operation is complete
 long getTareOffset();
 void setTareOffset(long newoffset);
 uint8_t update(); //if conversion is ready; read out 24 bit data and add to data set

 protected:
 uint8_t conversion24bit(); //if conversion is ready: returns 24 bit data and starts the next conversion
 long smoothedData();
 uint8_t sckPin; //HX711 pd_sck pin
 uint8_t doutPin; //HX711 dout pin
 uint8_t GAIN;
 float calFactor;
 volatile long dataSampleSet[DATA_SET + 1]; // data set, make voltile if interrupt is used 
 long tareOffset;
 int readIndex = 0;
 unsigned long conversionStartTime;
 unsigned long conversionTime;
 uint8_t isFirst = 1;
 uint8_t tareTimes;
 const uint8_t divBit = DIVB;
 bool doTare;
 bool startStatus;
 long startMultipleTimeStamp;
 long startMultipleWaitTime;
 uint8_t convRslt;
 bool tareStatus;
 unsigned int tareTimeOut = (SAMPLES + IGN_HIGH_SAMPLE + IGN_HIGH_SAMPLE) * 150; // tare timeout time in ms, no of samples * 150ms (10SPS + 50% margin)
 bool tareTimeoutFlag;
 bool tareTimeoutDisable = 0;
}; 

#endif

Best regards,
Kris

Kris_1989:
When you suggest loading up an HX711 library examples and get it working - what would that mean essentially? Should I tailor-amend the existing code or use it straight as it is?

The idea is to demonstrate to yourself that you have the HX711 wired up correctly and that the Arduino can communicate with it. To that end, pick the simplest possible example in the library - one that reads the device and prints what it returns.

You may need to adjust the pin numbers in the sketch to match your setup, or fir an initial test, make your wiring what the code expects.

Hi wildbill,

I think the main issue is that none of the code I see in any of the above HX711 examples makes any sense to me. There are no pin numbers in the HX711 code to begin with. Should I add that myself? If yes how, and also, should I add it in both the Joystick.h and the HX711.h files?

Is there someone who can tell me exactly what I need to do here based on my input? (let me know if I am posting in the wrong section of the forum, asking for such type of help)

I assume these questions I am raising sound ridiculous to someone that has experience here but right now this is as far as my capacity of understanding the topic goes.

Best regards,
Kris

I'm not sure what library you're using, nor have I used it myself, so I'm not the best person to give you detailed advice. However, assuming you're using the easily found version on Github, this is the example code I was suggesting: basic example

That's where you'll find the pin numbers to tweak.

When you install (copy the library to your Arduino\libraries folder) there will be a folder called examples. Open those in the Arduino IDE and try them out.

Normally you don't need to look inside the .h or .cpp files.

MorganS:
When you install (copy the library to your Arduino\libraries folder) there will be a folder called examples. Open those in the Arduino IDE and try them out.

Normally you don't need to look inside the .h or .cpp files.

Hi Morgan, Bill

I took my time to try to learn how all of this works, and tried what you suggested - it kinda worked.

Using\uploading the below code I managed to get variable reading in the Serial Monitor when pulling the lever. But now there is no joystick in Game Controllers section

#include "HX711.h"

// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = A1;
const int LOADCELL_SCK_PIN = A0;

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(80);
  
}


Then I tried copying this code right after the successful one above and uploading it - I got an error message.

#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);}}

I must be missing something, something simple. I really have no clue what to do next - would anyone agree to help me do this via Teamviewer?

Kris

"I got an error" gives no useful information. What was the error? "Redefinition of loop()"?

You can't have two functions with the same signature (same name, but a bit more complex than that.) Give the joystick ones a new name and call them from the main ones.

Hi Morgan,

Using this code:

#include "HX711.h"

// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = A1;
const int LOADCELL_SCK_PIN = A0;

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(85);
  
}


#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);}}

I am receiving the following error:

Arduino: 1.8.9 Hourly Build 2019/01/03 05:21 (Windows 10), Board: "Arduino/Genuino Micro"

C:\Users\Kris\Desktop\HX711_full_example_-_KR_WORKS_2\HX711_full_example_-_KR_WORKS_2.ino: In function 'void setup()':

HX711_full_example_-_KR_WORKS_2:28:6: error: redefinition of 'void setup()'

 void setup()

      ^

C:\Users\Kris\Desktop\HX711_full_example_-_KR_WORKS_2\HX711_full_example_-_KR_WORKS_2.ino:9:6: note: 'void setup()' previously defined here

 void setup() {

      ^

HX711_full_example_-_KR_WORKS_2:31:4: error: 'Joystick' was not declared in this scope

    Joystick.begin();}

    ^

C:\Users\Kris\Desktop\HX711_full_example_-_KR_WORKS_2\HX711_full_example_-_KR_WORKS_2.ino: In function 'void loop()':

HX711_full_example_-_KR_WORKS_2:35:6: error: redefinition of 'void loop()'

 void loop()

      ^

C:\Users\Kris\Desktop\HX711_full_example_-_KR_WORKS_2\HX711_full_example_-_KR_WORKS_2.ino:14:6: note: 'void loop()' previously defined here

 void loop() {

      ^

HX711_full_example_-_KR_WORKS_2:39:2: error: 'Joystick' was not declared in this scope

 {Joystick.setThrottle(mapped);}}

  ^

C:\Users\Kris\Desktop\HX711_full_example_-_KR_WORKS_2\joy.ino: In function 'void setup()':

joy:3:6: error: redefinition of 'void setup()'

 void setup()

      ^

C:\Users\Kris\Desktop\HX711_full_example_-_KR_WORKS_2\HX711_full_example_-_KR_WORKS_2.ino:9:6: note: 'void setup()' previously defined here

 void setup() {

      ^

C:\Users\Kris\Desktop\HX711_full_example_-_KR_WORKS_2\joy.ino: At global scope:

joy:8:11: error: redefinition of 'const int pinToButtonMap'

 const int pinToButtonMap = A0;

           ^

C:\Users\Kris\Desktop\HX711_full_example_-_KR_WORKS_2\HX711_full_example_-_KR_WORKS_2.ino:33:11: note: 'const int pinToButtonMap' previously defined here

 const int pinToButtonMap = A0;

           ^

C:\Users\Kris\Desktop\HX711_full_example_-_KR_WORKS_2\joy.ino: In function 'void loop()':

joy:10:6: error: redefinition of 'void loop()'

 void loop()

      ^

C:\Users\Kris\Desktop\HX711_full_example_-_KR_WORKS_2\HX711_full_example_-_KR_WORKS_2.ino:14:6: note: 'void loop()' previously defined here

 void loop() {

      ^

Multiple libraries were found for "Joystick.h"
 Used: C:\Users\Kris\Documents\Arduino\libraries\Joystick
 Not used: C:\Program Files (x86)\SimRig\Arduino\libraries\Joystick
exit status 1
redefinition of 'void setup()'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Give the joystick ones a new name and call them from the main ones.

Does that mean change #include <Joystick.h> to #include <HX711.h>?

Kris

Include both.

I did - then I got the error I posted above

Kris

You still have two setup() and two loop(). Fix that first.

Try this tutorial on merging 2 codes: Demo of merging the code from two sketches - Programming Questions - Arduino Forum

Hi Morgan and thank you for the tutorial - I learned something new today :),

I merged the two codes and uploaded successfully (no orange error messages, but I did get a notification that "Invalid library found in C:\Program Files (x86)\SimRig\Arduino\libraries\ArduinoJoystickLibrary-version-2.0: no headers files (.h) found in C:\Program Files (x86)\SimRig\Arduino\libraries\ArduinoJoystickLibrary-version-2.0"').

This is the code:

#include "HX711.h"

// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = A1;
const int LOADCELL_SCK_PIN = A0;

HX711 scale;

#include <Joystick.h>

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

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


void loop() {
 HX711LoopCode();
 JoystickLoopCode();
}
  
void HX711LoopCode() {

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

  delay(85);
 
}

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

Now I get an "HX711 not found" in the Serial Monitor and the throttle axis in the device under Game Controllers cannot be influenced by pulling the lever. it does however reduce its value from 700% to 100% in 20 seconds and then restarts in the same loop.

So I tried remapping the pins, and changed A0 to A1 and vice versa. This is the code I used in the second attempt:

#include "HX711.h"

// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = A0;
const int LOADCELL_SCK_PIN = A1;

HX711 scale;

#include <Joystick.h>

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

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


void loop() {
 HX711LoopCode();
 JoystickLoopCode();
}
  
void HX711LoopCode() {

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

  delay(85);
 
}

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

Now the Throttle axis stays between 147% and 150% and pulling the lever still does not result in any change in Game Controllers and I still get an "HX711 not found" in the Serial Monitor

Kris

You appear to have A0 in use as an analog input and as a digital input for the HX711. What do you really have connected? You need to use different pins for different devices.

If it is telling you "not found" then fix that problem first. If you have to, reload the previous code which worked.

The HX711's DT is connected to A1 on the Arduino and the SCK is connected to A0 - this was the setup used in all attempts\codes used.

The HX711 code alone works and results in a changing value feed in the Serial Monitor when handbrake lever is pulled

Kris

So once you have a good idea of the range of readings produced by the HX711, map that into the range of joystick values required and send that to the joystick library.

analogRead() should be removed/replaced.

MorganS:
So once you have a good idea of the range of readings produced by the HX711, map that into the range of joystick values required and send that to the joystick library.

analogRead() should be removed/replaced.

Do you mean that the mapping should happen here - int mapped = map(pot,0,1023,0,255);?

And that I should delete {int pot = analogRead(A1); from my code? What should I replace it with?

Kris

You should replace it with a reading from the HX711

OK - replaced

{int pot = analogRead(A1)

with

{int pot = Serial.print("HX711 reading: ");;

and now the Serial Monitor works - still no input in Game Controllers though

The Serial Monitor range from 0% pull applied to the handbrake, to 100% pull is '-176000' and '2300000' respectively. How do I map that? Do I input the previously mentioned two values in int mapped = map(pot,0,1023,0,255); ?

Kris