MatrixPilot / MatrixPilot

An OpenSource Autopilot
Other
120 stars 72 forks source link

Activating OSD_NATIVE on UDB5 board broke GPS Lock #75

Closed elgarbe closed 8 years ago

elgarbe commented 8 years ago

When I activate OSD_NATIVE on my UDB5 board, broke GPS signal. It is tested, and don't work, in bit bashing mode. OSD seems to work ok becouse I can see artificial horizon update when I move my plane.

phollands commented 8 years ago

I just want to note here in this issue log, that there was some prior discussion of the issue on uavdevboard at this link..

I did some tests this morning where I enabled the OSD with legacy pinout, and then commented out the main routine called mp_osd_run_step() which updates the OSD with the latest telemetry. GPS Lock was obtained in about a minute. I then took out the commenting so that mp_osd_run_step() was live and working. I rebooted. The GPS lock was not obtained after 5 minutes of the plane running MatrixPilot. I rebooted again, and GPS lock again was not obtained after 5 minutes of running the code.

You can see my test branch at this location, if you want to understand what I've been doing in more detail. (That link may go stale when I next rebase the branch onto any new changes in master).

phollands commented 8 years ago

If I comment out 1/4 of the main meat of the mp_osd_run_step() code, then my orange led flashes (rx interrupt on gps toggled on each interrupt) and my blue led flashes (full completion of gps parsing of messages, ready to commit lat / long etc).

If instead I keep all the mp_osd_run_step() code in place, but reduce the frequency of calling it from 8hz to 2HZ, again my blue and orange test LEDs start flashing correctly.

So I am starting to think that somehow, the priorities of the interrupts in the code are potentially not correct (or not what we think they are), and that the heartbeat_pulse() code which should be at priority 3, is actually at the same or a higher interrupt priority than the serial IO rx for the gps, which should be higher and be set at priority 4. In theory, there is no way that the mp_osd_run_step() should be able to stop the serial IO RX interrupt from being fired but that is what the tests say is happening.

Full details of each commit, and the results, for my testing is at my inverted_test branch.

ghost commented 8 years ago

Peter,

It sounds like you are closing in on the issue. If the OSD is using "bit banging", the intentional timing delays could be at the root of the problem. I agree with your reasoning about the the priorities of the interrupts. However, possibly there is some processing of the GPS messages that happens at a lower priority. That said, if that was a factor, I would expect that the orange led would continue to flash, while the blue led would stop. So I am puzzled.

Another thing to look at besides the interrupt priority is the possibility that something in the osd code is somehow simply turning off the GPS rx. But of course, the results you are getting in dropping from 8 Hz to 2 Hz would argue against that, and would support your theory about an issue with interrupt priorities.

Best regards, Bill

On Mon, Oct 10, 2016 at 10:49 AM, Pete Hollands notifications@github.com wrote:

If I comment out 1/4 of the main meat of the mp_osd_run_step() code, then my orange led flashes (rx interrupt on gps toggled on each interrupt) and my blue led flashes (full completion of gps parsing of messages, ready to commit lat / long etc).

If instead I keep all the mp_osd_run_step() code in place, but reduce the frequency of calling it from 8hz to 2HZ, again my blue and orange test LEDs start flashing correctly.

So I am starting to think that somehow, the priorities of the interrupts in the code are potentially not correct (or not what we think they are), and that the heartbeat_pulse() code which should be at priority 3, is actually at the same or a higher interrupt priority than the serial IO rx for the gps, which should be higher and be set at priority 4. In theory, there is no way that the mp_osd_run_step() should be able to stop the serial IO RX interrupt from being fired but that is what the tests say is happening.

Full details of each commit, and the results, for my testing is at my inverted_test branch. https://github.com/phollands/MatrixPilot/commits/inverted_test

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/MatrixPilot/MatrixPilot/issues/75#issuecomment-252643675, or mute the thread https://github.com/notifications/unsubscribe-auth/ANJqw73VoeyqOQ09NujKYTt3S0Jk7qLwks5qylCOgaJpZM4KSKe_ .

phollands commented 8 years ago

Hi Bill,

The Interrupt priority levels was not an issue. I made a mistake in my testing.

I have confirmed now that the GPS baud rate is not being changed from 9800 to 19200 on my Ublox, when the OSD is fully enabled. So that is progress. The little orange LED that shows me the interrupts coming in gave me the clue. The lighting changes in nature from 9800 baud to 19200 baud, especially when the Ublox is fully configured to provide all it's binary data.

I put the Blue LED to come on when the statement in the GPS startup is run to change to 19800. I showed that the baud rate change statement is not executed when the OSD is fully enabled (as in uncomment mp_osd_run_step() ).

Before that; I manually put breakpoints in the serial interrupt, and the mp_osd_run_step() routine, and confirmed by checking the status register that the interrupt priorities were 4 in the serial interrupt, and 3 during the mp_osd_run_step().

My hypothesis for why I did not see interrupts on the serial IO during some tests is:- During debugging I got the Ublox into a state where it no longer sent data at the right baud rate, and no interrupts were being generated. I was reseting the processor using the debugger, but forgot that I need to re-cycle the power on the Ublox for each test. So I came to the wrong conclusion when I saw no interrupts on the serial IO. In later testing, the serial IO is always interrupting after a power on, whether the OSD is running or not. So that is all good.

Now I just need to work out what is happening during the GPS initialisation (both for the EM506 and the Ublox. They both change baud rates during initialisation).

Best wishes, Pete

phollands commented 8 years ago

OK, I'm getting close to the problem I think. Here is a new hypothesis for me to test tomorrow.

heartbeat_counter is updated in the high priority (6) interrupt as part of the MPU6000 dma transfer. That is running at 200Hz.

But most of the processing is happening in heartbeat_pulse at priority 3, including the GPS initialisation. If the low priority hearbeat pulse takes more than 1/200th of a second to complete, then heartbeat_counter will be incremented on by 1, by the high priority MPU600dma transfer heartbeat, while the low priority heartbeat_pulse is still in the middle of executing.

Now the GPS countdown logic for initialising the GPS, is equating countdowns to hard numbers. e.g. if count == 20 then do something like change the baud rate.

But it is quite possible, if the heartbeat_pulse takes more than 1/200th of a second, that although the count was at say 20 when heartbeat_pulse started, by the time it gets to to the gps initialisation routine, the heartbeat counter may have been incremented by 1 to say 21. And so that particular initialisation statement (if count == 20) is never executed.

I'll check into this tomorrow. But everything fits with all the experiments today.

Best wishes, Pete

ghost commented 8 years ago

Peter,

Thanks. Yes, I definitely think that you are on to something. I appreciate all of the hard work and deep thinking you are doing.

Assuming that you have found the source of the problem, then the thing to do is to change the logic to be based on when a counter exceeds a value. It will complicate things a bit, you will need some extra logic to execute each initialization step just once.

I had some misgivings when we switched the heartbeat source from a dsPIC clock over to the MPU6000, because the MPU6000 is running asynchronous with respect to the dsPIC. Some alarm bells went off in my head, in fact, I made a personal decision to abandon trunk and continue to use my private branch for my own flying, with the older code that still uses the dsPIC clock.

I was relieved when everything seemed to work ok when we switched over in trunk, but now it seems at least one thing was broken. I wonder what else was broken in the process?

Best regards, Bill

On Mon, Oct 10, 2016 at 4:10 PM, Pete Hollands notifications@github.com wrote:

OK, I'm getting close to the problem I think. Here is a new hypothesis for me to test tomorrow.

heartbeat_counter is updated in the high priority (6) interrupt as part of the MPU6000 dma transfer. That is running at 200Hz.

But most of the processing is happening in heartbeat_pulse at priority 3, including the GPS initialisation. If the low priority hearbeat pulse takes more than 1/200th of a second to complete, then heartbeat_counter will be incremented on by 1, by the high priority MPU600dma transfer heartbeat, while the low priority heartbeat_pulse is still in the middle of executing.

Now the GPS countdown logic for initialising the GPS, is equating countdowns to hard numbers. e.g. if count == 20 then do something like change the baud rate.

But it is quite possible, if the heartbeat_pulse takes more than 1/200th of a second, that although the count was at say 20 when heartbeat_pulse started, by the time it gets to to the gps initialisation routine, the heartbeat counter may have been incremented by 1 to say 21. And so that particular initialisation statement (if count == 20) is never executed.

I'll check into this tomorrow. But everything fits with all the experiments today.

Best wishes, Pete

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/MatrixPilot/MatrixPilot/issues/75#issuecomment-252732931, or mute the thread https://github.com/notifications/unsubscribe-auth/ANJqw9DWeoqCMbTvtEz0WBgcJIQ0tGzYks5qypusgaJpZM4KSKe_ .

ghost commented 8 years ago

Peter, Another possible solution, if the OSD code is really doing bit-banging, is to change it over to use the dsPIC SPI support instead. That will reduce the amount of time that the OSD code sits in timer loops. Best regards, Bill

On Mon, Oct 10, 2016 at 7:04 PM, William Premerlani wpremerlani@gmail.com wrote:

Peter,

Thanks. Yes, I definitely think that you are on to something. I appreciate all of the hard work and deep thinking you are doing.

Assuming that you have found the source of the problem, then the thing to do is to change the logic to be based on when a counter exceeds a value. It will complicate things a bit, you will need some extra logic to execute each initialization step just once.

I had some misgivings when we switched the heartbeat source from a dsPIC clock over to the MPU6000, because the MPU6000 is running asynchronous with respect to the dsPIC. Some alarm bells went off in my head, in fact, I made a personal decision to abandon trunk and continue to use my private branch for my own flying, with the older code that still uses the dsPIC clock.

I was relieved when everything seemed to work ok when we switched over in trunk, but now it seems at least one thing was broken. I wonder what else was broken in the process?

Best regards, Bill

On Mon, Oct 10, 2016 at 4:10 PM, Pete Hollands notifications@github.com wrote:

OK, I'm getting close to the problem I think. Here is a new hypothesis for me to test tomorrow.

heartbeat_counter is updated in the high priority (6) interrupt as part of the MPU6000 dma transfer. That is running at 200Hz.

But most of the processing is happening in heartbeat_pulse at priority 3, including the GPS initialisation. If the low priority hearbeat pulse takes more than 1/200th of a second to complete, then heartbeat_counter will be incremented on by 1, by the high priority MPU600dma transfer heartbeat, while the low priority heartbeat_pulse is still in the middle of executing.

Now the GPS countdown logic for initialising the GPS, is equating countdowns to hard numbers. e.g. if count == 20 then do something like change the baud rate.

But it is quite possible, if the heartbeat_pulse takes more than 1/200th of a second, that although the count was at say 20 when heartbeat_pulse started, by the time it gets to to the gps initialisation routine, the heartbeat counter may have been incremented by 1 to say 21. And so that particular initialisation statement (if count == 20) is never executed.

I'll check into this tomorrow. But everything fits with all the experiments today.

Best wishes, Pete

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/MatrixPilot/MatrixPilot/issues/75#issuecomment-252732931, or mute the thread https://github.com/notifications/unsubscribe-auth/ANJqw9DWeoqCMbTvtEz0WBgcJIQ0tGzYks5qypusgaJpZM4KSKe_ .

phollands commented 8 years ago

Hi Bill,

I understand your misgivings about trusting an external opaque device for a critical timing pulse. I imagine that Mark wanted to reduce the latency from measuring sensors, to taking action for flight control, on the Quads to the absolute minimum, and so based the udb_heartbeat_counter on the MPU6000 updates.

There is a separate issue that has really been uncovered during my investigations. Many parts of the low priority heartbeat_pulse() code initiate subroutines using something of the form:-

if ((udb_heartbeat_counter % (HEARTBEAT_HZ/40)) == 0)
    {
        // Do some important calculation or control;
    }

Here is the design issue:- Jitter of more than 1/200th of a second, causes some calculations to never be initiated.

The modulo arithmetic comparison, shown above, is operating on modulo 5 in the UDB5 AND AUAV3. If udb_heartbeat_counter increments by 1 during heartbeat_pulse() and suppose udb_heartbeat_counter is 40 at the start of heartbeat_pulse() but changes to 41 during hearbeat_pulse() [i.e. heartbeat_pulse() has taken more than 1/200th of a second and heartbeat() has incremented udb_heartbeat_counter] then the result of the above statement, (udb_heartbeat_counter % (HEARTBEAT_HZ/40)) , will become 1 and not 0, and the related logic will never be completed. That calculation is lost.

Jitter of more than 1/200th of a second can cause routines to not be initiated.

Where could this happen in the logic our code ? I am going to enclose a screenshot, because I cannot cut and paste this data out of MPLAB-X. Some of the following lines are in fact comments and should be ignored. And some of the lines shown are running in the high priority heartbeat() routine, and so will never miss a beat, and so will always run their respective routines. But there are quite a few that have a 1 in 5 chance of not running when there is significant jitter of more than 1/200th of a second.

screen shot 2016-10-11 at 06 12 36

When the main heartbeat is running at 40HZ (e.g. on the UDB4), then we can have jitter of up to 1/40th of a second and the routines will all run in the same way as normal. But with 200HZ, our coding scheme actually penalises any lower priority routine from running if the jitter is more than /200th of a second, even though the lower priority routine may be running at 40hz, 10hz or even 1hz.

When you put that modulo arithmetic issue alongside the gps countdown initialisation scheme which is based on equality and not less than or more than, then I can see why the GPS is not getting initialised when the OSD bit banging SPI routines are running.

So onto solutions .... I will be very interested to hear your views.

I wonder if your have some other ideas.

Best wishes, Pete

phollands commented 8 years ago

You can see an example of slitting udb_heartbeat_counter into udb_heartbeat_counter and udb_pulse_counter at this location. The example works correctly with OSD SPI bit bashing enabled, in that the GPS initiates correctly, and starts to receive full message sets (as shown using LED indicators in the code which are not shown in the commit).

i.e. I now have two variables:- uint16_t udb_heartbeat_counter = 0; uint16_t udb_pulse_counter = 0;

udb_heartbeat_counter is used in heartbeat() [high priority level 6 interrupt] udb_pulse_counter is used in heartbeat_pulse() [lower priority level 3 interrupt]

The result is that heartbeat_pulse() will never lose a beat, but it can potentially, temporarily slip in relation to it's counter relative to the counter in heartbeat(). If it were too slip too often, we would end up with a classic problem of interrupts not completing in time before they are re-called, which is a separate issue. But our issue here is 1/200th of a second jitter. The main cpu is running at 30%, so there is plenty of time for routines to "catch up" if they fall behind, for a moment.

Bill, I've not put in a pull request for the commit above yet, until I hear about your own views on the best way forward.

Best wishes, Pete

ghost commented 8 years ago

Peter,

I like your idea of a separate counter for the low priority routine. It is simple and robust:

"One could consider heartbeat_pulse() having it's own pulse_heartbeat_couunter that is incremented in it's own low priority routine. So then it will never miss a beat. In fact's it is easer to change the name of udb_heartbeat_counter in the high priority code (much less use cases, and simpler logic"

Once again, thank you so much for the great amount of effort that you have put into this, and to the continued support you provide for this project.

Best regards, Bill

On Tue, Oct 11, 2016 at 1:33 AM, Pete Hollands notifications@github.com wrote:

Hi Bill,

I understand your misgivings about trusting an external opaque device for a critical timing pulse. I imagine that Mark wanted to reduce the latency from measuring sensors, to taking action for flight control, on the Quads to the absolute minimum, and so based the udb_heartbeat_counter on the MPU6000 updates.

There is a separate issue that has really been uncovered during my investigations. Many parts of the low priority heartbeat_pulse() code initiate subroutines using something of the form:-

if ((udb_heartbeat_counter % (HEARTBEAT_HZ/40)) == 0) { // Do some important calculation or control; }

Here is the design issue:- Jitter of more than 1/200th of a second, causes some calculations to never be initiated.

The modulo arithmetic comparison, shown above, is operating on modulo 5 in the UDB5 AND AUAV3. If udb_heartbeat_counter increments by 1 during heartbeat_pulse() and suppose udb_heartbeat_counter is 40 at the start of heartbeat_pulse() but changes to 41 during hearbeat_pulse() [i.e. heartbeat_pulse() has taken more than 1/200th of a second and heartbeat() has incremented udb_heartbeat_counter] then the result of the above statement, (udb_heartbeat_counter % (HEARTBEAT_HZ/40)) , will become 1 and not 0, and the related logic will never be completed. That calculation is lost.

Jitter of more than 1/200th of a second can cause routines to not be initiated.

Where could this happen in the logic our code ? I am going to enclose a screenshot, because I cannot cut and paste this data out of MPLAB-X. Some of the following lines are in fact comments and should be ignored. And some of the lines shown are running in the high priority heartbeat() routine, and so will never miss a beat, and so will always run their respective routines. But there are quite a few that have a 1 in 5 chance of not running when there is significant jitter of more than 1/200th of a second.

[image: screen shot 2016-10-11 at 06 12 36] https://cloud.githubusercontent.com/assets/542066/19259473/ddedf0fc-8f79-11e6-9ff3-091e313f64d7.png

When the main heartbeat is running at 40HZ (e.g. on the UDB4), then we can have jitter of up to 1/40th of a second and the routines will all run in the same way as normal. But with 200HZ, our coding scheme actually penalises any lower priority routine from running if the jitter is more than /200th of a second, even though the lower priority routine may be running at 40hz, 10hz or even 1hz.

When you put that modulo arithmetic issue alongside the gps countdown initialisation scheme which is based on equality and not less than or more than, then I can see why the GPS is not getting initialised when the OSD bit banging SPI routines are running.

So onto solutions .... I will be very interested to hear your views.

  • I will try out the SPI module with Leo for the OSD routines, but that is only a patch up really to the existing jitter stopping routines from executing.
  • One could consider heartbeat_pulse() having it's own pulse_heartbeat_couunter that is incremented in it's own low priority routine. So then it will never miss a beat. In fact's it is easer to change the name of udb_heartbeat_counter in the high priority code (much less use cases, and simpler logic).

I wonder if your have some other ideas.

Best wishes, Pete

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/MatrixPilot/MatrixPilot/issues/75#issuecomment-252818298, or mute the thread https://github.com/notifications/unsubscribe-auth/ANJqw2nuc-nLgTKZK9rXX53cj1Gz3fWaks5qyx-2gaJpZM4KSKe_ .

ghost commented 8 years ago

Peter, Yes, there were good reasons to switching to the MPU6000 for the heartbeat. My main reason for being uneasy about that is that if the MPU6000 fails, manual control mode could get locked out. That said, the MPU6000 has shown itself to be reliable, I have never seen it fail. So, eventually, I will switch over to trunk. And once again, thank you, Peter. Best regards, Bill

On Tue, Oct 11, 2016 at 1:33 AM, Pete Hollands notifications@github.com wrote:

Hi Bill,

I understand your misgivings about trusting an external opaque device for a critical timing pulse. I imagine that Mark wanted to reduce the latency from measuring sensors, to taking action for flight control, on the Quads to the absolute minimum, and so based the udb_heartbeat_counter on the MPU6000 updates.

There is a separate issue that has really been uncovered during my investigations. Many parts of the low priority heartbeat_pulse() code initiate subroutines using something of the form:-

if ((udb_heartbeat_counter % (HEARTBEAT_HZ/40)) == 0) { // Do some important calculation or control; }

Here is the design issue:- Jitter of more than 1/200th of a second, causes some calculations to never be initiated.

The modulo arithmetic comparison, shown above, is operating on modulo 5 in the UDB5 AND AUAV3. If udb_heartbeat_counter increments by 1 during heartbeat_pulse() and suppose udb_heartbeat_counter is 40 at the start of heartbeat_pulse() but changes to 41 during hearbeat_pulse() [i.e. heartbeat_pulse() has taken more than 1/200th of a second and heartbeat() has incremented udb_heartbeat_counter] then the result of the above statement, (udb_heartbeat_counter % (HEARTBEAT_HZ/40)) , will become 1 and not 0, and the related logic will never be completed. That calculation is lost.

Jitter of more than 1/200th of a second can cause routines to not be initiated.

Where could this happen in the logic our code ? I am going to enclose a screenshot, because I cannot cut and paste this data out of MPLAB-X. Some of the following lines are in fact comments and should be ignored. And some of the lines shown are running in the high priority heartbeat() routine, and so will never miss a beat, and so will always run their respective routines. But there are quite a few that have a 1 in 5 chance of not running when there is significant jitter of more than 1/200th of a second.

[image: screen shot 2016-10-11 at 06 12 36] https://cloud.githubusercontent.com/assets/542066/19259473/ddedf0fc-8f79-11e6-9ff3-091e313f64d7.png

When the main heartbeat is running at 40HZ (e.g. on the UDB4), then we can have jitter of up to 1/40th of a second and the routines will all run in the same way as normal. But with 200HZ, our coding scheme actually penalises any lower priority routine from running if the jitter is more than /200th of a second, even though the lower priority routine may be running at 40hz, 10hz or even 1hz.

When you put that modulo arithmetic issue alongside the gps countdown initialisation scheme which is based on equality and not less than or more than, then I can see why the GPS is not getting initialised when the OSD bit banging SPI routines are running.

So onto solutions .... I will be very interested to hear your views.

  • I will try out the SPI module with Leo for the OSD routines, but that is only a patch up really to the existing jitter stopping routines from executing.
  • One could consider heartbeat_pulse() having it's own pulse_heartbeat_couunter that is incremented in it's own low priority routine. So then it will never miss a beat. In fact's it is easer to change the name of udb_heartbeat_counter in the high priority code (much less use cases, and simpler logic).

I wonder if your have some other ideas.

Best wishes, Pete

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/MatrixPilot/MatrixPilot/issues/75#issuecomment-252818298, or mute the thread https://github.com/notifications/unsubscribe-auth/ANJqw2nuc-nLgTKZK9rXX53cj1Gz3fWaks5qyx-2gaJpZM4KSKe_ .

elgarbe commented 8 years ago

I will like to add my thanks to the time and effort to make MP a complete and reliable solution for AP.

Best whises, Leo

elgarbe commented 8 years ago

Pete, I will make some ground test in an hour or so. Wich branch do I have to pull to test? Thank

phollands commented 8 years ago

Leo,

The branch is fix_osd That should consist of the latest master, with the commit to fix the GPS starting with OSD bit bash enabled. If you can, I would try to branch your own flight branch to a new branch e.g. gps_fixed_test , and then merge from my own branch osd_fix to your branch gps_fixed_test. :-).

If all that is too much, then I could send you a patch file. You can then then use source_tree to apply the patch to your current flight branch. Note that in this case, You will not want commit that patch change to your branch, as later you will instead want to take the commit from master, and you do not want to have a conflict.

I have now test flown fix_osd, #77 with OSD enabled and bit bash enabled, and the flight went smoothly without problems. I have just to check the telemetry and kmz files.

Best wishes, Pete

elgarbe commented 8 years ago

Ok, I add new remote to my repo. It called Peter and point to your github repo. I checkout my flight branch, it called my_options_flight Then Fetch from Peter remote. Then, select Peter/fix_osd and click on Merge Then push to my repo just in case you want to see am I doing thing ok. And that is! right?

phollands commented 8 years ago

Leo, That is excellent. It all looks correct to me for the ground / flight test on your plane.

I see that you raised some of your Autonomous flight from 50 to 120 meters. How sensible :-)

elgarbe commented 8 years ago

Ok, it work great! https://youtu.be/w3YF-8NnE5o yes, on sunday I make 3 test flight (to get good CG and motor axis angle) and can't test autonomous flight becouse I've remeber that I configure WP to 50mts... I corrected it yesterday, but it was really bad wheter! I will try to test SPI now...

phollands commented 8 years ago

Ok. But I have not done much with the SPI module other than fix the legacy pinout for MISO for the UDB4/UDB5. I have only really been working on the bitbashing SPI version of OSD. Anyway, no harm done by trying a ground test of the spi module.

On 11 October 2016 at 18:29, elgarbe notifications@github.com wrote:

Ok, it work great! https://youtu.be/w3YF-8NnE5o (it will be up in a couple of minutes) yes, on sunday I make 3 test flight (to get good CG and motor axis angle) and can't test autonomous flight becouse I've remeber that I configure WP to 50mts... I corrected it yesterday, but it was really bad wheter! I will try to test SPI now...

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/MatrixPilot/MatrixPilot/issues/75#issuecomment-252986540, or mute the thread https://github.com/notifications/unsubscribe-auth/AAhFct4Chl5A2opjUt1J0wAviFqWvaDuks5qy8d4gaJpZM4KSKe_ .

phollands commented 8 years ago

I liked the youtube video. Thanks for sharing. It a "thumbs up" from Leo, and a thumbs up from my flight test, and now Travis is building MatrixPilot-SIL (Software in the Loop) correctly. So I expect to give the pull request #77 one last review tomorrow, and then merge.

phollands commented 8 years ago

Fixed in #77 .