Arduino /C++ Questions…

Advert

Arduino /C++ Questions…

Home Forums Help and Assistance! (Offered or Wanted) Arduino /C++ Questions…

Viewing 25 posts - 1 through 25 (of 31 total)
  • Author
    Posts
  • #477485
    Neil Wyatt
    Moderator
      @neilwyatt

      I'm a died in the wool lover of assembly langauge, just because…

      But I have a project (my equatorial platform) where simplicity is more important than having fun with assembler.

      So I'm using an Arduino nano; I've managed to get it controlling an LCD, but i need to do some basic maths.

      Essentially I will need a large integer which will be used to time the delay between stepper motor steps, to be fine tuned empirically (as using rubber rollers means the exact ratio can't be predicted).

      To track the sun, moon or stars/planets need three different rates. To simplify life I want the compiler to work out two of the rates from the first. Starting with solar means I can calibrate the platform in daylight.

      After all the faffle, I'm just asking can I do this (1273 is the estimated delay in microseconds):

      int SOLAR_RATE = 1273000;
      int SIDEREAL_RATE = SOLAR_RATE * 1.002737909;

      or do I need to 'cast' SOLAR_RATE into a float?

      And if so how do I do it?

      Advert
      #33610
      Neil Wyatt
      Moderator
        @neilwyatt
        #477492
        Nick Clarke 3
        Participant
          @nickclarke3

          Neil –

          I think you first problem might be the limited number of decimal places in a float – from memory 6 and values longer that that are truncated not rounded.

          And doubles are exactly the same size – I suspect they are only in the language for compatibility purposes.

          Edited By Nick Clarke 3 on 04/06/2020 17:07:41

          #477497
          Neil Wyatt
          Moderator
            @neilwyatt
            Posted by Nick Clarke 3 on 04/06/2020 17:06:15:

            Neil –

            I think you first problem might be the limited number of decimal places in a float – from memory 6 and values longer that that are truncated not rounded.

            And doubles are exactly the same size – I suspect they are only in the language for compatibility purposes.

            Edited By Nick Clarke 3 on 04/06/2020 17:07:41

            I'd spotted that although I wasn't sure what level of precision it will be. Given what I need 6 figures won't be problem, I probably need a precision of one part in 10,000.

            #477500
            Alan Vos
            Participant
              @alanvos39612

              I would be considering an arbitrary precision integer maths library.

              #477503
              SillyOldDuffer
              Moderator
                @sillyoldduffer

                The Arduino is limited to a single precision floating point library but the compiler supports long long integers, which look good for this. They're not mentioned in the Arduino documentation.

                Integer types available:

                short int is 8 bit integer +/- 256

                int is 16 bit integer +/- 32768

                long is 32 bit integer +/- 2147483648

                long long is 64 bit integer +/- 9223372036854775808

                If the calculation doesn't need negative numbers declaring these as unsigned doubles the range

                unsigned int = 0 to 65536

                unsigned long = 0 to 4294967296

                unsigned long long = 0 to 18446744073709551616

                As int and long vary depending on CPU, also supported are c -types like uint8, uint64 etc, so the programmer can guarantee the number of bits he's working with, mostly good for portability.,

                Of course, because the Arduino CPU is basically 16 bit, using long long will generate more code, consume memory, and calculate a bit slower.

                Dave

                PS Nucleo, is good for this, it's a 32bit processor with an FPU so does double.  And unsigned long long is 128 bits, good up to 340282366920938463463374607431768211456

                Edited By SillyOldDuffer on 04/06/2020 17:35:37

                #477508
                SillyOldDuffer
                Moderator
                  @sillyoldduffer
                  Posted by Neil Wyatt on 04/06/2020 16:45:15:

                  After all the faffle, I'm just asking can I do this (1273 is the estimated delay in microseconds):

                  int SOLAR_RATE = 1273000;
                  int SIDEREAL_RATE = SOLAR_RATE * 1.002737909;

                  or do I need to 'cast' SOLAR_RATE into a float?

                  And if so how do I do it?

                   

                  int SOLAR_RATE = 1273000; Will fail because a 16 bit only holds up to 32768

                  long SOLAR_RATE = 1273000; is fine. Conventionally expressed 1273000L as a reminder this is a long.

                  int SIDEREAL_RATE = SOLAR_RATE * 1.002737909; works up to a point:

                  An integer multiplied by a float will promote the result to a float so SOLAR_RATE * 1.002737909 is OK

                  Probably not wanted is the float result being chopped down to fit into the 16 bit int SIDEREAL_RATE.

                  float SIDEREAL_RATE = SOLAR_RATE * 1.002737909  // OK

                  There's at least one double floating point library for Arduino (Float64) : never tried it, probably take up a lot of space on a Nano which only has about 32k bytes for absolutely everything!

                  Dave

                  Edited By SillyOldDuffer on 04/06/2020 17:50:16

                  #477510
                  Alan Vos
                  Participant
                    @alanvos39612

                    Something I found. The URL to the code does still work.

                    Arbitrary precision (big number) library port for Arduino

                    All theory to me. I don't have an Arduino.

                    #477511
                    John Haine
                    Participant
                      @johnhaine32865

                      Maybe you could re-cast the problem, Neil. Could you use two different delay values, one a bit small and the other a bit large, where you normally use the smaller one but occasionally the larger, so on average you get the right number? I recall you mentioning a similar algorithm in an earlier post in the context of digital dividing.

                      I use this sort of approach on my reinvented Synchronome, where every so often (actually at the moment every 157 pendulum swings), in effect I delay the pulse that increments the dial by 1 sec. On average this gives a correct reading +/- 0.5 sec. The "157" is a software parameter I can change.

                      #477516
                      Frances IoM
                      Participant
                        @francesiom58905

                        one approach is to use a regular clock tick at the necessary rate then to use this to run a program (or steps thereof that runs for a shorter time than the clock interval – then wait for next tick – longer programs are split into phases a
                        with each clock tick incrementing modulo some factor a phase count which decides which phase to rum

                        #477519
                        Neil Wyatt
                        Moderator
                          @neilwyatt

                          Thanks folks, the combination of your feedback and my own musings has got me 'thinking aloud':

                          Getting long, accurate delays is trivial in assembler, but a compiled language introduces all sorts of unknown delays… I did think of cascading a microsecond and millisecond delay or working directly with interrupts.

                          Then I did some calculations and realised my existing gearing is about five times to coarse and ideally should be even finer.

                          I've ordered a 20:1 worm and gear to slow my stepper down so the delay will be around 590ms.

                          This is in the awkward zone where 1ms may not be good enough resolution and still too long for delay microseconds.

                          I think two things will improve accuracy:

                          Polling micros() so I don't have to introduce any reset delay.

                          As short-term errors won't be critical, I can also hard code patterns to add an extra millisecond to approximate 0.1ms accuracy (sort of pseudo bressenham)

                          Say the base time is 250ms

                          590.0 ms = 590 ms ten times

                          590.1 ms = 591, 590, 590, 590, 590, 590, 590, 590, 590, 590

                          590.2 ms = 591, 590, 590, 590, 590, 591, 590, 590, 590, 590

                          590.3 ms = 591, 590, 590, 591, 590, 590, 590, 591, 590, 590

                          and so on…

                          I can store the delay * 10 and use this sort of approach (psuedocode)

                          ARRAY LOOKUP(9,9) {populated with the offsets]

                          Stored figure *10

                          Base delay = stored figure/10

                          Fractional delay = stored figure MOD 10

                          FOR N= 0 TO 9

                          DELAY(N) = Base delay + LOOKUP (fractional delay,N)

                          NEXT N

                          The actual delay process will be:

                          LOOP

                          IF MILLIS() < COUNT GOTO LOOP

                          COUNT = COUNT + DELAY(N)

                          N ++

                          IF N>9 N=0

                          {CHECK FOR BUTTON PRESSES/LIMIT SWITCH}

                          GOTO LOOP

                          The whole loop should last much less than 1ms to execute so I should get excellent 'granularity'

                          Let's hope the drive train can be sorted without too much trouble.

                          #477523
                          Neil Wyatt
                          Moderator
                            @neilwyatt

                            If I was doing this in assembler, I would use a timer on interrupt to increment a counter set a flag when a stepper pulse was due.

                            The main program loop would just look to see if this flag was set, step the stepper and clear the flag.

                            #477529
                            duncan webster 1
                            Participant
                              @duncanwebster1

                              If you really need that many decimal places try

                              unsigned long SOLAR_RATE = 1,273,000;

                              unsigned long long ERIC = 2737909*SOLAR_RATE //this is actually 10e9 times too big

                              unsigned long SIDEREAL_RATE = (SOLAR_RATE + ERIC/1000000000)

                              The brackets are to make it execute in the right order.

                              doing the arithmetic step by step you get

                              SOLAR_RATE = 1,273,000

                              ERIC = (2,737,909*1,273,000)=3,485,358,157,000 //this is why you need long long and it might as well be unsigned

                              SIDEREAL_RATE = 1,273,000 + 3,485,358,157,000/1,000,000,000 = 1,273,000 + 3485 = 1,276,485

                              Doing it in floats gives 1,276,485.358157, but do you really need that sort of precision. If not knock numbers off the end of the 2,737,909, and the same number off the end of the 1,000,000,000

                              #477530
                              Andy Carlson
                              Participant
                                @andycarlson18141
                                Posted by Neil Wyatt on 04/06/2020 19:39:56:

                                If I was doing this in assembler, I would use a timer on interrupt to increment a counter set a flag when a stepper pulse was due.

                                The main program loop would just look to see if this flag was set, step the stepper and clear the flag.

                                You can still do that in 'C/C++' on an Arduino although with all the macros it starts to look fairly non 'C' like…

                                https://learn.adafruit.com/multi-tasking-the-arduino-part-2/timers

                                #477537
                                Neil Wyatt
                                Moderator
                                  @neilwyatt

                                  Thanks Duncan.

                                  I've decided to give it a try using millisecond resolution, as that will be good enough for visual use.

                                  If I get that working, I can gear it down and do something more complex next.

                                  The basic approach I looked at works, it's cycling through displaying 0, 1276, 1273 and 1317.

                                  I expect I will need your approach when I try for greater precision later.

                                  Neil

                                  #477538
                                  Joseph Noci 1
                                  Participant
                                    @josephnoci1

                                    SOD said….

                                    PS Nucleo, is good for this, it's a 32bit processor with an FPU so does double. And unsigned long long is 128 bits, good up to 340282366920938463463374607431768211456

                                    If you are not also 'died in the wool' Arduino, SOD's suggestion of using the Nucleo is a good one for you – not only gets rid of any big number issues/computation capability, but can also run very fast – 160MHz – perhaps you don't need that speed for computation results, but that will rid you of your timing problems, reduce the jitter on timing computations, and make unpredictable timing results due to compiler constructs irrelevant, due to being much smaller at those clock speeds. Unless part of your project fun is byteing away at the bits and nibbles..

                                    Joe

                                    #477545
                                    Martin Kyte
                                    Participant
                                      @martinkyte99762
                                      Posted by Neil Wyatt on 04/06/2020 19:39:56:

                                      If I was doing this in assembler, I would use a timer on interrupt to increment a counter set a flag when a stepper pulse was due.

                                      The main program loop would just look to see if this flag was set, step the stepper and clear the flag.

                                      So can you find a suitable Real Time Clock to generate your interrupt?

                                      regards Martin

                                      #477547
                                      Neil Wyatt
                                      Moderator
                                        @neilwyatt

                                        Gosh this is fun!

                                        My code fell over because I tried to declare an array using type string.

                                        Apparently it's type String

                                        All other types start with a lowercase letter, but not String…

                                        The best thing about computers is how logical they are…

                                        #477556
                                        Neil Wyatt
                                        Moderator
                                          @neilwyatt

                                          Actually this is enjoyable… AVR Assembler has got so many extensions now it shares so many concepts and syntax with C++ so I'm not as lost as I expected.

                                          Nucleo looks good but is a bit more expensive (Nanos are almost free if you buy three at a time…)

                                          Also, it looks like I can use my assembler direct on an arduino and even use some of my routines inline.

                                          Finally the AVR IDE works with Aduino so I might swap over (its vastly more powerful, with emulation etc.)

                                          #477562
                                          IanT
                                          Participant
                                            @iant
                                            Posted by Neil Wyatt on 04/06/2020 16:45:15:

                                            I'm a died in the wool lover of assembly langauge, just because…

                                            But I have a project (my equatorial platform) where simplicity is more important than having fun with assembler.

                                            So I'm using an Arduino nano; I've managed to get it controlling an LCD, but i need to do some basic maths.

                                            First a disclaimer – I know absolutely nothing about equatorial platforms – or the maths involved – and my suggestiion will be met with some scepticism I've no doubt. However, I did use the Arduino & Microchip IDEs for a while but my 'embedded' development platform of choice these days is Micromite Basic (MMB)

                                            I have MMB installed on several versions of the PIC32 (I use the 28pin DIL versions as programmable logic), an RPi 3B and this Win 10 PC. However, there are also versions of MMB running on the STM Nucleo (ARM) platforms – and for this application – one option with MMB would be to simply throw processing power at the problem using a NUCLEO-H743ZI2 running at 400Mhz ( MMB on an ARM = "Armmite" )

                                            The 'Armmite' H7 uses the built-in hardware floating point capability of the STM32H743ZI2 processor which gives double precision floating point.

                                            The H7 also has 96 free I/O pins, supports 25 16-bit analogue inputs, has two I2C ports, four SPI ports, eight high speed PWM channels , two 12-bit DACs, a high speed counter input, and four serial COM ports – e.g. you can control a lot of bells and whistles with it.

                                            All of these features being controlled very simply (and directly) via a modern high-level language that can be interactively programmed & debugged – and installed on a Nucleo H7 that costs about £25 (inc VAT) – a little bit more than a Nano perhaps but how much is your time worth?

                                            "But it's BASIC ! " (Shock and Horror) – "And it's an Interpreter ! " (Even More Shock and Horror )

                                            I know Arduino is used by many here – however I've been using MMB for some time and it not only 'scales' very well across its various platforms but most importantly, it is very easy to learn AND debug (something I think is simply very, very under-rated – until your latest programme won't actually work of course!).

                                            MMB is a modern version of the Basic language (no GOTOs or Line Numbers – unless you really want them of course) and you can just sit at your console and type your programme in – no compile, test, recompile cycles. If MMB detects an error – it drops you straight back to the error line. Want to test a subroutine? – Just type the subroutine name! Want to control a Servo? – one line of MMB – and just run it to test your Servo. It's interactive.

                                            Are Interpreters slow? Yes (compared with Compilers) but what is slow these days? My slowest (28 pin) PIC32 is 10 times faster than my old Z80 Nascom 2. The top end Armmites can execute over 250,000 lines of MMB a second (an RPi will run MMB even faster but is not "power & go" – nor simple! ).

                                            This manual lists the main H7 features and details the board piin-outs and additional H7 language commands – but it is only an addendum to the main Micromite (& Micromite Plus) language manuals (

                                            Armmite H7 Manual

                                            I don't know what level of performance you actualy need Neil – but I'm pretty sure the Armmite will do the job for you. More importantly – it will most likely also let you do the job faster.

                                            Regards

                                            IanT

                                            PS For anyone here who recalls the Colour Maximite (a SBC that runs MMB) – Geoff has just released the Colour Maximite 2, based on a very fast ARM chip and with some very impressive VGA graphics.

                                            Colour Maximite 2

                                            PPS I'm afraid It takes me quite some time to type these things in 'two-fingered' and there's been a few posts this evening since I started out typing. I suspect my suggestion will not be meet with too much favour as Neil (and the others) are clearly very happy with their IDE. But for anyone looking for something simple to use – and easy to debug – please consider MMB. It will save you a lot of time and will be more than good enough for most things you are likely to want to do.

                                             

                                            Edited By IanT on 04/06/2020 22:58:09

                                            #477637
                                            Neil Wyatt
                                            Moderator
                                              @neilwyatt

                                              It's always interesting to hear about other alternatives.

                                              It's worth pointing out that, in principle, the controller for this could be replaced by a 555 timer controlled with a potentiometer to fine-tune the rate and pulse the stepper driver.

                                              Some people just use geared DC motors and speed controllers.

                                              If I want 32-bit I'd probably go for the Arduino Due which has an ARM processor (a sort of piritual successor to the BBC Micro ) which is available for £12-15.

                                              Neil

                                              #477643
                                              SillyOldDuffer
                                              Moderator
                                                @sillyoldduffer

                                                Thinking about Neil's precision problem kept me awake last night. What a sad life I lead.

                                                • It's not necessary to calculate SIDEREAL_RATE on the Arduino, it could be done offline with an arbitrary precision calculator and plugged in as a constant. With Neil's example (1273000 and 1.002737909) the answer to 50 places of decimals is1276485.358157000
                                                • Looking it up, I found Neil's 1.002737909 is an approximation. When astronomical accuracy is needed further corrections are made, as per the 'Relationship between solar time and sidereal time intervals' section of the Wikipedia Article. An arbitrary precision calculator could factor that in too if necessary.
                                                • But what level of numeric accuracy is needed? Neil mentions his 1273000 figure will be fine tuned to compensate his rubber rollers. I suspect roller error will dwarf the floating point problem! No reason why reasonable effort shouldn't be put into improving calculation accuracy, but lots of precision is hard work.
                                                • Part of the hard work involves the inaccuracies inherent in float point even when lots of bits are available. Under the bonnet there's a conversion between decimal and binary that also causes problems when extreme precision is essential. For example, on my 64 bit laptop a long double (128 bits) stores
                                                  • 1.002737909 as
                                                  • 1.00273790899999992731750353414099663
                                                • Computers use native binary for speed, but if memory space and performance aren't critical Alan's recommended Bignumber library is a good solution. C++ on big machines have Decimal types, which guarantee digit accuracy as needed by accountants, but no-one's made them available for 16 bit microcontrollers.
                                                • Lastly, it's not difficult to do timer interrupts with μs accuracy in the range 1 to a tad over 8 seconds (in so far as the computer clock is accurate!) Although Arduino lets the programmer get close to the machine when needed, it's usually quicker to use a library. In this case TimerOne should do what Neil wants with interrupts, without requiring any low-level setting up. Let someone else do the hard work.

                                                Dave

                                                #477644
                                                John Haine
                                                Participant
                                                  @johnhaine32865

                                                  I think the Arduino cycle time is 4 us – at least when I've uses "micros" for clock timing that's the resolution. The Nano uses a ceramic resonator for its clock so not too accurate. May not be an issue.

                                                  #477648
                                                  Graham Stoppani
                                                  Participant
                                                    @grahamstoppani46499
                                                    Posted by Neil Wyatt on 04/06/2020 16:45:15:

                                                    I'm a died in the wool lover of assembly language, just because…

                                                    Back in the dim and distant past when I was doing my Computing degree, one of the things we dabbled with was VAX assembly language. I remember students commenting on how friendly it was compared to some other languages. Where they would refuse to compile due to the smallest of errors 'String and string' being a good example the assembler would really try to execute your code however mangled it was. smiley

                                                    #477654
                                                    Nick Clarke 3
                                                    Participant
                                                      @nickclarke3
                                                      Posted by Graham Stoppani on 05/06/2020 11:00:32:

                                                      Posted by Neil Wyatt on 04/06/2020 16:45:15:

                                                      I'm a died in the wool lover of assembly language, just because…

                                                      Back in the dim and distant past when I was doing my Computing degree, one of the things we dabbled with was VAX assembly language. I remember students commenting on how friendly it was compared to some other languages. Where they would refuse to compile due to the smallest of errors 'String and string' being a good example the assembler would really try to execute your code however mangled it was. smiley

                                                      Students learning C after Pascal told me the same thing – Pascal demanded far more accuracy or the program wouldn't run while C would produce some amazing, if nonsensical results from mistakes in the code. Similar to your VAX assembler C really tried to execute your code however mangled it was. .

                                                      After leaving us several went on to one of the local universities where their first programming was in ADA – That taught them to be rigorous in their coding as it was totally unforgiving.

                                                      Edited By Nick Clarke 3 on 05/06/2020 11:45:41

                                                    Viewing 25 posts - 1 through 25 (of 31 total)
                                                    • Please log in to reply to this topic. Registering is free and easy using the links on the menu at the top of this page.

                                                    Advert

                                                    Latest Replies

                                                    Viewing 25 topics - 1 through 25 (of 25 total)
                                                    Viewing 25 topics - 1 through 25 (of 25 total)

                                                    View full reply list.

                                                    Advert

                                                    Newsletter Sign-up