Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 15 FirstFirst 1 2 3 4 12 ... LastLast
Results 26 to 50 of 360

Thread: Teensy 3.x multithreading library first release

  1. #26
    What kind of display is that? Serial com?!

  2. #27
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    1,991
    yes uart, most people use widgets but i decided to learn and use photoshop to make animations. beware this lcd has a mcu built in and can run standalone, however, i prefer to use teensy as host since thats what im familiar with

    im also jumping 10 frames as per teensy code, however, theres 230 frames i can incrementally go smooth, if i need smoother i can just redo the images again in photoshop with... 500 frames this is where the map function will save you time

  3. #28
    And the lcd partnumber is?

  4. #29
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    1,991
    Click image for larger version. 

Name:	IMG_0042.jpg 
Views:	126 
Size:	134.7 KB 
ID:	9487wel they have many but i have the 7" as per video, uLCD-70DT
    the code is dead simple one liners in teensy/arduino, not pages and pages of lcd code
    the images and lcd layout, theres a separate IDE for that which even a non programmer can get up and running, once i photoshop the custom digits i can "upload" it to the car lcd
    Last edited by tonton81; 01-24-2017 at 05:39 PM.

  5. #30
    Yes 4d systems i came across their lcds once but they a expensive thank you for your help. But I am affraid some people are going to be very angry. This thread is about multitasking i hope the admin can forgive me for trashing the thread and if he can delete the posts

  6. #31
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    1,991
    i sorta hope this thread turns out well, its amazing how much throughput of data goes during canbus traffic and 24/7 read/write, multitasking can be necessary

  7. #32
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,423
    Quote Originally Posted by Tady View Post
    What kind of displays do you use is not these? Graphical? I have a ili9341 laying around maybe i can adapt the code
    That is what I am using right now... But again all of my stuff is just for my own enjoyment...

    Edit: Maybe should break most of this out to new or existing thread as to not totally distract from the multithreading library... Sorry
    Last edited by KurtE; 01-24-2017 at 06:12 PM.

  8. #33
    Junior Member
    Join Date
    Oct 2016
    Posts
    10
    Very cool to see a multithreading library, thank you @ftrias! Will give it a shot on 3.2 soon.

  9. #34
    Senior Member
    Join Date
    Sep 2013
    Location
    Boston, MA
    Posts
    109
    Quote Originally Posted by Tady View Post
    Can someone explain me the thread.delay() function? And what if I woul use delay instead of thread.delay()? Woul it stop both threads?
    A regular "delay(100)" would use up 100 ms of CPU time doing nothing in a while loop. "threads.delay(100)" would give these 100 ms of CPU time to another thread. So by using "threads.delay()" instead of "delay()" you are making your other threads run faster.

  10. #35
    Yes i tested with both delays and saw that delay stops everything... Nice work!

  11. #36
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    1,369
    Hi Tady

    I finally got around to trying to use the lib in an actually situation = Reading 4 Sonar Sensors using the newping library example. The problem I am seeing is that the sensors are not always returning results using it in a multithread test. I am not sure if its me in how I am coding or maybe some conflict with the newping library. There are a couple of other ways to implement this but I wanted to what the problem is with this example first. One other thing is it seems very choppy and slower than just calling the function.

    Thanks
    Mike

    Here are the results:

    Code:
    0=0cm 1=13cm 2=21cm 3=44cm 
    0=0cm 1=0cm 2=20cm 3=45cm 
    0=16cm 1=0cm 2=21cm 3=45cm 
    0=16cm 1=999cm 2=0cm 3=29cm 
    0=16cm 1=13cm 2=0cm 3=39cm
    The actual code I am using for the test is:

    Code:
    #include <Arduino.h>
    #include "Threads.h"
    #include <NewPing.h>
    
    #define SONAR_NUM     4 // Number or sensors.
    #define MAX_DISTANCE 200 // Maximum distance (in cm) to ping.
    #define PING_INTERVAL 45 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).
    
    unsigned long pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor.
    unsigned int cm[SONAR_NUM];         // Where the ping distances are stored.
    uint8_t currentSensor = 0;          // Keeps track of which sensor is active.
    
    NewPing sonar[SONAR_NUM] = {     // Sensor object array.
      NewPing(27, 26, MAX_DISTANCE), //lower left sensor
      NewPing(36, 35, MAX_DISTANCE), //front middle
      NewPing(30, 29, MAX_DISTANCE), //lower rigth sensro
      NewPing(34, 33, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping.
    };
    
    int id1, id2, id3;
    volatile int p1 = 0;
    volatile int p2 = 0;
    volatile int p3 = 0;
    #define delayx delay
    
    void my_priv_func1(){
      while(1){
      for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors.
        if (millis() >= pingTimer[i]) {         // Is it this sensor's time to ping?
          pingTimer[i] += PING_INTERVAL * SONAR_NUM;  // Set next time this sensor will be pinged.
          if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
          sonar[currentSensor].timer_stop();          // Make sure previous timer is canceled before starting a new ping (insurance).
          currentSensor = i;                          // Sensor being accessed.
          cm[currentSensor] = 0;                      // Make distance zero in case there's no ping echo for this sensor.
          sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo).
        }
      }
        //threads.yield();
      }
    }
      
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
      delay(5000);
      pingTimer[0] = millis() + 75;           // First ping starts at 75ms, gives time for the Arduino to chill before starting.
      for (uint8_t i = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor.
        pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
    
      // put your main code here, to run repeatedly:
      Serial.print("Thread start ");
      id1 = threads.addThread(my_priv_func1,1);
      if (threads.getState(id1) == Threads::RUNNING) Serial.println("OK");
    }
    
    
    void echoCheck() { // If ping received, set the sensor distance to array.
      if (sonar[currentSensor].check_timer()){
        cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
      } else {
        cm[currentSensor] = 999; 
      }
    }
    
    void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.
      for (uint8_t i = 0; i < SONAR_NUM; i++) {
        Serial.print(i);
        Serial.print("=");
        Serial.print(cm[i]);
        Serial.print("cm ");
      }
      Serial.println();
    }
    
    void loop() {
    
    }
    Last edited by mjs513; 03-17-2017 at 02:22 PM. Reason: Additional Info

  12. #37
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    1,369
    Me again. Think its a conflict with the example for multiple pings in the library. I re-wrote and heres the results follow. Any suggestions for making this more efficient would be appreciated. Want to do some timing tests and will let you know how it works out.

    Code:
    Thread start OK
    0=200cm 1=15cm 2=15cm 3=19cm 
    0=21cm 1=15cm 2=16cm 3=18cm 
    0=21cm 1=15cm 2=15cm 3=18cm 
    0=21cm 1=15cm 2=15cm 3=18cm 
    0=21cm 1=15cm 2=16cm 3=18cm
    This is the version that worked:
    Code:
    #include <Arduino.h>
    #include "Threads.h"
    #include <NewPing.h>
    
    #define SONAR_NUM     4 // Number or sensors.
    #define MAX_DISTANCE 200 // Maximum distance (in cm) to ping.
    #define PING_INTERVAL 45 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).
    
    unsigned int cm[SONAR_NUM];         // Where the ping distances are stored.
    uint8_t currentSensor = 0;          // Keeps track of which sensor is active.
    
    
    NewPing sonarll(27, 26, MAX_DISTANCE); //lower left sensor
    NewPing sonarlc(36, 35, MAX_DISTANCE); //front middle
    NewPing sonarlr(30, 29, MAX_DISTANCE); //lower rigth sensro
    NewPing sonarhd(34, 33, MAX_DISTANCE); // Each sensor's trigger pin, echo pin, and max distance to ping.
    
    
    int id1, id2, id3;
    volatile int p1 = 0;
    volatile int p2 = 0;
    volatile int p3 = 0;
    #define delayx delay
    
    void my_priv_func1(){
      while(1){
        cm[0] = 0;  
        unsigned int uS = sonarll.ping();
        //unsigned int uS = sonarll.ping_median();
        cm[0] = uS / US_ROUNDTRIP_CM;
        threads.delay(PING_INTERVAL);  
      
        cm[1] = 0;  
        uS = sonarlc.ping();
        //uS = sonarlc.ping_median();
        cm[1] = uS / US_ROUNDTRIP_CM;
        threads.delay(PING_INTERVAL); 
      
        cm[2] = 0;  
        uS = sonarlr.ping();
        //uS = sonarlr.ping_median();
        cm[2] = uS / US_ROUNDTRIP_CM;
        threads.delay(PING_INTERVAL);
    
        cm[3] = 0;  
        uS = sonarhd.ping();
        uS = sonarhd.ping_median();
        cm[3] = uS / US_ROUNDTRIP_CM;
        threads.delay(PING_INTERVAL);
    
        for (uint8_t i = 0; i < SONAR_NUM; i++) {
          if(cm[i] == 0) cm[i] = MAX_DISTANCE;
         }
        oneSensorCycle();
      }
    }
      
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
      delay(5000);
      Serial.print("Thread start ");
      id1 = threads.addThread(my_priv_func1,1);
      if (threads.getState(id1) == Threads::RUNNING) Serial.println("OK");
    }
    
    
    void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.
      for (uint8_t i = 0; i < SONAR_NUM; i++) {
        Serial.print(i);
        Serial.print("=");
        Serial.print(cm[i]);
        Serial.print("cm ");
      }
      Serial.println();
    }
    
    void loop() {
    
    }

  13. #38
    Senior Member
    Join Date
    Sep 2013
    Location
    Boston, MA
    Posts
    109
    I'm afraid I don't have a sonar module handy, but the one issue that sticks out in the code is that "currentSensor" can change between being set in my_priv_func1() and triggering echoCheck(). You set currentSensor in my_priv_func1(), set the echoCheck() callback and then the code keeps running; the loop goes to the next sensor and if it's trigger time is up, it will change currentSensor. If all this happens before echoCheck() is called by the NewPing library, then echoCheck will be looking at the wrong currentSensor.

    There could be other issues at play with the threading library

  14. #39
    Senior Member
    Join Date
    Sep 2013
    Location
    Boston, MA
    Posts
    109
    I just saw your reply and it seems you fixed the problem so please ignore my last message.

  15. #40
    Senior Member
    Join Date
    Sep 2013
    Location
    Boston, MA
    Posts
    109
    Any suggestions for making this more efficient would be appreciated.
    Efficient in terms of total CPU time used? Or how frequently you can read the sensors?

    This is just a suggestion I can't test. I think you can ping all sensors at the same time and then read the results as they come in. For example, you can call ping_trigger() for all the sensors at once and then have a section (or a "for" loop, as in your original example with the array of sensors) that calls "check_timer()" for each sensor. If it returns true, then you check the time and have your distance. When you collect data for all sensors (or a timeout occurs), then you break out of the loop.

    EDIT: fix text to call ping_trigger() rather than ping()
    Last edited by ftrias; 03-17-2017 at 03:28 PM.

  16. #41
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    1,369
    @ftrias. Thanks for explaining the issue with the first test sketch. Think you are correct in your assessment. Always nice to know why something doesn't work one way but works another way. So I never ignore responses. they all get stored away for future use. Have to think about all sensor triggering at the same time, hmm, thinking about the echo - one sensor may read another sensors echo. Best way to do it is to give it a try I guess.

  17. #42
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    1,369
    @ftrias I managed to create three threads: One for reading sonar sensors, one for IR sensors and a third for reading a BNO055. It all works. Since this is my first attempt at using threads was wondering if you could take a look at the way I implemented it and let me know if I need any changes for using threads. Once this is finished I will be incorporating it into my teensy autonomous rover to see how it works. One thing I did notice is the BNO055 reads seem to slow the sensor reads way down when using threading. Not sure why.

    Oh, whats the best way to time the threads. Just curious.

    Thanks again for your great library.


    Anyway here it is:
    Code:
    #include <Arduino.h>
    #include "Threads.h"
    #include <NewPing.h>
    #include <Streaming.h>
    #include <vector>
    #include <EEPROM.h>
    #include <Wire.h>
    #include <Adafruit_Sensor.h>
    #include <Adafruit_BNO055.h>
    #include <utility/imumaths.h>
    
    /* Set the delay between fresh samples for BNO055*/
    #define BNO055_SAMPLERATE_DELAY_MS (100)
    Adafruit_BNO055 bno = Adafruit_BNO055(55);
    
    float yar_heading, pitch, roll;
    
    #define telem Serial
    
    #define SONAR_NUM     4 // Number or sensors.
    #define MAX_DISTANCE 200 // Maximum distance (in cm) to ping.
    #define PING_INTERVAL 45 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).
    
    unsigned int cm[SONAR_NUM];         // Where the ping distances are stored.
    uint8_t currentSensor = 0;          // Keeps track of which sensor is active.
    
    NewPing sonarll(27, 26, MAX_DISTANCE); //lower left sensor
    NewPing sonarlc(36, 35, MAX_DISTANCE); //front middle
    NewPing sonarlr(30, 29, MAX_DISTANCE); //lower rigth sensro
    NewPing sonarhd(34, 33, MAX_DISTANCE); // Each sensor's trigger pin, echo pin, and max distance to ping.
    
    //IR Sensor Pins
    const int leftIRsensor = A22;   //Front
    const int rightIRsensor = A2;   //Rear
    int frtIRdistance, rearIRdistance;
    int max_IR_distance = 200;
    
    int id1, id2, id3;
    
    void my_priv_func1(){
      while(1){
        cm[0] = 0;  
        unsigned int uS = sonarll.ping();
        //unsigned int uS = sonarll.ping_median();
        cm[0] = uS / US_ROUNDTRIP_CM;
        threads.delay(PING_INTERVAL);  
      
        cm[1] = 0;  
        uS = sonarlc.ping();
        //uS = sonarlc.ping_median();
        cm[1] = uS / US_ROUNDTRIP_CM;
        threads.delay(PING_INTERVAL); 
      
        cm[2] = 0;  
        uS = sonarlr.ping();
        //uS = sonarlr.ping_median();
        cm[2] = uS / US_ROUNDTRIP_CM;
        threads.delay(PING_INTERVAL);
    
        cm[3] = 0;  
        uS = sonarhd.ping();
        //uS = sonarhd.ping_median();
        cm[3] = uS / US_ROUNDTRIP_CM;
        threads.delay(PING_INTERVAL);
    
        for (uint8_t i = 0; i < SONAR_NUM; i++) {
          if(cm[i] == 0) cm[i] = MAX_DISTANCE;
         }
      }
    }
    
    
    void my_priv_func2(){
      while(1){  
      int sum = 0;
      for (int i=0; i<3; i++) {
        int sensor_value = analogRead(leftIRsensor);  //read the sensor value
        if(sensor_value < 100){
          sensor_value = 100; 
        }
        sum = sum + sensor_value;
        threads.delay(5);
        }
        frtIRdistance = 27495 * pow(sum/3,-1.36); //convert readings to distance(cm)
    
      sum = 0;
      for (int i=0; i<3; i++) {
        int sensor_value = analogRead(rightIRsensor);  //read the sensor value
        if(sensor_value < 100){
          sensor_value = 100; 
        }
        sum = sum + sensor_value;
        threads.delay(5);
      }
      rearIRdistance = 25445 * pow(sum/3,-1.362); //convert readings to distance(cm)
      }
    }
    
    
    void my_priv_func3(){
      while(1){
        sensors_event_t event;
        bno.getEvent(&event);
        imu::Vector<3> euler = bno.getVector(Adafruit_BNO055::VECTOR_EULER);
    
        roll = (float)event.orientation.y;
        pitch = (float)event.orientation.z;
        yar_heading = (float)event.orientation.x;
      }
    }
    
    
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
      Wire.begin(400000);
      
      BNO055_Init();
    
      delay(5000);
      Serial.print("Thread start ");
      id1 = threads.addThread(my_priv_func1,1);
      id2 = threads.addThread(my_priv_func2,1);
      id3 = threads.addThread(my_priv_func3,1);
      if (threads.getState(id1) == Threads::RUNNING) Serial.println("Sonar thread started");
      if (threads.getState(id2) == Threads::RUNNING) Serial.println("IR thread started");
      if (threads.getState(id3) == Threads::RUNNING) Serial.println("BNO055 thread started");
    }
    
    
    void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.
      for (uint8_t i = 0; i < SONAR_NUM; i++) {
        Serial.print(i);
        Serial.print("=");
        Serial.print(cm[i]);
        Serial.print("cm ");
      }
      Serial.println();
      telem << "IR Distances: " << frtIRdistance << " -- " << rearIRdistance << endl;
      telem << -roll << "," << -pitch << "," << yar_heading << endl;
    
    }
    
    void loop() {
        oneSensorCycle();
    }

  18. #43
    Senior Member
    Join Date
    Sep 2013
    Location
    Boston, MA
    Posts
    109
    @mjs513, I'll give it my best, but without hardware or software to test, it's hard to say.

    One of the problems with threads is that it slices up run time into 100 millisecond intervals (this can be shortened). So things like this echo, which require very precise timing, probably won't work if you are caught between thread switches. For example, if you send out the "ping" and are waiting for the "ping" to return, expecting it to take 20 microseconds, but the thread decides to switch, your thread will have to wait 100 ms before the it will get CPU time again. So it will seem to your thread that over 100ms have elapsed. This could be fixed by rewriting the NewPing library to use interrupts, but that's some work. Or you could disable interrupts with NoInterrupts() while waiting for your pings to return.

    Also, when you call "threads.delay()" you are handing over your thread's time to the next slice, and it's not very accurate. So in real time, you may loose up to 100ms for each one of those. One way to minimize this is to reduce the time slice time with "setTimeSlice()". I really should have done a better job setting a global time slice and making the delay function more accurate. But in my defense, this is just the first version, and threads are just not a good way to do time-sensitive tasks.

    Hope that helps.

  19. #44
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    1,369
    @ftrias First and foremost. For a first release of a library this is working absolutely great. I am learning as I go here so excuse me if I don't always make sense. The library is great and I hope more people use it and give you feedback on it. Second thanks for the info on the time slices. Things are beginning to make a little more sense.

    Just for clarity the sonar and IR threads are working great now. The problem, which I have an idea on, is with the BNO055 IMU. Think it uses some sort of interrupt for when the data is ready. In that case I would have to change the time slice or not use it within the thread. If you want I will keep you posted on how it works out.

    Thanks for all your help.
    Mike

    UPDATE: Changed the time slice on the BNO055 thread and working a lot better.
    Last edited by mjs513; 03-17-2017 at 11:44 PM. Reason: added info

  20. #45
    Senior Member
    Join Date
    Jan 2013
    Posts
    843
    @mjs513

    The default timeslice is WAY too large. Setting all thread timeslices to 1 as opposed to the default 100 results in about 1% overhead. Make sure to include thread 0 (which executes loop()): "threads.setTimeSlice(0, 1);".

    Using a different timer with 100us ticks (the systick timer used by default has 1000us ticks), results in about 3% overhead with 1 tick timeslices.

  21. #46
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    1,369
    @tni

    Took your suggestion and saw a dramatic improvement. However, had to change the timeslice for the sonar sensors to get reasonable results to threads.setTimeSlice(1,25). Probably could be lower, value was just off the top of my head. Thanks for the suggestions and the info.

  22. #47
    Senior Member
    Join Date
    Sep 2013
    Location
    Boston, MA
    Posts
    109
    The 100 millisecond thread slice time comes from the default Linux slice time, before the scheduling was changed to a dynamic system called CPS. I looked briefly at doing a dynamic scheduling but it seems like overkill.

    To make it easier, I can add a "threads.setDefaultTimeSlice(...)" that will change the time slice for all new threads create.

    @tni, how did you implement the 100us slices? I looked at using IntervalTimer (or directly the PIT timer) but maybe there is a better way.
    Last edited by ftrias; 03-18-2017 at 05:46 PM.

  23. #48
    Senior Member
    Join Date
    Jan 2013
    Posts
    843
    Quote Originally Posted by ftrias View Post
    @tni, how did you implement the 100us ticks? I looked at using IntervalTimer (or directly the PIT timer) but maybe there is a better way.
    I used IntervalTimer. I wouldn't use the PIT directly (to minimize conflicts with other code wanting to use the timers).

    There is a ton of other timers that can trigger interrupts, but IntervalTimer / PIT is probably the least likely to cause conflicts.

  24. #49
    Senior Member
    Join Date
    Sep 2013
    Location
    Boston, MA
    Posts
    109
    @tni, would you mind sharing your code so other (including me) can try it?

  25. #50
    Senior Member
    Join Date
    Jan 2013
    Posts
    843
    Quote Originally Posted by ftrias View Post
    @tni, would you mind sharing your code so other (including me) can try it?
    The change is pretty trival. I renamed "systick_isr" in thread.cpp and removed the systick increment:
    Code:
    //void __attribute((naked)) systick_isr(void)
    void __attribute((naked)) ctx_switch_timer_isr(void) {
        //systick_millis_count++;
    In the sketch:
    Code:
    IntervalTimer ctx_switch_timer;
    extern void ctx_switch_timer_isr();
    void setup() {
        ctx_switch_timer.begin(ctx_switch_timer_isr, 100);
        ...
    Last edited by tni; 03-18-2017 at 06:03 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •