Engine Dyno Projekt

Hi there,
I wanted to show you my little project I´m working on for a very long time now.
I am building my own engine dyno utilizing a water brake which I manufactured myself.

It is one of those project where you wanted a DIY solution because you thaught it would be too expensive to buy one, but ends up costing you years of your life :upside_down_face:

In short, a water brake is a very very inefficient water pump. In fact it is so bad of a pump, that all the power of an engine is transformed into heat.
The absorbed power is proportional to the amount of water inside the water brake.
The more water, the more power is absorbed.
I don´t want to go too much in the "mechanical" details, because I want to focus on my problems with electronics and programming. If someone has interest on the mechanical stuff, I´m happy to talk about it. At last I´m just a mechanical engineer and not very good at prorgamming.

You can´t measure power directly, that´s where the arduino stuff comes in.
To get power, we need torque and RPM.

RPM is measured by a light barrier and a disc with 18 holes on the shaft of the waterbrake.7
Tourque is measured by a load cell (utilizing a HX711 module) mounted on a torque arm.

To regulate the amount of water inside the housing I built two stepper valves out of stepper motors, planetary gearboxes and normal sliding valves. I mounted a potentiometer to the back of the stepper motor via a worm gear to get absolute positioning.

These two stepper valves get their juice from two Pololu T500 TIC stepper drivers.

All this stuff to this point is sitting in a small electrical cabinet directly on the water brake and is controlled by an Arduino Nano.

Later I want to "remote control" all the stuff to get a safe distance to a running engine at full power :smile:

That´s why I plan on building a small box or case with all the buttons, switches, displays and so on where I can control everything and see all my values.

Right now this box is just a second Arduino Nano

I hope this gives you a small idea what my setup/plan looks like.

Right now I need some help with the I2C communication between the stepper drivers and the two Arduinos.

The Arduino on the water brake is my master right now and is reading a potentiometer which transaltes to a desired valve position (to two valve position to be exact) and sends them over to the T500s.
This is working fine right now.

My problem is the communication between the two Arduinos.
The Master sends values over to the slave, which prints them out to the serial port.
I have a very long cable between those two Nanos (10m), that´s why I reduced the clock speed drastically. I wanted to be on the safe side, because I think that I will have a lot more noice from running electrical motors, a running combustion engine and so on, so I added two Adafruit LTC4311 active terminators. One to each end of the chain.

Now comes the fun part:
If I unplug both of the LTC4311s and reboot the system, everything is working fine.
If I plug them in and reboot, the I2C bus just stops working.
I double checked all the connections a hundred times, but can´t find an error.
The best part is, if I unplug the LTC4311 while the system is running (well... not running) the I2C bus immediatly jumps to life and is working again.

Has someone ever had similar problems with these LTC4311s?

A second (future) problem is, that I will need a two way communication (I´m not sure if this is the right name) between the two Nanos.
Both need to read values from potentiometers or buttons and send them to each other.
I utilized the "I2C_anything"-library because I need to send int, float and so on, not just bytes.
But I can´t find an example where the master is reading AND writing on the I2C-Bus.
Can anyone help me out here?

I will post my two codes down here. The master is the Nano on the water brake and the slave is my little "box".

MASTER:

//DYNO MASTER

#include <Wire.h>
#include <HX711.h>
#include <I2C_Anything.h>
#include <Tic.h>


#define DZM_InputPin 2
#define LOADCELL_DOUT_PIN 10
#define LOADCELL_SCK_PIN 9
#define posBrakeValvePin A0
#define posBypassValvePin A1
#define targetValvePin A2

//I2C communication
const byte SLAVE_ADDRESS = 8;

//variables for RPM measurement
volatile unsigned long RPM_T2 = 0; 
volatile unsigned long RPM_Count = 0;
unsigned int RPM = 0;
unsigned long RPM_T1 = 0;
int teeth = 18;

// variables for scale
int force;

//variables for potentiometers
int posBypassValve = 0;
int posBrakeValve = 0;
int targetValve = 0;

//variables for valves
int32_t TicPosBrake = 0;
int32_t TicPosBypass = 0;
int32_t TicBrakeCurrentPos = 0;
int32_t TicBypassCurrentPos = 0;
int32_t TargetTicPosBrake = 0;
int32_t TargetTicPosBypass = 0;

//variables for calculations
//int targetRPM = 0;
//int RPMmin = 0;
//int RPMmax = 9000;


HX711 scale;

TicI2C TicBrake(14);
TicI2C TicBypass(15);


void setup(){
  
  Wire.begin();
  //Wire.setClock(1000);
  TWBR = 255;
  TWSR = 3; 
 
  Serial.begin(9600);
  


  //defining pins
  pinMode(DZM_InputPin, INPUT_PULLUP);
  pinMode(posBrakeValvePin, INPUT);
  pinMode(posBypassValvePin, INPUT);
  pinMode(targetValvePin, INPUT);
  

  //setup interrupts for rpm measurement
  attachInterrupt(0, RPM_Meter, FALLING);    // Interrupt0 wird bei fallender Flanke auf Pin2



  //initializing of scale
  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
  scale.set_scale(2280.f);
  scale.tare();

  //Setup for Tics
  TicBrake.exitSafeStart();
  TicBypass.exitSafeStart();

  posBrakeValve = analogRead(posBrakeValvePin);
  posBypassValve = analogRead(posBypassValvePin);

  TicPosBrake = map(posBrakeValve, 65, 820, 0, 236805);
  TicPosBypass = map(posBypassValve, 65, 820, 0, 236805);
  
  TicBrake.haltAndSetPosition(TicPosBrake);
  TicBypass.haltAndSetPosition(TicPosBypass);
  
  
}

void resetCommandTimeout()
{
  TicBrake.resetCommandTimeout();
  TicBypass.resetCommandTimeout();
}

void loop(){

  //RPM measurement
  if (RPM_T2 > RPM_T1) {
  RPM = (unsigned)(long)(60000 * RPM_Count / (RPM_T2 - RPM_T1));
  RPM = RPM/teeth;
  RPM_T1 = RPM_T2;
  RPM_Count = 0;
  }
  else {
    RPM = 0;
  } 

  
  //Getting force value
  force = scale.get_units(5),1;


  //Getting potentiometer values
  posBrakeValve = analogRead(posBrakeValvePin);
  posBypassValve = analogRead(posBypassValvePin);
  targetValve = analogRead(targetValvePin);

  //Setting Valve Positions
  if(targetValve <= 512){
    TargetTicPosBrake = map(targetValve, 0, 512, 0, 236805);
    TargetTicPosBypass = 236805; 
  }

  if(targetValve >= 512){
    TargetTicPosBrake = 236805;
    TargetTicPosBypass = map(targetValve, 512, 1024, 236805, 0);
  }

  TicBrake.setTargetPosition(TargetTicPosBrake);
  TicBypass.setTargetPosition(TargetTicPosBypass);

  delay(10);

  //Calculating values
//  targetRPM = map(targetRPMRaw, 2, 1021, RPMmin, RPMmax);

//  //Getting Tic positions
//  TicBrake.exitSafeStart();
//  TicBypass.exitSafeStart();
//
//  posBrakeValve = analogRead(posBrakeValvePin);
//  posBypassValve = analogRead(posBypassValvePin);
//
//  TicPosBrake = map(posBrakeValve, 65, 820, 0, 236805);
//  TicPosBypass = map(posBypassValve, 65, 820, 0, 236805);
//  
//  TicBrake.haltAndSetPosition(TicPosBrake);
//  TicBypass.haltAndSetPosition(TicPosBypass);
//  
//  TicBrakeCurrentPos = TicBrake.getCurrentPosition();
//  TicBypassCurrentPos = TicBypass.getCurrentPosition();
//
//  resetCommandTimeout();
  


  //Printing values on serial monitor
  Serial.print("RPM: ");
  Serial.println(RPM);
  Serial.print("Force: ");
  Serial.println(force);
  Serial.print("Brake Valve Pos.: ");
  Serial.println(posBrakeValve);
  Serial.print("Bypass Valve Pos.: ");
  Serial.println(posBypassValve);
  Serial.print("Target Valve: ");
  Serial.println(targetValve);
//  Serial.print("Target RPM: ");
//  Serial.println(targetRPM);
  Serial.print("Current Pos Brake: ");
  Serial.println(TicBrakeCurrentPos);
  Serial.print("Current Pos Bypass: ");
  Serial.println(TicBypassCurrentPos);
  Serial.print("Calculated Pos Brake: ");
  Serial.println(TicPosBrake);
  Serial.print("Calculated Pos Bypass: ");
  Serial.println(TicPosBypass);  
  Serial.print("Target Pos Brake: ");
  Serial.println(TargetTicPosBrake);
  Serial.print("Target Pos Bypass: ");
  Serial.println(TargetTicPosBypass);    
  Serial.println();
  
  delay(10);

   Wire.beginTransmission (SLAVE_ADDRESS);
   //I2C_writeAnything (targetRPM);
   I2C_writeAnything (RPM);
   I2C_writeAnything (force);
   I2C_writeAnything (posBrakeValve);
   I2C_writeAnything (posBypassValve);
   Wire.endTransmission ();

   delay (10);
  
  TicBrake.exitSafeStart();
  TicBypass.exitSafeStart();
    
}



//Function for RPM measurement
void RPM_Meter () {

  RPM_Count++;
  RPM_T2 = millis();
}


And the SLAVE:

//DYNO SLAVE

#include <Wire.h>
#include <I2C_Anything.h>


const byte MY_ADDRESS = 8;


void setup()
{
  Wire.begin (MY_ADDRESS);
  Serial.begin (9600);
  Wire.onReceive (receiveEvent);
}


volatile boolean haveData = false;
//volatile int targetRPM = 0;
volatile unsigned int RPM = 0;
volatile int force = 0;
volatile int posBrakeValve = 0;
volatile int posBypassValve = 0;


void loop()
{
  if (haveData)
    {
    //Serial.print("Target RPM: ");
    //Serial.println(targetRPM);
    Serial.print("RPM: ");
    Serial.println(RPM);
    Serial.print("Force: ");
    Serial.println(force);
    Serial.print("Brake Valve Pos.: ");
    Serial.println(posBrakeValve);
    Serial.print("Bypass Valve Pos.: ");
    Serial.println(posBypassValve);  
    Serial.println();  
    haveData = false;
    }

}

// called by interrupt service routine when incoming data arrives
void receiveEvent (int howMany)
 {
 if (howMany >= (sizeof RPM) + (sizeof force) + (sizeof posBrakeValve) + (sizeof posBypassValve))
   {
   //I2C_readAnything (targetRPM);
   I2C_readAnything (RPM);
   I2C_readAnything (force);
   I2C_readAnything (posBrakeValve);
   I2C_readAnything (posBypassValve);
   haveData = true;
   }
 }

Please be kind, as I said I´m not a programming guy. To be honest I´m miles away from it :grinning:

Regards,
Josh

You would have a kinder reception if you present this as a non-working system that needs "Project Guidance", than as a Showcased project. Please request that a moderator move it to that sub forum. It's the flag icon below your post.

In the first 30 seconds, I can see huge problems with your code.

With all that hardware in play, we deserve some views of it - photos, links, diagrams, all that stuff.

Thanks for the information.
I flagged it and sent a request to a moderator.

1 Like

Topic moved to the "Project Guidance" category as requested.

Best wishes for success with your project @GeneralEdelweiss

I didn´t do any schematics yet.
I attached two pictures, just for overview.

Maybe it would be a bit too much, if I uploaded a schematic of the whole system. What parts of the system would be of most interest regarding all the I2C stuff?

In the second picture you can see the connector to the second arduino (the one 10m away) down left in the photo.
The grey cable with 3 wires (blue, black, white) is just the power supply.
The potentiometer floating in the box ist the one where I adjust my valve positions.
The red pcbs under the potentiometer are the stepper drivers.
The floating pin header above the potentiometer and stepper driver is where I plugged the LTC4311.
In the top, left to the Nano is the HX711.

Here are some links of the used hardware:
Stepper driver: Pololu - Tic T500 USB Multi-Interface Stepper Motor Controller
HX711: HX711 Load Cell Amplifier - Wägezellen-Verstärker | EXP Tech
Adafruit LTC4311: Overview | Adafruit LTC4311 I2C Extender / Active Terminator | Adafruit Learning System


Entertaining but of no help.
Split the project into small parts and make the part work before even thinking about any other parts.
The massive (unreadable) text tells the story that "some knowledge" is requested....

I did split in in small parts and got it working one by one. First I did the reading of the RPM, then the measurement of force via the HX711, the I2C communication with the stepper valves and so on.
I just now ran into problems with the second Nano on the I2C bus.

Hello @GeneralEdelweiss

Interesting project.
I2C is not designed for working over long distances but it can be made to work. I use it for temperature sensors around my house for my heating. I've found that I2C can lock up and stop working. To deal with this you need to detect that it's happened then do something about it. Doing something about it can be ending the 2 wire connection, setting the pins used for SCL and SDA to outputs then making them go high - low - high in the correct sequence to issue a stop on the bus, then restarting the bus.

However, for simple point to point communication between 2 devices you would probably be better using serial. Serial will work over a long cable without any messing about and is easy to isolate if required.

A Nano does not have a spare serial port. My solution would be to use a Nano Every, which has a spare serial port you could use.

I'm not familiar with the LCT 4311, I might look it up later when I'm on my computer, but at the moment I've no idea what it does or how you are using it.

as mentioned already, I2C is not a bus for long distances.
I2C stands for Inter-Integrated Circuit.

I would use a serial connection, either RS232 or even RS485. If you start playing around with serial commands, please also read

Serial Input Basics

which will give you a good start.

The mentioned Nano Every could be a good choice because of it's HW Serials and the somehow pin compatibility for your screw terminal boards.

Hello everyone,
I threw a small schematic together. In this drawing I didn´t draw every single wire to make it not too confusing. My intention was to give you all an idea about what components are connected with each other, where they get their power from and where the signals are going.
The physical connection of the I2C wires is made like i drew it in terms of daisy-chaining.

I hope this helps.

@PerryBebbington
Thank you very much for your answer.
I know that I2C is not intended for such long distances. That´s why I reduced the clock speed.
The reason why I choose I2C is because in the future I will have about 4 7-Segment displays to control which require I2C.
I was thinking about keeping the I2C for communication with the stepper drivers and Nano #1 and between the T500s and Nano #2. Then I could use the serial ports to communicate between Nano #1 and Nano #2.
The only problem is that I wanted to be able to get the data off of the Arduino onto my laptop when doing dyno runs.

As I said the bus is running fine, at least without the LCT4311 connected.

OK, so I now know what an LCT4311 is.
Based on my experience I would not bother with it, I2C will work over 10m if you are careful. You say you slowed the clock, how slow? What value pull up resistors do you have? I suggest maybe 2k2 at each end of the I2C bus will help.

Wiring is critical. Signals should be in the same cable as their return path. I suggest for I2C you use twisted pair, either cat 5/6 or telephone cable. Each signal (SCL or SDA) should be 1 wire of a pair, with the other wire being ground / 0V. I cannot tell from the diagram what kind of cable you have used. You can use the other 2 pairs (in cat 5/6) for power.

Nice try with the diagram but not showing every wire does not remove confusion it removes important details. Please draw a schematic that shows every wire and shows which wires are in the same cable, especially for I2C.

I don't see that as a problem with a Nano Every, the USB port will go to your laptop, serial 1 on each Nano Every will go to the other Nano Every. While I think I2C can be made to work, using serial would be better and less likely to be troublesome.

Right now all cables are normal single wire cables running in pairs to the devices. Maybe you can see it on the photo I posted yesterday. They are the green and yellow cables.
Currently I don´t use any pullup resistors at all, because the LTC4311 would replace them.
That´s also why I´m wondering why the bus is working without these active terminators.

Could it be a software problem that my bus crashes when I use he LTC4311s?

If I draw every single wire in the diagram it would just add all the connections like the 4 wires of each stepper or the 3 wires to every potentiometer (that´s why I wrote small tags to those connections). The cables for the I2C connection is wired as I drew it. Just imagine the green/yellow line as two wires.

If I would switch to the Nano Every I would have two independent I2C networks, is this correct?
One network would sit in the electrical box on my brake and would consist of the Nano talking to my stepper drivers via I2C.
The other network is in my "control box" connecting the other Nano with all my displays. Then the communication between those two Nanos is done by Serial, right?
This sounds interesting, as it will eliminate my problem with the two way communication over I2C and the trouble of a long distance over I2C.

EDIT:
As for the clock speed, it´s these two lines of code:

  TWBR = 255;
  TWSR = 3; 

I got these from a website where there was a table with all the clock speeds and corresponding values. I can´t find it anymore right now.

Within your cabinet that's probably OK, however, I am more concerned about the 10m cable between the Nanos. Use twisted pairs as I described above, without the LCT4311 and report on the results.

I2C does not work without pull up resistors, they are as crucial as wires are. If it works at all, ever, then it has pull up resistors. Some boards include them, some don't. I don't know for the boards you have.

I doubt it, but that's based on general experience rather then specific knowledge of what you are doing.

No, you would use I2C for the short distances within the box and serial for communication between the boxes. Serial is much more suited to long distance communication than I2C is.

In your code you marked that as

//Wire.setClock(1000);

I suspect it won't go at 1000Hz, but I don't know and I can't test it at the moment. Try at the default speed before trying a lower speed.

I think you are reaching the point where you need to write some simple code that just communicates over I2C and reports the results in the serial monitor. Get that working before adding anything else.

You are absolutley right. Currently I´m running a standard non-twisted pair cable between the Nanos, that´s a no-no.

I assume that the T500 have these integrated, I need to google that.

That´s what I meant. I use the I2C protocol for the communication inside the two boxes (cabinet on the brake and "control-box" that is 10m away from the brake).
Then I will just connect these two boxes with Serial.

Sorry, that´s some old stuff. I tried different things while searching for my errors and commented it away.

As I wrote many times, the code I posted in my first post is working as intended (as far as I can tell with my slave-Nano plotting the values measured by the master onto my serial monitor).
Just only without the LTC4311 active terminators. :thinking:
I´m not adding anything else to the bus. I in fact got everything working one after the other. I just ran into the problem with the LTC4311. Since then I added nothing to my monstrosity.

I really like your suggestion with the Nano Every stuff. This sounds like it would work more reliably. I will then have to tinker with the now-new-to-me Serial communication, but worst case would be that I will learn something :grinning:

I suggest you read this when you start using serial:

Hello everyone,

I got my two Nano Every in the mail today and started tinkering.
I kept it simple and it´s just the two naked Everys and a potentiometer on a breadboard.
One Every (program labeled with "Suitcase") is reading the potentiometer and is sending it to the other Arduino (program labeled with "Cabinet"). I utilized the "SerialTransfer" library for easier handling.
So far everything is working just fine.
The next step for me would be to make it a two way communication.
I read the thread suggested by PerryBebbington, but I must admit it is not very beginner-friendly.
While googling I found many examples for my problem, but they never adressed the two problems I will have later:

  1. Two way communication
  2. Sending MULTIPLE integers or floats

Both Arduinos will read sensors/potentiometers and need to send these values (integers) to the other Arduino.

Here are the two codes, currently just one way communication with one integer:

//Suitcase
#include <SerialTransfer.h>

SerialTransfer dataTransfer;

struct __attribute__((packed)) STRUCT {
  int potiValueTx;
} testStruct;

#define potiPin A6

int potiValue = 0;

void setup() {

  Serial.begin(9600);
  Serial1.begin(9600);
  dataTransfer.begin(Serial1);

  pinMode(potiPin, INPUT);
}

void loop() {

  potiValue = analogRead(potiPin);

  testStruct.potiValueTx = potiValue;

  uint16_t sendSize = 0;
  sendSize = dataTransfer.txObj(testStruct, sendSize);
  dataTransfer.sendData(sendSize);


  Serial.println(potiValue);
}

//Cabinet
#include <SerialTransfer.h>

SerialTransfer dataTransfer;

struct __attribute__((packed)) STRUCT {
  int potiValueRx;
} testStruct;

int potiValue = 0;

void setup() {

  Serial.begin(9600);
  Serial1.begin(9600);
  dataTransfer.begin(Serial1);

}

void loop() {

  if(dataTransfer.available()){

    uint16_t recSize = 0;

    recSize = dataTransfer.rxObj(testStruct, recSize);

    Serial.println(testStruct.potiValueRx);

  }

}

I am not familiar with that library but it appears to send all the data in a struture to an identical struct at the receiving end. You have one integer in your struct, a struct is just a way of grouping together some related variables, so if you want to send 2 variables put 2 variables in your struct at each end and you should find they get sent.

To send the other way just swap the code over from one end to the other.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.