i have a question on how to program a certain sequence for my robot.
lets say if i would to program to make it run from position a to b, i have a sensor attach to it that should it detect x, it would perform an action called y at the position where it detect x, where action y doesnt change its position.
i would like the robot to continue from where it left after performing action y to go towards b. however i do not know how to pause the sequence from a to b and continue from where it left off after performing action y. i am controlling only the motor of the wheels and its timing so i can only set the speed of the wheels for a certain time.
is there a pause function in general( not sleep) in c++ and to continue running its lines of code from where it paused?
for now i do know how to reset its action but thats not what i want.
example( making the robot move from a to b in 10 seconds, detect object x at 3 seconds, do action y at position when t =3 seconds, continue motion for remaining 7 seconds after action y has been done)
You can try to use some event (message) driving architecture like the following pseudo code:
vector<action> action_sequence={do_a,do_b,do_c};
int i=0;
while(1)
{
e = WaitForMessage();
switch(e.code)
{
case do_action:
action_sequence[i].run();//perform an action
...//some code to have a scheduler thread to send next
//do_action message in certain seconds to this thread.
i++;
default:
...
}
}
The answer would depend on your code, are you using windows messaging, are you using thread, etc. Assuming that you are using neither, just linear code you could implement your own sleep function which is passed a function by the caller which is used to access if the sleep should be preempted. If preempted, then the function returns the time left so the action can be continued later.
This allows linear code to handle your situation. I knocked up a sample. Will explain the bits.
typedef bool (*preempt)(void);
DWORD timedPreemptableAction (DWORD msTime, preempt fn)
{
DWORD startTick = GetTickCount();
DWORD endTick = startTick + msTime;
DWORD currentTick;
do
{
currentTick = GetTickCount();
}
while (fn () == false && currentTick < endTick);
return currentTick > endTick ? 0 : endTick-currentTick;
}
The key function above, obtains start time in milliseconds, and will not exit until the timeout expires - or the user provided function returns true.
This user provided function could poll input devices such as a keyboard press etc. For now to match your question, I have added a user function which returns true, after 3 seconds:
DWORD startToTurnTicks = 0;
bool startToTurn (void)
{
bool preempt = false;
// TODO Implement method of preemption. For now
// just use a static timer, yep a little hacky
//
// 0 = uninitialized
// 1 = complete, no more interruptions
// >1 = starting tick count
if (startToTurnTicks == 0)
{
startToTurnTicks = GetTickCount();
}
else
{
if (startToTurnTicks != 1)
{
if ((startToTurnTicks + 3000) < GetTickCount())
{
startToTurnTicks = 1;
preempt = true;
}
}
}
return preempt;
}
Now we have a function which waits for N time and can exit, and a user function which will return true after 3 seconds, now the main call:
bool neverPreempt (void)
{
return false;
}
int main (void)
{
int appResult = 0;
DWORD moveForwardTime = 1000*10;
DWORD turnTime = 1000*3;
DWORD startTicks = GetTickCount();
printf ("forward : %d seconds in\n",
(GetTickCount()-startTicks)/1000);
moveForwardTime = timedPreemptableAction (moveForwardTime, &startToTurn);
printf ("turn : %d seconds in\n",
(GetTickCount()-startTicks)/1000);
turnTime = timedPreemptableAction (turnTime, &neverPreempt);
printf ("turn complete : %d seconds in\n",
(GetTickCount()-startTicks)/1000);
if (moveForwardTime > 0)
{
printf ("forward again : %d seconds in\n",
(GetTickCount()-startTicks)/1000);
moveForwardTime = timedPreemptableAction (moveForwardTime, &neverPreempt);
printf ("forward complete : %d seconds in\n",
(GetTickCount()-startTicks)/1000);
}
return appResult;
}
In the main code you see timedPreemptableAction is called 3 times. The first time we pass the user function which turns true after 3 seconds. This first call exits after three seconds returning 7 seconds left. The output from the app returns:
f:\projects\cmake_test\build\Debug>main
forward : 0 seconds in
turn : 3 seconds in
turn complete : 6 seconds in
forward again : 6 seconds in
forward complete : 13 seconds in
Started to move forward #0 seconds, "paused" #3 seconds, restored #6 and finished #13.
0->3 + 6->13 = 10 seconds.
Related
I have a class executing in a thread.
But I only want to allow it to run for 10 seconds.
Note... I have no means of passing any boolean into the class to stop execution.
So, How can I set up a thread to terminate after 10 seconds?
The class I am testing has potential infinite recursion that may take place and it is pointless to let it run longer than 10 seconds.
TEST_METHOD(TM_ClientServer_Threads)
{
bool bDone = false;
int ii = 0;
std::thread tCounter([&bDone, &ii]()
{
// Black Box: can't touch this; can't pass in a Boolean
while(true)
{
ii++;
}
}
);
std::thread tTimer([&bDone, &tCounter]()
{
Sleep(1000);
bDone = true;
// kill the tCounter thread ?
}
);
tCounter.join();
tTimer.join();
ii = ii + 0; // break point here
}
Hoping someone can see what I'm missing as it's gotta be right there staring at me in the face..
I've got this code (below) set up on an ESP32 to spawn a thread that simply monitors the state of a pin connected to a switch. Essentially this code is supposed to wait for the button to be held for 3 seconds and then do something important. The actual input seems to read fine, but for some reason once I've pressed the button, the button state is stuck for like 15 seconds after un-pressing the switch.
For example,
Press the switch, the actualBtnState reads 1, buttonState reads 1 (after 50us),and btnPressTime increments as expected.
Release switch, actualBtnState reads 0, btnState reads 1, and btnPressTime stops incrementing.
After 50us, expecting to see btnState read 0 and then trigger the else or elseif blocks (depending on how long the button was held). Actual results continue to read btnState = 1 and btnPressTime = [whatever the last held time was] for a solid 15 seconds or more. actuyalBtnState reads correctly at 0 this entire time and for some reason lastDebounceTime keeps incrementing?
I should note that this is part of a much larger project, hence the threading. I also can't seem to print anything within the resetBtnCB function as I immediately get a "guru mediation error kernel panic whatever-the-error-is" error and the esp reboots.
Code:
#include <Arduino.h>
#define BUTTON_PIN 27
// Variables will change:
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
unsigned long buttonPressTime = 0; //Amount of time the button has been held down
unsigned long actualBtnState = 0; //The actual reading from the pin without noise filtering
void resetBtnCB(void *pvParameters)
{
pinMode(BUTTON_PIN, INPUT);
while (true)
{
// read the state of the switch into a local variable:
int reading = digitalRead(BUTTON_PIN);
actualBtnState = reading;
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState)
{
// reset the debouncing timer
lastDebounceTime = millis();
}
unsigned long timeSinceDebounce = millis() - lastDebounceTime;
if (timeSinceDebounce > debounceDelay)
{
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
buttonState = reading;
if (buttonState == HIGH)
{
buttonPressTime += timeSinceDebounce;
}
else if (buttonPressTime > 300)
{
buttonPressTime = 0;
// SUCCESS! Do something important here as we've held the button for x seconds
}
else
{
buttonPressTime = 0;
}
}
// save the reading. Next time through the loop, it'll be the lastButtonState:
lastButtonState = reading;
vTaskDelay(10);
}
}
void setup()
{
Serial.begin(115200);
xTaskCreate(resetBtnCB, "reset_button", 1024, NULL, 10, NULL);
}
void loop()
{
char debug[512];
sprintf(debug, "button state %u, lastD %u, buttonPressTime %u, actualBtnState %u, lastBtnState %u", buttonState, lastDebounceTime, buttonPressTime, actualBtnState, lastButtonState);
Serial.println(debug);
delay(50);
yield();
}
I have a job that should be ran with minimum interval of 5 seconds. Trigger that starts this job can be executed in any moment and in any frequency.
What is the best way to solve such a case in RTOS environment?
I want to make a function that creates a task if it does not exist. Existing task should wait for minimum interval to pass before doing anything. While it is waiting, function that should create it should skip the creation of a new task.
What is the right way to check if task was created but didn't finish yet?
Should I use tasks at all in this case?
Code example below:
#define CONFIG_MIN_INTERVAL 5000
uint32_t last_execution_timestamp = 0;
TaskHandle_t *task_handle = NULL;
bool task_done = true;
static void report_task(void *context)
{
if (esp_timer_get_time() / 1000 < last_execution_timestamp + CONFIG_MIN_INTERVAL)
{
ESP_LOGI(stateTAG, "need to wait for for right time");
int time_to_wait = last_execution_timestamp + CONFIG_MIN_INTERVAL - esp_timer_get_time() / 1000;
vTaskDelay(time_to_wait / portTICK_PERIOD_MS);
}
// do something...
task_done = true;
vTaskDelete(task_handle);
}
void init_report_task(uint32_t context)
{
if (!task_done)
{
ESP_LOGI(stateTAG, "TASK already exists");
}
else
{
ESP_LOGI(stateTAG, "Creating task");
xTaskCreate(&report_task, "report_task", 8192, (void *)context, 4, task_handle);
task_done = false;
}
}
eTaskGetState can be used to check if a task is already running, but such a solution can be susceptible to races. For example your task is technically still "running" when it's in fact "finishing", i.e. setting task_done = true; and preparing for exit.
A better solution could be to use a queue (or a semaphore) and have the task run continuously, waiting for the messages to arrive and processing them in a loop.
Using a semaphore, you can do xSemaphoreTake(sem, 5000 / portTICK_PERIOD_MS); to wait for either a wake-up condition or a timeout of 5 seconds, whichever comes first.
== EDIT ==
if there is no events task should wait. Only if event happens it should run the job. It should run it immediately if there was no execution in past 5 seconds. If there was an execution it should wait until 5 seconds since last execution and only then run it
You can achieve that by carefully managing the semaphore's ticks to wait. Something like this (untested):
TickType_t nextDelay = portMAX_DELAY;
TickType_t lastWakeup = 0;
const TickType_t minDelay = 5000 / portTICK_PERIOD_MS;
for (;;) {
bool signalled = xSemaphoreTake(sem, nextDelay);
TickType_t now = (TickType_t)(esp_timer_get_time() / (portTICK_PERIOD_MS * 1000));
if (signalled) {
TickType_t ticksSinceLastWakeup = now - lastWakeup;
if (ticksSinceLastWakeup < minDelay) {
// wakeup too soon - schedule next wakeup and go back to sleep
nextDelay = minDelay - ticksSinceLastWakeup;
continue;
}
}
lastWakeup = now;
nextDelay = portMAX_DELAY;
// do work ...
}
I'm using SuspendThread / ResumeThread to modify the RIP register between the calls through GetThreadContext / SetThreadContext. It allows me to execute arbitrary code in a thread in another process.
So this works, but sometimes ResumeThread takes about 60 seconds to resume the target thread.
I understand that I'm somewhat abusing the API through this usage, but is there any way to speed this up? Or something I should look at that might indicate a bad usage?
The target thread is a sample program that loops over itself.
uint64_t blarg = 1;
while (true) {
Sleep(100);
std::cout << blarg << std::endl;
blarg++;
if (blarg == std::numeric_limits<uint64_t>::max()) {
blarg = 0;
}
}
The Suspend / Resume sequence is very simple as well:
void hijackRip(uint64_t targetAddress, DWORD threadId){
HANDLE targetThread = OpenThread(THREAD_ALL_ACCESS, FALSE, threadId);
NTSTATUS suspendResult = SuspendThread(targetThread);
CONTEXT threadContext;
memset(&threadContext, 0, sizeof(threadContext));
threadContext.ContextFlags = CONTEXT_ALL;
BOOL getThreadContextResult = GetThreadContext(targetThread, &threadContext);
threadContext.Rip = targetAddress;
BOOL setThreadContextResult = SetThreadContext(targetThread, &threadContext);
DWORD resumeThreadResult = ResumeThread(targetThread);
}
Again, this works, I can redirect execution correctly, but only 30 / 60 seconds after executing this function.
I am working with a application where the requirement is execute a function after every 100ms.
Below is my code
checkOCIDs()
{
// Do something that might take more than 100ms of time
}
void TimeOut_CallBack(int w)
{
struct itimerval tout_val;
int ret = 0;
signal(SIGALRM,TimeOut_CallBack);
/* Configure the timer to expire after 100000 ... */
tout_val.it_value.tv_sec = 0;
tout_val.it_value.tv_usec = 100000; /* 100000 timer */
/* ... and every 100 msec after that. */
tout_val.it_interval.tv_sec = 0 ;
tout_val.it_interval.tv_usec = 100000;
checkOCIDs();
setitimer(ITIMER_REAL, &tout_val,0);
return ;
}
Function TimeOut_CallBack ( ) is called only once and then on checkOCIDs( ) function must be executed after a wait of 100ms continuously.
Currently, The application is going for a block as checkOCIDs( ) function takes more than 100ms of time to complete and before that the Timer Out is triggered.
I do not wish to use while(1) with sleep( ) / usleep( ) as it eats up my CPU enormously.
Please suggest a alternative to achieve my requirement.
It is not clear whether the "check" function should be executed while it is in progress and timer expires. Maybe it would be ok to you to introduce variable to indicate that timer expired and your function should be executed again after it completes, pseudo-code:
static volatile bool check_in_progress = false;
static volatile bool timer_expired = false;
void TimeOut_CallBack(int w)
{
// ...
if (check_in_progress) {
timer_expired = true;
return;
}
// spawn/resume check function thread
// ...
}
void checkThreadProc()
{
check_in_progress = true;
do {
timer_expired = false;
checkOCIDs();
} while(timer_expired);
check_in_progress = false;
// end thread or wait for a signal to resume
}
Note, that additional synchronization may be required to avoid race conditions (for instance when one thread exists do-while loop and check_in_progress is still set and the other sets timer_expired, check function will not be executed), but that's depends on your requirements details.