Hi there,
I'm a french student working on an autonomous parafoil recovery system, (https://www.youtube.com/watch?v=vNYQW6N5U98 https://hackaday.io/project/176621-r2home) designed for weather balloons or model rockets. I'm working on this project for a little while now, but I'm only really starting to work on the "flight controller" part of the project.
Here is a picture of the system :
I already have all the hardware ready for further software development, but I'm starting to reach my (very low) limit in terms of programming knowledge, so I'm looking for advices or ideas, to get me closer to my goal. It mainly concerns issues about serial communication, and time management in a loop.
Here is a picture of the latest version of my flight controller :
As you can see, it's mainly just a Teensy 4.1, on a fancy PCB with fancy connectors. There are just also two different powering circuits on it, one for the Teensy, with a buckconverter, and then a linear regulator. And another powering circuit for the servos.
This flight controller need to communicate continuously with multiples devices, like for example a GNSS receiver (SAM M8Q), a barometer (BMP280), an SBUS receiver, a telemetry transceiver (SiK Radio), while also controlling two PWM signals for servos, reading one PWM signal coming as a feedback from one of the servos. The Teensy is also recording ~40 importants flight variables on a µSD card onboard at a rate of 20Hz. Finally the Teensy is managing a buzzer (passive buzzer) and an Adafruit RGB led.
Here is the actual version of the software, it is running OK, but I'm encountering many problems that I'm going to explain just a bit later : https://github.com/YohanHadji/R2Home/tree/main/R2Home_rls_V0.96_DEBUG
If you don't want to read the full code, which I would fully understand, here is the short version with only the main loop :
What getdata() does is checking :
1. Is there any new char from the GPS ?
2. Is it time to poll the barometer ? If yes -> poll the barometer
3. Get RC commands
4. Check battery voltage
What datacmpt() does is "computing" all the data :
1. Based on GPS data, check if the GPS is healthy or not
2. If GPS has been updated, compute navigation data again
3. Compute vertical speed, from barometric data
4. Run the altitude fusion between barometer and GPS
5. Get all the data into strings, to prepare them for single shot SD datalog, and telemetry send.
6. Check if it's time to log data or send it via telemetry
flight_state() is the flight mode state machine, it contains all the conditions to transition from one flight mode, manual for example, to another, autopilot for example
What applycmd() does is deciding based on the flight mode what goes into the servo command variable, either the manual command, or the autopilot command
What updatecmd(100) does, is updating the servo command at a given rate, 100Hz in that case. Why do I need such a function ? Because one of the servo I'm using, is a, continuous rotation, digital feedback servo. So it means I have to read a feedback at 100Hz or less or more, and update the command I'm giving to this servo with a PID, to be able to control it, not in speed, but by rotation angle, like a normal servo, but on a wider angle range.
Finally what userinter() does is :
1. Feeding the EasyBuzzer lib, this lib is very useful to offload the work to get buzzer alerts on flight mode transition etc.
2. Monitor the battery voltage, and if critical, trigger another buzzer alert. A
3. Changing and updating the state of the Adafruit RGB led. This RGB led is describing the flight mode, and helps me to know if the system is ready for flight.
Now let's talk about the problems I'm facing. The first problem I have, is that I'm having troubles, getting a stable UART communication between the GNSS receiver I'm using, and the Teensy 4.1.
Here is the situation : the GNSS receiver, is sending at a given rate navigation messages trough UART, and I have a small function that is counting how much time has passed since the last UART message has been received correctly by the Teensy 4.1. Now if I run the GPS code part alone, everything is working great, and in a very logical way, this time is oscillating between 0 and 100ms (if for example the GNSS receiver is set to send a message at 10Hz).
However as soon as I run the complete code, the communication isn't stable anymore, and sometime, the Teensy keeps missing GNSS messages for >10s, while the looptime is of course staying well under 1ms. Fortunately, I think I've found a first part of the problem: it becomes way less frequent when I stop executing this line of code that allows to read the pwm feedback value from the servo :
And this is where I started to learn about interrupts. Here is my understanding, please tell me if I'm wrong: to execute this function, the Teensy needs to stop everything else, wait for the pulse to go high, then for the pulse to go low, and then start everything again. So if the GNSS receiver was transmitting anything while the Teensy was measuring the length of the pulse, then this message is lost (?)
And this is also where I started realizing that maybe this function isn't the only one in my code to be able to freeze the UART communication. The main problem here, is that there are no ways to really precisely know when the GNSS will send a new message to make sure I'm not reading a pulse at the same time, or doing anything else that would also freeze the code.
Is there a generic way to "protect" the UART communication and give it "admin roles" over everything else? In my case getting those GNSS messages is one of the most important thing the µC has to do. I have found nothing so far, but I'm surely just looking for the wrong thing or with the right words. Otherwise are there maybe generic rules for the Teensy to make sure I'm not using a function that can prevent other functions from working properly?
I also have other similar problems on this project, but I think I should solve this one first.
Thank you in advance for your ideas or suggestions.
Yohan
I'm a french student working on an autonomous parafoil recovery system, (https://www.youtube.com/watch?v=vNYQW6N5U98 https://hackaday.io/project/176621-r2home) designed for weather balloons or model rockets. I'm working on this project for a little while now, but I'm only really starting to work on the "flight controller" part of the project.
Here is a picture of the system :
I already have all the hardware ready for further software development, but I'm starting to reach my (very low) limit in terms of programming knowledge, so I'm looking for advices or ideas, to get me closer to my goal. It mainly concerns issues about serial communication, and time management in a loop.
Here is a picture of the latest version of my flight controller :
As you can see, it's mainly just a Teensy 4.1, on a fancy PCB with fancy connectors. There are just also two different powering circuits on it, one for the Teensy, with a buckconverter, and then a linear regulator. And another powering circuit for the servos.
This flight controller need to communicate continuously with multiples devices, like for example a GNSS receiver (SAM M8Q), a barometer (BMP280), an SBUS receiver, a telemetry transceiver (SiK Radio), while also controlling two PWM signals for servos, reading one PWM signal coming as a feedback from one of the servos. The Teensy is also recording ~40 importants flight variables on a µSD card onboard at a rate of 20Hz. Finally the Teensy is managing a buzzer (passive buzzer) and an Adafruit RGB led.
Here is the actual version of the software, it is running OK, but I'm encountering many problems that I'm going to explain just a bit later : https://github.com/YohanHadji/R2Home/tree/main/R2Home_rls_V0.96_DEBUG
If you don't want to read the full code, which I would fully understand, here is the short version with only the main loop :
Code:
void loop() {
tloop = millis();
getdata();
datacmpt();
flight_state();
applycmd();
updatecmd(100);
userinter();
loop_time = (millis()-tloop);
if (loop_time<100) {watchdog.reset();}
}
What getdata() does is checking :
1. Is there any new char from the GPS ?
2. Is it time to poll the barometer ? If yes -> poll the barometer
3. Get RC commands
4. Check battery voltage
What datacmpt() does is "computing" all the data :
1. Based on GPS data, check if the GPS is healthy or not
2. If GPS has been updated, compute navigation data again
3. Compute vertical speed, from barometric data
4. Run the altitude fusion between barometer and GPS
5. Get all the data into strings, to prepare them for single shot SD datalog, and telemetry send.
6. Check if it's time to log data or send it via telemetry
flight_state() is the flight mode state machine, it contains all the conditions to transition from one flight mode, manual for example, to another, autopilot for example
What applycmd() does is deciding based on the flight mode what goes into the servo command variable, either the manual command, or the autopilot command
What updatecmd(100) does, is updating the servo command at a given rate, 100Hz in that case. Why do I need such a function ? Because one of the servo I'm using, is a, continuous rotation, digital feedback servo. So it means I have to read a feedback at 100Hz or less or more, and update the command I'm giving to this servo with a PID, to be able to control it, not in speed, but by rotation angle, like a normal servo, but on a wider angle range.
Finally what userinter() does is :
1. Feeding the EasyBuzzer lib, this lib is very useful to offload the work to get buzzer alerts on flight mode transition etc.
2. Monitor the battery voltage, and if critical, trigger another buzzer alert. A
3. Changing and updating the state of the Adafruit RGB led. This RGB led is describing the flight mode, and helps me to know if the system is ready for flight.
Now let's talk about the problems I'm facing. The first problem I have, is that I'm having troubles, getting a stable UART communication between the GNSS receiver I'm using, and the Teensy 4.1.
Here is the situation : the GNSS receiver, is sending at a given rate navigation messages trough UART, and I have a small function that is counting how much time has passed since the last UART message has been received correctly by the Teensy 4.1. Now if I run the GPS code part alone, everything is working great, and in a very logical way, this time is oscillating between 0 and 100ms (if for example the GNSS receiver is set to send a message at 10Hz).
However as soon as I run the complete code, the communication isn't stable anymore, and sometime, the Teensy keeps missing GNSS messages for >10s, while the looptime is of course staying well under 1ms. Fortunately, I think I've found a first part of the problem: it becomes way less frequent when I stop executing this line of code that allows to read the pwm feedback value from the servo :
Code:
pulseIn(feedback_pin, HIGH, 1200)
And this is where I started to learn about interrupts. Here is my understanding, please tell me if I'm wrong: to execute this function, the Teensy needs to stop everything else, wait for the pulse to go high, then for the pulse to go low, and then start everything again. So if the GNSS receiver was transmitting anything while the Teensy was measuring the length of the pulse, then this message is lost (?)
And this is also where I started realizing that maybe this function isn't the only one in my code to be able to freeze the UART communication. The main problem here, is that there are no ways to really precisely know when the GNSS will send a new message to make sure I'm not reading a pulse at the same time, or doing anything else that would also freeze the code.
Is there a generic way to "protect" the UART communication and give it "admin roles" over everything else? In my case getting those GNSS messages is one of the most important thing the µC has to do. I have found nothing so far, but I'm surely just looking for the wrong thing or with the right words. Otherwise are there maybe generic rules for the Teensy to make sure I'm not using a function that can prevent other functions from working properly?
I also have other similar problems on this project, but I think I should solve this one first.
Thank you in advance for your ideas or suggestions.
Yohan