binaryArduino DroneCAN

A library to send CAN messages compatible with Ardupilot and PX4 UAV autopilots.

About

We made a library to make DroneCAN development as simple as possible. the Arduino DroneCAN repository allows you to get started with Ardupilot/PX4 compatible CAN messages and functionality straight out of the box using Beyond Robotix CAN node hardware.

circle-exclamation

Github Repository:

Installation

There are a few ways of working with Arduino Code, we recommend the following steps for seamless integration with the project.

  1. Connect your STLINK to your CAN node

  2. Press upload!

If you want to use the master branch, remember to clone submodules:

Bootloader details

ArduinoDroneCAN uses a modified AP_Bootloader to allow app updates over CAN. The standard AP_Bootloader cannot be used. The bootloader bin can be found in the project repository.

From release 1.3.1 the bootloader is flashed at the same time as the app flashing using the "Micro-Node-Bootloader" configuration.

Breakpoint debugging

We haven't been able to successfully start breakpoint debugging while a bootloader is on the node. So far.

For now, the "Micro-Node-No-Bootloader" platformio configuration is required. Remember, you will no longer have the bootloader so you won't be able to update programs over CAN. Once you've done your debugging sessions, you can then switch back to the other config for app deployment!

Detailed Example

The Arduino DroneCAN project reduces using DroneCAN down to creating an object, initialising the object, and one method to call in your loop function.

General advice

  • Avoid the delay() function! this will disrupt any CAN activities. We show best practises for your loop function later

  • Respect the watchdog. IWatchdog.reload() needs calling within the timeout time (2 seconds in our examples)

  • Following the format of our example https://github.com/BeyondRobotix/Arduino-DroneCAN/blob/master/src/main.cpparrow-up-right will reduce the likelyhood of strange behaviour.

  • If your program starts acting up, strip your program back to our example and build gradually from there. You'll find where bugs get introduced.

  • If your node goes into "maintenance" mode then it means your program is crashing

The Setup

app_setup, dronecan.init and IWatchdog.begin must all be called at the start of setup. Doing another activities before or between functions may result in instabilities. Remember, the watchdog is running after this so call IWatchdog.reload() if you do any long running activities.

app_setup()

app_setup is required to be called at the start of the Arduino setup() function. This function is required as part of the transfer from the bootloader to app control. The function is internally disabled when non bootloader mode is selected in PlatformIO.

dronecan.init()

Next, we initialise the dronecan object and optionally set version number of your software to appear in NodeInfo. In the init() method, we pass two functions which we'll explain later, a parameter list and lastly the name of the node for NodeInfo.

Watchdog

Our program requires starting the watchdog, remove it at your own peril! (it's started in the bootloader and from our testing, starting it here again is best)

DroneCAN looping

We can't use the loop() function normally used in Arduino, for some reasons related to bootloader things which we haven't solved yet.

Instead, we do a while(true)

Fixed interval loops

The following code sets us up to run our if statement at 10Hz, checking if 100ms has passed since our last call. This is because we want to only send our CAN message at 10Hz and we want to call our "dronecan.cycle()" function to be called as much as possible to ensure CAN messages are send and received in a timely manner. We want to avoid delay() as much as possible!

Sensor reading

Next, we want to read in our sensor value. This could be from anything, a current monitor, position sensor.. in this example, we read in the temperature of our STM32 processor. You would have had to have initialised your sensor before the while(true) statement of course.

Sending DroneCAN messages

Next, we initialise our DroneCAN battery message packet and we assign one of its attributes a value from when we read in our sensor. We've used a battery message, since Ardupilot supports 8 of these by default, Mission planner can display information from any of these 8 and Ardupilot logs all battery instances. There may be messages suitable for your application, but be aware, Ardupilot does not support many DroneCAN messages.

Finally, we send our DroneCAN message. For some equipment type can messages, we can use this very simple function:

For messages which are not in this type list:

we have to do the full boilerplate for a UAVCAN/DroneCAN message:

End of the loop

Outside our fixed interval if statment, we call our dronecan.cycle() method, which is required, and we also reset our watchdog timer.

Reading in CAN packets

onTransferReceived and shouldAcceptTransfer are required to be defined in our program and passed to dronecan.init. These functions are used to recieve any DroneCAN messages. We've put an example of decoding a Magnetometer message below. in onTransferRecieved, you can manipulate the recieved packet and use gobal variables or parameters etc to transfer information out of this function. DroneCANonTransferReceived must always be called at the end of this function for our library to work.

to allow a different message to be recieved, shouldAcceptTransfer needs the new message adding to it, following the same pattern as the magnetometer message example. As before, the last line of this function must remain the same for our library to work correctly.

Other things

parameters

We passed the custom_parameters object into dronecan.init. This parameters object needs "NODEID" in the list since we use that. The first value after the type dictates the default value, second the minimum for the parameter and the last the maximum. These min/maxes may or may not be shown in Mission planner etc and may or may not make any functional difference.

You can set and retrieve parameters easily. parameters get saved to flash so they'll be recalled on next boot.

Full example!

Last updated