Introduction
Modern cars contain a great number of electronic parts and components (ECUs, infotainment system, instrumental cluster, etc.) connected via some communication bus, typically a CAN, or Controller Area Network.
All these electronics need to be programmed and thoroughly tested, especially because they can affect driving safety. This testing process requires establishing a communication channel with a vehicle CAN bus.
But in many cases, it is difficult to find real cars to test on. In this article, we will propose an alternative way to test automotive applications using an Arduino board, Raspberry Pi, FreeRTOS, and the Qt framework.
CAN bus testing challenges
There are several reasons for why we developed an alternative testing method in the first place. Firstly, firing up a real car every time we need to check some minor changes is annoying and limits scalability.
Secondly, every car can have different CAN signals depending on the OEM and model. And it’s even more complicated with Tier-1 suppliers or aftermarket vehicles. Sure, OEMs do sometimes sell special off-the-shelf kits for CAN testing, but the price of those is rather high.
So the main challenges of CAN bus testing are:
- using real cars is impractical;
- different vehicles have different CAN signals;
- off-the-shelf CAN testing kits are expensive.
And here’s how we overcame them.
Building the solution
We chose FreeRTOS for our solution, as it’s a free and open source real-time OS that can run on relatively low-frequency devices. FreeRTOS is also relatively similar to Blackberry QNX, which is widely used in automotive.
As for hardware, we decided to pick Arduino to be our ECU emulator, since it’s cheap and easy to work with. Plus, there are a lot of compatible extension boards called hats that are easy to find and integrate.
Here’s a quick schematic of the proof-of-concept stand that we did.
This stand served as a quick way for us to ensure that the solution works.
Arduino has its own developer environment, which makes it a bit difficult to transfer code to other platforms. Nevertheless, we decided to employ a more portable software solution called PlatformIO. It’s a framework for embedded development that allows you to write one code for multiple different boards and frameworks.
As a result, we basically created a FreeRTOS task for every use case we needed.
We didn’t spend that much on the components, and Arduino handled it surprisingly well. PlatformIO allowed us to deploy the project on real life hardware used in cars with little changes. We could also use the hardware we got as a logger for the CAN signals in the car with different firmware.
However, Arduino UNO was only powerful enough to handle 3 buttons. It did not have enough memory to send CAN messages from the SD card. FreeRTOS was also quite demanding for that little board, so we went for Arduino Mega for the final solution.
How it works
The structure of the project looked as follows:
All the config was extracted to separate files to simplify porting to different platforms, and the main file was set to contain the Arduino setup function.
Here’s how the solution works:
- User clicks the button on the Arduino board.
- A Specific FreeRTOS task is triggered that sends a given CAN message through the CAN bus to Raspberry Pi. The message contains some meaningful data byte that indicates whether the component was switched on or off.
- Raspberry Pi receives the CAN message and processes it, then visualises it in the Qt application.
The process can be visualised like this:
The FreeRTOS tasks turned out to be relatively simple. For example, here’s the proof-of-concept task to send a specific signal when the button is pressed:
void TaskSendHighBeamMessage(void *pvParameters)
{
(void)pvParameters;
uint8_t ucHighBeamMessage[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint8_t ucLastButtonState = HIGH;
uint8_t ucCurrentButtonState;
uint8_t ucIsHighBeamOn = LOW;
TickType_t xDelay = 256 / portTICK_PERIOD_MS;
for (;;)
{
ucCurrentButtonState = digitalRead(HIGH_BEAM_BUTTON_PIN);
if (ucLastButtonState == LOW && ucCurrentButtonState == HIGH)
{
Serial.println("TaskSendHighBeamMessage: high beam toggled");
ucIsHighBeamOn = !ucIsHighBeamOn;
ucHighBeamMessage[IVO_CAN_DATA_INDEX] = ucIsHighBeamOn;
CAN.sendMsgBuf(IVO_CAN_HIGH_BEAM, 0, 8, ucHighBeamMessage);
}
// save the last state
ucLastButtonState = ucCurrentButtonState;
vTaskDelay(xDelay);
}
}
Demo app
Writing tests for the Arduino solution has proven to be tricky, as it’s not possible to connect our hardware to GitHub Actions. In addition, some of the stakeholders wanted to see this project visualised.
So we decided to create a GUI demo app to show what can be done with our hardware. We had some Raspberry Pi 3 and 4 lying around, so we dusted the tablets off and decided to use them as a portable and tactile demonstration stand that anyone could fiddle with.
We created a simple app using the cross-platform C++ based framework Qt 5 that could run on Raspberry. But it wasn’t a smooth ride from start to finish.
Repository issues
For some reason, prebuilt Qt libraries were not included in the default apt repository on Raspberry Pi OS, and it wasn’t mentioned anywhere. We tried to build Qt from sources, but it didn’t work either. In short, we wasted a couple of days fighting with Qt, only to accidentally find out about the proper apt repo.
To spare some time to anyone who might encounter the same problem, here’s what you need to install for Qt and its IDE, Qt Creator:
- On Raspberry, open the console and open the apt repositories list:
sudo nano /etc/apt/sources.list
- Uncomment all lines in that file.
- If there are no comments (like # deb-src …), then add these ones:
deb-srchttp://deb.debian.org/debian bullseye main contrib non-free deb-srchttp://security.debian.org/debian-security bullseye-security main contrib non-free deb-srchttp://deb.debian.org/debian bullseye-updates main contrib non-free deb-srchttp://raspbian.raspberrypi.org/raspbian/ bullseye main contrib non-free rp
- Save the file with Ctrl+O and exit with Ctrl+X.
- Then you will need to install all the necessary libs, instruments, and so on:
sudo apt install build-essential cmake unzip pkg-config gfortran ninja-build sudo apt build-dep qt5-qmake libqt5gui5 libqt5webengine-data libqt5webkit5 libudev-dev libinput-dev libts-dev libxcb-xinerama0-dev libxcb-xinerama0 gdbserver sudo apt install libxcb-randr0-dev libxcb-xtest0-dev libxcb-shape0-dev libxcb-xkb-dev
sudo apt install qtcreator
After all that, you should have everything necessary for Qt development. You may still need to install some other component libs for Qt Creator, e.g. for sockets. They are usually named something like libqt5<libname>5
.
Conclusion
The developed device and software have improved our workflow dramatically. But still it’s not perfect, leaving us enough space for improvement. We plan to add more features and to convert this tool to a convenient and flexible tech stand for testing automotive applications.
If you wish to suggest any improvements or have any further questions on the topic, feel free to contact us here.
Author:
Andrey Mukamolov
Android Developer