How to write a driver code for external devices/ i2c messages from arduino to pixhawk

Hello all

I have an airspeed sensor and a pressure sensor which is to be integrated to the pixhawk. I think I will have to write the device driver code too. Have a couple of doubts :slight_smile:

  1. Can multiple i2c devices can be connected to the pixhawk using an i2c splitter ?

  2. This one is about device driver code. I had looked into the existing device drivers code and I see a pattern of how to write the driver code. Just have some little doubts on this :

    a) It is mandatory that I have to write the code in that particular pattern ? Google tells me the kernel interacts with the driver codes and you have to write that in a particular format . Is that so ? How can I get more information about this ?

b) Does the class ioctl and read functions are accessible to the OS only ? Lets say I want to write a daemon app and is it possible to read a device output value of a sensor using the read function defined in the class file ?

  1. Is it possible to send information as i2c/spi/can packets from arduino/teensy to pixhawk and pixhawk can read it using the respective protocol. Can someone provide more info regarding this

A tutorial on writing drivers would be very helpful to enrich sensors supported by pixhawk.


  1. Yes -

  2. This definitely needs some improvement, but the best answer at the moment is to start with a similar driver as a template. If it’s a driver for something common that already integrates with the system (gyro, accel, pressure, etc), then the only pattern you actually need to follow is to publish the correct uORB message.

a) These days PX4 itself almost exclusively consumes data from uORB, however most of the drivers are still accessible via IOCTL. This is how Ardupilot was using PX4 drivers.

b) Yes - you open() the device and can read/write, although I’d recommend going with uORB instead.

  1. Yes I suppose, but I’m not sure I understand why. What’s the full idea?

I’m personally pursuing a simplified driver framework that significantly reduces the required boilerplate, but it’s not going to be ready short term.

@hamishwillee - FYI (interest in driver documentation)

Thanks @dagar

So in terms of docs we just finished and we also have which I hope to rewrite (with your help) in the coming week.

For the I2C doc it

  • provides overview of what I2C can do,

  • suggests you should include drivers/device/i2c.h, and provide an implementation of the abstract base classI2C`

  • suggests you include headers for the type of device (drv_*.h) in /src/drivers/ - e.g. drv_baro.h. (What do these provide? Helper methods or are they things you have to override?)

  • explains how to put into firmware

  • Provides links to helpful examples and other docs

Some questions

  1. Is that about right for “recommendations”? Is there anything else in the “framework” we need to talk about .

  2. Is it worth adding a note that the only requirement is to publish to the right uORB topic - that you can get the information from hardware any way you like (though presumably the underlying classes in the framework exist to make this easy for you (?)

Thanks a lot @dagar and @hamishwillee

Right now I’m looking at the driver code of mpu6000 and hc_sr04 and trying to figure how the coding part is done. I don’t have any experience when it comes device coding so I have difficulties understanding the way IOCTL and READ functions works.The way I understand is this functions are used by the kernel of the OS to manipulate the devices ( am I correct ? ).

I’m trying to get a sound understanding of the whole picture.Can you suggest me some links/pdfs were I could get more information regarding ioctl/read functions.

Regarding the third point :

Currently I’m using Teensy board to read some pressure values and serially send those values to pixhawk which is working fine. I would be better if I can the data packets ( pressure values in this case ) from Teensy/Arduino to pixhawk through any of the protocol’s i2c/can/spi. Its like pixhawk will see the micro-controller board as just another can/spi device. If that’s possible then I could just read the data from the respecitve port from pixhawk. That’s the idea here !..Just want to have your opinion on it.

Abin Ephrem

What’s the actual sensor? Why have the Teensy/Arduino involved at all?

@abin_ephrem , I think I have done something similar to what you are talking about, using an Adafruit Trinket (Arduino compatible) to read a hall effect sensor and a current sensor and send the data over I2C to the Pixhawk. Basically all I did was copy the driver for the MS4525DO airspeed sensor, give it a new I2C address, modify it so that its “collect()” function read as many bytes as I needed from the Arduino, then publish it to a new topic and log it. The thread I started about this is here, you might find parts of it useful: PX4/Pixhawk compatible RPM sensor?

@dagar @annavt

Yes…something similar to what @annavt did. Actually right now I’m trying to measure the propeller speed of a fixed wing aircraft using a simple optical sensor and using the pwm input of pixhwak to calculate the rpm. I’m able to get the rpm approximately using this method but at higher rpm (6000-8000) there is an error of about 200 rpm. Guess I will try to implement what @annavt did.

Earlier I was working with in implementing Five Hole Probe experiment in a small fixed wing aircraft to calculate alpha,beta and velocity. I had 5 analog pressure sensors and teensy will acquire the pressure values and send it to pixhawk serially where I will read it and publish to a new topic. I believe it would be better if I can send the pressure data using CAN/SPI protocol rather that sending it via serial. Looking at what @annavt did I believe its quite possible too now.

Also I would like to understand more about ioctl() functions and device driver coding. Right now I’m depending on the pixhawk firmware and google. Is there better source where I could find a bit more information ?

There’s plenty of general information, but to be honest it’s not necessary.

To over simplify, a driver in PX4 isn’t necessarily anything special. Unless you want to interface with the existing calibration routines you don’t even need to worry about IOCTLs.

You’re “driver” would simply be a module that reads from serial (simple open/read/write/close) and then publishes a uORB message. If it’s i2c you use the i2c cdev interface, if it’s spi you use the spi cdev interface. Get data into the system by publishing over uORB and ignore ioctl read/write/configure.


Thanks a lot man. All I need to go through the existing drivers and make the required changes.

I have some doubts regarding the pwm_input driver code. I want to measure the pulses using the Aux pins ( aux 5 and 6 pins can be configured as input pins right ) of pixhawk to measure the rpm of the propeller. Currently I’m using simple read function to read from the device (/dev/pwmin0). Instead of using read() I want to configure the device with ISR to get a continuous reading. Is that possible with pixhawk ?Is it possible to configure the ISR to the pwm input pin ( using the Aux 5 pin ) and when ever there is a falling edge it should increment a counter.

The built in pwm_input driver does not publish any messages to the pwm_input topic. I can use a simple read() function and publish the messages on to the topic but instead of using read I want the ISR to publish the message to the pwm_input topic. How to make this function static int pwmin_tim_isr(int irq, void *context, void *arg) publish messages to the topic. I’m stuck here for the last couple of days.