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_ */