GPS Module, Extensions for handling other sentences, and u-blox NEO-6M GPS receiver #580
Replies: 17 comments
-
Posted at 2014-09-27 by @allObjects part 2 of 5 of: GPS Module, Extensions, and u-blox NEO-6M GPS receiver All code fragments of previous post and this one can coexist and can therefore be copied and pasted into the Web IDE edit pane, sent at the same time to the board, and individually invoked from the console pane or custom made functions. The following setup is common to both - basic and enhanced - modes. Again, notice comments for the inline vs. module way of using the code.
The code below - example A) - shows the basic mode usage and validates the backward compatibility.
For convenience - and coexistence in the Web IDE and sending to board - I added a goXyz...() function to be invoked in the command pane to run the vaious modes A) through C). The goBasic() function connects the gps and passes the callback handler function .gpsHandlerFunction() as specified in A) above. This function is the same as used in Espruino's module documentation - http://www.espruino.com/GPS. Instead of defining it inline while passing it, it is defined as a variable and used in all scenarios to write to the console the data objects which is created by the various line handlers.
After sending the code to the board, enter goBasic() into the command pane to use the GPS module in basic mode. Example B) is kind of a twitter: uses an wrapping line handler to wrap the defaultLineHandler() of the GPS module and is thus reusing it. The .includeDefaultLineHandler property with value true, makes the enhance GPS module to add the defaultLineHandler() function as same named method to the passed handler object.
Invoke the function below in the command pane to run example B).
part 2 of 5 of: GPS Module, Extensions, and u-blox NEO-6M GPS receiver |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-09-27 by @allObjects part 3 of 5 of: GPS Module, Extensions, and u-blox NEO-6M Example C_ shows - finally - extensions with two line handlers in addition the to reused defaultLineHandler() of the GPS module:
Use the related goEnhancedWithDefaultAndOther() function to run the example.
The raw handler shows the line 'as is' in the console for the purpose of exploring all the sentences the GPS receiver sends on serial data event, creating the following out put:
part 3 of 5 of: GPS Module, Extensions, and u-blox NEO-6M |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-09-27 by DrAzzy
Why not extend the GPS module itself to fix this, and put in a pull request? Modifying the module code would be a much more graceful solution, I'd say. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-09-27 by @allObjects On my way to there. Question is: how much should it be backward compatible? |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-09-29 by @gfwilliams
It needs to be completely backwards compatible. People do use it as-is and will be upset if their code breaks. What about something like this:
So that way the module code is backwards compatible, and only needs changing to:
Not tested, but it should work. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-09-29 by @allObjects I'm in very 'violent' agreement with the 100% backward compatibility - nothing is as annoying as trying something out of the box and it does not work... and stops working after a while. Other comments:
Therefore I chose to use different type(s) for 2nd argument. Type is handled only once at connect execution time. The handler object's constructions allows to reuse the existing line handling. @gordon, you did not mention the addition of the tag in the existing handleGPSLine() function. Would you consider the code with the addition still compatible? Furthermore, you did not mention the renaming of the internals. Would that keep the compatibility for the people? May be a general discussion about initial setup of modules whit very limited, exemplary functionality is worth a discussion. The questions to answer would be:
|
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-09-30 by @gfwilliams Well, your method with the object as the second argument seems good, but I'd remove I don't think renaming internal things would cause problems - they'll probably just be minified anyway. I'd try not to use long variable/function names though (while still trying to keep them informative and readable). In terms of modules:
Just to clear up my thinking here, if given the following choices:
I think the first option is the right one for Espruino. Espruino straddles a difficult line - it's trying to be easy to use, but it is a microcontroller with very limited storage. I don't think we should waste that storage on functionality that most people won't use when they pull in the module. About the addition of the tag: Yes, it'd be compatible - but I don't think you should add it. If you're extending the GPS module yourself, why can't you just add it if you need it? Otherwise for everyone else it's just wasting their memory. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-09-30 by @allObjects part 4 of 5 of: GPS Module, Extensions, and u-blox NEO-6M GPS receiver @gordon, had some time to think... and code... under the influence of your input. The code below is a first attempt.
Output in console: Basically - for the usage of the module - either:
or:
Basically - for the implementation -
Btw, I would consider above approach a Lambda or functional approach, where after module load 'no' application nor object oriented object is (yet) available, but merely a bootstrap function, which is not even equally to a 'new' or a constructor. This 'into an object wrapped' function has first to be called in order to get a (useful) object (with state, and now also with function) back. - Btw, what is/was the rational of returning the {line:""} object on .connect()? - The module documentation http://www.espruino.com/Writing+Modules follows more the object-oriented approach, even though - due to the nature of JS - the 'class definition' is a function. For the GPS module I would like to have a similar approach chosen, even if the GPS stays a Singleton / would not have a constructor, so that already with require("GPS") an object is available for custom alteration. I will look into this option in a next phase while - of course - keeping 100% compatibility with current 'usage documentation'. I still try to find what's right for Espruino. Having now lived many years - and still live - in a world of memory abundance, doing the right thing for Espruino is a welcome challenge. Not that I waste memory or cycles - I actually have the opposite habit - because I started out with having just 16KB (Kilo bytes) for application AND data AND ANY utility code - such as ISAM-create/read/update/delete, input routines, etc., and some of my Espruino-like hardware real world projects had just 256 bytes and 1KB EPROM and 4MHz 8-bit processing capabilities. Since then there is always the frugal guy in the back of my head watching over my spending of both memory and cycles, because even in today's memory and cycle paradise resources are limited... if not technically, then more so economically (currently building software for 15K+ concurrent transactional users - where user AND operator has to be kept happy: first one w/ snappy response times and latter one w/ spending 'no fancy' $s). @gordon, some pointers about the implementation of js in Espruino is very welcome here. I provide you an example in more detail at (see http://forum.espruino.com/conversations/255954) from code I'm working on: An array with a lot of small string elements in source code uses obviously more memory than one with few but long strings that later are chopped up into the small ones and stored again in the very same array. The short string are of the form of "keyNMO". Back to the GPS discussion at hand: Add the following code to the above one, send code to board, and use command go2() in the command pane to get the gps connected and handling lines (just) with the custom RMC line handler instead of the module's own ggaHandler. For simplicity, same already known callback is used.
Output in console: You may notice that the ggaHandler 'is lost' for good... (became inaccessible for good). The module's valuable ggaHandler can though easily be reused/included in the custom handling. Just provide the first tuple of 'handler duos' with null (no) line handler. On connect, the module's ggaHandler will be pulled and paired up with the callback provided in the first handler duo. To make that obvious / visible, a different calback2 call back is provided. Add the following code to the above one, send code to board, and use command go2() in the command pane to get the gps connected and handling now two lines, the GGA tagged line with the module's own line handler and callback2(), and the RMC tagged line with the custom line handler and initially established callback().
Output in console: I'm not really sure about the overall value of enabled - but I liked the option to to shut up the console... - last but not least for copying console output to this post without having a nervously scrolling away text - or, in the target application - to quiet down the display... ;) What should be discussed is the value of the try-catch-block. In different context I had issues with the process stopping after some time - less than one hour - and errors showing in the console. Especially with line handlers that do not take into account when the GPS is not yet providing complete data, for example, while still trying to get enough satellites for decently reliable position determination. What I'm though confident about is:
part 4 of 5 of: GPS Module, Extensions, and u-blox NEO-6M GPS receiver |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-09-30 by DrAzzy Re: Strings A string takes 1 jsvar per 12 characters. A simple array takes 2 jsvars per elements in the array, plus each of the elements has to be stored. Large simple arrays are very inefficient in Espruino. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-09-30 by @allObjects @drazzy, this explains why I ran out of memory... but how do you explain that after adding even more logical strings (keys) in less physical strings, but then storing them back with the old format - 1 key per element - out of memory condition was avoided? The explanation would be: A string takes 1 jsvar per 12 characters in the source code. Does that sound right? |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-09-30 by DrAzzy I cannot explain that. Maybe gordon can. I'd missed the bit about your being able to create the same array with split and not getting the out of memory error - that makes not a bit of sense to me either. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-09-30 by @allObjects ...may be I tapped into memory beyond the safety margins, which is a sure call for disaster... I'll start a new conversation - http://forum.espruino.com/conversations/255954 - for that memory stuff and cross reference to keep this one focused on the GPS with the tint of Extensibility and what is right for Espruino. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-09-30 by @allObjects part 5 of 5 of: GPS Module, Extensions, and u-blox NEO-6M GPS receiver PS: If you want to see the raw data in the console all the times, add a line handler and callback tuple with an alway false returning line handler as last to the handlers. This will get you all lines send by the GPS receiver printed in the console.
Output in the console:
|
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-10-01 by @gfwilliams Hopefully I've covered the question of memory usage in the other post... I'm afraid I don't have that much time at the moment, so can't give you a very in-depth reply... Returning just Moving to a more object oriented approach would be better I guess - it would push the memory usage up but it might be worth it. I'm not convinced about your approach with the array. To me, it is slower and uses more memory in all cases, and users have to understand about the array and structure their code around it (even if it's not what they want to do). Surely it is much better to have them define an array themselves if they want that behaviour. Same with What about (not tested):
I believe this will use a bit more memory, but it has a few advantages:
What do you think? |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-10-01 by @allObjects Thanks for sinking your already scarce time resource into this. I'm sure you would like to have satellite brains and body clones working for you and executing all the creative ideas going on in your master brain... ;) - something like this happens in my dreams. Back to - nevertheless - exciting reality:
Gives me enough food for thought to take the next step in adjusting into the architecture and spirit of Espruino as a whole. I'm sure the two links in the addendum post will explain the term root scope. I will resume with the memory conversation when resuming with the related project, which is: [http://forum.espruino.com/conversations/127039] (http://forum.espruino.com/conversations/127039) - Exploring 2.8" Color TFT Touch LCD by PacMan Game attempt. What I'm thinking about you suggested 'new' implementation of GPS module - well: I'm going back to school is for sure part of it... other parts are: I began with list of thoughts below... until paying closer attention to '.start()' method... and got stuck in it.... which toppled almost everything but the first thought to the point of actually being wrong... and to being wrong about code 'annihilates' - or at least - questions most of my (professional) past... therefore: Disregard the list. I will come back, re-think/buke and re-write the list. For now I can say that I 'see' great progress. ;). To have an idea where this all is heading for, take a look at the running application of the GPS module at http://forum.espruino.com/conversations/255759 - DIY Marine GPS using enhanced GPS Module, u-blox NEO-6M GPS receiver, and ILI9341 Module controlled 2.8" Color TFT LCD.
|
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-10-01 by @gfwilliams Cool - yes, start/stop would miss out on some lines - I don't think that would cause problems. My feeling with enable is it's actually not that much more inefficient to implement it in the callback fn (after all, it only gets called once a second, at most 10 times a second). 'root scope' - It's not really the correct term - you'd probably be more used to 'Closure'/'Lambda'. For instance the obvious example:
Also applies to modules, which are implemented a lot like:
So what I'm saying is, if you define |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-10-01 by @allObjects I'm not concerned about missing out on lines. I see more the challenge in getting partial / incomplete lines (GPS sentences) on (re-)start/resume. On the other hand, the very rigid tag extract and check would then just make the partial line to be skipped too. The next one though is pickup for sure, which - with (most) receiver's default configuration - shows up right within the next second (I have seen increasing the sentence (set) frequency on u-blox receivers, which of course requires also to increase serial's speed/baud rate in order to send the - also configurable set of - messages within the configured time period. Thanks for backfilling the term 'root scope'. I like it also for enforcing 'privacy' / enhanced encapsulation... (as 'private' in Java). It is a neat, JS distinctive thing to be able to establish things in the function/method body definition that then can only be seen from within the 'definition-time-scope' and will 'stay for ever' - or at least as the function/method is not garbage collected . The same happens to all things defined in modules when not exported... because it happens all in require()'s scope... (that's why the current GPS module's handleGPSLine() function is not accessible / lacks/suffers from accessibility - lacking or benefiting from absent accessibility is though always dependent on the design intention). In GPS module I have seen single method export... and in my embedded code, I did emulate the multiple exports because require() returned that kind of object (see line 56 in post http://forum.espruino.com/comments/11857912/ - part 4 of 5). From your code snipped I conclude that you can have a 'collection' of exports... - or, more precisely - an object (instance) with named properties - or plain js object - POJSO (like POJO as in Java). I hoped for and assumed something like that... and now I see how it is done. Because in the Espruino and a-like realm most challenges come from connecting to things / devices - and module help with that a great deal: hide the nitty-gritty, always the same looking things and (can also) provide additional convenience (methods). I see though the module technique not limited to that only and can see many other application that would have something else than connect as the initial method to get going. I could also see start and stop as a different scope than connect/disconnect, because start, stop, pause, and resume have a different feel to me... almost as we distinguish also boot/cold-start/warm-boot/start,... similar like sleep, deep sleep, and hibernate... none of these are reset or boot. These various types of processes or sequences/sets of life-cycle steps exist all in their own rights.... Oooops: I have - again - to remind my dreamy mind that with Espruino I deal with (very) limited resources... and thus many of these processes have to collapse into dedicated, simplified ones - just as needed. It's almost going back 50 or 60+ years in computing, when computers were built for a distinctive task... Only later systems, such as, for example, IBM System /360 computer announced early 60' were declared as a general purpose machines - not just to do Operations Research (OR), or Accounting, or... you name it. The key logo / badge for this first IBM general purpose computer was a compass rose: you can go any direction with this thing (see http://www.computerhistory.org/revolution/mainframe-computers/7/161). Today, with 'cheap' hardware available in masses, we can go back to the future and 'back' to dedication... and there is need for a big warehouse, a power plant, and cooling towers for operating such things. I bet that Espruino has multitude of processing power and with wifi connectivity unlimited storage compared to /360 systems with relative little memory - some models with much less and some with more then Espruino - and 7+MB disk storage... and /360s were called a Main Frames... ;-): Everything has it's season. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2014-09-27 by @allObjects
A five part series
In preparation for a navigation and tracking device with GPS and Display I looked into using the GPS module. The current module is very frugal. It supports just the NMEA $PGGA - essential Fix 3D position - sentence - basically: time, longitude, latitude, and altitude.
Initially I wanted to use my 20+ years old Magellan marine GPS with RS232 serial connectivity, but I dropped it in favor of a more recent and readily available ublox NEO-6M module, the same as used in Espruinos GPS moduel doc - http://www.espruino.com/GPS.
Hardware and software connectivity worked right away out of box. It took some time for the GPS module to pickup the satellites, but everything came together nicely.
From the past I knew that NMEA has also sentences that deliver, bearing, speed, etc... Speed over ground and bearing are part of a the NMEA $PGRMC - essential pvt (position/velocity/time) - sentence.
Looking into the implementation of the GPS module to extend it with a handler for other sentences - handleGPSLine()-methods - was a bit sobering... to say the least. My basic expectation was to find an externally extensible sentence filter with hooks and registration for other line handlers, or at least a way to override the already implemented, default GPS line handler. Unfortunately, the module is built in a way that ,gives no access what so ever for modifications or extensions. ;(
Sure, it is not much code there, but what I liked and noticed by rolling up the history of the modules especially in the forum, that quite some enhancements and validation went into the on.data method to extract and process available - (CR) LF delimited = lines.
Below is some code that is backward compatible and allows even the reuse of the existing default lineHandler for the use in extended mode. (The code is temporarily adjusted to run embedded while elaborating on the extensibility - see respective comments.)
Btw, I added the tag into the line handler's return object. It is useful when having only one callback for multiple sentences.
The basic idea of detecting and operating in the extended mode vs. the basic mode is by passing a handler object vs a handler callback function. Line 23 implements the detection. With this approach backward compatibility is given, and extensibility is opened up.
I adjusted some names to make the code extensions and the multi purpose use of the existing implementation pattern obvious.
The existing internal - not exposed - .handleGPSLine() function is renamed to defaultLineHandler, and is assigned to an internal variable named lineHandler in basic mode - when a in the .connect() a callback function is passed as handler (line 24). This variable is then used in the serial's on-data callback for each detected line (line 37). The function expects - as in the original code - a line and the external, custom callback for the line handler for invocation with the data object as built from the line.
The above setup to retain backward compatibility create constraints/requirements for the handler object in the enhanced mode: the handler object has to have a .lineHandler() method that accepts the same line and callback function arguments as the (existing) .handleGPSLine() - respectively renamed - .defaultLineHandler() function. This handler object's .lineHandler() method is then also assigned to the same internal variable named lineHandler, and corollary, is then also invoked by the serial's on-data callback for each detected line (line 37).
When the handler object includes a true evaluating .includeDefaultLineHandler property, it is complemented with the .defaultLineHandler() function as same-named method and therefore accessible in the handler object's lineHandler method - as the follow up post will show.
part 1 of 5 of: GPS Module, Extensions, and u-blox NEO-6M GPS receiver
Beta Was this translation helpful? Give feedback.
All reactions