Unsupported Sensors? Try Arduino + Lua!

@Yuri_Rage thanks for sharing this. I’m trying to implement for a 16bit digital flow sensor that uses a 2 byte register for flow measurement. I was able to get the sensor working on Arduino uno but am having issues outputting to ardupilot. When running the LUA script, I get ‘did not return a function error (0x0)’.

Code:
sfm3300_ardunio_to_px4.lua (3.1 KB)
sfm3300_ardunio_ino.txt (2.1 KB)

The problem looks to be either with implementation of I2C_slave on the arduino sketch or with the LUA script itself.

The lines circled in red below are the only I2C_slave commands that I’ve added to my existing ardunio sketch. Following this, there is a loop that continuously runs a function to output and print data from a single flow measurement register (flowSensor.begin() function is called from a header file). See attached sfm3300_ardunio_ino for full code.

With my LUA script, I suspect the issue is most likely in the update function shown below. I am unsure whether I’m using the correct register in the write_register function on line 81. I currently have the 16bit flow measurement register.

Would very much appreciate if you’d be able to take a look and provide any feedback - thanks.

@Yuri_Rage I updated both the ardunio and lua scripts to simplify- here’s where I landed. LUA script now runs, but outputs 0 instead of the expected flow rate. Any ideas on the issue here? Thanks

Arduino Sketch with I2C Slave commands:

LUA Script:

Code:
sfm3300_ardunio_to_px4.lua (2.0 KB)

Assuming the sketch code to read your sensor data is valid (which it does not appear to be since you seem to be ignoring bytes and also attempting to store them in varying types), you’re sending a float value but not collecting it properly in Lua. Look at the DS18B20 example. Floats are 4 bytes and have to be “reassembled” on the autopilot side. It would make more sense to send the raw data and do the conversion in Lua.

Additionally, you’re giving the Arduino the same address as the sensor, so even if any of the code was functional, it would be unpredictable in results.

But…since your device already appears to be an I2C device, there really isn’t a need to use my library. You could just interact with it directly from the autopilot via Lua.

The intent of this project is to provide data from a non-I2C device to the autopilot, using the Arduino and I2C as a conduit.

Thanks for the advice.I resorted to ardunio + lua because the standard ardupilot firmware can only read I2C devices with 8 bit registers and my device uses 16 bit registers.

I see the unpack_ieee754_float() function implemented in the ds18b20 example but am struggling to understand how it works and what needs to be changed for my use case.

My virtual registers should be 2 bytes where the 1st byte (register 0) stores the size of the data and the second stores the actual data (register 1). It looks like the unpack_ieee754_float() function in the ds18b20 example takes a 4x1 table as the input (perhaps to account for the additional data registers?) where I need to take a 2x1 table.

1 Like

Use your Arduino sketch to read the data and store it in an integer or float as needed. Use the example scripts to see how those types can be handled across the I2C interface between the Arduino and the autopilot.

And be careful - the library uses the Wire object already. If you reinitialize it for use with another I2C device, you may get strange results (I wrote this as a way to interface non-I2C devices).

1 Like

Thanks @Yuri_Rage . I was able to get a very basic example working where I write a fixed float using Slave.writeRegisters() in the Arduino sketch, then unpack the 32 bit number in LUA via unpack_ieee754_float() and output to Mission planner.

When I apply the same methodology to my sensor, read_register_data() outputs a nil table. So there appears to be an issue with reading the register from the Arduino in LUA. I verified that the Arduino sketch outputs the intended float data from the sensor, but when I connect the Arduino + sensor to the PX4 I2C port and run the LUA script there is an issue collecting the data (even before being unpacked).

The only issue I can think of here is incorrect inputs to the arduino_i2c = i2c.get_device(I2C_BUS, SLAVE_ADDR) function. In the LUA script, I set the SLAVE_ADDR to 0x09 (not the sensor address 0x40) which is the address used to designate the Arduino board. I also verified that I set the correct I2C_BUS index.

I’m not really sure what else to try at this point, would appreciate any other troubleshooting recommendations you may have. Thanks.

LUA script:

I suspect this has to do with mishandling the Wire object in your Arduino code.

I am using Wire.write() and Wire.read() to read the data register in the sketch. To avoid reinitializing, do I need to find a workaround that does not use wire object at all?

You should use the TwoWire library and different SDA/SCL pins. Or rewrite my library to do that.

What you’re doing now will be entirely ineffective.

Again, I did not envision nor account for the use case where the Arduino will act as both master and slave.

1 Like

Hi @Yuri_Rage
I have a lua driver for a temperature sensor that is working well. I would now like to see it on my GCS, I can see it in Mission planner by sending a named float, but I also need to see it in QGC (on herelink). QGC allows me to view the temperatures of the battery, so if I can write to these values then I’ll be all set.
I think one can send a mavlink message to set these values, but I have no idea how to do this from within lua.
How would I go about setting the BATTERY_STATUS.Temperature value from within lua?

You can’t without a binding to the battery monitor backend. Like @iampete, I don’t have a solution for you if QGC doesn’t display custom float values.

Excellent work @Yuri_Rage thanks.
works great with Arduino nano, but could not compile on ESP32.
Got compilation error: " Compilation error: exit status 1 "
the error: "Arduino\libraries\I2C_Slave\src/I2C_Slave.h:58:46: error: ‘_registers’ declared as an ‘inline’ variable ".
The code line that triggers the error:
" inline volatile char _registers[BUFFER_LENGTH]; // BUFFER_LENGTH from Wire.h "

is it possible to eliminate it ?

That looks like a problem with your build environment. I did not write Wire.h, but I do know that Espressif often updates the libraries that get included with various IDEs.

Thanks for the quick response @Yuri_Rage , checked it on another pc and got the same warning, wonder if this is Espressif related… have no idea on how to check it as well…
using wire.h directly did not yield this error.

I just compiled for ESP32 in a recently updated PlatformIO environment, and I do see a compiler warning about similar, but the build finishes and results in a functional binary.

If you are using PlatformIO, the following platformio.ini entry fixes the warning (forcing compilation with gnu++17):

[env:esp32]
platform = espressif32
board = esp32dev
build_unflags = -std=gnu++11
build_flags = -std=gnu++17

using Arduino IDE 2.0.4 that gives me the error and stops compiling.
compiling for AVR Nano platform did not give this error.

I’m not going to rewrite the library because Arduino’s sh*tty IDE won’t accept compiler flags. Recommend using PlatformIO or another, better build environment.

3 Likes

Well @Yuri_Rage … you were right, my ESP32 board library was obsolete, changed to the correct (and updated one) and now it works … many thanks :slight_smile:

1 Like

Thats a very interesting blog post. I’m planning on using it to add multiple rpm sensors.

Can you please explain the connection of the arduino to the autopilot? Lets say that we have an arduino Nano and a cube orange.

Whatever pins you use as SCL and SDA on the Arduino must be connected to the I2C port on the autopilot, along with a common ground.

1 Like