Welcome! Log In Create A New Profile

Advanced

Get a random seed to randomize auto file order [C++, MarlinFW]

Posted by daninet 
Get a random seed to randomize auto file order [C++, MarlinFW]
March 04, 2023 06:01AM
Hi,
I'm a novice programmer when it comes to C++ and I'm utterly unfamiliar with the marlin firmware when it comes to the coding part (even though I have been using and configuring Marlin for a decade).
My situation is the following: I made a kinetic sand are table, similar to the sisyphus table if you are familiar with it. I have used 3d printer components (SKR mini board, pencake steppers etc) to make a 2d mechanical rail that moves a magnet.
I have my patterns made in gcode, but these patterns are made slow, hence I'm looking for an option to randomize their order, whenever I turn on my table a different pattern will start.
My issue is since I'm unfamiliar with the firmware as a code I don't know how to get a random seed and I need help. The random(0,10); function is not truly random and has the same order every time I turn on the machine.

So here is what I have so far, I have modified line 840 in cardreader.cpp

#if DISABLED(NO_SD_AUTOSTART)
/**

    Run all the auto#.g files. Called:
        On boot after successful card init.
        From the LCD command to Run Auto Files
        /
        void CardReader::autofile_begin() {
        autofile_index = 1;
        (void)autofile_check();
        }
        /*
    Run the next auto#.g file. Called:
        On boot after successful card init
        After finishing the previous auto#.g file
        From the LCD command to begin the auto#.g files
    Return 'true' if an auto file was started
    */
    bool CardReader::autofile_check() {
    if (!autofile_index) return false;

if (!isMounted())
mount();
else if (ENABLED(SDCARD_EEPROM_EMULATION))
settings.first_load();

// Don't run auto#.g when a PLR file exists
if (isMounted() && TERN1(POWER_LOSS_RECOVERY, !recovery.valid())) {
char autoname[10];
sprintf_P(autoname, PSTR("/auto%c.g"), '0' + autofile_index - 1);
if (fileExists(autoname)) {
cdroot();
openAndPrintFile(autoname);
// Generate a random number between 2 and 10
int randomNumber = random(2,10);
autofile_index = randomNumber;
//
return true;
}
}
autofile_cancel();
return false;
}
#endif`


The above code works but random(2,10); is the same sequence at every boot so I'm at where I was originally with the sequential order.
I clearly need some random seed to randomize my numbers but I don't know how to get a random seed. For example is there a function that counts uptime in milliseconds? My homing sequence in auto0.g is always different length so this would be a good way to randomize let's say with the middle square law.
Or is there a function to read a state of an analog pin that is floating?
I hope you get my issue, I need some guidance on this and maybe if you know the answer a short code snippet as I'm just learning c++

Thank you for any input.
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 04, 2023 04:27PM
If you start with the same seed you'll always get the same sequence.

The clasic method of getting a variable seed is to query the real time clock. Unfortunately Marlin doesn't support the RTC on the CPUs that have them.

What you might try is grabbing the least significant byte of the millis() counter.

millis_t seed_32 = millis();
uint16_t seed_16 = seed_32 & 0xFFFF;



I couldn't find a definition of the random function that I trusted so I went with the builtin rand():

#include      /* srand, rand */

/* initialize random seed: */
millis_t seed_32 = millis();
uint16_t seed_16 = seed_32 & 0xFFFF;
srand (seed_16);
#define M 2    // lowest number of desired range
#define N 10  // highest number of desired range
int randomNumber = M + rand() / (RAND_MAX / (N - M + 1) + 1);
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 05, 2023 11:06AM
thank you for your help

I have added your code, after the open and prinf file line. Also I'm not sure if you intended to include anything, i have used #include stdlib.h i think the forum formatting removes
< >

My files are executed in a different order now but they are not random. Same different order every time I turn on the machine.
My code looks like this:

#if DISABLED(NO_SD_AUTOSTART)
  /**
   * Run all the auto#.g files. Called:
   * - On boot after successful card init.
   * - From the LCD command to Run Auto Files
   */
  void CardReader::autofile_begin() {
    autofile_index = 1;
    (void)autofile_check();
  }
  /**
   * Run the next auto#.g file. Called:
   *   - On boot after successful card init
   *   - After finishing the previous auto#.g file
   *   - From the LCD command to begin the auto#.g files
   *
   * Return 'true' if an auto file was started
   */
  bool CardReader::autofile_check() {
    if (!autofile_index) return false;

    if (!isMounted())
      mount();
    else if (ENABLED(SDCARD_EEPROM_EMULATION))
      settings.first_load();

    // Don't run auto#.g when a PLR file exists
    if (isMounted() && TERN1(POWER_LOSS_RECOVERY, !recovery.valid())) {
      char autoname[10];
      sprintf_P(autoname, PSTR("/auto%c.g"), '0' + autofile_index - 1);
      if (fileExists(autoname)) {
        cdroot();
        openAndPrintFile(autoname);
        // Generate a random number between 2 and 10
        /* initialize random seed: */
        millis_t seed_32 = millis();
        uint16_t seed_16 = seed_32 & 0xFFFF;
        srand (seed_16);
        #define M 2    // lowest number of desired range
        #define N 10  // highest number of desired range
        int randomNumber = M + rand() / (RAND_MAX / (N - M + 1) + 1);
        autofile_index = randomNumber;
        return true;
      }
    }
    autofile_cancel();
    return false;
  }
#endif

Edited 1 time(s). Last edit at 03/05/2023 11:08AM by daninet.
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 05, 2023 12:58PM
I was afraid of that. The time of execution is pretty stable so calling millis() is just always returning the same value.

There's a chance that using micros() instead of millis() will work. Unfortunately it has the same possible problem.

The last option I can think of is to save the seed generated by rand() into EEPROM and then read it back the next time. The psuedocode would look something like this:
#define seed_addr ?????
uint16_t seed_16 = EEPROM_READ(seed_addr);
srand (seed_16);
seed_next = rand();
EEPROM_WRITE(seed_addr, seed_next);
.
.
int randomNumber = M + seed_next / (RAND_MAX / (N - M + 1) + 1);  // notice that rand() has been replaced by seed_next
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 06, 2023 02:14AM
Can we save it on the SD instead? I'm afraid writing the eeprom constantly will wear it off
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 07, 2023 03:34AM
Yes, you can wear out the EEPROM.

This was an interesting problem. Here's a working set of code that does what you want. M220_re-entrant.zip

I highjacked the M220 gcode for this exercise. You should be able to easily modify it for your use.

There were a lot of twists in getting this to work. See the NOTES section in the M220_re-entrant.zip file for details.

To use it you need to init the SD card with the following files. File name case is important.
  • seed.txt // should have reasonable value in it
  • auto0.g
  • auto1.g
  • ...
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 07, 2023 08:15AM
wow you really put work into this. I won't be able to thank you enough for this. smileys with beer
the code you have provided in this M220 file "makes perfect sense", I mean it does look it does what you have described but I cannot wrap my head around it why it is in the M220.cpp
Can I just use the code in the cardreader.cpp or it has to stay in the M220?
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 07, 2023 02:47PM
Here's a corrected M220_re-entrant_fixed.zip. The old one had some garbage in it from when I was creating the notes section.

I chose M220 to make testing easier. That way I could invoke it via pronterace.

I recommend NOT replacing the current autofile_check(). Best to leave the existing code alone.

Here's a fully stand alone version: random_auto_g_file_loader.zip

The code can go anywhere convenient. You may need to adjust the #include statements.
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 09, 2023 02:21AM
I got quite a few compilation error for your stand alone file. I started with a clean git clone Marlin version 2.12
I have added the lines into the MarlinCore.cpp
Then there were some easy ones like the #include contained an extra ../ for the path
As I understand we are still using the randomNumber parameter so I declared it in cardreader.cpp
int randomNumber = 2;

and have called it in line 853
autofile_index = randomNumber;


But here are the below ones I could not figure out:
In file included from Marlin\src\sd\random_auto_g_file_loader.cpp:51:
Marlin\src\sd\../feature/powerloss.h: In static member function 'static bool PrintJobRecovery::exists()':
Marlin\src\sd\../feature/powerloss.h:178:40: error: 'class CardReader' has no member named 'jobRecoverFileExists'
  178 |     static bool exists() { return card.jobRecoverFileExists(); }
      |                                        ^~~~~~~~~~~~~~~~~~~~
Marlin\src\sd\../feature/powerloss.h: In static member function 'static void PrintJobRecoveryeye popping smileypen(bool)':
Marlin\src\sd\../feature/powerloss.h:179:46: error: 'class CardReader' has no member named 'openJobRecoveryFile'
  179 |     static void open(const bool read) { card.openJobRecoveryFile(read); }
      |                                              ^~~~~~~~~~~~~~~~~~~
In file included from C:\Users\danin\.platformio\packages\framework-arduinoststm32\cores\arduino/WString.h:29,
                 from C:\Users\danin\.platformio\packages\framework-arduinoststm32\cores\arduino/Print.h:27,
                 from C:\Users\danin\.platformio\packages\framework-arduinoststm32\cores\arduino/Stream.h:26,
                 from C:\Users\danin\.platformio\packages\framework-arduinoststm32\cores\arduino/HardwareSerial.h:29,
                 from C:\Users\danin\.platformio\packages\framework-arduinoststm32\cores\arduino/WSerial.h:5,
                 from C:\Users\danin\.platformio\packages\framework-arduinoststm32\cores\arduino/wiring.h:47,
                 from C:\Users\danin\.platformio\packages\framework-arduinoststm32\cores\arduino/Arduino.h:36,
                 from Marlin\src\sd\../module/../inc/../HAL/./STM32/../shared/Marduino.h:36,
                 from Marlin\src\sd\../module/../inc/../HAL/./STM32/HAL.h:28,
                 from Marlin\src\sd\../module/../inc/../HAL/HAL.h:30,
                 from Marlin\src\sd\../module/../inc/MarlinConfig.h:31,
                 from Marlin\src\sd\../module/motion.h:31,
                 from Marlin\src\sd\random_auto_g_file_loader.cpp:48:
Marlin\src\sd\random_auto_g_file_loader.cpp: In function 'bool random_auto_g_file_loader()':
Marlin\src\sd\random_auto_g_file_loader.cpp:127:51: error: 'utostr3' was not declared in this scope; did you mean 'ftostr3'?
  127 |             sprintf_P(autoname, PSTR("AUTO%s.g"), utostr3(randomNumber));
      |                                                   ^~~~~~~
C:\Users\danin\.platformio\packages\framework-arduinoststm32\cores\arduino/avr/pgmspace.h:71:40: note: in definition of macro 'sprintf_P'
   71 | #define sprintf_P(s, ...) sprintf((s), __VA_ARGS__)
      |                                        ^~~~~~~~~~~
Marlin\src\sd\random_auto_g_file_loader.cpp: In function 'uint8_t get_max_autofile()':
Marlin\src\sd\random_auto_g_file_loader.cpp:160:45: error: 'utostr3' was not declared in this scope; did you mean 'ftostr3'?
  160 |       sprintf_P(autoname, PSTR("AUTO%s.g"), utostr3(counter));
      |                                             ^~~~~~~
C:\Users\danin\.platformio\packages\framework-arduinoststm32\cores\arduino/avr/pgmspace.h:71:40: note: in definition of macro 'sprintf_P'
      |                                        ^~~~~~~~~~~
*** [.pio\build\STM32F103RC_btt\src\src\sd\random_auto_g_file_loader.cpp.o] Error 1
Marlin\src\sd\cardreader.cpp: In static member function 'static bool CardReader::autofile_check()':
Marlin\src\sd\cardreader.cpp:853:26: error: 'randomNumber' was not declared in this scope
  853 |         autofile_index = randomNumber;
      |                          ^~~~~~~~~~~~
*** [.pio\build\STM32F103RC_btt\src\src\sd\cardreader.cpp.o] Error 1

I have attached all the files that I have changed from the git clone.
Attachments:
open | download - Configuration_adv.h (173.3 KB)
open | download - Configuration.h (124 KB)
open | download - MarlinCore.cpp (48.3 KB)
open | download - pins_BTT_SKR_MINI_E3_V2_0.h (2.8 KB)
open | download - cardreader.cpp (39.8 KB)
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 09, 2023 12:50PM
Here's a version of random_auto_g_file_loader.cpp that works with 2.1.2: random_auto_g_file_loader.zip

I made the following changes:
  • Disabled the check for power loss recovery. It apparently doesn't compile in 2.1.2
  • Changed the integer to string function to one that was available in 2.1.2

I doubt that your changes to cardreader.cpp actually do anything. The variable randomNumber in cardreader.cpp is treated as a different variabkle than the randomNumber in random_auto_g_file_loader.cpp.

I was surprised to see X2_USE_ENDSTOP set to Z_STOP_PIN. If you have compile issues then try changing it to _ZMIN_ .
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 10, 2023 02:34AM
That Z_STOP_PIN was a surprise for me also when I switched from 2.0.9 to 2.1.2
The pin names were changed in the board's pins file and I got all kinds of compilation error for using ZMIN that worked before

Thank you for your work, really. thumbs up
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 10, 2023 12:16PM
Did you get it to work?
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 16, 2023 02:47PM
Hi!
Nope, unfortunately not. So maybe I'm not understanding your instructions.
If I keep cardreader.cpp untouched and compile the firmware with your file (with the instructions about inserting the lines in the loop), the files are executed in order as the cardreader.cpp commands.
Do we need any modification to that file? I don't see where your code is injected.
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 16, 2023 04:08PM
Did you create the file seed.txt on the SD card?
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 17, 2023 03:11AM
yes, i have the seed.txt and i have a 5 digit integer in it
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 17, 2023 01:53PM
Enable the debug prints and then post the log. That should tell me what is going on.
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 19, 2023 10:19AM
Hi
The following happens:
Homing happens, then immediately after homing connection breaks and the board restarts. Homes again, then again restarts

echo:Now fresh file: seed.txt
Writing to file: seed.txt
echo:Now fresh file: AUTO3.g
File opened: AUTO3.g Size: 1343625
File selected
Exception in thread read thread:
Traceback (most recent call last):
  File "printrun\printcore.py", line 333, in _readline
  File "printrun\printcore.py", line 329, in _readline_nb
  File "serial\serialwin32.py", line 275, in read
serial.serialutil.SerialException: ClearCommError failed (PermissionError(13, 'The device does not recognizes the command.', None, 22))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "threading.py", line 932, in _bootstrap_inner
  File "threading.py", line 870, in run
  File "printrun\printcore.py", line 418, in _listen
  File "printrun\printcore.py", line 387, in _listen_until_online
  File "printrun\printcore.py", line 354, in _readline
IndexError: tuple index out of range

Edited 3 time(s). Last edit at 03/19/2023 10:52AM by daninet.
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
March 19, 2023 03:32PM
What do you have in your auto files?

Does the USB port going down also happen if you manually execute the commands in the auto files?
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
April 21, 2023 09:20AM
I'm back, sorry for not following up I had other mechanical difficulties with my project I had to solve and I could not provide feedback.
I have switched boards from skr mini to ramps1.4 as I had to experiment with different drivers. This swap has shown that the issue is unrelated to the board, the ramps does it as well exactly the same way.
So to recap:
1. I have a working marlin on my board. I can run gcode from the sdcard and run auto.g files from the SD card without any issue.
2. I add the random g file loader of yours, add the lines in the main loop compile and upload. Compiles without error
3. I turn on the machine and it starts with auto0.g which has a single homing command in it.
4. The machine starts to execute the auto1.g, I did not find there is any randomness applied it's always auto1g. At the exact same point after the first line of the gcode marlin crashes and restarts. USB and everything goes down. It does a full restart and starts with auto0g just as you turn on the machine.

The machine is a drawing machine as I have mentioned and I generate gcode for it with sandify.org. I have attached the gcode. But as I have mentioned I doubt it is related to the gcode and it is unrelated to my board also.
Help me how can I provide you info for debugging and I will do it.

Thank you,,
Attachments:
open | download - auto0.g (15 bytes)
open | download - auto1.g (164.4 KB)
open | download - auto2.g (1.31 MB)
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
April 21, 2023 10:11AM
please post url to patched code, or attach as zip, so we can see exactly what you changed and are running
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
April 23, 2023 12:56PM
I have made a google drive folder as i have uploaded a few videos also.
https://drive.google.com/drive/folders/1WkbYzSKrhYUENwa1pyWRByKdNaRsDIwH?usp=sharing
First video will show you i have movement without autog loader. The auto1.g file runs on the video and shows progress at about 30min.
The second video will show you what happens if I compile the autog loader file. auto0.g starts, then auto1.g runs (always auto1.g no randomness) and crashes around line 3. It always crashes after the same amount of time. I suspect from the debug the crash correlates to writing frequency of the seed.txt? It is just my guess.

From the project and what you see on the images. Might not be related but gives better understanding what i want to achieve:
Its a sand art table, second version. I have rebuilt it to be more quiet and efficient, first version was certesian with 3 stepper, this second one is hbot.
Currently running ramps1.4 with 2 tmc2208 with uart. corexy did not compile without Z so I have a fake Z axis defined but it does nothing.
On the ramps you can see an LM2596 step down converter taped on with kapton. The project runs from a 3s6p battery pack in the table with max voltage of 12.6v. The mega has a voltage regulator that can handle max 12v so I had to desolder d1 diode and use a more robust voltage regulator set to 6-7v.
The project earlier had an SKR mini board I had the exact same results with auto g loader.
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
April 24, 2023 01:40AM
Ive had a play and found lots of stuff

1) the random number generator was not working as it should at all
2) the code provided actually opens up the auto#.G file and injected to gcode within into marlin. This only works for very small files or buffer over runs happen and crash marlin

a few things I changed

1) disabled the default marlin autostart, implemented our own method instead
2) I only save the new seed on startup, saves ware and tear on the sdcard, you dont need a new seed for every random number
3) updated random number generator so it works a lot better
4) change random number generator to not repeat the same number twice in a row
5) I start a file printing by queuing M23 AUTO{number}.G\nM24 thus marlin prints it like normal


Is designed to start marlin with sdcard in slot. it wont work correctly by inserting new sdcard (that can probably be added, later)
attached are the changed files
Configuration.h
Configuration_adv.h
MarlinCore.cpp
random_auto_g_file_loader.cpp
pins_RAMPS.h

Edited 3 time(s). Last edit at 04/24/2023 06:48AM by Dust.
Re: Get a random seed to randomize auto file order [C++, MarlinFW]
April 24, 2023 10:55AM
smileys with beer
working!
Thank you for your and Bob's help on putting this together
Sorry, only registered users may post in this forum.

Click here to login