Problem with SMC 18v7 under Linux

Recently I’m trying to use Pololu Simple High-Power Motor Controller 18v7 to control the motor of an RC car. I can use the
Mini Maestro 12-Channel USB Servo Controller to control the steering servo using the code below:

void setPosition(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); 
} 
 
void setSpeed(int speed, 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_SERVO_VARIABLE, speed *4, servo, 0, 0, (ushort)5000); 
          libusb_close(device_handle); 
          break; 
        } 
      } 
    } 
  } 
  libusb_free_device_list(device_list, 0); 
  libusb_exit(ctx); 
}

However, I have no idea how to rewrite the libusb_control_transfer function to set the speed of the smc. I saw sentence like

controlTransfer(0x40, (byte)uscRequest.REQUEST_SET_SERVO_VARIABLE, value, servo);

in Usc.cs and the corresponding libusb command is

libusb_control_transfer(device_handle, 0x40, 
            REQUEST_SET_SERVO_VARIABLE, speed *4, servo, 0, 0, (ushort)5000);

and it works fine; I also found

controlTransfer(0x40, (Byte)SmcRequest.SetSpeed, speed, (Byte)direction);

in Smc.cs, so I wrote the following program to control the motor:

#include <unistd.h>  
#include <stdlib.h>  
#include <curses.h>  
#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 safeStart(bool active) 
{ 
  const unsigned short vendorId = 0x1ffb; 
  unsigned short productIDArray[] =  
  { 
    0x98,0xA1,0x9C,0x9E
  }; 
  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_USB_KILL, (active ? 1 : 0),0, 0, 0, (ushort)5000); 
          libusb_close(device_handle); 
          break; 
        } 
      } 
    } 
  } 
  libusb_free_device_list(device_list, 0); 
  libusb_exit(ctx); 
}  

void setSpeed(int speed, int direction) 
{ 
  const unsigned short vendorId = 0x1ffb; 
  unsigned short productIDArray[] =  
  { 
    0x98,0xA1,0x9C,0x9E
  }; 
  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_SPEED, speed *4, direction, 0, 0, (ushort)5000); 
          libusb_close(device_handle); 
          break; 
        } 
      } 
    } 
  } 
  libusb_free_device_list(device_list, 0); 
  libusb_exit(ctx); 
} 
 
 
int main() 
{ 
  int direction;
  int speed; 
  bool active;
  cout << "Activate motor: "; 
  cin >> active; 
  cout << "Set speed: "; 
  cin >> speed; 
  cout << "Set direction: "; 
  cin >> direction; 
// DIRECTION_FORWARD 0
// DIRECTION_REVERSE 1
// DIRECTION_BRAKE   2
safeStart(active);
while(1)
{
  setSpeed(speed, direction);
} 
  return 0; 
}

However, it doesn’t work (Compiled successfully ). I tried SmcCenter, it works fine, so no connection or powering problems. Can someone tell me what’s wrong with my program?

Hello, qiaosong.

You are calling lots of libusb functions that can fail. When they fail, they return error codes to indicate the reason that they failed. You should be checking the return values of these functions to help you narrow down the cause of the problem. Also, you should print an error message if no matching device is found.

You should make sure that you set the “active” variable to 0. Otherwise, you will be activating the USB kill switch.

After deactivating the USB kill switch, you should send the Exit Safe Start command. This is exactly what the resume() method in the Smc class does.

If you still can’t get your code to work, please simplify it to the simplest possible thing that should work but does not and post it here again. You should just have one function which turns off the USB kill switch, exits safe start mode, and sets the speed. You should only call libusb_get_device_list once. You should check all return codes from libusb functions. There should be no user input; I can’t tell what you typed into the program and that could easily be causing problems.

–David

Thank you very much! After adding the exits safe start command, the program works fine.