[libusb] linux/windows set position with unmanaged C++

Hello, blinpa.

Using libusb in Windows is probably more trouble than it is worth. I recommend downloading the Pololu USB SDK and using the Visual C++ Maestro example included with it, which is based on UsbWrapper.dll, which uses WinUSB. Instructions are in the README.txt file of the SDK.

–David

Hello, I tried your code and I get a segmentation fault error on this line:

libusb_control_transfert(device_handle, 0x40, …

What’s the problem ?

Probably the call to libusb_open on the previous line failed, leaving the device_handle in an invalid or undefined state. To debug this, he first thing I would do is add error checking to the code; almost all the libusb functions have a return value that let you see if an error happened. If it did, then your program should print the error message and exit.

–David

Yes it seems to be that, I have the segmentation fault on libusb_close if I remove the line with libusb_control_transfert.
I checked and libusb_open is returning -3.

Okay. Then the next step is to look up that error code on this page:

libusb.sourceforge.net/api-1.0/group__misc.html

Also, here is the documentation of libusb_open:

libusb.sourceforge.net/api-1.0/g … 7fa81c89d1

I think you need to download the Pololu USB SDK and follow the part of the instructions that helps you set a udev rule. That should give you permission to access the device.

–David

Yes I saw it’s a access denied error…
A bout the rule you mean copying 99-polulu-rule , I already did that also the UscCmd works to control my servo, then the problem must be somewhere else :frowning:

I just tried to run my program by launching directly my bin file from terminal with sudo and it’s working this way. Is there a way to avoid that ?

You should be able to get the permission right so you can access the device as a normal user. I am not sure why UscCmd would work while your program does not, but could you try unplugging the Maestro and plugging it back in to make sure the latest udev rules have been applied? --David

I looked at the 99-pololu-rule in the etc/… and it was empty ! Then now it works, thank you.

Hello again, is there a way to retreive the servo position ?

Yes. The Maestro has a native USB command for getting an array of structs where each struct holds data about one channel. This struct has a “position” field that holds the current width of pulses that the Maestro is sending. The command is implemented in the Pololu USB SDK in the Usc class. The method you should look at is getVariables(out ServoStatus[] servos). The exact protocol you need to use depends on whether you have a Mini Maestro or a Micro Maestro and you can see those details in the source code.

–David

I already used it in windows but in linux, using libusb I use libusb_control_transfer(device_handle, 0x40, REQUEST_SET_TARGET, position, servo, 0, 0, (ushort)5000); for “setposition” but don’t know how to do a getposition…

I find some code about getvariable to get all servos variables in one time, I will see if it works…

Hi,

I realize it’s some time since this thread was active. However, I’m posting in the hope that somebody has some C code for getposition on the Maestro in USB mode. I’ve tried to adapt some of the other source examples without success, and am now stalled until I can figure it out so any assistance would be gratefully received.

On a slightly different note, I’m going to have to learn a bit more about how USB resources work under Linux, as scanning for the Maestro on every pass and then releasing again is killing my timing! (Will get worse once I have getpostion as well!) Again, if anyone has C code for an efficient way to get the USB resource during init, and then not release it until the application exits, that would also be gratefully received…

Cheers,
Simon.

Hello, Simon.

Unfortunately, we do not have any C code using the Maestro’s native USB. However, we do have some C++ examples in the Pololu USB Software Development Kit (SDK) for the Maestro that you might find helpful. Also, you might find it helpful to look at this thread on implementing the Get Position command in C++ using the SDK.

By the way, if you are using libusb, you can store the libusb_device_handle pointer in a global variable that gets set at the start of your program. You can find more information about the device handling and enumeration of libusb here.

- Amanda

Hi Amanda, Thanks for the fast reply.

hello every body,
I would like to thank carrotSnack for his work. I tested the code and works fine.
Here the code compiled with Visual C++ 2012 on Windows 10 x64.
I used the channel 1 of the servo.

Also in order to build libusb you have to download the zip file from libusb.org/.
Then go to msvc folder and open the visual studio project called libusb.
Then go to configuration manager and change the active solution platform to x64 and Press build.
then go to output folder \libusb-1.0.9\x64\Debug\lib you will find the generated output file libusb.lib.

In another project , create a console application add carrotSnack files and then Right Click on project property
then in C/C++ then General then Additional Include libraries and add the absolute path to \libusb-1.0.9\libusb (this folder contains libusb.h)
in Linker General you go to Addtional Library directory and you add \libusb-1.0.9\x64\Debug\lib
in Linker Input you go to Addtional Dependencies and you add \libusb-1.0.9\x64\Debug\lib\libusb-1.0.lib

With this you should be compiling the project successfully.

Have a nice project :smiley: :smiley:

…but did you manage to read the current position?

Using the examples, with a REQUEST_GET_SERVO_POSITION (0x87), I always get a response of LIBUSB_ERROR_PIPE, control request was not supported by the device.

Using some of the binaries provided (Usc.dll or MaestroControlCenter) I can see that the position can be read, but not using the request above.

Sadly, it’s time to trawl for recommendations on another USB servo controller, because I simply can’t get this one to work…

Hello, Simon.

I am sorry you are having trouble getting the position of a servo in a C program using the Maestro’s native USB interface. The Pololu USB SDK does not define the constant REQUEST_GET_SERVO_POSITION that you mentioned, but it does define REQUEST_GET_SERVO_SETTINGS, which has the value 0x87. That request is only supported on the Mini Maestros. If you have a Micro Maestro 6-channel servo controller, you should use REQUEST_GET_VARIABLES (0x83) to get the positions of all the servos. I recommend referring to the files Usc.cs and Usc_protocol.cs in the Pololu USB SDK to see how these requests work. If you would like help getting your code to work, please tell me what kind of Maestro you have and post your C code here, along with a description of how it is behaving.

–David

Hi David,

Thanks for your reply - I had been following various code examples (notably libusc) which do seem to have checking for channelCnt == 6 (implying support Micro Maestro) but also use the invalid REQUEST_GET_SERVO_SETTINGS (0x87).

(Apologies for the typo in the macro name, as I’d been using my Windows PC to type on this forum, rather than the Linux box I’m developing on, and so that was an error on my part)

Using REQUEST_GET_VARIABLES (0x83) I’m now able to correctly get the positions of all six axes. For what it’s worth, the code I’m now using is below.

Thanks,
Simon.


const unsigned short	vendorId = 0x1ffb;
unsigned short		productIDArray[]={0x0089, 0x008a, 0x008b, 0x008c};
unsigned char		buffer[MICRO_MAESTRO_VARIABLE_BUFFER_LEN];
libusb_context 		*ctx=0;
libusb_device 		**device_list=0;
libusb_device 		*device;
int 			count;
int			i, Id;

microMaestroVariables	uMaestroVariables;
servoSetting		servo[NUMBER_OF_SERVO_CHANNELS];
int			retval, src_offset;


libusb_init(&ctx);
count = libusb_get_device_list(ctx, &device_list);

for(i=0;i<count;i++)
{
	device = device_list[i];
	{
		for( Id=0; Id<4; Id++ )
		{
			if(deviceMatchesVendorProduct(device, vendorId, productIDArray[Id]))
			{
				// OK, we've found a Pololu controller
				libusb_open(device, &device_handle);
				break;
			}
		}
	}
}


// the data in the returned buffer is tightly packed, 7 bytes for each channel
// but servo[].position is a short and so will be aligned on an even address by the compiler
// get variables from controller into intermediate buffer
retval = libusb_control_transfer(device_handle, 0xC0, REQUEST_GET_VARIABLES, 0, 0, &buffer[0], MICRO_MAESTRO_VARIABLE_BUFFER_LEN, 5000 );
if( retval != MICRO_MAESTRO_VARIABLE_BUFFER_LEN )
{
	perror( "Invalid response from Pololu Micro Maestro" );
	return( retval );
}

// get the servo data from the controller
for( i=0; i<NUMBER_OF_SERVO_CHANNELS; i++ )
{
	// do some motor movement, just to demonstrate
	libusb_control_transfer(device_handle, 0x40, REQUEST_SET_TARGET, (1000 + i * 100) * 4, i, 0, 0, (ushort)5000);

	src_offset = sizeof( microMaestroVariables ) + i * LENGTH_OF_SERVO_SETTINGS_BUFFER;

	// get all elements of servoSetting
	memcpy( &servo[i], &buffer[src_offset], LENGTH_OF_SERVO_SETTINGS_BUFFER );
	printf( "Servo %d, offset %3d: Position: %4d, Target: %4d\n", i, src_offset, (unsigned int )(servo[i].position / 4), (unsigned int )(servo[i].target / 4 ) );

	// don't really need to memcpy all seven bytes, as in the line above
	// get just two bytes of position if that's all that's required
	printf( "Servo %d, offset %3d: Position: %4d\n", i, src_offset, (unsigned int )((buffer[src_offset+1] << 8 | buffer[src_offset]) / 4) );
}


libusb_close(device_handle);

libusb_free_device_list(device_list, 0);
libusb_exit(ctx);

return 0;

I’ve created a modified header file based on the various code examples to meet my needs, so in my project, microMaestro.h is:

/*
 * microMaestro.h
 *
 *  Created on: 30 Mar 2016
 *      Author: SC
 */

#ifndef MICROMAESTRO_H_
#define MICROMAESTRO_H_

#define	NUMBER_OF_SERVO_CHANNELS		6
#define	MICRO_MAESTRO_VARIABLE_BUFFER_LEN	140
#define	LENGTH_OF_SERVO_SETTINGS_BUFFER		7


// copied from: pololu-usb-sdk/Maestro/protocol.h
// These are the values to put in to bRequest when making a setup packet
// for a control transfer to the Maestro.  See the comments and code in Usc.cs
// for more information about what these requests do and the format of the
// setup packet.
enum uscRequest
{
    REQUEST_GET_PARAMETER = 0x81,
    REQUEST_SET_PARAMETER = 0x82,
    REQUEST_GET_VARIABLES = 0x83,
    REQUEST_SET_SERVO_VARIABLE = 0x84, // (also clears the serial timeout timer)
    REQUEST_SET_TARGET = 0x85,   // (also clears the serial timeout timer)
    REQUEST_CLEAR_ERRORS = 0x86, // (also clears the serial timeout timer)
};

// this structure copied from: pololu-usb-sdk/Maestro/protocol.h
//
struct servoSetting
{
    unsigned short	position;
    unsigned short	target;
    unsigned short	speed;
    unsigned char	acceleration;

    // this is seven bytes long.
    // making an array of this struct will naturally add a padding byte
    // so that the next element aligns to an even address
    // sizeof( servoSetting ) also returns 8 bytes, so need to
    // #define LENGTH_OF_SERVO_SETTINGS_BUFFER 7
};

typedef struct servoSetting servoSetting;


// this structure modified from: pololu-usb-sdk/Maestro/Usc/Usc_protocol.cs
//
struct microMaestroVariables
{
	/// <summary>
	/// The number of values on the data stack (0-32).  A value of 0 means the stack is empty.
	/// </summary>
	unsigned char stackPointer;

	/// <summary>
	/// The number of return locations on the call stack (0-10).  A value of 0 means the stack is empty.
	/// </summary>
	unsigned char callStackPointer;

	/// <summary>
	/// The error register.  Each bit stands for a different error (see uscError).
	/// If the bit is one, then it means that error occurred some time since the last
	/// GET_ERRORS serial command or CLEAR_ERRORS USB command.
	/// </summary>
	unsigned short errors;

	/// <summary>
	/// The address (in bytes) of the next bytecode instruction that will be executed.
	/// </summary>
	unsigned short programCounter;

	/// <summary>Meaningless bytes to protect the program from stack underflows.</summary>
	/// <remarks>This is public to avoid mono warning CS0169.</remarks>
	short buffer[3];

	/// <summary>
	/// The data stack used by the script.  The values in locations 0 through stackPointer-1
	/// are on the stack.
	/// </summary>
	short stack[32];

	/// <summary>
	/// The call stack used by the script.  The addresses in locations 0 through
	/// callStackPointer-1 are on the call stack.  The next return will make the
	/// program counter go to callStack[callStackPointer-1].
	/// </summary>
	unsigned short callStack[10];

	/// <summary>
	/// 0 = script is running.
	/// 1 = script is done.
	/// 2 = script will be done as soon as it executes one more instruction
	///     (used to implement step-through debugging features)
	/// </summary>
	unsigned char scriptDone;

	/// <summary>Meaningless byte to protect the program from call stack overflows.</summary>
	/// <remarks>This is public to avoid mono warning CS0169.</remarks>
	unsigned char buffer2;

	// NOTE: C# does not allow fixed arrays of structs; after these variables,
	// 6 copies of servoSetting follow on the Micro Maestro.

	// 6x 7 byte structure of servo setting follows in libusb_control_transfer
};

typedef struct microMaestroVariables microMaestroVariables;


#endif /* MICROMAESTRO_H_ */
1 Like