00001 /*!@file sc8000.C Interface to a Serial Servo Controller sc8000 00002 derived from ssc*/ 00003 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00006 // University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: Lior Elazary <elazary@usc.edu> 00035 // 00036 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Devices/sc8000.C $ 00037 // $Id: sc8000.C 6990 2006-08-11 18:13:51Z rjpeters $ 00038 // 00039 00040 #include "Devices/sc8000.H" 00041 00042 #include "Component/OptionManager.H" 00043 #include "Devices/Serial.H" 00044 00045 // ###################################################################### 00046 SC8000::SC8000(OptionManager& mgr, const std::string& descrName, 00047 const std::string& tagName, const char *defdev) : 00048 ModelComponent(mgr, descrName, tagName), 00049 itsPort(new Serial(mgr)) 00050 { 00051 // set a default config for our serial port: 00052 itsPort->configure(defdev, 9600, "8N1", false, false, 1); 00053 00054 // attach our port as a subcomponent: 00055 addSubComponent(itsPort); 00056 00057 // Initialize our internals: 00058 zero = new rutz::shared_ptr<NModelParam<float> >[SSCNUMSERVOS]; 00059 posmult = new rutz::shared_ptr<NModelParam<float> >[SSCNUMSERVOS]; 00060 negmult = new rutz::shared_ptr<NModelParam<float> >[SSCNUMSERVOS]; 00061 pos = new short[SSCNUMSERVOS]; 00062 for (uint i = 0; i < SSCNUMSERVOS; i ++) 00063 { 00064 pos[i] = 32768; char buf[20]; 00065 sprintf(buf, "Zero%d", i); 00066 zero[i] = NModelParam<float>::make(buf, this, 0.0F); 00067 00068 sprintf(buf, "PosMult%d", i); 00069 posmult[i] = NModelParam<float>::make(buf, this, 1.0F); 00070 00071 sprintf(buf, "NegMult%d", i); 00072 negmult[i] = NModelParam<float>::make(buf, this, 1.0F); 00073 } 00074 } 00075 00076 // ###################################################################### 00077 SC8000::~SC8000() 00078 { } 00079 00080 // ###################################################################### 00081 bool SC8000::move(const int servo, const float position) 00082 { return moveRaw(servo, calibToRaw(servo, position)); } 00083 00084 // ###################################################################### 00085 float SC8000::getPosition(const int servo) const 00086 { 00087 if (servo < 0 || servo >= SSCNUMSERVOS) 00088 LFATAL("Invalid servo number %d -- ABORT", servo); 00089 return rawToCalib(servo, pos[servo]); 00090 } 00091 00092 // ###################################################################### 00093 void SC8000::calibrate(const int servo, const short neutralval, const short minval, 00094 const short maxval) 00095 { 00096 if (servo < 0 || servo >= SSCNUMSERVOS) 00097 LFATAL("Invalid servo number %d -- ABORT", servo); 00098 00099 zero[servo]->setVal(float(neutralval)); 00100 negmult[servo]->setVal(1.0F / (float(neutralval) - float(minval))); 00101 posmult[servo]->setVal(1.0F / (float(maxval) - float(neutralval))); 00102 } 00103 00104 // ###################################################################### 00105 bool SC8000::moveRaw(const int servo, const short rawpos) 00106 { 00107 // Command Buffer: 00108 // [0] is start character 00109 // [1] is start character 00110 // [2] is which servo to move (servo mask) 00111 // [3] digital mask 00112 // [4] is position to move servo to (high order) 00113 // [5] is position to move servo to (low order) 00114 00115 char command[6]; 00116 command[0] = 126; 00117 command[1] = 126; 00118 command[2] = 1 << (servo-1); //set servo mask to only one servo (1 index base) 00119 command[3] = 48; //ascii for 0 (digital ports off) 00120 00121 //servo positions are 2 bytes 00122 command[4] = (unsigned char)((rawpos >> 8) & 0xFF); 00123 command[5] = (unsigned char)(rawpos); 00124 00125 00126 // write command buffer 00127 if (itsPort->write(command, 6) == 6) 00128 { 00129 // update our position: 00130 pos[servo] = rawpos; 00131 return true; 00132 } 00133 else 00134 return false; 00135 } 00136 00137 // ###################################################################### 00138 short SC8000::getPositionRaw(const int servo) const 00139 { 00140 if (servo < 0 || servo >= SSCNUMSERVOS) 00141 LFATAL("Invalid servo number %d -- ABORT", servo); 00142 00143 return pos[servo]; 00144 } 00145 00146 // ###################################################################### 00147 float SC8000::rawToCalib(const int servo, const short rawpos) const 00148 { 00149 if (servo < 0 || servo >= SSCNUMSERVOS) 00150 LFATAL("Invalid servo number %d -- ABORT", servo); 00151 00152 float position; 00153 if (rawpos >= short(zero[servo]->getVal())) 00154 position = (float(rawpos) - zero[servo]->getVal()) * 00155 posmult[servo]->getVal(); 00156 else 00157 position = (float(rawpos) - zero[servo]->getVal()) * 00158 negmult[servo]->getVal(); 00159 00160 if (position < -1.0F) position = -1.0F; 00161 else if (position > 1.0F) position = 1.0F; 00162 00163 return position; 00164 } 00165 00166 // ###################################################################### 00167 short SC8000::calibToRaw(const int servo, const float position) const 00168 { 00169 if (servo < 0 || servo >= SSCNUMSERVOS) 00170 LFATAL("Invalid servo number %d -- ABORT", servo); 00171 00172 if (position > 1.0F || position < -1.0F) 00173 LFATAL("Invalid position %f (range -1.0..1.0) -- ABORT", position); 00174 00175 int rawpos; 00176 if (position < 0.0F) 00177 rawpos = int(position / negmult[servo]->getVal() + 00178 zero[servo]->getVal() + 0.49999F); 00179 else 00180 rawpos = int(position / posmult[servo]->getVal() + 00181 zero[servo]->getVal() + 0.49999F); 00182 00183 if (rawpos < 0) rawpos = 0; else if (rawpos > 65535) rawpos = 65535; 00184 00185 return short(rawpos); 00186 } 00187 00188 // ###################################################################### 00189 /* So things look consistent in everyone's emacs... */ 00190 /* Local Variables: */ 00191 /* indent-tabs-mode: nil */ 00192 /* End: */