I'm using a gyroscope, which returns angular velocity in floats. I'm trying to use this data with the arduino mouse library. The move function requires a signed character. I'm not what the best way is to convert the float data from the sensor into signed char.

In what way can I do this, losing the least in terms of precision?

I found out you can use dtostrf to transfer floats into an array of characters, but not sure what to do following this or if it's even the best way.

I would appreciate any guidance.

  • this appears to be a general C++ programming question, not an Arduino related question ... please do your research in the C++ language realm – jsotola Apr 22 at 19:00
  • Besides data type concerns, there are scaling concerns. Exactly what does the signed char represent for the mouse move function? What mouse library are you using? What range of float values might you get from the gyroscope? If it's, for example, -300.0 to +300.0 then you'll at least need to scale that down before converting to a char-sized integer. – lurker Apr 22 at 19:01
  • this should help duckduckgo.com/?q=c%2B%2B+float+to+signed&ia=web – jsotola Apr 22 at 19:02
  • Thanks for the responses. Scaling will be necessary as the values do tend to be in the 300 range maximum per sample size. The signed character of the standard arduino library represents the amount of movement on screen, relative to the previous cursor position. I did try researching this in both the C++ and arduino realms, but couldn't find the answer so I decided to try asking. – Zhelyazko Grudov Apr 22 at 19:07

The mouse library expects the movement coordinates to be provided as 8-bit signed integers, which corresponds to the int8_t data type. This type is actually an alias to signed char, but calling it this way is confusing, as the word char somehow implies a type meant to store characters, which is definitely not the case here.

Converting a float to any integer type can be done by plain assignment, with two caveats:

  • If the float exceeds the range of the integer, the assignment will wrap around modulo 2^(integer size in bits). This is undesirable and can be prevented by first constrain()ing the float to the appropriate range.
  • The assignment rounds towards zero, whereas rounding to the nearest integer is better if you want to minimize the errors. This can be achieved with the round() macro.

In summary:

// In global context:
const float scale = 0.4;  // scale factor for mouse moves

// Within loop():
float rotation = get_data_from_gyroscope();
int8_t mouse_move = round(constrain(rotation * scale, -128, +127));

Note that the optimal scale can only be determined experimentally: you have to tweak it until your input device “feels” right.

  • Thank you very much again, Edgar! It feels to me this is a very important part of the implementation as you can lose the precision of the sensor in the conversion, so I'm grateful to have an expert jumping in. – Zhelyazko Grudov Apr 23 at 8:26

You are misunderstanding the type char. It is named character, because in ASCII representation you can use it to save one character. But internally it just is a number. The Arduino doesn't care, if you save characters in it or numbers, because characters are also numbers for it.

A signed char, like the move() function of the library uses` has 1 byte and is signed, thus can hold numbers from -128 to 127.

While the documentation is not clear about what the x and y parameters really represent the answer to this question is clear about it. Basically the whole range from -128 to +127 represents a whole inch (or what the computer thinks is an inch). So this results in a resolution of 1" / (127 - -128) = 1" / 255 = 0.0039" (or about 0.1mm). I don't know, what values you are getting from the sensor, but you will have to scale it to somewhere in the -128 to 127 range (depends on how sensitive you want it to be). And you won't loose precision here. The sensor values most likely are more precise, than the range of the mouse move() function.

The calculation will then be as simple as

signed char mouse_x = sensor_x * factor + offset;

The result of the calculation will implicitly converted to a 1 byte signed integer (this is what signed char is). If you want to make it clearer what happens here, you can also write:

signed char mouse_x = (signed char)(sensor_x * factor + offset);

This is not needed, but you might wanna do it for clarity.

Seen in Edgar Bonets answer: You might wanna contrain the value of above calculation to the -128 to 127 range. If you get an unexpected high value from your sensor, the above calculation would overflow the mouse_x variable (not good for correct values). So capping the values to that range with the constrain() function is definitely good. Refer to Edgars answer and the documentation for this.

  • Hi Chrisl, thank you very much for the detailed response. I really appreciate you taking the time. Between your and Edgar's responses I feel like I have a much better understanding of the issue. You both should know newbies are really grateful when you help out. Or they should be! – Zhelyazko Grudov Apr 23 at 8:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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