Feature request: message queueing and mutex for Arduino

Support forum for MegunoLink
Post Reply
sheimend
Posts: 5
Joined: Thu Aug 05, 2021 5:22 pm

Tue May 02, 2023 10:43 pm

A lot of my MegunoLink use cases involve capturing data as fast as possible during an experiment. For instance, sweeping through a frequency range and recording the output at each frequency, or moving a motor from A to B and recording some output variable. I want those tests to run as quickly as they can, and I want my data to be as granular as it can be.

However, plotting data using the myPlot.SendData() command is always the bottleneck since serial communication is typically the slowest link in the chain. So, I do a few things to eek out more speed:

1. Run separate threads for "run the experiment" code and "send the data to Meguno".
2. Use a message queue so the "run the experiment" code can quickly add new data to the stack
3. Bundle up data points into batches and send them using the batch send signature of myPlot.SendData(). This is a major speed booster.

As a result of the multithreading, I have to protect against simultaneous threads trying to write to Meguno. To do that, I use a simple mutex.

It would be awesome if all of this were wrapped in the SendData() command by default. So, that's my feature request.

Here's some not-quite-complete code showing the relevant sections and my approach. The speed boost here is sometimes 10x greater than just sending data inside my CaptureData() method.

Code: Select all


//MegunoLink
XYPlot myPlot;
InterfacePanel Panel;


std::mutex meglock;

TaskHandle_t messageTask;

class DataPoint {
public:
    char* title;
    int position;
    float force;
    
    
    DataPoint() {
        title = "";
        position = 0;
        force = 0;
    }

    DataPoint(char* _title, int _position, float _force)
    {
        title = _title;
        position = _position;
        force = _force;
    }
};

QList<DataPoint> mQueue;

setup()
{
	//process the message queue on a different thread
	 xTaskCreatePinnedToCore(processMessageQueue, "processMessageQueue", 5000, NULL, 5, &messageTask, 1);

}

void processMessageQueue(void* pvParameters)
{
    for (;;)
    {
        
        if (mQueue.length() > 0)
        {
            int l = mQueue.length();
            int* positions = new int[1];
            positions = (int*)malloc(l * sizeof(int));

            float* forces = new float[1];
            forces = (float*)malloc(l * sizeof(float));
            
            char* title = mQueue.front().title;
            for (int i = 0; i < l; i++)
            {
                DataPoint p = mQueue.front();
                positions[i] = p.position;
                forces[i] = p.force;
                mQueue.pop_front();
            }
            if (meglock.try_lock())
            {
                myPlot.SendData(title, positions, forces, l, 0);
                meglock.unlock();
            }
           
        }
        vTaskDelay(75);
    }
}

void CaptureData(){

	//do some stuff
	 DataPoint pt("my test name", xValue, yValue);            
	 mQueue.push_back(pt);
}



Post Reply