![]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
In my last post I have described OWI-007 Robotic Arm parallel port protocol. They have a newer, more advanced model called Robotic Arm Edge: You can use USB interface module to connect it to PC. Unfortunately official software works only under Windows and do not provide API. I have been able to reverse engineer their USB protocol and write sample code which allows to control the arm from Mac and Linux. This is USB device with vendor id 0x1267 and product id 0. The device is controlled by 3 byte commands sent via USB control transfers. Command format is byte0, byte1, byte2. Each byte controls a group of arm features. All motors could be controlled independently. Most commands start action which is continued until next action is signalled. Byte '00' universally used as stop action. Bit numbering in byte:
Meaning of bits in each byte: Byte 0 First byte controls grip, shoulder and wrist. Bits are assigned as following:
Sample commands, activating single motor:
Sample commands activating 2 motors simultaneously:
Byte1 Second byte controls base. Bits are assigned as following:
Sample commands:
Byte 2 Third byte controls LED light inside the grip. Bits are assigned as following:
Sample commands:
Sample source code using libusb: #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <string.h> #include <libusb-1.0/libusb.h> #define EP_INTR (1 | LIBUSB_ENDPOINT_IN) #define ARM_VENDOR 0x1267 #define ARM_PRODUCT 0 #define CMD_DATALEN 3 libusb_device * find_arm(libusb_device **devs) { libusb_device *dev; int i = 0; while ((dev = devs[i++]) != NULL) { struct libusb_device_descriptor desc; int r = libusb_get_device_descriptor(dev, &desc); if (r < 0) { fprintf(stderr, "failed to get device descriptor"); return NULL; } if(desc.idVendor == ARM_VENDOR && desc.idProduct == ARM_PRODUCT) { return dev; } } return NULL; } int main(int ac, char **av) { if(ac!=4) { fprintf(stderr,"Usage: armedgetest CMD0 CMD1 CMD2\n"); return 1; } unsigned char cmd[3]; cmd[0]=(unsigned char)strtol(av[1],NULL,16); cmd[1]=(unsigned char)strtol(av[2],NULL,16); cmd[2]=(unsigned char)strtol(av[3],NULL,16); libusb_device **devs; libusb_device *dev; struct libusb_device_handle *devh = NULL; int r; ssize_t cnt; r = libusb_init(NULL); if (r < 0) { fprintf(stderr, "failed to initialize libusb\n"); return r; } libusb_set_debug(NULL,2); cnt = libusb_get_device_list(NULL, &devs); if (cnt < 0) return (int) cnt; dev=find_arm(devs); if(!dev) { fprintf(stderr, "Robot Arm not found\n"); return -1; } r = libusb_open(dev,&devh); if(r!=0) { fprintf(stderr, "Error opening device\n"); libusb_free_device_list(devs, 1); libusb_exit(NULL); return -1; } fprintf(stderr, "Sending %02X %02X %02X\n", (int)cmd[0], (int)cmd[1], (int)cmd[2] ); int actual_length=-1; r = libusb_control_transfer(devh, 0x40, //uint8_t bmRequestType, 6, //uint8_t bRequest, 0x100, //uint16_t wValue, 0,//uint16_t wIndex, cmd, CMD_DATALEN, 0 ); if(!(r == 0 && actual_length >= CMD_DATALEN)) { fprintf(stderr, "Write err %d. len=%d\n",r,actual_length); } libusb_close(devh); libusb_free_device_list(devs, 1); libusb_exit(NULL); fprintf(stderr, "Done\n"); return 0; } Sample usage: ./armedgetest 00 00 01 sleep 3 ./armedgetest 00 00 00 will turn the light on for 3 seconds and then would turn it off. It have been tested on MacOS X, but should work on Linux as well. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Previous Entry · Leave a comment · Share · Next Entry |