USBInterface.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2013, Osnabrueck University
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  * * Redistributions of source code must retain the above copyright notice,
00009  *   this list of conditions and the following disclaimer.
00010  * * Redistributions in binary form must reproduce the above copyright notice,
00011  *   this list of conditions and the following disclaimer in the documentation
00012  *   and/or other materials provided with the distribution.
00013  * * Neither the name of the Osnabrueck University nor the names of its
00014  *   contributors may be used to endorse or promote products derived from this
00015  *   software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00037 #include "USBInterface.h"
00038 
00039 #include <iostream>
00040 using std::cout;
00041 using std::endl;
00042 
00043 int USBPololuInterface::MOVE_TARGET_TIMEOUT = 1000;
00044 int USBPololuInterface::MOVE_TARGET_MAX_TRYS = 1000;
00045 
00046 USBPololuInterface::USBPololuInterface(uint16_t v_id, uint16_t p_id)
00047 : m_device(0), m_context(0), m_deviceHandle(0)
00048 {
00049     // Create new libusb context
00050     libusb_init(&m_context);
00051 
00052     // Open device
00053     struct libusb_device **devs;
00054     struct libusb_device_descriptor info;
00055 
00056     // Get list of devices and counts
00057     int count = libusb_get_device_list(m_context,&devs);
00058 
00059     // Walk the list, read descriptors, and dump some output from each
00060     int pololuCount = 0;
00061     for (int i = 0; i < count;i++)
00062     {
00063         libusb_get_device_descriptor(devs[i],&info);
00064 
00065         if(info.idVendor == v_id && info.idProduct == p_id)
00066         {
00067             pololuCount++;
00068             m_device = devs[i];
00069         }
00070     }
00071 
00072     // Warn if several boards are connected
00073     if(pololuCount > 1)
00074     {
00075         cout << "USBPololuInterface: Detected " << pololuCount << "boards. Using last detected one." << endl;
00076     }
00077 
00078     // Try to open device
00079     int ret = -1;
00080     if(m_device)
00081     {
00082         ret = libusb_open(m_device, &m_deviceHandle);
00083     }
00084 
00085     if(ret < 0)
00086     {
00087         cout << "USBPololuInterface: Unable to open device." << endl;
00088     }
00089 
00090 }
00091 
00092 
00093 
00094 string USBPololuInterface::getErrorDescription(int code)
00095 {
00096     switch(code)
00097     {
00098     case -1:
00099         return "I/O error.";
00100     case -2:
00101         return "Invalid parameter.";
00102     case -3:
00103         return "Access denied.";
00104     case -4:
00105         return "Device does not exist.";
00106     case -5:
00107         return "No such entity.";
00108     case -6:
00109         return "Busy.";
00110     case -7:
00111         return "Timeout.";
00112     case -8:
00113         return "Overflow.";
00114     case -9:
00115         return "Pipe error.";
00116     case -10:
00117         return "System call was interrupted.";
00118     case -11:
00119         return "Out of memory.";
00120     case -12:
00121         return "Unsupported/unimplemented operation.";
00122     case -99:
00123         return "Other error.";
00124     default:
00125         return "Unknown error code.";
00126     };
00127 }
00128 
00129 void USBPololuInterface::controlTransfer(char requestType, char request, ushort value, ushort index)
00130 {
00131     if(m_deviceHandle)
00132     {
00133         int result = libusb_control_transfer(
00134                 m_deviceHandle,
00135                 requestType,
00136                 request,
00137                 value,
00138                 index,
00139                 0, 0, 5000);
00140 
00141         if(result < 0)
00142         {
00143             cout << "USBPololuInterface::controlTransfer(): " << getErrorDescription(result) << endl;
00144         }
00145     }
00146     else
00147     {
00148         cout << "USBPololuInterface::controlTransfer(): Device not open." << endl;
00149     }
00150 }
00151 
00152 void USBPololuInterface::controlTransfer(
00153         char requestType,
00154         char request,
00155         ushort value,
00156         ushort index,
00157         unsigned char* data,
00158         ushort length)
00159 {
00160     if(m_deviceHandle)
00161     {
00162         int result = libusb_control_transfer(
00163                 m_deviceHandle,
00164                 requestType,
00165                 request,
00166                 value,
00167                 index,
00168                 data, length, 5000);
00169 
00170         if(result < 0)
00171         {
00172             cout << "USBPololuInterface::controlTransfer(): " << getErrorDescription(result) << endl;
00173         }
00174     }
00175     else
00176     {
00177         cout << "USBPololuInterface::controlTransfer(): Device not open." << endl;
00178     }
00179 }
00180 
00181 
00182 uint8_t USBPololuInterface::channelToPort(uint8_t channel)
00183 {
00184     if (channel <= 3)
00185     {
00186         return channel;
00187     }
00188     else if (channel < 6)
00189     {
00190         return uint8_t(channel + 2);
00191     }
00192     cout << "USBPololuInterface::channelToPort(): Unsupported channel: << " << channel << endl;
00193     return 0;
00194 }
00195 
00196 
00197 void USBPololuInterface::setRawParameter(ushort parameter, ushort value, int bytes)
00198 {
00199     ushort index = (ushort)((bytes << 8) + parameter); // high bytes = # of bytes
00200     controlTransfer(0x40, uscRequest::REQUEST_SET_PARAMETER, value, index);
00201 }
00202 
00203 
00204 uscParameter USBPololuInterface::specifyServo(uscParameter p, uint8_t servo)
00205 {
00206     return (uscParameter)((uint8_t)(p) + servo * servoParameterBytes);
00207 }
00208 
00209 uint8_t USBPololuInterface::normalSpeedToExponentialSpeed(ushort normalSpeed)
00210 {
00211     ushort mantissa = normalSpeed;
00212     uint8_t exponent = 0;
00213 
00214     while (true)
00215     {
00216         if (mantissa < 32)
00217         {
00218             // We have reached the correct representation.
00219             return (uint8_t)(exponent + (mantissa << 3));
00220         }
00221 
00222         if (exponent == 7)
00223         {
00224             // The number is too big to express in this format.
00225             return 0xFF;
00226         }
00227 
00228         // Try representing the number with a bigger exponent.
00229         exponent += 1;
00230         mantissa >>= 1;
00231     }
00232 }
00233 
00234 void USBPololuInterface::setUscSettings(uscSettings settings)
00235 {
00236     // Serial settings are not supported
00237     setRawParameter(uscParameter::PARAMETER_SCRIPT_DONE, (ushort)(settings.scriptDone ? 1 : 0), sizeof(ushort));
00238     setRawParameter(uscParameter::PARAMETER_SERVOS_AVAILABLE, settings.servosAvailable, sizeof(uint8_t));
00239     setRawParameter(uscParameter::PARAMETER_SERVO_PERIOD, settings.servoPeriod, sizeof(uint8_t));
00240 
00241 
00242     uint8_t ioMask = 0;
00243     uint8_t outputMask = 0;
00244 
00245     std::list<channelSetting>::iterator it;
00246 
00247     int i = 0;
00248     for(it = settings.channelSettings.begin(); it != settings.channelSettings.end(); it++)
00249     {
00250         channelSetting setting = *it;
00251 
00252 
00253         if (setting.mode == ChannelMode::Input || setting.mode == ChannelMode::Output)
00254         {
00255             ioMask |= (uint8_t)(1 << channelToPort(i));
00256         }
00257 
00258         if (setting.mode == ChannelMode::Output)
00259         {
00260             outputMask |= (uint8_t)(1 << channelToPort(i));
00261         }
00262 
00263 
00264 
00265         // Make sure that HomeMode is "Ignore" for inputs.  This is also done in
00266         // fixUscSettings.
00267         HomeMode correctedHomeMode = setting.homeMode;
00268         if (setting.mode == ChannelMode::Input)
00269         {
00270             correctedHomeMode = HomeMode::Ignore;
00271         }
00272 
00273         // Compute the raw value of the "home" parameter.
00274         ushort home;
00275         if (correctedHomeMode == HomeMode::Off) home = 0;
00276         else if (correctedHomeMode == HomeMode::Ignore) home = 1;
00277         else home = setting.home;
00278 
00279         setRawParameter(specifyServo(uscParameter::PARAMETER_SERVO0_HOME, i), home, sizeof(ushort));
00280         setRawParameter(specifyServo(uscParameter::PARAMETER_SERVO0_MIN, i), (ushort)(setting.minimum / 64), sizeof(ushort));
00281         setRawParameter(specifyServo(uscParameter::PARAMETER_SERVO0_MAX, i), (ushort)(setting.maximum / 64), sizeof(ushort));
00282         setRawParameter(specifyServo(uscParameter::PARAMETER_SERVO0_NEUTRAL, i), setting.neutral, sizeof(uint16_t));
00283         setRawParameter(specifyServo(uscParameter::PARAMETER_SERVO0_RANGE, i), (ushort)(setting.range / 127), sizeof(ushort));
00284         setRawParameter(specifyServo(uscParameter::PARAMETER_SERVO0_SPEED, i), normalSpeedToExponentialSpeed(setting.speed), sizeof(uint16_t));
00285         setRawParameter(specifyServo(uscParameter::PARAMETER_SERVO0_ACCELERATION, i), setting.acceleration, sizeof(uint8_t));
00286     }
00287 
00288     setRawParameter(uscParameter::PARAMETER_IO_MASK_C, ioMask, sizeof(uint8_t));
00289     setRawParameter(uscParameter::PARAMETER_OUTPUT_MASK_C, outputMask, sizeof(uint8_t));
00290 
00291 }
00292 
00293 
00294 
00295 
00296 
00297 void USBPololuInterface::getServoStatus(int servo, servoStatus& status)
00298 {
00299     // Alloc memory for maestro board status struct and 6 servo status structs
00300     int packet_size = sizeof(maestroStatus) + 6 * sizeof(servoStatus);
00301     unsigned char* buffer = new unsigned char[packet_size];
00302 
00303     // Request data
00304     controlTransfer(0xC0, REQUEST_GET_VARIABLES, 0, 0, buffer, packet_size);
00305 
00306     // Parse buffer data into servo status
00307     unsigned char* p = buffer;
00308     servoStatus servos[6];
00309     for(int i = 0; i < 6; i++)
00310     {
00311         servos[i] = *(servoStatus*)(p + sizeof(maestroStatus) + sizeof(servoStatus) * i);
00312     }
00313 
00314     // Set output data
00315     status.position     = servos[servo].position / 4;
00316     status.target       = servos[servo].target / 4;
00317     status.speed        = servos[servo].speed;
00318     status.acceleration = servos[servo].acceleration;
00319 }
00320 
00321 void USBPololuInterface::setTarget(int servo, ushort value)
00322 {
00323     // Target values have to be set in micro seconds. Conversion factor
00324     // from absolute values to mic. sec. is '4' (see Pololu SDK)
00325     controlTransfer(0x40, REQUEST_SET_TARGET, 4.0 * value, servo);
00326 }
00327 
00328 void USBPololuInterface::moveToTarget(int servo, ushort target)
00329 {
00330     setTarget(servo, target);
00331     servoStatus status;
00332 
00333     // Wait until servo has reached target position
00334     int i = 0;
00335     do
00336     {
00337         usleep(MOVE_TARGET_TIMEOUT);
00338         getServoStatus(servo, status);
00339         i++;
00340     }
00341     while(status.position != target && i < MOVE_TARGET_MAX_TRYS);
00342 
00343     // Check for timeout
00344     if(i == MOVE_TARGET_MAX_TRYS)
00345     {
00346         cout << "USBPololuInterface::moveToTarget(): Timeout. Target position " << target << " out of servo range?" << endl;
00347     }
00348 }
00349 
00350 void USBPololuInterface::moveToTarget(int servo, ushort target, ushort time)
00351 {
00352     servoStatus status;
00353     getServoStatus(servo, status);
00354 
00355     // Calculate steps to target and timeout
00356     int steps   = std::fabs(status.position - target);
00357     int timeout = time * 1000 / steps;
00358 
00359     // Decide if we have to increment or decrement
00360     int initialPosition = status.position;
00361     int factor = 1;
00362     if(initialPosition > target) factor *= -1;
00363 
00364     // Move to target
00365     for(int i = 0; i <= steps; i++)
00366     {
00367         setTarget(servo, initialPosition + factor * i);
00368         usleep(timeout);
00369     }
00370 
00371 }
00372 
00373 void USBPololuInterface::setSpeed(int servo, ushort value)
00374 {
00375     controlTransfer(0x40, REQUEST_SET_SERVO_VARIABLE, value, servo);
00376 }
00377 
00378 USBPololuInterface::~USBPololuInterface()
00379 {
00380     // Close device
00381     if(m_deviceHandle)
00382     {
00383         libusb_close(m_deviceHandle);
00384     }
00385 
00386     // Release context if valid
00387     if(m_context)
00388     {
00389         libusb_exit(m_context);
00390     }
00391 
00392 
00393 }


kurt3d
Author(s): Thomas Wiemann, Benjamin Kisliuk, Alexander Mock
autogenerated on Wed Sep 16 2015 10:24:29