And who is doing the task management?
In Arduino Forum/Platform, people do use ESP32 and FreeRTOS; so, there are helps; whereas, propeller-chip based Learning Kit is not visible in Arduino Forum. Arduino IDE supports ESP32S as an Arduino Dev Board, and it also supports the compilation of the FreeRTOS Library functions
If using dual-core ESP32, let the tasks be distributed between the cores. The FreeRTOS will take care of tasks management with respect to data exchange between the cores using shared variable or queue.
If OP doesn't understand how to do basic Arduino-style "multi tasking" (i.e. BwoD, "many things at a time", etc), then suggesting OS-based multi-task, multi-core programming is unproductive at best ... counterproductive at worst.
This suggests when two events have an intersecting period, one precedes the other purely by being in the code first. A third condition might be of interest at that intersection. A while ago, a request for "events happening simultaneously" became this...
// https://wokwi.com/projects/366159375120487425
// each character on this timing graph represents 50ms.
// interval[0] flops between 0 and 1, interval[1] flops between 2 and 3, simultaneous gets a 4
// interval[0] 0 and 1 every 200ms |---*---*---*---*---*---*---*---*---*---*---*---*---*---*---*...
// interval[1] 2 and 3 every 500ms |---------*---------*---------*---------*---------*---------*...
// interval[0] & interval[1] = 1000ms |---0---1-2-0---1---4---1---0-2-1---0---4---0---1-2-0---1---4...
unsigned long interval[] = {200, 500}; // set two event intervals
unsigned long previousTime[] = {0, 0}; // clear two event timers
unsigned long currentTime; // use for all intervals
bool intervalEvent[2]; // two events
bool intervalOccurred[2]; // two events happened
int intervalCount[2] = {0, 2}; // two event starting values
void setup() {
Serial.begin(115200);
welcome();
}
void loop() {
unsigned long currentTime = millis(); // update "now" time for all intervals and timers
if (currentTime - previousTime[0] >= interval[0]) { // 200ms interval
previousTime[0] = currentTime; // event occurred, set new start time
intervalOccurred[0] = 1; // flag for simultaneous events
}
if (currentTime - previousTime[1] >= interval[1]) { // 500ms interval
previousTime[1] = currentTime; // event occurred, set new start time
intervalOccurred[1] = 1; // flag for simultaneous events
}
if (intervalOccurred[0] && intervalOccurred[1]) { // 200ms and 500ms intervals together
intervalOccurred[0] = 0; // clear flag for 200ms event
if (intervalCount[0] == 0) { // if 200ms count is 0
intervalCount[0]++; // increase count - if it is 0 change it to 1
}
else if (intervalCount[0] == 1) { // if 200 count is 1
intervalCount[0]--; // decrease count - if it is 1 change it to 0
}
intervalOccurred[1] = 0; // clear flag for 500ms event
if (intervalCount[1] == 2) { // if 500 count is 2
intervalCount[1]++; // increase count
}
else if (intervalCount[1] == 3) { // if 500 count is 3
intervalCount[1]--; // decrease count
}
Serial.print(4);
}
if (intervalOccurred[0]) { // 200ms event has occurred
intervalOccurred[0] = 0; // clear flag
if (intervalCount[0] == 0) { // if count is 0
Serial.print(0); // print count
intervalCount[0]++; // increase count
}
else if (intervalCount[0] == 1) { // if count is 1
Serial.print(1); // print count
intervalCount[0]--; // decrease count
}
}
if (intervalOccurred[1]) { // 500ms event has occurred
intervalOccurred[1] = 0; // clear flag
if (intervalCount[1] == 2) { // if count is 2
Serial.print(2); // print count
intervalCount[1]++; // increase count
}
else if (intervalCount[1] == 3) { // if count is 3
Serial.print(3); // print count
intervalCount[1]--; // decrease count
}
}
}
void welcome() {
Serial.println("Each character on this timing graph represents 50ms.");
Serial.println("interval[0] flops 0 and 1 every 200ms |---*---*---*---*---*---*---*---*---*---*---*---*---*---*---*...");
Serial.println("interval[1] flops 2 and 3 every 500ms |---------*---------*---------*---------*---------*---------*...");
Serial.println("interval[0] & interval[1] = 4 at 1000ms |---0---1-2-0---1---4---1---0-2-1---0---4---0---1-2-0---1---4...");
}
I got into this life eating hobby when a friend showed me a Parallax Basic Stamp.
So guess how much I enjoyed it when at every step of the way these little toys got bigger and better in any way you could measure.
I can only guess how y'all feel, those for whom the Arduino UNO is a small limited machine compared to what kind of things you might have been doing with "real" computers…
Yeah, old.
a7
Yes. In my demo, the processes are all independent--as if you renamed different sketches' loops() into different, independent functions. I wanted to show a repetitive timeline process (ABCD) allowing independent tasks to happen (2&3).
If one needed interactions between the components, you'd have to expose some of the internals to external/global scopes and deal with the interactions as needed.
Here's the toy code with the plain, specialDelay, and full non-blocking in a Wokwi:
And before the Stamp there was Z-World running on a Z180.
The Z-World Z-Core and Rugged Giant was programmed using Dynamic C. Dynamic C had a costate function that was as close to multitasking we could get back then. It would be great if the Arduino IDE could include costate function
That does it too, with less code even!
some more redundant turned to functions..
then out with the delays..
probably look something like this..
#include <Servo.h>
#define ECHO_PING 0
#define CHECK_LEFT 1
#define CHECK_MID 2
#define CHECK_RIGHT 3
#define LEFT_HIT 4
#define MID_HIT 5
#define RIGHT_HIT 6
#define LAST_WAIT 7
byte outerState = ECHO_PING;
byte innerState = 0;
unsigned long lastDelay = 0;
unsigned int intervalDelay;
Servo rf;
Servo rb;
Servo lf;
Servo lb;
Servo headx;
Servo headz;
//motor drivers connections
byte m1A1 = 37;
byte m1A2 = 39;
byte m2A1 = 41;
byte m2A2 = 43;
byte m3A1 = 26;
byte m3A2 = 28;
byte m4A1 = 29;
byte m4A2 = 31;
byte m5A1 = 33;
byte m5A2 = 35;
byte m6A1 = 34;
byte m6A2 = 36;
//wheel angle manuver
byte servostep = 4;
byte distancechange = 20;
byte timetocheck = 3000;
//wheels initial
byte inrf = 88;
byte inlf = 92;
byte inrb = 94;
byte inlb = 92;
//wheels right
byte rightrf = 101;
byte rightlf = 105;
byte rightrb = 107;
byte rightlb = 105;
///wheels left
byte leftrf = 75;
byte leftlf = 79;
byte leftrb = 81;
byte leftlb = 79;
//front wheels set value
int leftRF = leftrf;
int leftLF = leftlf;
int rightRF = rightrf;
int rightLF = rightlf;
//back wheels set value
int leftRB = leftrb;
int leftLB = leftlb;
int rightRB = rightrb;
int rightLB = rightlb;
//servo pins
byte rfpin = 4;
byte rbpin = 5;
byte lfpin = 2;
byte lbpin = 3;
byte headxpin = 6;
byte headzpin = 9;
// Define ultrasonic sensor pins
byte echoL = 10;
byte triggerL = 11;
byte echoM = 12;
byte triggerM = 13;
byte echoR = 22;
byte triggerR = 24;
// Define servo objects
int headxcurrent = 93;
byte headxin = 93;
byte headzin = 90;
int headzcurrent = 90;
int headxsteps = 10;
int headzsteps = 10;
// Define distance thresholds
byte minDistance = 30; // Minimum distance in cm
byte maxDistance = 120; // Maximum distance in cm
// Function to calculate distance
int getDistance(int triggerPin, int echoPin) {
// Send trigger pulse
digitalWrite(triggerPin, LOW);
delayMicroseconds(2);
digitalWrite(triggerPin, HIGH);
delayMicroseconds(10);
digitalWrite(triggerPin, LOW);
// Read echo pulse duration
long duration = pulseIn(echoPin, HIGH);
// Calculate distance in cm
int distance = duration * 0.034 / 2;
return distance;
}
void setup() {
//head code start
headx.attach(headxpin);
headz.attach(headzpin);
headx.write(93);
headz.write(90);
//head code end
// Initialize servo objects
rf.attach(rfpin);
rb.attach(rbpin);
lf.attach(lfpin);
lb.attach(lbpin);
// Initialize ultrasonic sensor pins
pinMode(triggerL, OUTPUT);
pinMode(echoL, INPUT);
pinMode(triggerM, OUTPUT);
pinMode(echoM, INPUT);
pinMode(triggerR, OUTPUT);
pinMode(echoR, INPUT);
// Set initial servo positions
ServoInit();
// Wait for servo initialization
delay(500);
// Set motor control pins as outputs
pinMode(m1A1, OUTPUT);
pinMode(m1A2, OUTPUT);
pinMode(m2A1, OUTPUT);
pinMode(m2A2, OUTPUT);
pinMode(m3A1, OUTPUT);
pinMode(m3A2, OUTPUT);
pinMode(m4A1, OUTPUT);
pinMode(m4A2, OUTPUT);
pinMode(m5A1, OUTPUT);
pinMode(m5A2, OUTPUT);
pinMode(m6A1, OUTPUT);
pinMode(m6A2, OUTPUT);
}
void loop() {
int distanceL;
int distanceM;
int distanceR;
switch (outerState) {
case ECHO_PING: // Read distances from ultrasonic sensors
distanceL = getDistance(triggerL, echoL);
distanceM = getDistance(triggerM, echoM);
distanceR = getDistance(triggerR, echoR);
Forward();
outerState = CHECK_LEFT;
break;
case CHECK_LEFT: if (distanceL >= minDistance && distanceL <= maxDistance) {
outerState = LEFT_HIT;
innerState = 0;
}
else
outerState = CHECK_MID;
break;
case CHECK_MID: if (distanceM >= minDistance && distanceM <= maxDistance) {
outerState = MID_HIT;
innerState = 0;
}
else
outerState = CHECK_RIGHT;
break;
case CHECK_RIGHT: if (distanceR >= minDistance && distanceR <= maxDistance) {
outerState = RIGHT_HIT;
innerState = 0;
}
else {
outerState = LAST_WAIT;
SetDelay(100);
}
break;
case LEFT_HIT:
switch (innerState) {
case 0: ServoInit();
AllStop();
SetDelay(500);
innerState++;
break;
case 1: if (CheckDelay()) innerState++; break;
case 2: TurnRight();
SetDelay(700);
innerState++;
break;
case 3: if (CheckDelay()) innerState++; break;
case 4: Forward();
SetDelay(3000);
innerState++;
break;
case 5: if (CheckDelay()) innerState++; break;
case 6: Straight(); outerState = CHECK_MID; break;
}
break;
case MID_HIT:
switch (innerState) {
case 0: ServoInit();
AllStop();
SetDelay(500);
innerState++;
break;
case 1: if (CheckDelay()) innerState++; break;
case 2: if (distanceR > distanceL) {
TurnLeft();
}
else if (distanceR < distanceL) {
TurnLeft();
}
SetDelay(700);
innerState++;
break;
case 3: if (CheckDelay()) innerState++; break;
case 4: Backwards();
SetDelay(2200);
innerState++;
break;
case 5: if (CheckDelay()) innerState++; break;
case 6: Straight();
SetDelay(700);
innerState++;
break;
case 7: if (CheckDelay()) innerState++; break;
case 8: AllStop();
SetDelay(500);
innerState++;
break;
case 9: if (CheckDelay()) innerState++; break;
case 10: if (distanceR > distanceL) {
TurnLeft();
}
else if (distanceR < distanceL) {
TurnRight();
}
else if (distanceM > distanceL && distanceR) {
ServoInit();
}
SetDelay(700);
innerState++;
break;
case 11: if (CheckDelay()) innerState++; break;
case 12: Forward();
SetDelay(3000);
innerState++;
break;
case 13: if (CheckDelay()) innerState++; break;
case 14: ServoInit(); outerState = CHECK_RIGHT; break;
}
break;
case RIGHT_HIT:
switch (innerState) {
case 0: ServoInit();
AllStop();
SetDelay(700);
innerState++;
break;
case 1: if (CheckDelay()) innerState++; break;
case 2: TurnLeft();
SetDelay(2000);
innerState++;
break;
case 3: if (CheckDelay()) innerState++; break;
case 4: Forward();
SetDelay(3000);
innerState++;
break;
case 5: if (CheckDelay()) innerState++; break;
case 6: Straight(); outerState = LAST_WAIT; SetDelay(100); break;
}
break;
case LAST_WAIT: if (CheckDelay()) outerState = ECHO_PING; break;
}
}
void SetDelay(unsigned int mills) {
lastDelay = millis();
intervalDelay = mills;
}
bool CheckDelay() {
if (millis() - lastDelay >= intervalDelay) {
return true;
} else return false;
}
void TurnRight() {
rb.write(rightrf);
lb.write(rightlf);
}
void TurnLeft() {
rf.write(leftrf);
lf.write(leftlf);
}
void Straight() {
rf.write(inrf);
lf.write(inlf);
}
void ServoInit() {
rf.write(inrf);
lf.write(inlf);
rb.write(inrb);
lb.write(inlb);
}
void AllStop() {
digitalWrite(m1A1, LOW);
digitalWrite(m1A2, LOW);
digitalWrite(m2A1, LOW);
digitalWrite(m2A2, LOW);
digitalWrite(m3A1, LOW);
digitalWrite(m3A2, LOW);
digitalWrite(m4A1, LOW);
digitalWrite(m4A2, LOW);
digitalWrite(m5A1, LOW);
digitalWrite(m5A2, LOW);
digitalWrite(m6A1, LOW);
digitalWrite(m6A2, LOW);
}
void Forward() {
digitalWrite(m1A1, HIGH);
digitalWrite(m1A2, LOW);
digitalWrite(m2A1, LOW);
digitalWrite(m2A2, HIGH);
digitalWrite(m3A1, LOW);
digitalWrite(m3A2, HIGH);
digitalWrite(m4A1, HIGH);
digitalWrite(m4A2, LOW);
digitalWrite(m5A1, HIGH);
digitalWrite(m5A2, LOW);
digitalWrite(m6A1, HIGH);
digitalWrite(m6A2, LOW);
}
void Backwards() {
digitalWrite(m1A1, LOW);
digitalWrite(m1A2, HIGH);
digitalWrite(m2A1, HIGH);
digitalWrite(m2A2, LOW);
digitalWrite(m3A1, HIGH);
digitalWrite(m3A2, LOW);
digitalWrite(m4A1, LOW);
digitalWrite(m4A2, HIGH);
digitalWrite(m5A1, LOW);
digitalWrite(m5A2, HIGH);
digitalWrite(m6A1, LOW);
digitalWrite(m6A2, HIGH);
}
give it a go..
have fun.. ~q
Shouldn't these be static or global to persist between iterations?
Thank you so much for making the changes to the code. I will try it out as soon as the batteries for the car are ready. I will reply to this tomorrow after testing it!
I will test both codes, first the one qubits-us perfectionated and then if it gives me trouble because of those, I will move them I guess.
I actually tried something like this but the millis intervals were inside of the main loop which I guess were the same as the originals delays I had. I'm really new to programing so I tried to solve utilizing the knowledge I have.
Yeah, honestly my problem is that I didn't buy a board with multi-core functionality...I was reading some of the replies and someone said that some boards with multi-core functionality can run 7 different codes at the same time without counters or state machines. Next time when working on something like this I will get another more capable board.
Very interesting question.
As loop is the most outer loop and code-execution will stay always inside loop
the variables were not destroied.
But wait! Hidden away behind and above loop() there is another function that calls loop()
which means loop() is entered and left. Leaving a function => destroy local / non-static variables.
Then it will depend on the code if the variables get values assigned new as the first thing that happens inside loop.
At least a suitable operating system has to be running to do the task management.
My project is kind of ambitious as it requires, I think 40 something pins in order to work...the problem is that I didn't do that much research before initiating the project. Trust me that looking at the inside of the car is a hell...I can't imagine myself desoldering every single cable from the board. My only hope is the code.
So, I basically need a whole computer in order to do that? Maybe a Raspberry Pi?
Like which?
You can do multiple things simultaneous-ish if make your timeline serial though one iteration of loop() (with time-sharing delays replacements), or you can make the timeline nonblocking and leave a fast, free-running event loop with a state machine that remembers state between successive iterations of loop().
It could work like that with the bits in loop instead of the separate function, but you need to make sure that the time
I´m not familar with the realtime behaiviour of this type of calculator.