Outside Fursuit
For this purpose, "Server" is Fursuit (Central Unit) and "Client" is device connecting to Fursuit.Navigation summary
Fursuit Specifications
Buttons
-
save slots
-
finger_1
thumb - finger_2
- finger_3
- finger_4
-
finger_5
artificial thumb
-
finger_1
-
yaw_closed
detection if is yaw closed or not
Axis
- ear_left
- ear_right
- yaw
Packets
-
0x0?
Password
- 0x00 login (request)
- 0x01 login (request,encrypted)
- 0x02 login (response)
- 0x03 setPassword (request)
- 0x04 setPassword (request,encrypted)
- 0x05 setPassword (response)
-
0x1?
Info
- 0x10 getMainInfo (request)
- 0x11 getMainInfo (response)
- 0x12 getLedInfo (request)
- 0x13 getLedInfo (response)
- 0x14 getWingsInfo (request)
- 0x15 getWingsInfo (response)
- 0x16 getServoInfo (request)
- 0x17 getServoInfo (response)
- 0x18 getUserInputInfo (request)
- 0x19 getUserInputInfo (response)
-
0x2?
Status
- 0x20 getStatus (request)
- 0x21 getStatus (response)
-
0x3?
Slots
- 0x30 saveToSlot
- 0x31 loadFromSlot
- 0x4? User Input
-
0x5?
Leds
- 0x50 setLedColor
- 0x51 getLedColor (request)
- 0x52 getLedColor (response)
-
0x6?
Wings
- 0x60 setWings
- 0x61 getWings (request)
- 0x62 getWings (response)
-
0x7?
Servo
- 0x70 setServoAngle
- 0x71 getServoAngle (request)
- 0x72 getServoAngle (response)
Communication Start
Communication | Packet |
C -> S | login (request) |
S -> C | login (response) |
Possible end of communication (Wrong Password) | |
S -> C | getMainInfo (response) |
getStatus (response) | |
From now, order may be different. Not all packets may be send. |
|
S -> C | getLedInfo (response) |
getWingsInfo (response) | |
getServoInfo (response) | |
getUserInputInfo (response) |
After this start, any packets (in right direction) excluding login packets (both request + response).
Password
login (request)
ID | 0x00 |
---|---|
Direction | Client -> Server |
Size | 4 bytes |
Byte ID | Data Type | Name | Value |
---|---|---|---|
0 | uint / uint32 | password | 0 - 4,294,967,295 |
login (response)
ID | 0x02 |
---|---|
Direction | Server -> Client |
Size | 1 byte |
Byte ID | Data Type | Name | Value |
---|---|---|---|
0 | byte | success |
0 ~ success >= 0 ~ fail |
setPassword (request)
ID | 0x03 |
---|---|
Direction | Client -> Server |
Size | 12 bytes |
Byte ID | Data Type | Name | Value |
---|---|---|---|
0 | uint / uint32 | master_password | 0 - 4,294,967,295 |
4 | uint / uint32 | new_password | 0 - 4,294,967,295 |
8 | uint / uint32 |
~new_password Binary inverted new_password |
0 - 4,294,967,295 |
setPassword (response)
ID | 0x05 |
---|---|
Direction | Server -> Client |
Size | 1 byte |
Byte ID | Data Type | Name | Value |
---|---|---|---|
0 | byte | success |
0 ~ success >= 0 ~ fail |
Info
getMainInfo (request)
ID | 0x10 |
---|---|
Direction | Client -> Server |
Size | 0 bytes |
getMainInfo (response)
ID | 0x11 |
---|---|
Direction | Server -> Client |
Size | 34 bytes |
Byte ID | Data Type | Name | Value |
---|---|---|---|
0-15 |
char[16] string |
fursuit_name | {fursuit_name} |
16-31 |
char[16] string |
fursuit_owner | {fursuit_owner} |
32 | byte | battery_count | {battery_count} |
33 | byte | temp_sensor_count | {temp_sensor_count} |
getLedInfo (request)
ID | 0x12 |
---|---|
Direction | Client -> Server |
Size | 0 bytes |
getLedInfo (response)
ID | 0x13 |
---|---|
Direction | Server -> Client |
Size | 1 byte + {led_count} |
Byte ID | Data Type | Name | Value |
---|---|---|---|
0 | byte | led_count | {led_count} |
{led_count} count 17 bytes per item |
byte | led_color_number |
{led_color_number} (byte count) 0 = HIGH / LOW (1 byte) 1 = 1 color 3 = RGB color |
char[16] string |
led_name | {led_name} |
getWingsInfo (request)
ID | 0x14 |
---|---|
Direction | Client -> Server |
Size | 0 bytes |
getWingsInfo (response)
ID | 0x15 |
---|---|
Direction | Server -> Client |
Size | 1 byte + {wings_count} |
Byte ID | Data Type | Name | Value |
---|---|---|---|
0 | byte | wings_count | {wings_count} |
{wings_count} count 16 bytes per item |
char[16] string |
wing_name | {wing_name} |
getServoInfo (request)
ID | 0x16 |
---|---|
Direction | Client -> Server |
Size | 0 bytes |
getServoInfo (response)
ID | 0x17 |
---|---|
Direction | Server -> Client |
Size |
1 byte + {servo_count} * 16 |
Byte ID | Data Type | Name | Value |
---|---|---|---|
0 | byte | servo_count | {servo_count} |
{servo_count} count 16 bytes per item |
char[16] string |
servo_name | {servo_name} |
getUserInputInfo (request)
ID | 0x18 |
---|---|
Direction | Client -> Server |
Size | 0 bytes |
getUserInputInfo (response)
ID | 0x19 |
---|---|
Direction | Server -> Client |
Size |
2 bytes + {user_buttons_count} * 16 + {user_axis_count} * 16 |
Byte ID | Data Type | Name | Value |
---|---|---|---|
0 | byte | user_buttons_count | {user_buttons_count} |
{user_buttons_count} count 16 bytes per item |
char[16] string |
user_button_name | {user_button_name} |
1 + {user_buttons_count} * 16 |
byte | user_axis_count | {user_axis_count} |
{user_axis_count} count 16 bytes per item |
char[16] string |
user_axis_name | {user_axis_name} |
Status
getStatus (request)
ID | 0x20 |
---|---|
Direction | Client -> Server |
Size | 0 bytes |
getStatus (response)
ID | 0x21 |
---|---|
Direction | Server -> Client |
Size |
2 * {battery_count} bytes + 2 * {temp_sensor_count} bytes |
Byte ID | Data Type | Name | Value |
---|---|---|---|
??? {battery_count} count |
ushort / uint16 fixed point number (3 decimal) |
Battery {battery_id} | 0.000 - 65.535 |
??? {temp_sensor_count} count |
ushort / uint16 fixed point number (3 decimal) |
Temperature Sensor {temp_sensor_id} | 0.000 - 65.535 |
Slots
saveToSlot
ID | 0x30 |
---|---|
Direction | Client -> Server |
Size | 1 byte |
Byte ID | Data Type | Name | Value |
---|---|---|---|
0 | byte | slot | 1 - 5 |
loadFromSlot
ID | 0x31 |
---|---|
Direction | Client -> Server |
Size | 1 byte |
Byte ID | Data Type | Name | Value |
---|---|---|---|
0 | byte | slot | 1 - 5 |
User Input
getUserInputButtons (request)
ID | 0x40 |
---|---|
Direction | Client -> Server |
Size | 0 bytes |
getUserInputButtons (response)
ID | 0x41 |
---|---|
Direction | Server -> Client |
Size | {user_buttons_count} bytes |
Byte ID | Data Type | Name | Value |
---|---|---|---|
{user_buttons_count} count | byte | {user_button_name} |
0 ~ LOW >0 ~ HIGH |
getUserInputAxis (request)
ID | 0x42 |
---|---|
Direction | Client -> Server |
Size | 0 bytes |
getUserInputAxis (response)
ID | 0x43 |
---|---|
Direction | Server -> Client |
Size | {user_axis_count} bytes |
Byte ID | Data Type | Name | Value |
---|---|---|---|
{user_axis_count} count | byte | {user_axis_name} | 0 - 255 |
Leds
setLedColor
ID | 0x50 |
---|---|
Direction | Client -> Server |
Size |
{led_count} count, different byte number |
Byte ID | Data Type | Name | Value |
---|---|---|---|
??? | byte | {led_name} |
0 / 255 0 - 255 |
getLedColor (request)
ID |
0x51 {led_count} count, different byte number |
---|---|
Direction | Client -> Server |
Size | 0 bytes |
getLedColor (response)
ID | 0x52 |
---|---|
Direction | Server -> Client |
Size |
{led_count} count, different byte number |
Byte ID | Data Type | Name | Value |
---|---|---|---|
??? {led_count} count, different byte number |
byte | {led_name} |
0 / 255 0 - 255 |
Wings
setWings
ID | 0x60 |
---|---|
Direction | Client -> Server |
Size | {wings_count} bytes |
Byte ID | Data Type | Name | Value |
---|---|---|---|
??? | byte | {wings_name} | 0 - 100 |
byte | wing_speed |
0 - 25,500 (0 - 255) * 100 |
getWings (request)
ID | 0x61 |
---|---|
Direction | Client -> Server |
Size | 0 bytes |
getWings (response)
ID | 0x62 |
---|---|
Direction | Server -> Client |
Size | {wings_count} bytes |
Byte ID | Data Type | Name | Value |
---|---|---|---|
??? | byte | {wings_name} | 0 - 100 |
byte | wing_speed |
0 - 25,500 (0 - 255) * 100 |
Servo
setServoAngle
ID | 0x70 |
---|---|
Direction | Client -> Server |
Size | {servo_count} bytes |
Byte ID | Data Type | Name | Value |
---|---|---|---|
??? | byte | {servo_name} | 0 - 255 |
getServoAngle (request)
ID | 0x71 |
---|---|
Direction | Client -> Server |
Size | 0 bytes |
getServoAngle (response)
ID | 0x72 |
---|---|
Direction | Server -> Client |
Size | {servo_count} bytes |
Byte ID | Data Type | Name | Value |
---|---|---|---|
??? | byte | {servo_name} | 0 - 255 |
Inside Fursuit
In order to make everything smooth, I decided to use multiple microprocessors (Arduino Micro). Arduino has build-in Serial which we will use for communication (Serial.available() for available bytes).Serial Port has different speed. Most common speed is 9,600 but for us, faster is better so we will use 115,200 which is fastest which Arduino supports.
#if defined(__AVR_ATmega32U4__)
#define Communication Serial1
#define CommunicationEvent serialEvent1
#else
#define Communication Serial
#define CommunicationEvent serialEvent
#endif
Because we want to use on-board
Serial
and it is different some boards, we will define "alias". Serial
is on Arduino Uno (and derives), Serial1
is on Arduino Leonardo (and derives as Arduino Micro) because ATmega32U4 has Serial
for USB communication.void setup()
{
Communication.begin(115200);
}
We also need to specify the speed of Serial Port. Thanks to our alias,
Communication
is Serial
or Serial1
based on what we need.The
#define
also defines CommunicationEvent
which is name of function which is called when we receive data (byte) over Serial. It is called Serial Event but when you look at Arduino page, you can read that it does not work on Leonardo and Micro but it does not apply on serialEvent1()
.You can check it yourself by code below. Connect pins RX (0) and TX (1) together and run code below. Then comment out the
and try it again. First time it should work normally (as Serial.write()
), second time it should not work.void setup()
{
// put your setup code here, to run once:
Serial.begin(9600);
Serial1.begin(9600);
}
void serialEvent1()
{
Serial.write(Serial1.read());//COMMENT ME
}
void loop()
{
// put your main code here, to run repeatedly:
Serial1.write('0');
delay(1000);
}
The protocol itself is simple - just send raw data specified pin. Each unit has its own pin.
There is one exception - Servo and LED Control. It is because Arduino Micro has only one hardware Serial.