Skip to content
Snippets Groups Projects
Commit ea843761 authored by Guillem Alenyà's avatar Guillem Alenyà
Browse files

trunk/tags/branches creation

parents
No related branches found
No related tags found
No related merge requests found
Showing with 2228 additions and 0 deletions
# Pre-requisites about cmake itself
CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
if(COMMAND cmake_policy)
cmake_policy(SET CMP0005 NEW)
cmake_policy(SET CMP0003 NEW)
endif(COMMAND cmake_policy)
# The project name and the type of project
PROJECT(comm)
SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib)
SET(CMAKE_INSTALL_PREFIX /usr/local)
IF (NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "DEBUG")
ENDIF (NOT CMAKE_BUILD_TYPE)
SET(CMAKE_C_FLAGS_DEBUG "-g -Wall")
SET(CMAKE_C_FLAGS_RELEASE "-O3")
ADD_SUBDIRECTORY(src)
FIND_PACKAGE(Doxygen)
FIND_PATH(IRI_DOC_DIR doxygen.conf ${CMAKE_SOURCE_DIR}/doc/iri_doc/)
IF (IRI_DOC_DIR)
ADD_CUSTOM_TARGET (doc ${DOXYGEN_EXECUTABLE} ${CMAKE_SOURCE_DIR}/doc/iri_doc/doxygen.conf)
ELSE (IRI_DOC_DIR)
ADD_CUSTOM_TARGET (doc ${DOXYGEN_EXECUTABLE} ${CMAKE_SOURCE_DIR}/doc/doxygen.conf)
ENDIF (IRI_DOC_DIR)
ADD_CUSTOM_TARGET (distclean @echo cleaning cmake files)
IF (UNIX)
ADD_CUSTOM_COMMAND(
COMMENT "distribution clean"
COMMAND make ARGS clean
COMMAND rm ARGS -rf ${CMAKE_SOURCE_DIR}/build/*
TARGET distclean
)
ELSE(UNIX)
ADD_CUSTOM_COMMAND(
COMMENT "distclean only implemented in unix"
TARGET distclean
)
ENDIF(UNIX)
ADD_CUSTOM_TARGET (uninstall @echo uninstall package)
IF (UNIX)
ADD_CUSTOM_COMMAND(
COMMENT "uninstall package"
COMMAND xargs ARGS rm < install_manifest.txt
TARGET uninstall
)
ELSE(UNIX)
ADD_CUSTOM_COMMAND(
COMMENT "uninstall only implemented in unix"
TARGET uninstall
)
ENDIF(UNIX)
IF (UNIX)
SET(CPACK_PACKAGE_FILE_NAME "iri-${PROJECT_NAME}-dev-${CPACK_PACKAGE_VERSION}${DISTRIB}${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
SET(CPACK_PACKAGE_NAME "iri-${PROJECT_NAME}-dev")
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Part of IRI-laboratory libraries. More information at http://wikiri.upc.es/index.php/Robotics_Lab")
SET(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
SET(CPACK_GENERATOR "DEB")
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "labrobotica@iri.upc.edu")
SET(CPACK_SET_DESTDIR "ON") # Necessary because of the absolute install paths
INCLUDE(CPack)
ELSE(UNIX)
ADD_CUSTOM_COMMAND(
COMMENT "packaging only implemented in unix"
TARGET uninstall
)
ENDIF(UNIX)
#edit the following line to add the librarie's header files
FIND_PATH(dynamixel_INCLUDE_DIR dynamixel.h dynamixelserver.h dynamixelexceptions.h /usr/include/iridrivers /usr/local/include/iridrivers)
FIND_LIBRARY(dynamixel_LIBRARY
NAMES dynamixel
PATHS /usr/lib /usr/local/lib /usr/local/lib/iridrivers)
IF (dynamixel_INCLUDE_DIR AND dynamixel_LIBRARY)
SET(dynamixel_FOUND TRUE)
ENDIF (dynamixel_INCLUDE_DIR AND dynamixel_LIBRARY)
IF (dynamixel_FOUND)
IF (NOT dynamixel_FIND_QUIETLY)
MESSAGE(STATUS "Found dynamixel: ${dynamixel_LIBRARY}")
ENDIF (NOT dynamixel_FIND_QUIETLY)
ELSE (dynamixel_FOUND)
IF (dynamixel_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find dynamixel")
ENDIF (dynamixel_FIND_REQUIRED)
ENDIF (dynamixel_FOUND)
Copyright (C) 2009-2010 Institut de Robòtica i Informàtica Industrial, CSIC-UPC.
Author shernand (shernand@iri.upc.edu)
All rights reserved.
This file is part of Generic dynamixel driver library
Generic dynamixel driver library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
# Doxyfile 1.5.5
@INCLUDE_PATH = ../doc/
@INCLUDE = doxygen_project_name.conf
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NUMBER =
OUTPUT_DIRECTORY = ../doc
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = NO
ABBREVIATE_BRIEF =
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 8
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
TYPEDEF_HIDES_STRUCT = NO
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = NO
SORT_BRIEF_DOCS = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = YES
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = YES
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = ../src \
../doc/main.dox
INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.c \
*.h \
*.cpp
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS = *.tab.c \
*.tab.h \
lex* \
*glr.h \
*llr.h \
*glr.c \
*llr.c \
*general.h
EXCLUDE_SYMBOLS =
EXAMPLE_PATH = ../src/examples
EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
IMAGE_PATH = ../doc/images
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
REFERENCES_LINK_SOURCE = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
HTML_DYNAMIC_SECTIONS = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = YES
USE_PDFLATEX = NO
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = _USE_MPI=1
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
MSCGEN_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = NO
INCLUDED_BY_GRAPH = NO
CALL_GRAPH = YES
CALLER_GRAPH = YES
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = NO
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 2
DOT_TRANSPARENT = YES
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO
PROJECT_NAME = "Generic dynamixel driver"
File added
doc/images/dyn_server_states.png

36 KiB

/*! \mainpage Generic dynamixel driver
\section Introduction
This library provide a server to handle all the devices connected to a Dynamixel Bus and also low level read and write functions to access each one of this devices.
The server allows to:
- Scan the bus for devices: it checks all the possible addresses (from 0 to 254) for all the possible frequencies. Once a device responds in a given frequency, all other frequencies are discarded.
- Change the ID of a given device on the bus. By default all devices came with the same address (0) and it is necessary to change it in order to have multiple devices on the same bus.
- Change the bus baudrate. Some device have a slow baudrate by default and to achive the peak performance it is necessary to change it.
For each device, the following operations are provided:
- Read and write to any 8 or 16 bit register. Allow access to all the device registers.
- Synchronized write operations. Allow loading a given value to a given register to all the devices at the same time. The value is sent to the device using a REG_WRITE operation, but it does not take effect until the ACTION command is sent.
- Broadcast a command to several devices.
There exists a Graphical User Interface (GUI) application which allows easy access to all the features provided by this library. This application can be downloaded from <A href="http://wikiri.upc.es/index.php/Dynamixel_Manager">here</a>
\subsection Pre-Requisites
This package requires of the following libraries and packages
- <A href="http://www.cmake.org">cmake</A>, a cross-platform build system.
- <A href="http://www.doxygen.org">doxygen</a> and
<A href="http://www.graphviz.org">graphviz</a> to generate the documentation.
- stdc++,
- <A href="http://wikiri.upc.es/index.php/Utilities_library">utilities library</a>, a set of basic tools to develop software.
- <A href="http://wikiri.upc.es/index.php/Communications_library">communications library</a>, a set of comunication drivers used to access the dynamixel bus.
.
All the IRI-related dependencies can be automatically installed by calling
- sudo make dep
.
from the <em>build</em> folder and after calling the <em>cmake ..</em> command.
Under MacOS most of the packages are available via <a href="http://www.finkproject.org/">fink</a>. <br>
\subsection Compilation
Just download this package, uncompress it, and execute
- cd build
- cmake ..
.
to generate the makefile and then
- make
.
to obtain the shared library (in this case called <em>iriutils.so</em>) and
also all the example programs.
The <em>cmake</em> only need to be executed once (make will automatically call
<em>cmake</em> if you modify one of the <em>CMakeList.txt</em> files).
To generate this documentation type
- make doc
.
The files in the <em>build</em> directory are genetated by <em>cmake</em>
and <em>make</em> and can be safely removed.
After doing so you will need to call cmake manually again.
\subsection Configuration
The default build mode is DEBUG. That is, objects and executables
include debug information.
The RELEASE build mode optimizes for speed. To build in this mode
execute
- cmake .. -DCMAKE_BUILD_TYPE=RELEASE
.
The release mode will be kept until next time cmake is executed.
\subsection Installation
In order to be able to use the library, it it necessary to copy it into the system.
To do that, execute
- make install
.
as root and the shared libraries will be copied to <em>/usr/local/lib/iriutils</em> directory
and the header files will be copied to <em>/usr/local/include/iriutils</em> dierctory. At
this point, the library may be used by any user.
To remove the library from the system, exceute
- make uninstall
.
as root, and all the associated files will be removed from the system.
\section Customization
To build a new application using these library, first it is necessary to locate if the library
has been installed or not using the following command
- FIND_PACKAGE(dynamixel)
In the case that the package is present, it is necessary to add the header files directory to
the include directory path by using
- INCLUDE_DIRECTORIES(${dynamixel_INCLUDE_DIR})
Finally, it is also nevessary to link with the desired libraries by using the following command
- TARGET_LINK_LIBRARIES(<executable name> ${dynamixel_LIBRARY})
.
All these steps are automatically done when the new project is created following the instructions
in <A href="http://wikiri.upc.es/index.php/Create_a_new_development_project">here</a>
\section License
This package is licensed under a
<a href="http://www.gnu.org/licenses/lgpl.html">
LGPL 3.0 License</a>.
\section Disclaimer
This is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
# edit the following line to add all the source code files of the library
SET(sources dynamixel.cpp dynamixelserver.cpp dynamixelexceptions.cpp)
# edit the following line to add all the header files of the library
SET(headers dynamixel.h dynamixelserver.h dynamixelexceptions.h)
INCLUDE_DIRECTORIES(.)
# edit the following line to find the necessary packages
FIND_PACKAGE(iriutils REQUIRED)
FIND_PACKAGE(comm REQUIRED)
# edit the following line to add the necessary include directories
INCLUDE_DIRECTORIES(${iriutils_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${comm_INCLUDE_DIR})
ADD_LIBRARY(dynamixel SHARED ${sources})
#edit the following line to add the necessary system libraries (if any)
TARGET_LINK_LIBRARIES(dynamixel ${iriutils_LIBRARY})
TARGET_LINK_LIBRARIES(dynamixel ${comm_LIBRARY})
INSTALL(TARGETS dynamixel
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib/iridrivers
ARCHIVE DESTINATION lib/iridrivers
)
INSTALL(FILES ${headers} DESTINATION include/iridrivers)
INSTALL(FILES ../Finddynamixel.cmake DESTINATION ${CMAKE_ROOT}/Modules/)
ADD_SUBDIRECTORY(examples)
#include "eventexceptions.h"
#include "dynamixelexceptions.h"
#include "dynamixel.h"
#include "ftdiserver.h"
#include <iostream>
#include <sstream>
CDynamixel::CDynamixel(std::string& cont_id)
{
this->event_server=CEventServer::instance();
this->usb_dev=NULL;
this->usb_access=NULL;
this->usb_rx_event_id="";
this->node_address=-1;
this->id_register=0x03;
this->baudrate_register=0x04;
}
unsigned char CDynamixel::compute_checksum(unsigned char *packet,int len)
{
int i=0;
short int checksum=0;
if(packet==NULL)
{
/* handle exceptions */
throw CDynamixelException(_HERE_,"Invalid packet structure",this->node_address);
}
else
{
if(len<=0)
{
/* handle exceptions */
throw CDynamixelException(_HERE_,"Invalid packet length",this->node_address);
}
else
{
for(i=2;i<len;i++)
checksum+=packet[i];
checksum=~checksum;
checksum=checksum%256;
}
}
return checksum;
}
void CDynamixel::set_baudrate(int baudrate)
{
if(this->usb_dev!=NULL)
{
baudrate=((2000000/baudrate)-1);
this->write_byte_register(this->baudrate_register,baudrate);
}
else
{
/* handle exceptions */
}
}
void CDynamixel::set_id(unsigned char id)
{
if(this->usb_dev!=NULL)
{
this->write_byte_register(this->id_register,id);
this->node_address=id;
}
else
{
/* handle exceptions */
}
}
void CDynamixel::read_byte_register(unsigned char address,unsigned char *value)
{
unsigned char packet[8]={0xFF,0xFF,0x00,0x04,0x02,0x00,0x00,0x00};
std::list<std::string> events;
unsigned char data[7];
std::string error_msg;
int num=0,read=0;
if(this->usb_dev!=NULL)
{
this->usb_access->enter();
packet[2]=this->node_address;
packet[5]=(unsigned char)address;
packet[6]=1;
packet[7]=this->compute_checksum(packet,8);
if(this->usb_dev->write(packet,8)!=8)
{
/* handle exceptions */
this->usb_access->exit();
throw CDynamixelException(_HERE_,"Unexpected error while writing to the dynamixel device",this->node_address);
}
else
{
events.push_back(this->usb_rx_event_id);
try{
while(read<7)
{
this->event_server->wait_all(events,2000);
num=this->usb_dev->get_num_data();
if(num>(7-read))
this->usb_dev->read(&data[read],7-read);
else
this->usb_dev->read(&data[read],num);
read+=num;
}
}catch(CEventTimeoutException &e){
this->usb_access->exit();
throw;
}
if(this->compute_checksum(data,7)!=0)
{
/* handle exceptions */
this->usb_access->exit();
throw CDynamixelException(_HERE_,"Cheksum error in the received packet from dynamixel device",this->node_address);
}
else
{
*value=data[5];
if(data[4]!=0x00)
{
/* handle exceptions */
if(data[4]&0x01)
error_msg+="\nThe supply voltage is out of range";
if(data[4]&0x02)
error_msg+="\nThe goal position is out of range";
if(data[4]&0x04)
error_msg+="\nThe internal temperature is too high";
if(data[4]&0x08)
error_msg+="\nThe provided parameter is out of range";
if(data[4]&0x10)
error_msg+="\nThe packet sent to the dynamixel device had an invalid checksum";
if(data[4]&0x20)
error_msg+="\nOverload";
if(data[4]&0x40)
error_msg+="\nInvalid instruction";
this->usb_access->exit();
throw CDynamixelAlarmException(_HERE_,error_msg,this->node_address,data[4]);
}
}
}
this->usb_access->exit();
}
else
{
/* handle exceptions */
throw CDynamixelException(_HERE_,"The communication device is not ready to send data",this->node_address);
}
}
void CDynamixel::read_word_register(unsigned char address,unsigned short int *value)
{
unsigned char packet[8]={0xFF,0xFF,0x00,0x04,0x02,0x00,0x00,0x00};
std::list<std::string> events;
unsigned char data[8];
std::string error_msg;
int num=0,read=0;
if(this->usb_dev!=NULL)
{
this->usb_access->enter();
packet[2]=this->node_address;
packet[5]=(unsigned char)address;
packet[6]=2;
packet[7]=this->compute_checksum(packet,8);
if(this->usb_dev->write(packet,8)!=8)
{
/* handle exceptions */
this->usb_access->exit();
throw CDynamixelException(_HERE_,"Unexpected error while writing to the dynamixel device",this->node_address);
}
else
{
events.push_back(this->usb_rx_event_id);
try{
while(read<8)
{
this->event_server->wait_all(events,2000);
num=this->usb_dev->get_num_data();
if(num>(8-read))
this->usb_dev->read(&data[read],8-read);
else
this->usb_dev->read(&data[read],num);
read+=num;
}
}catch(CEventTimeoutException &e){
this->usb_access->exit();
throw;
}
if(this->compute_checksum(data,8)!=0)
{
/* handle exceptions */
this->usb_access->exit();
throw CDynamixelException(_HERE_,"Cheksum error in the received packet from dynamixel device",this->node_address);
}
else
{
*value=data[5]+data[6]*256;
if(data[4]!=0x00)
{
/* handle exceptions */
if(data[4]&0x01)
error_msg+="\nThe supply voltage is out of range";
if(data[4]&0x02)
error_msg+="\nThe goal position is out of range";
if(data[4]&0x04)
error_msg+="\nThe internal temperature is too high";
if(data[4]&0x08)
error_msg+="\nThe provided parameter is out of range";
if(data[4]&0x10)
error_msg+="\nThe packet sent to the dynamixel device had an invalid checksum";
if(data[4]&0x20)
error_msg+="\nOverload";
if(data[4]&0x40)
error_msg+="\nInvalid instruction";
this->usb_access->exit();
throw CDynamixelAlarmException(_HERE_,error_msg,this->node_address,data[4]);
}
}
}
this->usb_access->exit();
}
else
{
/* handle exceptions */
throw CDynamixelException(_HERE_,"The communication device is not ready to send data",this->node_address);
}
}
void CDynamixel::write_byte_register(unsigned char address, unsigned char data)
{
unsigned char packet[8]={0xFF,0xFF,0x00,0x04,0x03,0x00,0x00,0x00};
std::list<std::string> events;
unsigned char answer[6];
std::string error_msg;
int num=0,read=0;
if(this->usb_dev!=NULL)
{
this->usb_access->enter();
packet[2]=this->node_address;
packet[5]=(unsigned char)address;
packet[6]=data;
packet[7]=this->compute_checksum(packet,8);
if(this->usb_dev->write(packet,8)!=8)
{
/* handle exceptions */
this->usb_access->exit();
throw CDynamixelException(_HERE_,"Unexpected error while writing to the dynamixel device",this->node_address);
}
else
{
events.push_back(this->usb_rx_event_id);
try{
while(read<6)
{
this->event_server->wait_all(events,1000);
num=this->usb_dev->get_num_data();
if(num>(6-read))
this->usb_dev->read(&answer[read],6-read);
else
this->usb_dev->read(&answer[read],num);
read+=num;
}
}catch(CEventTimeoutException &e){
this->usb_access->exit();
throw;
}
if(this->compute_checksum(answer,6)!=0)
{
/* handle exceptions */
this->usb_access->exit();
throw CDynamixelException(_HERE_,"Cheksum error in the received packet from dynamixel device",this->node_address);
}
else
{
if(answer[4]!=0x00)
{
/* handle exceptions */
if(answer[4]&0x01)
error_msg+="\nThe supply voltage is out of range";
if(answer[4]&0x02)
error_msg+="\nThe goal position is out of range";
if(answer[4]&0x04)
error_msg+="\nThe internal temperature is too high";
if(answer[4]&0x08)
error_msg+="\nThe provided parameter is out of range";
if(answer[4]&0x10)
error_msg+="\nThe packet sent to the dynamixel device had an invalid checksum";
if(answer[4]&0x20)
error_msg+="\nOverload";
if(answer[4]&0x40)
error_msg+="\nInvalid instruction";
this->usb_access->exit();
throw CDynamixelAlarmException(_HERE_,error_msg,this->node_address,answer[4]);
}
}
}
this->usb_access->exit();
}
else
{
/* handle exceptions */
throw CDynamixelException(_HERE_,"The communication device is not ready to send data",this->node_address);
}
}
void CDynamixel::write_word_register(unsigned char address, unsigned short int data)
{
unsigned char packet[9]={0xFF,0xFF,0x00,0x05,0x03,0x00,0x00,0x00,0x00};
std::list<std::string> events;
unsigned char answer[6];
std::string error_msg;
int num=0,read=0;
if(this->usb_dev!=NULL)
{
this->usb_access->enter();
packet[2]=this->node_address;
packet[5]=(unsigned char)address;
packet[6]=((unsigned char *)&data)[0];
packet[7]=((unsigned char *)&data)[1];
packet[8]=this->compute_checksum(packet,9);
if(this->usb_dev->write(packet,9)!=9)
{
// handle exceptions
this->usb_access->exit();
throw CDynamixelException(_HERE_,"Unexpected error while writing to the dynamixel device",this->node_address);
}
else
{
events.push_back(this->usb_rx_event_id);
try{
while(read<6)
{
this->event_server->wait_all(events,1000);
num=this->usb_dev->get_num_data();
if(num>(6-read))
this->usb_dev->read(&answer[read],6-read);
else
this->usb_dev->read(&answer[read],num);
read+=num;
}
}catch(CEventTimeoutException &e){
this->usb_access->exit();
throw;
}
if(this->compute_checksum(answer,6)!=0)
{
/* handle exceptions */
this->usb_access->exit();
throw CDynamixelException(_HERE_,"Cheksum error in the received packet from dynamixel device",this->node_address);
}
else
{
if(answer[4]!=0x00)
{
/* handle exceptions */
if(answer[4]&0x01)
error_msg+="\nThe supply voltage is out of range";
if(answer[4]&0x02)
error_msg+="\nThe goal position is out of range";
if(answer[4]&0x04)
error_msg+="\nThe internal temperature is too high";
if(answer[4]&0x08)
error_msg+="\nThe provided parameter is out of range";
if(answer[4]&0x10)
error_msg+="\nThe packet sent to the dynamixel device had an invalid checksum";
if(answer[4]&0x20)
error_msg+="\nOverload";
if(answer[4]&0x40)
error_msg+="\nInvalid instruction";
this->usb_access->exit();
throw CDynamixelAlarmException(_HERE_,error_msg,this->node_address,answer[4]);
}
}
}
this->usb_access->exit();
}
else
{
/* handle exceptions */
throw CDynamixelException(_HERE_,"The communication device is not ready to send data",this->node_address);
}
}
void CDynamixel::registered_byte_write(unsigned char address, unsigned char data)
{
unsigned char packet[8]={0xFF,0xFF,0x00,0x04,0x04,0x00,0x00,0x00};
std::list<std::string> events;
unsigned char answer[6];
std::string error_msg;
int num=0,read=0;
if(this->usb_dev!=NULL)
{
this->usb_access->enter();
packet[2]=this->node_address;
packet[5]=(unsigned char)address;
packet[6]=data;
packet[7]=this->compute_checksum(packet,8);
if(this->usb_dev->write(packet,8)!=8)
{
/* handle exceptions */
this->usb_access->exit();
throw CDynamixelException(_HERE_,"Unexpected error while writing to the dynamixel device",this->node_address);
}
else
{
events.push_back(this->usb_rx_event_id);
try{
while(read<6)
{
this->event_server->wait_all(events,1000);
num=this->usb_dev->get_num_data();
if(num>(6-read))
this->usb_dev->read(&answer[read],6-read);
else
this->usb_dev->read(&answer[read],num);
read+=num;
}
}catch(CEventTimeoutException &e){
this->usb_access->exit();
throw;
}
if(this->compute_checksum(answer,6)!=0)
{
/* handle exceptions */
this->usb_access->exit();
throw CDynamixelException(_HERE_,"Cheksum error in the received packet from dynamixel device",this->node_address);
}
else
{
if(answer[4]!=0x00)
{
/* handle exceptions */
if(answer[4]&0x01)
error_msg+="\nThe supply voltage is out of range";
if(answer[4]&0x02)
error_msg+="\nThe goal position is out of range";
if(answer[4]&0x04)
error_msg+="\nThe internal temperature is too high";
if(answer[4]&0x08)
error_msg+="\nThe provided parameter is out of range";
if(answer[4]&0x10)
error_msg+="\nThe packet sent to the dynamixel device had an invalid checksum";
if(answer[4]&0x20)
error_msg+="\nOverload";
if(answer[4]&0x40)
error_msg+="\nInvalid instruction";
this->usb_access->exit();
throw CDynamixelAlarmException(_HERE_,error_msg,this->node_address,answer[4]);
}
}
}
this->usb_access->exit();
}
else
{
/* handle exceptions */
throw CDynamixelException(_HERE_,"The communication device is not ready to send data",this->node_address);
}
}
void CDynamixel::registered_word_write(unsigned char address, unsigned short int data)
{
unsigned char packet[9]={0xFF,0xFF,0x00,0x05,0x04,0x00,0x00,0x00,0x00};
std::list<std::string> events;
unsigned char answer[6];
std::string error_msg;
int num=0,read=0;
if(this->usb_dev!=NULL)
{
this->usb_access->enter();
packet[2]=this->node_address;
packet[5]=(unsigned char)address;
packet[6]=((unsigned char *)&data)[0];
packet[7]=((unsigned char *)&data)[1];
packet[8]=this->compute_checksum(packet,9);
if(this->usb_dev->write(packet,9)!=9)
{
// handle exceptions
this->usb_access->exit();
throw CDynamixelException(_HERE_,"Unexpected error while writing to the dynamixel device",this->node_address);
}
else
{
events.push_back(this->usb_rx_event_id);
try{
while(read<6)
{
this->event_server->wait_all(events,1000);
num=this->usb_dev->get_num_data();
if(num>(6-read))
this->usb_dev->read(&answer[read],6-read);
else
this->usb_dev->read(&answer[read],num);
read+=num;
}
}catch(CEventTimeoutException &e){
this->usb_access->exit();
throw;
}
if(this->compute_checksum(answer,6)!=0)
{
/* handle exceptions */
this->usb_access->exit();
throw CDynamixelException(_HERE_,"Cheksum error in the received packet from dynamixel device",this->node_address);
}
else
{
if(answer[4]!=0x00)
{
/* handle exceptions */
if(answer[4]&0x01)
error_msg+="\nThe supply voltage is out of range";
if(answer[4]&0x02)
error_msg+="\nThe goal position is out of range";
if(answer[4]&0x04)
error_msg+="\nThe internal temperature is too high";
if(answer[4]&0x08)
error_msg+="\nThe provided parameter is out of range";
if(answer[4]&0x10)
error_msg+="\nThe packet sent to the dynamixel device had an invalid checksum";
if(answer[4]&0x20)
error_msg+="\nOverload";
if(answer[4]&0x40)
error_msg+="\nInvalid instruction";
this->usb_access->exit();
throw CDynamixelAlarmException(_HERE_,error_msg,this->node_address,answer[4]);
}
}
}
this->usb_access->exit();
}
else
{
/* handle exceptions */
throw CDynamixelException(_HERE_,"The communication device is not ready to send data",this->node_address);
}
}
void CDynamixel::reset(void)
{
unsigned char packet[6]={0xFF,0xFF,0x00,0x02,0x06,0x00};
std::list<std::string> events;
unsigned char data[6];
int num=0,read=0;
if(this->usb_dev!=NULL)
{
this->usb_access->enter();
packet[2]=this->node_address;
packet[5]=this->compute_checksum(packet,6);
events.push_back(this->usb_rx_event_id);
if(this->usb_dev->write(packet,6)!=6)
{
// handle exceptions
this->usb_access->exit();
throw CDynamixelException(_HERE_,"Unexpected error while writing to the dynamixel device",this->node_address);
}
else
{
try{
while(read<6)
{
this->event_server->wait_all(events,1000);
num=this->usb_dev->get_num_data();
if(num>(6-read))
this->usb_dev->read(&data[read],6-read);
else
this->usb_dev->read(&data[read],num);
read+=num;
}
}catch(CEventTimeoutException &e){
this->usb_access->exit();
throw;
}
}
this->usb_access->exit();
}
else
{
/* handle exceptions */
throw CDynamixelException(_HERE_,"The communication device is not ready to send data",this->node_address);
}
}
unsigned char CDynamixel::get_id(void)
{
return this->node_address;
}
void CDynamixel::set_id_register(unsigned char reg)
{
this->id_register=reg;
}
void CDynamixel::set_baudrate_register(unsigned char reg)
{
this->baudrate_register=reg;
}
CDynamixel::~CDynamixel()
{
this->usb_dev=NULL;
this->usb_access=NULL;
this->usb_rx_event_id="";
this->node_address=-1;
}
#ifndef _DYNAMIXEL_H
#define _DYNAMIXEL_H
#include "dynamixelserver.h"
#include "eventserver.h"
#include "ftdimodule.h"
#include "mutex.h"
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
/**
* \brief
*
*/
class CDynamixel
{
private:
friend class CDynamixelServer;
/**
* \brief Handle to the communications device
*
*/
CFTDI *usb_dev;
/**
* \brief
*
*/
unsigned char node_address;
/**
* \brief mutual exclusion mechanism to access the usb
*
*/
CMutex *usb_access;
/**
* \brief Handle to the unique event server
*
*/
CEventServer *event_server;
/**
* \brief data reception event
*
*/
std::string usb_rx_event_id;
/**
* \brief
*
*/
unsigned char id_register;
/**
* \brief
*
*/
unsigned char baudrate_register;
/**
* \brief Function to compute the checksum of the data packets
*
*/
unsigned char compute_checksum(unsigned char *packet,int len);
/**
* \brief
*
*/
void set_baudrate(int baudrate);
/**
* \brief
*
*/
void set_id(unsigned char id);
public:
/**
* \brief
*
*/
CDynamixel(std::string& cont_id);
/**
* \brief Function to read a register
*
*/
void read_byte_register(unsigned char address, unsigned char *value);
/**
* \brief Function to read a register
*
*/
void read_word_register(unsigned char address,unsigned short int *value);
/**
* \brief Function to write to a register
*
*/
void write_byte_register(unsigned char address, unsigned char data);
/**
* \brief Function to write to a register
*
*/
void write_word_register(unsigned char address, unsigned short int data);
/**
* \brief Function to write to a register
*
*/
void registered_byte_write(unsigned char address, unsigned char data);
/**
* \brief Function to write to a register
*
*/
void registered_word_write(unsigned char address, unsigned short int data);
/**
* \brief
*
*/
void reset(void);
/**
* \brief
*
*/
unsigned char get_id(void);
/**
* \brief
*
*/
void set_id_register(unsigned char reg);
/**
* \brief
*
*/
void set_baudrate_register(unsigned char reg);
/**
* \brief
*
*/
virtual ~CDynamixel();
};
#endif
#include "dynamixelexceptions.h"
#include <sstream>
#include <string.h>
#include <stdio.h>
const std::string dynamixel_error_message="Dynamixel error - ";
const std::string dynamixel_server_error_message="Dynamixel server error - ";
CDynamixelException::CDynamixelException(const std::string& where,const std::string &error_msg,int dev_id):CException(where,dynamixel_error_message)
{
std::stringstream text;
this->error_msg+=error_msg;
this->error_msg+=" - device id: ";
text << dev_id;
this->error_msg+=text.str();
}
CDynamixelAlarmException::CDynamixelAlarmException(const std::string& where,const std::string &error_msg,int dev_id,unsigned char alarm):CException(where,dynamixel_error_message)
{
std::stringstream text;
this->error_msg+=error_msg;
this->error_msg+=" - device id: ";
text << dev_id;
this->error_msg+=text.str();
this->alarm=alarm;
}
unsigned char CDynamixelAlarmException::get_alarm(void)
{
return this->alarm;
}
CDynamixelServerException::CDynamixelServerException(const std::string& where,const std::string &error_msg):CException(where,dynamixel_server_error_message)
{
this->error_msg+=error_msg;
}
#ifndef _DYNAMIXEL_EXCEPTIONS
#define _DYNAMIXEL_EXCEPTIONS
#include "exceptions.h"
/**
* \brief Dynamixel exception
*
* This class is used to report general errors of the dynamixel devices. These
* errors are normally caused by invalid parameters passed to the functions.
* In this case the error message is used to identify which error has ocuurred.
*
*/
class CDynamixelException : public CException
{
public:
/**
* \brief Class constructor
*
* This constructor generates a standard error message with the error message
* provided as a parameter. The standard error message is "General dynamixel
* error - ", with the error message appended at the end. The base
* class constructor is called, so the same prefix is appended at the
* beginning to label the message as an exception.
*
* \param where a null terminated string with the information about the name
* of the function, the source code filename and the line where
* the exception was generated. This string must be generated
* by the _HERE_ macro.
*
* \param error_msg a null terminated string with the details of the error.
*
* \param dev_id an integer with the identifier of the dynamixel device that
* has generated the exception.
*/
CDynamixelException(const std::string& where,const std::string &error_msg, int dev_id);
};
/**
* \brief Dynamixel Alarm exception
*
* This class is used to report Alarm errors of the dynamixel devices which
* turn off them. The source of these errors are listed below:
*
* * Invalid instruction
* * Overload
* * Invalid checksum
* * Parameter out of range
* * Overheating
* * Invalid angle command
* * Invalid input voltage
*
* In this case the error message is used to identify which error has ocurred.
*
*/
class CDynamixelAlarmException : public CException
{
private:
unsigned char alarm;
public:
/**
* \brief Class constructor
*
* This constructor generates a standard error message with the error message
* provided as a parameter. The standard error message is "Dynamixel Alarm
* error - ", with the error message appended at the end. The base
* class constructor is called, so the same prefix is appended at the
* beginning to label the message as an exception.
*
* \param where a null terminated string with the information about the name
* of the function, the source code filename and the line where
* the exception was generated. This string must be generated
* by the _HERE_ macro.
*
* \param error_msg a null terminated string with the details of the error.
*
* \param dev_id an integer with the identifier of the dynamixel device that
* has generated the exception.
* \param alarm
*/
CDynamixelAlarmException(const std::string& where,const std::string &error_msg, int dev_id, unsigned char alarm);
/**
* \brief
*
*/
unsigned char get_alarm(void);
};
/**
* \brief Dynamixel server exception
*
*/
class CDynamixelServerException : public CException
{
public:
/**
* \brief Class constructor
*
* \param where a null terminated string with the information about the name
* of the function, the source code filename and the line where
* the exception was generated. This string must be generated
* by the _HERE_ macro.
*
* \param error_msg a null terminated string with the details of the error.
*/
CDynamixelServerException(const std::string& where,const std::string &error_msg);
};
#endif
#include "dynamixelexceptions.h"
#include "dynamixelserver.h"
#include "eventexceptions.h"
#include "ftdiserver.h"
#include <sstream>
CDynamixelServer *CDynamixelServer::pinstance=NULL;
CDynamixelServer::CDynamixelServer()
{
this->event_server=CEventServer::instance();
this->stop_scan_event_id="dynamixel_server_stop_scan_event";
this->event_server->create_event(this->stop_scan_event_id);
this->scan_done_event_id="dynamixel_server_scan_done_event";
this->event_server->create_event(this->scan_done_event_id);
this->thread_server=CThreadServer::instance();
this->scan_thread_id="dynamixel_server_scan_thread";
this->thread_server->create_thread(this->scan_thread_id);
this->thread_server->attach_thread(this->scan_thread_id,this->scan_thread,this);
this->state=dyn_created;
this->devices.clear();
this->comm_dev=NULL;
this->bus_info.baud_rate=-1;
this->bus_info.bus_id=-1;
}
CDynamixelServer::CDynamixelServer(const CDynamixelServer& object)
{
}
CDynamixelServer& CDynamixelServer::operator = (const CDynamixelServer& object)
{
return *this->pinstance;
}
CDynamixelServer *CDynamixelServer::instance(void)
{
if (CDynamixelServer::pinstance == NULL)
{
CDynamixelServer::pinstance = new CDynamixelServer(); // Creamos la instancia
}
return CDynamixelServer::pinstance; // Retornamos la dirección de la instancia
}
void *CDynamixelServer::scan_thread(void *param)
{
CDynamixelServer *dyn_server=(CDynamixelServer *)param;
CFTDIServer *ftdi_server=CFTDIServer::instance();
std::stringstream device_name;
std::string serial,name;
CDynamixel *device;
int freq=0,id=0;
bool end=false;
dyn_server->close();
dyn_server->state=dyn_scanning;
while(!end)
{
try{
serial=ftdi_server->get_serial_number(dyn_server->bus_info.bus_id);
dyn_server->comm_dev=ftdi_server->get_device(serial);
for(freq=1;freq<9;freq++)
{
dyn_server->set_baudrate(frequencies[freq-1]);
for(id=0;id<0xFD;id++)
{
if(dyn_server->event_server->event_is_set(dyn_server->stop_scan_event_id))
{
dyn_server->event_server->reset_event(dyn_server->stop_scan_event_id);
dyn_server->close();
pthread_exit(NULL);
}
else
{
try{
dyn_server->ping(id);
}catch(CEventTimeoutException &e){
continue;
}
dyn_server->dynamixel_access.enter();
dyn_server->bus_info.baud_rate=frequencies[freq-1];
device_name.str("");
device_name << "dynamixel_bus_" << dyn_server->bus_info.bus_id << "_dev_" << id;
name=device_name.str();
device=new CDynamixel(name);
device->usb_dev=dyn_server->comm_dev;
device->usb_access=&dyn_server->dynamixel_access;
device->node_address=id;
device->usb_rx_event_id=dyn_server->comm_dev->get_rx_event_id();
dyn_server->dynamixel_access.exit();
dyn_server->devices.push_back(device);
}
if(end) break;
}
if(dyn_server->bus_info.baud_rate!=-1)
{
end=true;
break;
}
}
}catch(CException &e){
dyn_server->close();
pthread_exit(NULL);
}
}
dyn_server->dynamixel_access.enter();
dyn_server->state=dyn_scan_done;
dyn_server->event_server->set_event(dyn_server->scan_done_event_id);
dyn_server->dynamixel_access.exit();
pthread_exit(NULL);
}
int CDynamixelServer::get_num_buses(void)
{
CFTDIServer *ftdi_server=CFTDIServer::instance();
int num_dev=0,i=0,num_buses=0;
std::string description;
this->dynamixel_access.enter();
try{
num_dev=ftdi_server->get_num_devices();
for(i=0;i<num_dev;i++)
{
description=ftdi_server->get_description(i);
if(description=="FT232R USB UART")
num_buses++;
}
}catch(CException &e){
/* handle exceptions */
this->dynamixel_access.exit();
throw;
}
this->dynamixel_access.exit();
return num_buses;
}
int CDynamixelServer::get_bus_id(void)
{
return this->bus_info.bus_id;
}
void CDynamixelServer::set_bus_id(int bus_id)
{
CFTDIServer *ftdi_server=CFTDIServer::instance();
std::string serial;
if(bus_id>(this->get_num_buses()-1))
{
/* handle exception */
throw CDynamixelServerException(_HERE_,"Invalid bus identifier");
}
else
{
if(this->bus_info.bus_id!=bus_id)
{
if(this->comm_dev!=NULL)
{
this->comm_dev->close();
delete this->comm_dev;
this->comm_dev=NULL;
}
serial=ftdi_server->get_serial_number(bus_id);
this->comm_dev=ftdi_server->get_device(serial);
this->bus_info.bus_id=bus_id;
}
}
}
void CDynamixelServer::start_scan(void)
{
if(this->bus_info.bus_id==-1)
{
/* handle exceptions */
throw CDynamixelServerException(_HERE_,"No bus has been selected.");
}
else
{
this->close();
this->thread_server->start_thread(this->scan_thread_id);
}
}
void CDynamixelServer::stop_scan(void)
{
if(this->state==dyn_scanning)
{
this->event_server->set_event(this->stop_scan_event_id);
this->thread_server->end_thread(this->scan_thread_id);
this->bus_info.bus_id=-1;
}
}
bool CDynamixelServer::is_scan_done(void)
{
if(this->bus_info.bus_id!=-1)
{
if(this->state==dyn_scan_done)
return true;
else
return false;
}
else
{
/* handle exceptions */
throw CDynamixelServerException(_HERE_,"No bus has been selected.");
}
}
std::string CDynamixelServer::get_scan_done_event_id(void)
{
return this->scan_done_event_id;
}
int CDynamixelServer::get_baudrate(void)
{
int baud_rate=0;
this->dynamixel_access.enter();
baud_rate=this->bus_info.baud_rate;
this->dynamixel_access.exit();
return baud_rate;
}
int CDynamixelServer::get_num_devices(void)
{
int num=0;
this->dynamixel_access.enter();
num=this->devices.size();
this->dynamixel_access.exit();
return num;
}
std::vector<int> CDynamixelServer::get_device_ids(void)
{
std::vector<int> ids;
int i=0;
this->dynamixel_access.enter();
for(i=0;i<this->devices.size();i++)
ids.push_back(this->devices[i]->get_id());
this->dynamixel_access.exit();
return ids;
}
CDynamixel *CDynamixelServer::get_device(int dev_id)
{
std::stringstream device_name;
CDynamixel *dynamixel=NULL;
std::string name,serial;
int i=0;
this->dynamixel_access.enter();
if(this->bus_info.bus_id==-1)
{
this->dynamixel_access.exit();
/* handle exceptions */
throw CDynamixelServerException(_HERE_,"No bus has been selected.");
}
else
{
for(i=0;i<this->devices.size();i++)
if(this->devices[i]->get_id()==dev_id)
dynamixel=this->devices[i];
}
this->dynamixel_access.exit();
if(dynamixel==NULL)
{
// try to ping the desired device
try{
if(this->bus_info.baud_rate==-1)
{
/* handle exceptions */
throw CDynamixelServerException(_HERE_,"No baudrate has been selected.");
}
else
{
this->ping(dev_id);
this->dynamixel_access.enter();
device_name.str("");
device_name << "dynamixel_bus_" << this->bus_info.bus_id << "_dev_" << dev_id;
name=device_name.str();
dynamixel=new CDynamixel(name);
dynamixel->usb_dev=this->comm_dev;
dynamixel->usb_access=&this->dynamixel_access;
dynamixel->node_address=dev_id;
dynamixel->usb_rx_event_id=this->comm_dev->get_rx_event_id();
this->dynamixel_access.exit();
}
}catch(CEventTimeoutException &e){
this->dynamixel_access.exit();
/* handle exceptions */
throw CDynamixelServerException(_HERE_,"No Dynamixel device found with the specified identifier");
}
}
return dynamixel;
}
void CDynamixelServer::set_baudrate(int baudrate)
{
TFTDIconfig ftdi_config;
int i=0;
if(this->comm_dev!=NULL)
{
if(baudrate <= 0 || baudrate > 1000000)
{
/* handle exceptions */
throw CDynamixelServerException(_HERE_,"Invalid baudrate");
}
else
{
try{
for(i=0;i<this->devices.size();i++)
this->devices[i]->set_baudrate(baudrate);
/* reconfigure the communciations device */
ftdi_config.word_length=8;
ftdi_config.stop_bits=1;
ftdi_config.parity=0;
ftdi_config.read_timeout = 1000;
ftdi_config.write_timeout = 1000;
ftdi_config.latency_timer = 1;
ftdi_config.baud_rate=baudrate;
this->comm_dev->config(&ftdi_config);
this->bus_info.baud_rate=baudrate;
}catch(CException &e){
/* handle exceptions */
throw;
}
}
}
else
{
/* handle exceptions */
throw CDynamixelServerException(_HERE_,"The communication device is not ready to send information");
}
}
void CDynamixelServer::set_id(int old_id, int new_id)
{
CDynamixel *dynamixel=NULL;
int i=0;
this->dynamixel_access.enter();
for(i=0;i<this->devices.size();i++)
{
if(this->devices[i]->get_id()==new_id)
{
/* handle exceptions */
this->dynamixel_access.exit();
throw CDynamixelServerException(_HERE_,"There exist an other device with the same identifier in the bus");
}
else if(this->devices[i]->get_id()==old_id)
dynamixel=this->devices[i];
}
this->dynamixel_access.exit();
if(dynamixel!=NULL)
dynamixel->set_id(new_id);
else
{
/* handle exceptions */
throw CDynamixelServerException(_HERE_,"No Dynamixel device found with the specified identifier");
}
}
void CDynamixelServer::action(void)
{
unsigned char packet[6]={0xFF,0xFF,0xFE,0x02,0x05,0x00};
if(this->comm_dev!=NULL)
{
packet[5]=0xFA;
this->dynamixel_access.enter();
if(this->comm_dev->write(packet,6)!=6)
{
// handle exceptions
this->dynamixel_access.exit();
throw CDynamixelServerException(_HERE_,"Unexpected error while writing to the communication device");
}
this->dynamixel_access.exit();
}
else
{
/* handle exceptions */
throw CDynamixelServerException(_HERE_,"The communication device is not ready to send information");
}
}
void CDynamixelServer::ping(int dev_id)
{
unsigned char packet[6]={0xFF,0xFF,0x00,0x02,0x01,0x00};
std::list<std::string> events;
unsigned char data[6];
int num=0,read=0;
if(this->comm_dev!=NULL)
{
this->dynamixel_access.enter();
packet[2]=dev_id;
packet[5]=(~(dev_id+3))%256;
events.push_back(this->comm_dev->get_rx_event_id());
if(this->comm_dev->write(packet,6)!=6)
{
/* handle exceptions */
this->dynamixel_access.exit();
throw CDynamixelServerException(_HERE_,"Unexpected error while writing to the communication device");
}
else
{
try{
do{
if(dev_id==0)
this->event_server->wait_all(events,200);
else
this->event_server->wait_all(events,100);
num=this->comm_dev->read(&data[read],6-read);
read+=num;
}while(read<6);
}catch(CEventTimeoutException &e){
this->dynamixel_access.exit();
throw;
}
}
this->dynamixel_access.exit();
}
else
{
/* handle exceptions */
throw CDynamixelServerException(_HERE_,"The communication device is not ready to send information");
}
}
void CDynamixelServer::close(void)
{
int i=0;
this->dynamixel_access.enter();
if(this->devices.size()>0)
{
this->devices.clear();
}
if(this->comm_dev!=NULL)
{
this->comm_dev->close();
delete this->comm_dev;
this->comm_dev=NULL;
}
this->state=dyn_created;
this->bus_info.baud_rate=-1;
this->dynamixel_access.exit();
}
#ifndef _DYNAMIXEL_SERVER_H
#define _DYNAMIXEL_SERVER_H
#include <vector>
#include "mutex.h"
#include "dynamixel.h"
#include "ftdimodule.h"
#include "eventserver.h"
#include "threadserver.h"
// forward declaration of the CDynamixel class
class CDynamixel;
/**
* \brief Dynamixel server states
*
* This enummertation type defines all the possible states of the dynamixel
* server. Each state is described next:
* * dyn_created: This is the default state when a dynamixel server is created.
* At this point the server is initialized but it is useless
* until a complete scan of the has been done.
* * dyn_scanning: This is the state after calling the start_scan() function is
* called, and until the scan is done. If the scan is stoped
* before it finishes, the server returns to the dyn_created
* state, and if the scan is successfull, it goes to the
* dyn_scan_done state.
* * dyn_scan_done: This is the ready state of the server. In this state the
* servers knows how many devices are present on the bus,
* together with their unique identifiers. If the devices on
* the bus change, it is necessary to repeat the scan.
*
* The different states of the dynamixel server and the functions to change
* them are shown in the next picture:
*
* \image html dyn_server_states.png
* \image latex dyn_server_states.eps "Dynamixel server states" width=10cm
*/
typedef enum {dyn_created,dyn_scanning,dyn_scan_done} dynamixel_state;
/**
* \brief Basic Dynamixel bus information
*
* This structure holds the identifier of the current bus used (in case there
* exist multiple buses) and also the baudrate of the bus.
*/
typedef struct
{
int baud_rate;
int bus_id;
}TBus_info;
/**
* \brief
*
*/
const int frequencies[9]={1000000,500000,400000,250000,200000,115200,57600,19200,9600};
/**
* \brief
*
*/
class CDynamixelServer
{
private:
/**
* \brief
*
*/
static CDynamixelServer *pinstance;
/**
* \brief
*
*/
CEventServer *event_server;
/**
* \brief
*
*/
std::string stop_scan_event_id;
/**
* \brief
*
*/
std::string scan_done_event_id;
/**
* \brief
*
*/
CThreadServer *thread_server;
/**
* \brief
*
*/
std::string scan_thread_id;
/**
* \brief
*
*/
dynamixel_state state;
/**
* \brief
*
*/
CFTDI *comm_dev;
/**
* \brief
*
*/
CMutex dynamixel_access;
/**
* \brief
*
*/
TBus_info bus_info;
/**
* \brief
*
*/
std::vector<CDynamixel *> devices;
protected:
/**
* \brief
*
*/
CDynamixelServer();
/**
* \brief
*
*/
CDynamixelServer(const CDynamixelServer &object);
/**
* \brief
*
*/
CDynamixelServer& operator = (const CDynamixelServer &object);
/**
* \brief
*
*/
static void *scan_thread(void *param);
public:
/**
* \brief
*
*/
static CDynamixelServer *instance(void);
/**
* \brief
*
*/
int get_num_buses(void);
/**
* \brief
*
*/
int get_bus_id(void);
/**
* \brief
*
*/
void set_bus_id(int bus_id);
/**
* \brief
*
*/
void start_scan(void);
/**
* \brief
*
*/
void stop_scan(void);
/**
* \brief
*
*/
bool is_scan_done(void);
/**
* \brief
*
*/
std::string get_scan_done_event_id(void);
/**
* \brief
*
*/
int get_baudrate(void);
/**
* \brief
*
*/
int get_num_devices(void);
/**
* \brief
*
*/
std::vector<int> get_device_ids(void);
/**
* \brief
*
*/
CDynamixel *get_device(int dev_id);
/**
* \brief
*
*/
void set_baudrate(int baudrate);
/**
* \brief
*
*/
void set_id(int old_id, int new_id);
/**
* \brief
*
*/
void action(void);
/**
* \brief
*
*/
void ping(int dev_id);
/**
* \brief
*
*/
void close(void);
};
#endif
# edit the following line to add the source code for the example and the name of the executable
ADD_EXECUTABLE(test_dynamixel_server test_dynamixel_server.cpp)
# edit the following line to add the necessary libraries
TARGET_LINK_LIBRARIES(test_dynamixel_server dynamixel)
# edit the following line to add the source code for the example and the name of the executable
ADD_EXECUTABLE(test_dynamixel_server_no_scan test_dynamixel_server_no_scan.cpp)
# edit the following line to add the necessary libraries
TARGET_LINK_LIBRARIES(test_dynamixel_server_no_scan dynamixel)
#include "eventexceptions.h"
#include "dynamixelserver.h"
#include <iostream>
int main(int argc, char *argv[])
{
CDynamixelServer *dyn_server=CDynamixelServer::instance();
CEventServer *event_server=CEventServer::instance();
int num_buses=0,num_dev=0,baudrate=0,i=0;
std::list<std::string> events;
std::vector<float> position;
std::vector<int> devices;
CDynamixel *dyn_motor;
short int motors=0x0001;
num_buses=dyn_server->get_num_buses();
std::cout << "Num. buses: " << num_buses << std::endl;
if(num_buses>0)
{
events.push_back(dyn_server->get_scan_done_event_id());
dyn_server->set_bus_id(0);
dyn_server->start_scan();
event_server->wait_first(events);
num_dev=dyn_server->get_num_devices();
std::cout << "Num. devices: " << num_dev << std::endl;
baudrate=dyn_server->get_baudrate();
std::cout << "Baudrate: " << baudrate << " bps" << std::endl;
devices=dyn_server->get_device_ids();
for(i=0;i<num_dev;i++)
std::cout << "Device " << i << ": id -> " << devices[i] << std::endl;
dyn_motor=dyn_server->get_device(devices[0]);
try{
dyn_server->set_bus_id(0);
dyn_server->start_scan();
event_server->wait_first(events,2000);
}catch(CException &e){
dyn_server->stop_scan();
std::cout << "Scanning canceled !!!" << std::endl;
}
num_dev=dyn_server->get_num_devices();
std::cout << "Num. devices: " << num_dev << std::endl;
baudrate=dyn_server->get_baudrate();
std::cout << "Baudrate: " << baudrate << " bps" << std::endl;
devices=dyn_server->get_device_ids();
for(i=0;i<num_dev;i++)
std::cout << "Device " << i << ": id -> " << devices[i] << std::endl;
}
}
#include "eventexceptions.h"
#include "dynamixelserver.h"
#include <iostream>
int main(int argc, char *argv[])
{
CDynamixelServer *dyn_server=CDynamixelServer::instance();
CEventServer *event_server=CEventServer::instance();
int num_buses=0,num_dev=0,baudrate=0,i=0;
std::vector<int> devices;
CDynamixel *dyn_motor;
short int motors=0x0001;
num_buses=dyn_server->get_num_buses();
std::cout << "Num. buses: " << num_buses << std::endl;
if(num_buses>0)
{
dyn_server->set_bus_id(0);
dyn_server->set_baudrate(1000000);
try{
dyn_motor=dyn_server->get_device(13);
std::cout << "device 13 found!!!" << std::endl;
}catch(CException &e){
std::cout << "device 13 not found on bus 0" << std::endl;
}
try{
dyn_motor=dyn_server->get_device(12);
std::cout << "device 12 found!!!" << std::endl;
}catch(CException &e){
std::cout << "device 12 not found on bus 0" << std::endl;
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment