Incorporating External Sensor Circuit Outputs into the APM Log Files

Hi Everyone,

I am looking for a way to log readings from an external custom sensor circuit with the APM logs. For hardware, I can use either the APM unit or an external Arduino to wire the sensor circuits and then read this value out into the APM. Once figuring this out, there is the additional challenge of getting this data into the APM logs in order to have precise location information for each sensor sample.

Does anyone know how I could do this???



Views: 7479

Reply to This

Replies to This Discussion

Hi Adam, a lot is possible if you don't mind coding it yourself. What sort of signal are you looking to monitor? What frequency do you need to record at? If you are just after a 'quick fix' then perhaps you could substitute your signal for either the voltage or current inputs currently monitored by the apm? Obviously you would have to disable any battery failsafes. If you do want to custom code a solution then you'll have to get familiar with the development tools/environment. I added the ability to log rssi to a version of arducopter, logging one of the inputs shouldn't to big a deal.

Hi James, I'm looking to monitor environmental conditions from small sensors wired to an Arduino. I would have about 6 different sensors outputs, so maybe PWM is the way to go? The frequency should be minimally 5 Hz. It sounds like custom code will be the way to go and I may even need a Pixhawk for the added memory space. What is everyone using currently to develop on Pixhawk's STM32F4?

If you are already using an Arduino to read the sensors then you could look at connecting it to the APM as an i2c slave device. The i2c port on the APM is where you attach the external magnetometer so you would need to get or make a 'Y' cable if you already use one of these (the i2c port supports connecting multiple devices in parallel, each individually addressable) There are plenty of Arduino i2c examples around on the net to follow but you can start here: The APM is already configured as the i2c master so you will have to code your Arduino as the slave device as in this example.

There are already 'user hooks' set up in the APM code to allow you to run your custom code at specified intervals (1, 3.3, 10, 50 and 100 Hz loops) If you strictly need 5Hz then you will have to use the 10Hz loop and perform your operations every 2nd call. It will be up to you to decide how you are going to format the data that is transferred to the APM and how you will format it in the log.

If you have not done so already, you should download and get familiar with the ArduXXX code and the development tools for your platform. Check out Once you can compile and run your own code on the APM, you will be a big step along the path to your goal. 

If you have any further questions along the way, I am happy to help as best I can.

Excellent, thank you James!


I actually found this quite interesting as I potentially have an application for this myself. I have had a bit of a play and I have managed to connect an Arduino Nano running 6 (virtual) sensors and transmitting the data to an APM2.5 via i2c.

The APM (running my modified Arducopter 3.2dev) is logging the data from the Nano at 10Hz and you can display the results in the MP log browser. I have included the files you need here including the sketch I used for the Nano emulating 6 attached sensors (putting out various waveforms with random amplitude and period). Currently it is set up to transfer 6 floating point numbers (float) which amounts to 6x4=24 bytes per read. Depending on your sensors, you could probably get away with two bytes per sample which will help reduce the load. As it is, at 10Hz there does not seem to be any problems.

To get the code to work, copy the contents on the attached zip file into the same folder your Ardupilot directory is in. It will overwrite the UserCode.pde and UserVariables.h files but if you haven't already added any customised the code, this is OK. You will need to alter APM_Config.h and uncomment the following lines:

#define USERHOOK_VARIABLES "UserVariables.h"
#define USERHOOK_INIT userhook_init(); // for code to be run once at startup

#define USERHOOK_MEDIUMLOOP userhook_MediumLoop();        // for code to be run at 10hz

Depending on what platform/compiler you are using, you may also have to disable various modules in this file so that the code fits on the APM.

You will also have to add the following two lines to the LogStructure definition in log.pde:

{ LOG_SENSORS_MSG, sizeof(log_Sensors),
"SENS", "ffffff", "Sine,Tri,SawR,SawF,Rand,Square" },

This is at line 694 in Arducopter 3.2dev

That should be it. Compile and upload to check it out!


James, I am on a very similar project. I wonder if it's such a good idea to use a 5V arduino nano, because I believe that the i2c bus from the magnetometer port is running 3.3V logic level. What do you think about this?

Hi Manu, yes this is a very good point and I was somewhat remiss in not covering this as the photo I have posted is obviously misleading... In my defence, the attached Arduino was there purely to facilitate a demonstration of the APM code :) The Nano you see in the pic has been modified to run off 3.3v . Quite a few of my Nanos end up this way as 3.3v is much more common now (I have not had any trouble at 16MHz but you may want to be careful if your application is mission critical). Other options would include disabling the internal pull ups and applying external pull ups to 3.3v (from APM as the 3.3v pin on Nano is supplied from the FTDI chip and is not available when not powered by USB), using a level shifter or using a 3.3v Arduino Pro Mini. 

Thanks for this answer. Now I am starting the funny part with handling i2c semaphore and checking that nothing goes wrong with the magnetometer + slave arduino. Did you try to send sensors data not only to the APM log, but to ground station with MAV message?

Did you get this working with magnetometer?

I made it work with an i2c splitter, so you keep the magnetometer installed.

 Did you have to do some kind of fault checking code because there were two devices on i2c bus?

Now I prefer to output some APM data to my external electronic device handling sensors rather than logging sensors data to the APM logs.

Anyway, it is the same about i2c protocol. You have to use AP_HAL::Semaphore to avoid errors.

What is working for me is to do something like this in the user code:

 AP_HAL::Semaphore* _i2c_sem = hal.i2c->get_semaphore();

if (!_i2c_sem->take(5))

//error check

if(hal.i2c->write(2,sizeof(DataToSend), DataToSend) !=0)
{//gcs_send_text_P(SEVERITY_LOW,PSTR("writing error"));


The function gcs_send_text_P is nice for debugging (text only), you get the message in Mission planner last tab.

One last thing when playing with user code before flying your copter: arm it without props, and play with it. Download dataflash logs and check PM messages about slow loops. I had an issue which was making the APM running very slow which was not good when flying...

Reply to Discussion


© 2020   Created by Chris Anderson.   Powered by

Badges  |  Report an Issue  |  Terms of Service