2

Code:

#include <Mouse.h>
#include <hiduniversal.h>
#include "hidmouserptparser.h"
#include <USBController.h>

USBController controller;
USB Usb;
HIDUniversal Hid(&Usb);
HIDMouseReportParser Mou(nullptr);
String x;
String y;
boolean isX; 
int recv;

void setup() {
    Mouse.begin();
    Usb.Init();
    delay(200);

    if (!Hid.SetReportParser(0, &Mou))
        ErrorMessage<uint8_t > (PSTR("SetReportParser"), 1);
}

void loop() {
    Usb.Task();
    recv = controller.read();
    if ((recv-48)==29){ // recv = M
        // , : -4
        // /n : -38
        x="";
        y="";
        isX = true; 
        while (true){
            recv = controller.read();
            if (recv!=0 && recv!=2){ // filter out 0 and 2
                if ((recv-48)==-38){ // -38 is a line break
                    break;
                }
                else if ((recv-48)==-4){ // switch to y value after comma
                    isX = false;
                    continue;
                }
            
                if (isX){
                    x+=String(recv-48);
                }
                else{
                    y+=String(recv-48);
                }
            }
        }
        Mouse.move(x.toInt(),y.toInt());
    }
}

void onButtonDown(uint16_t buttonId) {
    Mouse.press(buttonId);
}

void onButtonUp(uint16_t buttonId) {
    Mouse.release(buttonId);
}

void onMouseMove(int8_t xMovement, int8_t yMovement, int8_t scrollValue) {
    Mouse.move(xMovement, yMovement, scrollValue);
}

I'm using an Arduino leonardo with a usb host shield. My goal is to move my cursor to a specific location based on the data read in. Format of the data read in is "MX,Y" and a line break.

In the main loop,

  • I read the data and subtract 48 because that's the real number.
  • Then I check if the first character is M because that is where the beginning of my data starts.
  • Then I filter out 0 and 2 because those values are useless to me and randomly appear.
  • I loop to add the integer values as strings to x then switch to y after the comma appears.
  • Then I convert the string values to int and mouse.move.

The problem is the mouse movement is slow and jittery and I think it's because the toInt and String() methods are slowing it down. How could I improve my algorithm?

1 Answer 1

1

This:

while (true){
    recv = controller.read();
    // ...
}

is a blocking loop. This means that, while executing this part of the code, the Arduino is stuck for an indeterminate amount of time, and can do nothing else. Specifically, it cannot run Usb.Task(), which could well be the cause of the jittery behavior you are experiencing.

I would recommend reading the incoming data in a non blocking fashion: each time there is a byte to be read, read it and move on. Do not wait for the subsequent bytes. Only when you find an end of line would you handle the data you received. For example:

// Parse and execute a command received through USB.
executeCommand(String &command) {
    // Implementation left as an exercise to the reader.
}

// Whether we are presently receiving characters from a command.
bool receivingCommand = false;

// Received command, may be incomplete.
String command;

void loop() {
    Usb.Task();
    if (controller.available()) {
        char c = controller.read();
        if (!receivingCommand && c == 'M') {  // start of command
            receivingCommand = true;
        } else if (receivingCommand && c == '\n') {  // end of command
            executeCommand(command);
            command = "";
            receivingCommand = false;
        } else if (receivingCommand) {  // body of command
            command += c;  // buffer the received character
        }
    }
}

A better approach would be to avoid the String class, which is not friendly to your Arduino's memory, and use a plain C string, as explained in Reading Serial on the Arduino. This, however, is likely unrelated to your jitter issue.

2
  • Thanks! How would I use a C string to this program. My input is originally a float and I need to add that to a character array. Don't I need to convert it to a String first?
    – Jake Jin
    Commented Jun 14, 2023 at 22:28
  • @JakeJin: No, you do not need a String. You can convert a float to a character array using dtostrf(). Commented Jun 15, 2023 at 8:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.