[libusb] linux get position with unmanaged C++

Hi,

I am trying to use a micro maestro as an analog to digital converter. The following code works well if you try to set the target for a specific channel, e.g. to control a servo:

    #include <iostream>
    #include <libusb.h>
    #include "protocol.h"

    using namespace std;

    bool deviceMatchesVendorProduct(libusb_device *device, unsigned short idVendor, unsigned short idProduct)
    {
        libusb_device_descriptor desc;
        libusb_get_device_descriptor(device, &desc);
        return idVendor == desc.idVendor && idProduct == desc.idProduct;
    }

    void setTarget(int position, int servo)
    {
        const unsigned short vendorId = 0x1ffb;
        unsigned short productIDArray[]={0x0089, 0x008a, 0x008b, 0x008c};
        libusb_context *ctx=0;
        libusb_device **device_list=0;
        libusb_init(&ctx);
        int count=libusb_get_device_list(ctx, &device_list);
        for(int i=0;i<count;i++)
        {
            libusb_device *device=device_list[i];
            {
                for(int Id=0;Id<4;Id++)
                {
                    if(deviceMatchesVendorProduct(device, vendorId, productIDArray[Id]))
                    {
                        libusb_device_handle *device_handle;
                        libusb_open(device, &device_handle);
                        libusb_control_transfer(device_handle, 0x40, REQUEST_SET_TARGET, position*4, servo, 0, 0, (ushort)5000);
                        libusb_close(device_handle);
                        break;
                    }
                }
            }
        }
        libusb_free_device_list(device_list, 0);
        libusb_exit(ctx);
    }

    int main()
    {
        while(1)
        {
            int position;
            int servo=0;
            cout << "Enter position: ";
            cin >> position;
            setTarget(position, servo);
        }
        return 0;
    }

But as mentioned above I would like to read the current position of an output channel (Value between 0.00 to 255.00). Does anyone know how to get it work?
Many thanks in advance.

Kind regards,
Andreas

Hello, Andreas. First of all, you will need to use the Maestro Control Center (or UscCmd) to configure a Maestro channel as an input. This only needs to be done once.

The hard part is implementing the control transfer. You will need to look at the Usc class in UscCmd and implement your own version of the getVariables method. This will give you an array of ServoStatus structs; the element that corresponds to your channel will have the voltage reading stored in it, in the “position” field. All the structs involved are defined in Usc_protocol.cs in the Pololu USB SDK. You will probably need to read the documentation of libusb 1.0 too.

If you were using the Maestro’s virtual COM port, this would be a little more straightforward because you could just use the Get Position serial command. However, using the native USB interface is a fine choice and you should be able to get it working.

–David

Hi David,

Thank you for your answer.

But can it be that the struct defined in Protocol.h (uscVariables) is only vor the mini maestro devices? Here is the code from the Protocol.h file:

truct servoSetting
{
    int position;
    int target;
    unsigned int speed;
    unsigned int acceleration;
};

/* uscVariables: This struct stores all the variables that can be read via
   REQUEST_GET_VARIABLES.

   There are 12 bytes used per servo setting
 */
struct uscVariables
{
    // Fix bytecode_asm.asm if you change the order or size of
    // variables in this struct.

    // offset: 0
    unsigned int stackPointer;

    // offset: 1
    unsigned int callStackPointer;

    // offset: 2
     unsigned int errors;

    // offset: 4
     unsigned int programCounter;

    // offset: 6
    int buffer[3]; // protects other RAM from being corrupted by improper instructions

    // offset: 12
    int stack[32];

    // offset: 76
    unsigned int callStack[10];

    // offset: 96
    unsigned int scriptDone; // 1 = done; 2 = about to run a single step then be done - placed here to protect against accidental overwriting of Setting

    // offset: 97
    unsigned int buffer2; // protects other RAM from being corrupted by improper instructions

    // offset: 98
    struct servoSetting servoSetting[6];
}; // total length 139 bytes

I have tried the following code to read the device variables from a micro maestro:

	libusb_device_handle *device_handle;
	libusb_open(this->smallDevice, &device_handle);
	unsigned char* data = new unsigned char[sizeof(uscVariables)];
	int length = libusb_control_transfer(device_handle, 0xC0, REQUEST_GET_VARIABLES, 0, 0, data, sizeof(uscVariables),
			(ushort) 5000);
	printf("Length: %d\n", length);
	uscVariables variables = *(uscVariables*) data;
	for (int i = 0; i < sizeof(uscVariables); i++) {
		printf("%d-", *(data + i));
	}
	printf("\n");
	for (int i = 0; i < 6; i++) {
		printf("%d-", variables.servoSetting[i].target);
	}
	printf("\n");
	libusb_close(device_handle);

But the results can’t be:

Length: 140
0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-1-0-171-3-171-3-0-0-0-226-2-226-2-0-0-0-182-1-182-1-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-44-115-110-100-95-112-99-109-44-115-110-100-95-98-99-109-50-56-51-53-10-115-110-100-95-112-97-103-101-95-97-108-108-111-99-32-32-32-32-32-32-32-32-32-32-52-57-53-1-8-2-0-32-115-110-100-95-112-99-109-10-97-114-99-52-32-32-32-32-32-32-32-32-32-32-32-32-32-32-32-32-32-32-32-32-49-49-56-55-32-32-50-32-10-114-116-108-56-49-56-55-32-32-32-32-32-32-32-32-32-32-32-32-32-32-32-32-52-57-57-57-51-32-32-48-32-10-109-97-99-56-48-50-49-49-32-32-32-32-32-32-32-32-32-32-32-32-32-32-50-51-54-49-55-56-32-32-49-32-114-
538976288-942747936-538976311-960050208-540094770-909324832-

Length: 140
0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-1-0-171-3-171-3-0-0-0-229-2-229-2-0-0-0-183-1-183-1-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-110-105-120-32-32-50-32-32-32-32-32-32-91-32-65-67-67-32-93-32-32-32-32-32-83-69-81-80-65-67-75-69-84-32-32-76-73-83-84-69-78-73-78-71-32-32-32-32-32-52-52-52-32-32-32-32-32-32-49-51-55-47-117-100-101-118-100-32-32-32-32-32-32-32-32-32-32-32-47-114-117-110-47-117-100-101-118-47-99-111-110-116-114-111-108-10-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-
1685401399-1915691040-174878578-0-0-0-

Length: 140
0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-1-0-170-3-170-3-0-0-0-225-2-225-2-0-0-0-184-1-184-1-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-
0-0-0-0-0-0-

Length: 140
0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-1-0-172-3-172-3-0-0-0-229-2-229-2-0-0-0-183-1-183-1-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-
0-0-0-0-0-0-

Length: 140
0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-1-0-171-3-171-3-0-0-0-229-2-229-2-0-0-0-182-1-182-1-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-
0-0-0-0-0-0-

Is there a Protocol.h file including a struct for the micro maestro device? Because the Usc_Protocol.cs file brings definitions for the mini and micro device.

Regards
Andreas

Hello, Andreas. The first block of code you posted is not from the Maestro’s protocol.h file in the Pololu USB SDK. It is similar, but it looks like you have changed all the types from things like “u8” and “s16” to standard C types. You made several errors during that conversion, so I recommend that you double-check all the types in those two structs. In case you didn’t know, “u” stands for unsigned, “s” stands for signed, and the number after it is the number of bits. It would probably be best if you changed “u8” to “uint8_t” and “s16” to “int16_t”, etc. If I recall correctly, the protocol.h file we distribute only applies to the Micro Maestro.

–David

Solved the problem. The data types in the Protocol.h file are not correct in regard of their size in bytes. I have attached my solution. The datatypes from the Usc_settings.cs work pretty well.

	libusb_device_handle *device_handle;
	libusb_open(this->smallDevice, &device_handle);
	unsigned char* data = new unsigned char[sizeof(microMaestroVariables)];
	int length = libusb_control_transfer(device_handle, 0xC0, REQUEST_GET_VARIABLES, 0, 0, data, sizeof(microMaestroVariables),
			(ushort) 5000);
	printf("Length: %d\n", length);
	microMaestroVariables variables = *(microMaestroVariables*) data;
	for (unsigned int i = 0; i < sizeof(microMaestroVariables); i++) {
		printf("%d-", *(data + i));
	}
	printf("\n");
	for (int i = 0; i < 6; i++) {
		printf("%d-", variables.servoStatus[i].target);
	}
	printf("\n");
	libusb_close(device_handle);

definitions.h (1.54 KB)

Regards
Andreas

[quote=“DavidEGrayson”]Hello, Andreas. The first block of code you posted is not from the Maestro’s protocol.h file in the Pololu USB SDK. It is similar, but it looks like you have changed all the types from things like “u8” and “s16” to standard C types. You made several errors during that conversion, so I recommend that you double-check all the types in those two structs. In case you didn’t know, “u” stands for unsigned, “s” stands for signed, and the number after it is the number of bits. It would probably be best if you changed “u8” to “uint8_t” and “s16” to “int16_t”, etc. If I recall correctly, the protocol.h file we distribute only applies to the Micro Maestro.

–David[/quote]
Hi David,

yes, my file is broken. I dont know where its from. But finally I got it fixed. Thanks for your kind support.

Andreas