10. Command #1 & 2-led Blinky!
We will write the Python code that sends command #1 to observe what will happen. From our logs, we know that the sending command is from host-to-device. We should setBrequesttypeThe value is 0x40 (verify this value, you can viewBmrequesttypeBits of the command packets ),WindexAndWlengthOf zero
For command #1, setBrequestTo 0x06 andWvalueTo0x4. The last parameter is an empty array [], indicating no data transmission.
Ret = Dev. ctrl_transfer (0x40, 0x6, 0x4, 0, [])
We run the Python code and the result... Nothing happened!
Maybe this is just an initialization command. Lets replace it with the next command #2, setBrequestTo 0x06 andWvalueTo0x1
Ret = Dev. ctrl_transfer (0x40, 0x6, 0x1, 0, [])
import usb.core
import usb.util
import sys
# find our device
dev = usb.core.find(idVendor=0x045e, idProduct=0x02B0)
# was it found?
if dev is None:
raise ValueError('Device not found')
# set the active configuration. With no arguments, the first
# configuration will be the active one
dev.set_configuration()
ret = dev.ctrl_transfer(0x40, 0x6, 0x1, 0, [])
print ret
When we run this command, the motor still does not rotate, but the LED light stops flashing.
For the sake of fun, we run the previous command again and the LED light starts to flash again.
Now we have an idea: MaybeBrequest 0x6Used to control LED lights.
On your own, continue this line of thought by trying differentWvalueS from 0 on up to see what otherWvaluesDo, keep track of them all in a notebook or project file.
11. Command #3 & 4-Let's move!
In the previous section, we have conquered a command. Now we will conquer another command. Try to replicate command #3, SetBrequestTo0x31AndWvalueTo0xffd0(Also known as-48 for a 2-byte word)
Ret = Dev. ctrl_transfer (0x40, 0x31, 0xffd0, 0, [])
Run the Python script, the motor move its 'head' down.
Now try command #4,WvalueTo0xfff0(Also known as-16 for a 2-byte word)
Ret = Dev. ctrl_transfer (0x40, 0x31, 0xfff0, 0, [])
This makes the head move up.
Now, both the motor and led are under our control. Here is a video we shot a few minutes after getting the motor working, using a Python script to move it up and down)
12. Bonus accelerometer! (Bonus Sprint)
Let's go back and review this mysterious READ command.0x31This command is a bit vague. It is also in the log, be sure to set your filter to show bothHost-to-DeviceAndDevice-to-hostSince its a 'read' not a 'write'
We were pretty close with our commands, it seems that we should only read 10 bytes. It also looks like the data doesn't really change much wait t for a bit further down...
After we sent the commandBrequest 0x31(Motor movement), the seventh byte is changed many times. That implies that this data read is somehow affected by the motor, maybe the Motor Feedback byte?
Checking out a tear-down of the device (from ifixit) we see that there is an 'inclinometer '/accelerometer (kionix kxsd9 ). the Datasheet indicates it is used for image stabilization, and it has 3 axes (x y and Z) with 10 bits of data per axis.
Let's continue reading data.
import usb.core
import usb.util
import sys
import time
# find our device
dev = usb.core.find(idVendor=0x045e, idProduct=0x02B0)
# was it found?
if dev is None:
raise ValueError('Device not found')
dev.set_configuration()
while True:
# Get data from brequest 0x31
ret = dev.ctrl_transfer(0xC0, 0x31, 0x0, 0x0, 10)
print map(hex, ret)
As you shake the scripts running at the same time, you will clearly see that the changes in this data are related to motion.
To identify the accelerometer axes, rotate it only one way at a time and note what changes. you can also see how this data is in bytes but the accelerometer data shocould be a signed word because there are flips from 0xfff7 to 0x0007 which wowould indicate a negative to positive conversion.
We can cast two bytes to a signed value by 'hand' (in C this is a little easier, we know)
import usb.core
import usb.util
import sys
import time
# find our device
dev = usb.core.find(idVendor=0x045e, idProduct=0x02B0)
# was it found?
if dev is None:
raise ValueError('Device not found')
dev.set_configuration()
while True:
# Get data from brequest 0x31
ret = dev.ctrl_transfer(0xC0, 0x31, 0x0, 0x0, 10)
#print map(hex, ret)
x = (ret[2] << 8) | ret[3]
x = (x + 2 ** 15) % 2**16 - 2**15 # convert to signed 16b
y = (ret[4] << 8) | ret[5]
y = (y + 2 ** 15) % 2**16 - 2**15 # convert to signed 16b
z = (ret[6] << 8) | ret[7]
z = (z + 2 ** 15) % 2**16 - 2**15 # convert to signed 16b
print x, "\t", y, "\t", z
Now, when we run the script, we can see that the signed data is normal.
13. More Kinect!
We hope you enjoyed this reverse-engineering tutorial. For more information about open Kinect, please visit the GitHub repository and Google Group