Skip to content

On a Quest to find Sanbot's deepest secrets – Part 2 (USB protocol)

With part 1 ending in a dump of the Android applications running on the robot, it was time to investigate whether the robot could be controlled directly from a computer over the USB connection using the information obtained from that dump.

Legal note

This research was conducted on hardware legally owned by the author. All analysis is performed for the purposes of interoperability, repair, and educational research.

No proprietary firmware or copyrighted software is redistributed on this site.

Plugging the robot into my USB port

The first thing I had to do was partially disassemble the robot, because we need to access the internal USB port of the tablet. Where we can unplug the USB cable going to the MCU Head and body controller as well as the camera's and microphones.

After plugging in the USB cable and running lsusb the following devices appeared:

$ lsusb
Bus 001 Device 017: ID 2bc5:0401 Orbbec 3D Technology International, Inc Astra
Bus 001 Device 018: ID 05e3:0608 Genesys Logic, Inc. Hub
Bus 001 Device 019: ID 0483:5741 STMicroelectronics XXXXXXXXX-STM32 Virtual COM Port
Bus 001 Device 020: ID 1d6b:0102 Linux Foundation EEM Gadget
Bus 001 Device 021: ID 0483:5740 STMicroelectronics Virtual COM Port

From this it becomes clear that the robot exposes two USB CDC-ACM ports (VCOM) for the STM32 microcontrollers, presumably one for the head controller and one for the body controller. One 3d-camera from orbbec and Linux foundation EEM-gadget, which is the microphone and HD-camera situated in the head.

Orbbec 3D-Camera

The orbbec 3D camera matches with the astra orbbec camera driver, I found for windows on the GitHub of Vidicon Sanbot elf hacking project. And with firing up Windows, because the Linux SDK depends on very old libraries and I first wanted to get something working quickly. I was greeted with this screen using this openni-sdk. Later on when refitting this robot with new hardware/software, I will probably port the old openni-sdk to new dependencies as far as it is possible.

Orbbec astra 3d-shot of fire-extinguisher

HD-Camera, Microphones and Zigbee

The HD-Camera, Microphones and Zigbee are handled by the EEM gadget:

Bus 001 Device 020: ID 1d6b:0102 Linux Foundation EEM Gadget

This device runs its own small Linux-based firmware which manages the HD camera and the beamforming microphone array. To get that working I did some first attempts to reverse engineer the communications and found some useful clues. Such as there is a service running on the android tablet which sends the HD camera footage over local http port 5500. Which with adb forwarding can be easily captured to your pc.

Although it is interesting, I rather leave this work for a future blog post.

Microcontrollers usb protocol

The microcontrollers are connected to the tablet via USB CDC-ACM and expose virtual serial ports over which a custom framed binary protocol is sent.

The protocol has the format:

+--------------------+------------------------------+
| 16-byte header     | Content section              |
+--------------------+------------------------------+

The header consists of:

Offset Size Field Example Description
0 2 type A4 03 Message type (Java short -235490xA403)
2 2 subtype 00 00 Usually 0
4 4 msg_size 00 00 00 0C 32-bit content length
8 1 ack_flg 01 Ack flag
9 7 unuse 00..00 Always zero padding

Content section begins at offset 16

Content structure

The content section got the following structure:

|-- FRAME_HEAD (2B) --| ACK (1B) |-- MMNN (2B) --|----------- PAYLOAD (N B) -----------| CHECKSUM (1B) |
|                     |          |               |                                    |               |
| example: FF A5      | example:01 | example:00 07 | example: 04 02 00 04 00 00        | example: B6   |

LED Command Payload

|CMD|SUB|WHICH|MODE|RATE|RAND|
|04 |02 | ..  | .. | .. | .. |

Fields

Field Size Description
CMD 1 byte Command group. Always 0x04 for LED control.
SUB 1 byte LED subcommand. Always 0x02.
WHICH 1 byte Selects which LED group to control.
MODE 1 byte LED color or animation mode.
RATE 1 byte Speed or delay parameter for animations.
RAND 1 byte Randomization count used by some animation modes.

The payload is constructed as:

[0x04, 0x02, which_light, mode, rate, random_count]

WHICH (LED Target)

Value LED Group
0 All LEDs
1 Wheel LEDs
2 Left hand LEDs
3 Right hand LEDs
4 Left head LEDs
5 Right head LEDs
10 Head ring

MODE (LED Behavior)

Common values observed:

Value Behavior
1 Turn LEDs off
3 Red
4 Green
7 Blue
19–25 Various blinking / flicker animation modes

RATE

Controls animation timing.

Typical usage:

Value Meaning
0 Default speed
>0 Increasing delay / slower animation

RAND

Randomization parameter used by certain animation modes.

Value Meaning
0 Disabled
>0 Number of random iterations

Example

Turn head ring LEDs green:

04 02 00 04 00 00

Meaning:

Field Value Meaning
CMD 04 LED command
SUB 02 LED control
WHICH 00 Head ring
MODE 04 Green
RATE 00 Default speed
RAND 00 No randomness

Summary

┌───────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                                                                                           │
│ TYPE        SUBTYPE      MSG_SIZE         ACK     UNUSED PADDING                                          │
│ 2 bytes     2 bytes      4 bytes          1       7 bytes                                                  │
│ A4 03       00 00        00 00 00 0C       01      00 00 00 00 00 00 00                                      │
│                                                                                                           │
├──────────────────────────────────────────── Header (16 bytes) ───────────────────────────────────────────┤
│                                                                                                           │
│ FRAME_HEAD      ACK      MMNN (payload+1)      PAYLOAD (N bytes)                  CHECKSUM                │
│ 2 bytes         1        2 bytes               variable                           1 byte                  │
│ FF A5           01       00 07                 04 02 00 04 00 00                   B6                      │
│                                                                                                           │
├──────────────────────────────────────────── Content Section ─────────────────────────────────────────────┤
│                                                                                                           │
│                                  Total Frame = 22 + payload_len                                           │
│                                                                                                           │
└───────────────────────────────────────────────────────────────────────────────────────────────────────────┘