From 5f0f33b03f2c116b178dc7ff7f77b71dd6c016ef Mon Sep 17 00:00:00 2001 From: Matthew Barulic Date: Mon, 9 May 2016 17:28:03 -0400 Subject: [PATCH] Release 0.1.0 --- .gitignore | 95 + Doxyfile | 1716 +++++++++++++++++ README.md | 89 + autorally/CMakeLists.txt | 4 + autorally/package.xml | 45 + autorally_control/CMakeLists.txt | 54 + autorally_control/cfg/gpsWaypoint_params.cfg | 16 + .../include/autorally_control/placeholder.txt | 1 + .../launch/constantSpeedController.launch | 19 + .../launch/gpsImuEstimator.launch | 46 + autorally_control/launch/gpsWaypoint.launch | 22 + .../launch/joystickController.launch | 30 + autorally_control/launch/recordWpts.launch | 10 + autorally_control/nodelet_plugins.xml | 31 + autorally_control/package.xml | 62 + .../ConstantSpeedController/CMakeLists.txt | 10 + .../ConstantSpeedController.cpp | 217 +++ .../ConstantSpeedController.h | 114 ++ .../src/gpsWaypoint/CMakeLists.txt | 19 + .../src/gpsWaypoint/GenerateWaypoints | 76 + .../src/gpsWaypoint/gpsWaypoint.cpp | 317 +++ .../src/gpsWaypoint/gpsWaypoint.h | 115 ++ autorally_control/src/joystick/CMakeLists.txt | 12 + .../src/joystick/JoystickControl.cpp | 159 ++ .../src/joystick/JoystickControl.h | 111 ++ .../src/joystick/joystickControlMain.cpp | 47 + autorally_core/CMakeLists.txt | 71 + .../include/autorally_core/ChronyStatus.h | 94 + .../include/autorally_core/Diagnostics.h | 165 ++ .../include/autorally_core/PololuMaestro.h | 125 ++ .../include/autorally_core/RingBuffer.h | 78 + .../include/autorally_core/SafeSpeed.h | 155 ++ .../include/autorally_core/SerialCommon.h | 134 ++ .../autorally_core/SerialInterfaceThreaded.h | 217 +++ .../autorally_core/SerialSensorInterface.h | 127 ++ autorally_core/launch/arduinoOnboard.launch | 29 + autorally_core/launch/autorally.launch | 21 + .../launch/autorally_core_manager.launch | 7 + .../launch/autorally_imu_3dm_gx4.launch | 17 + autorally_core/launch/baseStation.launch | 11 + autorally_core/launch/camera.launch | 58 + autorally_core/launch/cameras.launch | 18 + autorally_core/launch/chronyStatus.launch | 5 + autorally_core/launch/gpsBase.launch | 37 + autorally_core/launch/gpsRover.launch | 35 + autorally_core/launch/hardware.machine | 15 + autorally_core/launch/imageRepublisher.launch | 7 + autorally_core/launch/ocs.launch | 11 + autorally_core/launch/robot.urdf | 116 ++ autorally_core/launch/runStop.launch | 21 + autorally_core/launch/servoInterface.launch | 36 + autorally_core/launch/stateEstimator.launch | 48 + autorally_core/launch/systemStatus.launch | 11 + autorally_core/launch/xbeeCoordinator.launch | 21 + autorally_core/launch/xbeeNode.launch | 20 + autorally_core/nodelet_plugins.xml | 31 + autorally_core/package.xml | 71 + autorally_core/setup.py | 35 + .../src/ChronyStatus/CMakeLists.txt | 10 + .../src/ChronyStatus/ChronyStatus.cpp | 199 ++ autorally_core/src/ChronyStatus/__init__.py | 0 .../src/ChronyStatus/chronyStatus.py | 128 ++ .../src/ChronyStatus/chronyStatusMain.cpp | 51 + autorally_core/src/ChronyStatus/getClients.sh | 12 + autorally_core/src/Diagnostics/CMakeLists.txt | 9 + .../src/Diagnostics/Diagnostics.cpp | 202 ++ .../src/ImageRepublisher/CMakeLists.txt | 19 + .../src/ImageRepublisher/ImageRepublisher.cpp | 115 ++ .../src/ImageRepublisher/ImageRepublisher.h | 30 + autorally_core/src/RingBuffer/CMakeLists.txt | 9 + autorally_core/src/RingBuffer/RingBuffer.cpp | 182 ++ autorally_core/src/RunStop/CMakeLists.txt | 10 + autorally_core/src/RunStop/RunStop.cpp | 155 ++ autorally_core/src/RunStop/RunStop.h | 100 + .../src/RunStop/RunStop/RunStop.ino | 74 + autorally_core/src/SafeSpeed/CMakeLists.txt | 10 + autorally_core/src/SafeSpeed/SafeSpeed.cpp | 227 +++ .../src/SerialSensorInterface/CMakeLists.txt | 11 + .../SerialSensorInterface/SerialCommon.cpp | 282 +++ .../SerialInterfaceThreaded.cpp | 285 +++ .../SerialSensorInterface.cpp | 177 ++ .../src/StateEstimator/BlockingQueue.h | 96 + .../src/StateEstimator/CMakeLists.txt | 17 + autorally_core/src/StateEstimator/IMU_GPS.cpp | 522 +++++ autorally_core/src/StateEstimator/IMU_GPS.h | 159 ++ autorally_core/src/arduino/ArduinoOnboard.cpp | 352 ++++ autorally_core/src/arduino/ArduinoOnboard.h | 158 ++ autorally_core/src/arduino/CMakeLists.txt | 10 + .../arduino/arduinoOnboard/arduinoOnboard.ino | 357 ++++ autorally_core/src/gps/CMakeLists.txt | 16 + autorally_core/src/gps/GPSHemisphere.cpp | 1042 ++++++++++ autorally_core/src/gps/GPSHemisphere.h | 222 +++ autorally_core/src/ocs/CMakeLists.txt | 28 + autorally_core/src/ocs/DiagnosticsEntry.cpp | 373 ++++ autorally_core/src/ocs/DiagnosticsEntry.hpp | 126 ++ autorally_core/src/ocs/ImageMaskEntry.cpp | 105 + autorally_core/src/ocs/ImageMaskEntry.hpp | 80 + autorally_core/src/ocs/main.cpp | 54 + autorally_core/src/ocs/main_window.cpp | 591 ++++++ autorally_core/src/ocs/main_window.hpp | 184 ++ autorally_core/src/ocs/main_window.ui | 1126 +++++++++++ autorally_core/src/ocs/qnode.cpp | 405 ++++ autorally_core/src/ocs/qnode.hpp | 272 +++ autorally_core/src/ocs/resources/images.qrc | 7 + .../src/ocs/resources/images.qrc.depends | 8 + .../src/ocs/resources/images/camera.png | Bin 0 -> 5145 bytes .../src/ocs/resources/images/car_logo.png | Bin 0 -> 13826 bytes .../src/ocs/resources/images/icon.png | Bin 0 -> 37139 bytes .../src/servoInterface/CMakeLists.txt | 16 + .../src/servoInterface/PololuMaestro.cpp | 134 ++ .../src/servoInterface/servoInterface.cpp | 415 ++++ .../src/servoInterface/servoInterface.h | 173 ++ .../src/servoInterface/servoInterfaceMain.cpp | 62 + autorally_core/src/systemStatus/__init__.py | 0 .../src/systemStatus/systemStatus.py | 247 +++ autorally_core/src/xbee/CMakeLists.txt | 13 + autorally_core/src/xbee/XbeeCoordinator.cpp | 207 ++ autorally_core/src/xbee/XbeeCoordinator.h | 112 ++ autorally_core/src/xbee/XbeeInterface.cpp | 556 ++++++ autorally_core/src/xbee/XbeeInterface.h | 262 +++ autorally_core/src/xbee/XbeeNode.cpp | 343 ++++ autorally_core/src/xbee/XbeeNode.h | 104 + autorally_core/test/CMakeLists.txt | 9 + autorally_core/test/diagnosticsTest.cpp | 259 +++ .../test/pololuMicroMaestroTest.cpp | 60 + .../test/serialSensorInterfaceTest.cpp | 108 ++ autorally_description/CMakeLists.txt | 14 + autorally_description/LICENSE.md | 191 ++ .../launch/autoRallyPlatform.launch | 36 + .../launch/autoRallyPlatformRviz.launch | 43 + autorally_description/launch/rviz.launch | 29 + autorally_description/package.xml | 41 + .../urdf/autoRallyPlatform.stl | Bin 0 -> 353984 bytes .../urdf/autoRallyPlatform.urdf.xacro | 672 +++++++ .../urdf/autoRallyPlatformFrontWheel.stl | Bin 0 -> 244984 bytes .../urdf/autoRallyPlatformRearWheel.stl | Bin 0 -> 244784 bytes autorally_description/urdf/autoRallyTrack.stl | Bin 0 -> 708084 bytes .../urdf/autoRallyTrack.urdf | 33 + autorally_description/urdf/jump18deg.stl | Bin 0 -> 3084 bytes autorally_description/urdf/jump18deg.urdf | 32 + autorally_description/urdf/jump22deg.stl | Bin 0 -> 3184 bytes autorally_description/urdf/jump22deg.urdf | 32 + autorally_description/urdf/jump26deg.stl | Bin 0 -> 3384 bytes autorally_description/urdf/jump26deg.urdf | 32 + autorally_description/urdf/jump30deg.stl | Bin 0 -> 3684 bytes autorally_description/urdf/jump30deg.urdf | 32 + autorally_gazebo/CMakeLists.txt | 21 + autorally_gazebo/LICENSE.md | 191 ++ .../config/autoRallyPlatformCtrlrParams.yaml | 52 + .../autoRallyPlatformJointCtrlrParams.yaml | 87 + .../launch/autoRallyJumpGazeboSim.launch | 108 ++ .../launch/autoRallyJumpWorld.launch | 66 + .../launch/autoRallyTrackGazeboSim.launch | 101 + .../launch/autoRallyTrackWorld.launch | 45 + .../nodes/autorally_controller.py | 600 ++++++ autorally_gazebo/nodes/wheelSpeedsGazebo.py | 70 + autorally_gazebo/package.xml | 47 + autorally_gazebo/setup.py | 32 + autorally_msgs/CMakeLists.txt | 32 + autorally_msgs/msg/imageMask.msg | 6 + autorally_msgs/msg/line2D.msg | 2 + autorally_msgs/msg/point2D.msg | 2 + autorally_msgs/msg/safeSpeed.msg | 4 + autorally_msgs/msg/servoMSG.msg | 6 + autorally_msgs/msg/wheelSpeeds.msg | 5 + autorally_msgs/package.xml | 45 + autorally_util/99-autoRally.rules | 41 + autorally_util/CMakeLists.txt | 12 + autorally_util/chrony.keys | 25 + autorally_util/chronyClient.conf | 323 ++++ autorally_util/chronyServer.conf | 319 +++ .../config/arChassisConfig_CHASSIS_NAME.yaml | 4 + .../config/camera_calibration_GUID.yaml | 20 + .../config/servoCommandPriorities.yaml | 4 + .../config/throttlePositionCalibration.yaml | 7 + autorally_util/package.xml | 51 + autorally_util/roscoreAutostart.sh | 7 + autorally_util/setCameraPermissions.sh | 5 + autorally_util/setupEnvLocal.sh | 10 + autorally_util/setupEnvRemote.sh | 10 + autorally_util/setupEnvVariables.sh | 72 + doc/autorally.png | Bin 0 -> 97938 bytes doc/autorally_repo.jpg | Bin 0 -> 192563 bytes mainpage.dox | 21 + 184 files changed, 20611 insertions(+) create mode 100644 .gitignore create mode 100644 Doxyfile create mode 100644 README.md create mode 100644 autorally/CMakeLists.txt create mode 100644 autorally/package.xml create mode 100644 autorally_control/CMakeLists.txt create mode 100755 autorally_control/cfg/gpsWaypoint_params.cfg create mode 100644 autorally_control/include/autorally_control/placeholder.txt create mode 100644 autorally_control/launch/constantSpeedController.launch create mode 100644 autorally_control/launch/gpsImuEstimator.launch create mode 100644 autorally_control/launch/gpsWaypoint.launch create mode 100644 autorally_control/launch/joystickController.launch create mode 100644 autorally_control/launch/recordWpts.launch create mode 100755 autorally_control/nodelet_plugins.xml create mode 100644 autorally_control/package.xml create mode 100644 autorally_control/src/ConstantSpeedController/CMakeLists.txt create mode 100644 autorally_control/src/ConstantSpeedController/ConstantSpeedController.cpp create mode 100644 autorally_control/src/ConstantSpeedController/ConstantSpeedController.h create mode 100644 autorally_control/src/gpsWaypoint/CMakeLists.txt create mode 100755 autorally_control/src/gpsWaypoint/GenerateWaypoints create mode 100644 autorally_control/src/gpsWaypoint/gpsWaypoint.cpp create mode 100644 autorally_control/src/gpsWaypoint/gpsWaypoint.h create mode 100644 autorally_control/src/joystick/CMakeLists.txt create mode 100644 autorally_control/src/joystick/JoystickControl.cpp create mode 100644 autorally_control/src/joystick/JoystickControl.h create mode 100644 autorally_control/src/joystick/joystickControlMain.cpp create mode 100644 autorally_core/CMakeLists.txt create mode 100644 autorally_core/include/autorally_core/ChronyStatus.h create mode 100644 autorally_core/include/autorally_core/Diagnostics.h create mode 100644 autorally_core/include/autorally_core/PololuMaestro.h create mode 100644 autorally_core/include/autorally_core/RingBuffer.h create mode 100644 autorally_core/include/autorally_core/SafeSpeed.h create mode 100644 autorally_core/include/autorally_core/SerialCommon.h create mode 100644 autorally_core/include/autorally_core/SerialInterfaceThreaded.h create mode 100644 autorally_core/include/autorally_core/SerialSensorInterface.h create mode 100644 autorally_core/launch/arduinoOnboard.launch create mode 100644 autorally_core/launch/autorally.launch create mode 100644 autorally_core/launch/autorally_core_manager.launch create mode 100644 autorally_core/launch/autorally_imu_3dm_gx4.launch create mode 100644 autorally_core/launch/baseStation.launch create mode 100644 autorally_core/launch/camera.launch create mode 100644 autorally_core/launch/cameras.launch create mode 100644 autorally_core/launch/chronyStatus.launch create mode 100644 autorally_core/launch/gpsBase.launch create mode 100644 autorally_core/launch/gpsRover.launch create mode 100644 autorally_core/launch/hardware.machine create mode 100644 autorally_core/launch/imageRepublisher.launch create mode 100644 autorally_core/launch/ocs.launch create mode 100644 autorally_core/launch/robot.urdf create mode 100644 autorally_core/launch/runStop.launch create mode 100644 autorally_core/launch/servoInterface.launch create mode 100644 autorally_core/launch/stateEstimator.launch create mode 100644 autorally_core/launch/systemStatus.launch create mode 100644 autorally_core/launch/xbeeCoordinator.launch create mode 100644 autorally_core/launch/xbeeNode.launch create mode 100755 autorally_core/nodelet_plugins.xml create mode 100644 autorally_core/package.xml create mode 100644 autorally_core/setup.py create mode 100644 autorally_core/src/ChronyStatus/CMakeLists.txt create mode 100644 autorally_core/src/ChronyStatus/ChronyStatus.cpp create mode 100755 autorally_core/src/ChronyStatus/__init__.py create mode 100755 autorally_core/src/ChronyStatus/chronyStatus.py create mode 100644 autorally_core/src/ChronyStatus/chronyStatusMain.cpp create mode 100755 autorally_core/src/ChronyStatus/getClients.sh create mode 100644 autorally_core/src/Diagnostics/CMakeLists.txt create mode 100644 autorally_core/src/Diagnostics/Diagnostics.cpp create mode 100644 autorally_core/src/ImageRepublisher/CMakeLists.txt create mode 100644 autorally_core/src/ImageRepublisher/ImageRepublisher.cpp create mode 100644 autorally_core/src/ImageRepublisher/ImageRepublisher.h create mode 100644 autorally_core/src/RingBuffer/CMakeLists.txt create mode 100644 autorally_core/src/RingBuffer/RingBuffer.cpp create mode 100644 autorally_core/src/RunStop/CMakeLists.txt create mode 100644 autorally_core/src/RunStop/RunStop.cpp create mode 100644 autorally_core/src/RunStop/RunStop.h create mode 100644 autorally_core/src/RunStop/RunStop/RunStop.ino create mode 100644 autorally_core/src/SafeSpeed/CMakeLists.txt create mode 100644 autorally_core/src/SafeSpeed/SafeSpeed.cpp create mode 100644 autorally_core/src/SerialSensorInterface/CMakeLists.txt create mode 100644 autorally_core/src/SerialSensorInterface/SerialCommon.cpp create mode 100644 autorally_core/src/SerialSensorInterface/SerialInterfaceThreaded.cpp create mode 100644 autorally_core/src/SerialSensorInterface/SerialSensorInterface.cpp create mode 100644 autorally_core/src/StateEstimator/BlockingQueue.h create mode 100644 autorally_core/src/StateEstimator/CMakeLists.txt create mode 100644 autorally_core/src/StateEstimator/IMU_GPS.cpp create mode 100644 autorally_core/src/StateEstimator/IMU_GPS.h create mode 100644 autorally_core/src/arduino/ArduinoOnboard.cpp create mode 100644 autorally_core/src/arduino/ArduinoOnboard.h create mode 100644 autorally_core/src/arduino/CMakeLists.txt create mode 100644 autorally_core/src/arduino/arduinoOnboard/arduinoOnboard.ino create mode 100644 autorally_core/src/gps/CMakeLists.txt create mode 100644 autorally_core/src/gps/GPSHemisphere.cpp create mode 100644 autorally_core/src/gps/GPSHemisphere.h create mode 100644 autorally_core/src/ocs/CMakeLists.txt create mode 100644 autorally_core/src/ocs/DiagnosticsEntry.cpp create mode 100644 autorally_core/src/ocs/DiagnosticsEntry.hpp create mode 100644 autorally_core/src/ocs/ImageMaskEntry.cpp create mode 100644 autorally_core/src/ocs/ImageMaskEntry.hpp create mode 100644 autorally_core/src/ocs/main.cpp create mode 100644 autorally_core/src/ocs/main_window.cpp create mode 100644 autorally_core/src/ocs/main_window.hpp create mode 100644 autorally_core/src/ocs/main_window.ui create mode 100644 autorally_core/src/ocs/qnode.cpp create mode 100644 autorally_core/src/ocs/qnode.hpp create mode 100644 autorally_core/src/ocs/resources/images.qrc create mode 100644 autorally_core/src/ocs/resources/images.qrc.depends create mode 100644 autorally_core/src/ocs/resources/images/camera.png create mode 100644 autorally_core/src/ocs/resources/images/car_logo.png create mode 100644 autorally_core/src/ocs/resources/images/icon.png create mode 100644 autorally_core/src/servoInterface/CMakeLists.txt create mode 100644 autorally_core/src/servoInterface/PololuMaestro.cpp create mode 100644 autorally_core/src/servoInterface/servoInterface.cpp create mode 100644 autorally_core/src/servoInterface/servoInterface.h create mode 100644 autorally_core/src/servoInterface/servoInterfaceMain.cpp create mode 100755 autorally_core/src/systemStatus/__init__.py create mode 100755 autorally_core/src/systemStatus/systemStatus.py create mode 100644 autorally_core/src/xbee/CMakeLists.txt create mode 100644 autorally_core/src/xbee/XbeeCoordinator.cpp create mode 100644 autorally_core/src/xbee/XbeeCoordinator.h create mode 100644 autorally_core/src/xbee/XbeeInterface.cpp create mode 100644 autorally_core/src/xbee/XbeeInterface.h create mode 100644 autorally_core/src/xbee/XbeeNode.cpp create mode 100644 autorally_core/src/xbee/XbeeNode.h create mode 100644 autorally_core/test/CMakeLists.txt create mode 100644 autorally_core/test/diagnosticsTest.cpp create mode 100644 autorally_core/test/pololuMicroMaestroTest.cpp create mode 100644 autorally_core/test/serialSensorInterfaceTest.cpp create mode 100644 autorally_description/CMakeLists.txt create mode 100644 autorally_description/LICENSE.md create mode 100644 autorally_description/launch/autoRallyPlatform.launch create mode 100644 autorally_description/launch/autoRallyPlatformRviz.launch create mode 100644 autorally_description/launch/rviz.launch create mode 100644 autorally_description/package.xml create mode 100644 autorally_description/urdf/autoRallyPlatform.stl create mode 100644 autorally_description/urdf/autoRallyPlatform.urdf.xacro create mode 100755 autorally_description/urdf/autoRallyPlatformFrontWheel.stl create mode 100755 autorally_description/urdf/autoRallyPlatformRearWheel.stl create mode 100644 autorally_description/urdf/autoRallyTrack.stl create mode 100644 autorally_description/urdf/autoRallyTrack.urdf create mode 100644 autorally_description/urdf/jump18deg.stl create mode 100644 autorally_description/urdf/jump18deg.urdf create mode 100644 autorally_description/urdf/jump22deg.stl create mode 100644 autorally_description/urdf/jump22deg.urdf create mode 100644 autorally_description/urdf/jump26deg.stl create mode 100644 autorally_description/urdf/jump26deg.urdf create mode 100644 autorally_description/urdf/jump30deg.stl create mode 100644 autorally_description/urdf/jump30deg.urdf create mode 100644 autorally_gazebo/CMakeLists.txt create mode 100644 autorally_gazebo/LICENSE.md create mode 100644 autorally_gazebo/config/autoRallyPlatformCtrlrParams.yaml create mode 100644 autorally_gazebo/config/autoRallyPlatformJointCtrlrParams.yaml create mode 100644 autorally_gazebo/launch/autoRallyJumpGazeboSim.launch create mode 100644 autorally_gazebo/launch/autoRallyJumpWorld.launch create mode 100644 autorally_gazebo/launch/autoRallyTrackGazeboSim.launch create mode 100644 autorally_gazebo/launch/autoRallyTrackWorld.launch create mode 100755 autorally_gazebo/nodes/autorally_controller.py create mode 100755 autorally_gazebo/nodes/wheelSpeedsGazebo.py create mode 100644 autorally_gazebo/package.xml create mode 100644 autorally_gazebo/setup.py create mode 100644 autorally_msgs/CMakeLists.txt create mode 100644 autorally_msgs/msg/imageMask.msg create mode 100644 autorally_msgs/msg/line2D.msg create mode 100644 autorally_msgs/msg/point2D.msg create mode 100644 autorally_msgs/msg/safeSpeed.msg create mode 100644 autorally_msgs/msg/servoMSG.msg create mode 100644 autorally_msgs/msg/wheelSpeeds.msg create mode 100644 autorally_msgs/package.xml create mode 100644 autorally_util/99-autoRally.rules create mode 100644 autorally_util/CMakeLists.txt create mode 100644 autorally_util/chrony.keys create mode 100644 autorally_util/chronyClient.conf create mode 100644 autorally_util/chronyServer.conf create mode 100644 autorally_util/config/arChassisConfig_CHASSIS_NAME.yaml create mode 100644 autorally_util/config/camera_calibration_GUID.yaml create mode 100644 autorally_util/config/servoCommandPriorities.yaml create mode 100644 autorally_util/config/throttlePositionCalibration.yaml create mode 100644 autorally_util/package.xml create mode 100755 autorally_util/roscoreAutostart.sh create mode 100755 autorally_util/setCameraPermissions.sh create mode 100755 autorally_util/setupEnvLocal.sh create mode 100644 autorally_util/setupEnvRemote.sh create mode 100644 autorally_util/setupEnvVariables.sh create mode 100644 doc/autorally.png create mode 100644 doc/autorally_repo.jpg create mode 100644 mainpage.dox diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1234897e --- /dev/null +++ b/.gitignore @@ -0,0 +1,95 @@ +# Folders I know to ignore +bin/ +build/ +devel/ +lib/ +doc/ +docs/ +cpp/ + +#ROS generated custom message header +*/msg_gen/ +*/srv_gen/ + +#ROS logs hanging around +*.log + +# any autosave files +*~ + +# Compiled Python files +*.pyc + +# Compiled Object files +*.slo +*.lo +*.o + +# Compiled Dynamic libraries +*.so + +# Compiled Static libraries +*.lai +*.la +*.a + +# images +*.png + +######################## +# Eclipse project files# +######################## +*.pydevproject +.project +.metadata +bin/** +tmp/** +tmp/**/* +*.tmp +*.bakgpsWaypoint_paramsConfig.h + +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +#*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath +######################## + +#ptam third party stuff +vision/thirdparty/* +*/thirdparty/* +vision/thirdparty/libcvd/version.txt + + +#matlab-generated header files +matlab_gen* + +# ROSNOBUILD files used to accelerate compilation +ROS_NOBUILD + +# autogenerated param stuff +control/include/control/gpsWaypoint_paramsConfig.h + + +vision/docs/ + +# autogenerated file for waypoint following +control/include/control/gpsWaypoint_paramsConfig.h + +########################## +# Qt user-specific files # +########################## +*.user diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 00000000..6ca90b69 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,1716 @@ +# Doxyfile 1.7.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "AutoRally" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "The AutoRally platform, developed at Georgia Tech, is a high-performance testbed for advanced perception and control research." + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = "doc/autorally.png" + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc/ + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 2 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES += copyright="2012 Georgia Institute of Technology" + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py *.f90 *.f *.for *.vhd *.vhdl *.pde *.ino + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = */msg_gen/* */build/* */.git/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is adviced to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called Helvetica to the output +# directory and reference it in all dot files that doxygen generates. +# When you want a differently looking font you can specify the font name +# using DOT_FONTNAME. You need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/README.md b/README.md new file mode 100644 index 00000000..87347d79 --- /dev/null +++ b/README.md @@ -0,0 +1,89 @@ +# AutoRally + +![alt text](doc/autorally_repo.jpg "Platform image") + +Software for the AutoRally research platform. + +AutoRally Platform Website: http://autorally.github.io + +AutoRally Research Website: http://rehg.org/autorally + +## Setup Instructions + +### Contents +1. [Install Prerequisites](#1-install-prerequisites) +2. [Clone repository](#2-clone-repository) +3. [Compilation/Running](#3-compilationrunning) +4. [Generate Documentation](#4-generate-documentation) +5. [Test Setup in Simulation](#5-test-setup-in-simulation) + +### 1. Install Prerequisites +1. __Install [Ubuntu 14.04 64-bit](http://www.ubuntu.com)__ +2. __Install required packages__ + + ```sudo apt-get install git doxygen openssh-server libusb-dev``` + + _Recommended Tools_ + + The following tools are useful, but not necessary for this project. + * feh + * cutecom + * cmake-curses-gui + * texinfo + * coriander + * synaptic + * arduino + * python-termcolor + + _Compute Box Dependencies_ + + When installing software on an AutoRally compute box, include these dependencies as well: + + ```sudo apt-get install lm-sensors acpi gpsd-clients``` + +3. __[Install](http://www.ros.org/install/) ros-indigo-desktop-full__ +4. __Install gtsam__ + + Follow the gtsam [Quick Start](https://bitbucket.org/gtborg/gtsam/) guide to clone and install the _develop_ branch of gtsam. + + Instead of `cmake ..`, use: + + ```cmake -DGTSAM_INSTALL_GEOGRAPHICLIB=ON -DGTSAM_WITH_EIGEN_MKL=OFF ..``` + + Once install is complete, make sure linux can see the shared library: + + ```sudo ldconfig``` + +### 2. Clone Repositories + +Clone the autorally and imu_3dm_gx4 repositories into a [catkin workspace](http://wiki.ros.org/catkin/workspaces). The suggested location is `~/catkin_ws/src/`, but any valid catkin worskspace source folder will work. + +```git clone https://github.com/AutoRally/imu_3dm_gx4.git``` + +```git clone https://github.com/AutoRally/autorally.git``` + +### 3. Install AutoRally ROS Dependencies + +Within the catkin workspace folder, run this command to install the packages this project depends on. + +```rosdep install --from-path src --ignore-src -y``` + +### 3. Compilation & Running + +To compile and install run `catkin_make` from the catkin workspace folder. + +Due to the additional requirement of ROS's distributed launch system, you must run `source autorally/autorally_util/setupEnvLocal.sh` before using any autorally components. For more information about how to set this system up for distributed launches on your vehicle platform, see the wiki. + +_Note:_ If you are unfamiliar with catkin, please know that you must run `source /devel/setup.sh` before ROS will be able to locate the autorally packages. This line can be added to your ~/.bashrc file. + +### 4. Generate Documentation + +You can generate / update code documentation by running `doxygen` in `autorally/`. + +To view code documentation open `autorally/doc/html/index.html` in a web browser. + +### 5. Test Setup in Simulation + +To test that your setup process was successful, run the AutoRally simulator with the following command. If you have a USB gamepad, plug it in to your computer before launching this simulator. You will be able to drive the virtual platform around using this gamepad. + +```roslaunch autorally_gazebo autoRallyTrackGazeboSim.launch``` diff --git a/autorally/CMakeLists.txt b/autorally/CMakeLists.txt new file mode 100644 index 00000000..1236dcf2 --- /dev/null +++ b/autorally/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 2.8.3) +project(autorally) +find_package(catkin REQUIRED) +catkin_metapackage() diff --git a/autorally/package.xml b/autorally/package.xml new file mode 100644 index 00000000..b7631cd0 --- /dev/null +++ b/autorally/package.xml @@ -0,0 +1,45 @@ + + + + autorally + 0.1.0 + Autorally metapackage + + Brian Goldfain + Brian Goldfain + + Brian Goldfain + + BSD + + http://autorally.github.io + + + catkin + + autorally_control + autorally_core + autorally_description + autorally_gazebo + autorally_msgs + autorally_util + + + + + + diff --git a/autorally_control/CMakeLists.txt b/autorally_control/CMakeLists.txt new file mode 100644 index 00000000..9a4f4905 --- /dev/null +++ b/autorally_control/CMakeLists.txt @@ -0,0 +1,54 @@ +cmake_minimum_required(VERSION 2.8.3) +project(autorally_control) + +find_package(catkin REQUIRED COMPONENTS + autorally_msgs + cmake_modules + dynamic_reconfigure + geometry_msgs + autorally_core + nav_msgs + nodelet + roscpp + sensor_msgs + std_msgs + tf +) + +find_package(Boost 1.49.0 REQUIRED) +find_package(Eigen REQUIRED) + +set(BUILD_FLAGS "-std=c++11 -Wuninitialized") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${BUILD_FLAGS}") + +generate_dynamic_reconfigure_options(cfg/gpsWaypoint_params.cfg) + +catkin_package( + DEPENDS Boost + CATKIN-DEPENDS roscpp std_msgs geometry_msgs nav_msgs nodelet dynamic_reconfigure autorally_core autorally_msgs + INCLUDE_DIRS include +) + +include_directories(include ${catkin_INCLUDE_DIRS} ${Boost_INCLUDE_DIR} ${Eigen_INCLUDE_DIRS}) + +add_subdirectory(src/ConstantSpeedController) +add_subdirectory(src/joystick) +add_subdirectory(src/gpsWaypoint) + +install(DIRECTORY launch/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch + FILES_MATCHING PATTERN "*.launch" PATTERN "*.machine" PATTERN "*.yaml" +) + +install(DIRECTORY include/${PROJECT_NAME}/ + DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +) + +install(DIRECTORY cfg/cpp/${PROJECT_NAME}/ + DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} + FILES_MATCHING PATTERN "*.h" +) + +install(FILES nodelet_plugins.xml + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +) diff --git a/autorally_control/cfg/gpsWaypoint_params.cfg b/autorally_control/cfg/gpsWaypoint_params.cfg new file mode 100755 index 00000000..c106de74 --- /dev/null +++ b/autorally_control/cfg/gpsWaypoint_params.cfg @@ -0,0 +1,16 @@ +#! /usr/bin/env python + +PACKAGE='autorally_control' +import roslib +roslib.load_manifest(PACKAGE) + +from dynamic_reconfigure.parameter_generator_catkin import * + +gen = ParameterGenerator() +# Name Type Level Description Default Min Max +gen.add("pGain", double_t, 0, "Proportional gain", -2.0, -10, 10) +gen.add("gpsHeading", bool_t, 0, "True to use gps heading, false for fused", False) +gen.add("wpRadius", double_t, 0, "Distance from waypoint to move to next", 1.5, 0.5, 10) +gen.add("wpnum", double_t, 0, "Distance from waypoint to move to next", 1.5, 0.5, 10) + +exit(gen.generate(PACKAGE, "gpsWaypoint", "gpsWaypoint_params")) diff --git a/autorally_control/include/autorally_control/placeholder.txt b/autorally_control/include/autorally_control/placeholder.txt new file mode 100644 index 00000000..6f25857d --- /dev/null +++ b/autorally_control/include/autorally_control/placeholder.txt @@ -0,0 +1 @@ +This file forces git to track include/autorally_control diff --git a/autorally_control/launch/constantSpeedController.launch b/autorally_control/launch/constantSpeedController.launch new file mode 100644 index 00000000..21dd788e --- /dev/null +++ b/autorally_control/launch/constantSpeedController.launch @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/autorally_control/launch/gpsImuEstimator.launch b/autorally_control/launch/gpsImuEstimator.launch new file mode 100644 index 00000000..a1d42bbc --- /dev/null +++ b/autorally_control/launch/gpsImuEstimator.launch @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_control/launch/gpsWaypoint.launch b/autorally_control/launch/gpsWaypoint.launch new file mode 100644 index 00000000..2e180244 --- /dev/null +++ b/autorally_control/launch/gpsWaypoint.launch @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/autorally_control/launch/joystickController.launch b/autorally_control/launch/joystickController.launch new file mode 100644 index 00000000..0ced8d2f --- /dev/null +++ b/autorally_control/launch/joystickController.launch @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_control/launch/recordWpts.launch b/autorally_control/launch/recordWpts.launch new file mode 100644 index 00000000..b681dd95 --- /dev/null +++ b/autorally_control/launch/recordWpts.launch @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/autorally_control/nodelet_plugins.xml b/autorally_control/nodelet_plugins.xml new file mode 100755 index 00000000..b95229f2 --- /dev/null +++ b/autorally_control/nodelet_plugins.xml @@ -0,0 +1,31 @@ + + + + Controller nodelet for when the vehicle is airborne + + + + + + + + Controller nodelet for when the vehicle is airborne + + + + + + + + Drive robot at a constant speed using wheel speed data + + + + + + + + Drive robot at a constant speed using wheel speed data + + + diff --git a/autorally_control/package.xml b/autorally_control/package.xml new file mode 100644 index 00000000..082c5728 --- /dev/null +++ b/autorally_control/package.xml @@ -0,0 +1,62 @@ + + + + autorally_control + 0.1.0 + All control software created for the autorally project resides here + + Brian Goldfain + + Brian Goldfain + + BSD + + http://autorally.github.io + + Brian Goldfain + + catkin + + roscpp + std_msgs + geometry_msgs + nav_msgs + sensor_msgs + nodelet + tf + autorally_msgs + autorally_core + cmake_modules + dynamic_reconfigure + + roscpp + message_runtime + std_msgs + geometry_msgs + nav_msgs + sensor_msgs + nodelet + tf + autorally_msgs + autorally_core + dynamic_reconfigure + + + + + + diff --git a/autorally_control/src/ConstantSpeedController/CMakeLists.txt b/autorally_control/src/ConstantSpeedController/CMakeLists.txt new file mode 100644 index 00000000..a9b4ef48 --- /dev/null +++ b/autorally_control/src/ConstantSpeedController/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(ConstantSpeedController ConstantSpeedController.cpp) +add_dependencies(ConstantSpeedController autorally_msgs_gencpp) +target_link_libraries(ConstantSpeedController ${catkin_LIBRARIES} ${Boost_LIBRARIES} RingBuffer) + +install(TARGETS + ConstantSpeedController + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) diff --git a/autorally_control/src/ConstantSpeedController/ConstantSpeedController.cpp b/autorally_control/src/ConstantSpeedController/ConstantSpeedController.cpp new file mode 100644 index 00000000..c21c41e3 --- /dev/null +++ b/autorally_control/src/ConstantSpeedController/ConstantSpeedController.cpp @@ -0,0 +1,217 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file servoInterface.cpp + * @author Brian Goldfain + * @date April 14,, 2014 + * @copyright 2014 Georgia Institute of Technology + * @brief Controller to drive robot at constant speed + * + * @details Detailed file description starts here. + ***********************************************/ + +#include +#include + +#include "ConstantSpeedController.h" + +#define PI 3.14159265 +#define DEGTORAD (PI/180) + +PLUGINLIB_DECLARE_CLASS(control, ConstantSpeedController, control::ConstantSpeedController, nodelet::Nodelet) + +namespace control +{ + +ConstantSpeedController::ConstantSpeedController(): + m_controllerState(DISABLED), + m_constantSpeedPrevThrot(0.0), + m_controlEnabled(true), + m_frontWheelsSpeed(0.0), + m_backWheelsSpeed(0.0), + m_integralError(0.0), + m_servoMSG(new autorally_msgs::servoMSG) +{} + +ConstantSpeedController::~ConstantSpeedController() +{} + +void ConstantSpeedController::onInit() +{ + NODELET_INFO("ConstantSpeedController initialization"); + ros::NodeHandle nh = getNodeHandle(); + ros::NodeHandle nhPvt = getPrivateNodeHandle(); + + loadThrottleCalibration(); + + m_mostRecentSafeSpeed.speed = 0; + + m_safeSpeedSub = nh.subscribe("safeSpeed", 1, + &ConstantSpeedController::safeSpeedCallback, this); + m_wheelSpeedsSub = nh.subscribe("wheelSpeeds", 1, + &ConstantSpeedController::wheelSpeedsCallback, + this); + m_servoMSGPub = nh.advertise + ("constantSpeedController/servoCommand", 1); + + if(!nhPvt.getParam("speedCommander", m_speedCommander) || + !nhPvt.getParam("accelerationRate", m_accelerationRate) || + !nhPvt.getParam("accelerationRate", m_accelerationRate) || + !nhPvt.getParam("KP", m_constantSpeedKP) || + !nhPvt.getParam("KD", m_constantSpeedKD) || + !nhPvt.getParam("KI", m_constantSpeedKI) || + !nhPvt.getParam("IMax", m_constantSpeedIMax)) + { + NODELET_ERROR("Could not get all ConstantSpeedController params"); + } + + m_servoMSG->header.frame_id = "constantSpeedController"; + m_servoMSG->steering = -5.0; + m_servoMSG->frontBrake = 0.0; + m_servoMSG->backBrake = 0.0; + + //m_accelerationProfile = generateAccelerationProfile(100); + + m_controlTimer = nh.createTimer(ros::Rate(1), + &ConstantSpeedController::controlCallback, this); + /*m_controlEnableTimer = nh.createTimer(ros::Rate(0.2), + &ConstantSpeedController::enableControlCallback, this);*/ + NODELET_INFO("ConstantSpeedController initialization complete"); + +} + +void ConstantSpeedController::safeSpeedCallback(const autorally_msgs::safeSpeedConstPtr& msg) +{ + //if the safespeed is from sender who can command the constant speed controller + //if(msg->sender == m_speedCommander) + //{ + if (m_mostRecentSafeSpeed.speed != msg->speed) + { + NODELET_INFO("ConstantSpeedController: set safespeed to %f", msg->speed); + } + m_mostRecentSafeSpeed = *msg; + //} + //else + //{ + //NODELET_WARN("ConstantSpeedController: safespeed from invalid source"); + //} +} + +void ConstantSpeedController::wheelSpeedsCallback(const autorally_msgs::wheelSpeedsConstPtr& msg) +{ + m_frontWheelsSpeed = 0.5*(msg->lfSpeed + msg->rfSpeed); + //m_backWheelsSpeed = 0.2*m_backWheelsSpeed + 0.4*(msg->lbSpeed + msg->rbSpeed); + + if (m_mostRecentSafeSpeed.speed > 0.1) + { + m_servoMSG->header.stamp = ros::Time::now(); + double p; + if(m_throttleMappings.interpolateKey(m_mostRecentSafeSpeed.speed, p)) + { + m_integralError += m_mostRecentSafeSpeed.speed - m_frontWheelsSpeed; + if (m_integralError > (m_constantSpeedIMax / m_constantSpeedKI)) + { + m_integralError = (m_constantSpeedIMax / m_constantSpeedKI); + } + + if (m_integralError < -(m_constantSpeedIMax / m_constantSpeedKI)) + { + m_integralError = -(m_constantSpeedIMax / m_constantSpeedKI); + } + + m_servoMSG->throttle = p + + m_constantSpeedKP*(m_mostRecentSafeSpeed.speed - m_frontWheelsSpeed); + m_servoMSG->throttle += m_constantSpeedKI * m_integralError; + m_servoMSG->throttle = std::max(0.0, std::min(1.0, m_servoMSG->throttle)); + + NODELET_INFO("interp %f, command %f",p, m_servoMSG->throttle); + m_servoMSGPub.publish(m_servoMSG); + m_constantSpeedPrevThrot = p; + } + else + { + NODELET_WARN("ConstantSpeedController could not interpolate speed %f", m_mostRecentSafeSpeed.speed); + m_servoMSG->throttle = 0; + } + } + else + { + m_servoMSG->throttle = 0; + m_servoMSGPub.publish(m_servoMSG); + } +} + +/*void ConstantSpeedController::enableControlCallback(const ros::TimerEvent& time) +{ + ros::NodeHandle nhPvt = getPrivateNodeHandle(); + if(!nhPvt.getParam("controlEnabled", m_controlEnabled) ) + { + NODELET_ERROR("Could not update ConstantSpeedController params"); + } +}*/ + +void ConstantSpeedController::controlCallback(const ros::TimerEvent& time) +{ + ros::NodeHandle nhPvt = getPrivateNodeHandle(); + nhPvt.getParam("KP", m_constantSpeedKP); + nhPvt.getParam("KD", m_constantSpeedKD); + nhPvt.getParam("KI", m_constantSpeedKI); + nhPvt.getParam("IMax", m_constantSpeedIMax); + +} + +void ConstantSpeedController::loadThrottleCalibration() +{ + NODELET_INFO("Loading calibration"); + ros::NodeHandle nhPvt = getPrivateNodeHandle(); + XmlRpc::XmlRpcValue v; + nhPvt.param("throttleCalibration", v, v); + std::map::iterator mapIt; + for(mapIt = v.begin(); mapIt != v.end(); mapIt++) + { + if(mapIt->second.getType() == XmlRpc::XmlRpcValue::TypeDouble) + { + std::pair toAdd(std::pair( + boost::lexical_cast(mapIt->first), + static_cast(mapIt->second))); + NODELET_INFO_STREAM("ConstantSpeedController added to add mapping " << + toAdd.first << ":" << toAdd.second); + if(!m_throttleMappings.update(toAdd)) + { + NODELET_ERROR_STREAM("ConstantSpeedController Failed to add mapping " << + toAdd.first << ":" << toAdd.second); + } + } else + { + NODELET_ERROR("ConstantSpeedController: XmlRpc throttle calibration formatted incorrectly"); + } + } + NODELET_INFO_STREAM("ConstantSpeedController: Loaded " << + m_throttleMappings.size() << + " throttle mappings"); +} + +} diff --git a/autorally_control/src/ConstantSpeedController/ConstantSpeedController.h b/autorally_control/src/ConstantSpeedController/ConstantSpeedController.h new file mode 100644 index 00000000..bc017dd5 --- /dev/null +++ b/autorally_control/src/ConstantSpeedController/ConstantSpeedController.h @@ -0,0 +1,114 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file ConstantSpeedController.h + * @author Brian Goldfain + * @date November 13, 2013 + * @copyright 2012 Georgia Institute of Technology + * @brief ConstantSpeedController class definition + * + ***********************************************/ +#ifndef JUMP_CONTROL_H_ +#define JUMP_CONTROL_H_ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +//#include + +namespace control +{ + +class ConstantSpeedController : public nodelet::Nodelet +{ + public: + ConstantSpeedController(); + ~ConstantSpeedController(); + void onInit(); + + private: + enum SpeedControllerState + { + DISABLED, + SETUP, + ACCELERATING, + MAINTAINING_SPEED, + }; + + SpeedControllerState m_controllerState; + ros::Subscriber m_safeSpeedSub; + ros::Subscriber m_wheelSpeedsSub; + ros::Publisher m_servoMSGPub; /// m_throttleMappings; + std::vector m_accelerationProfile; + void safeSpeedCallback(const autorally_msgs::safeSpeedConstPtr& msg); + void wheelSpeedsCallback(const autorally_msgs::wheelSpeedsConstPtr& msg); + + void enableControlCallback(const ros::TimerEvent& time); + void controlCallback(const ros::TimerEvent& time); + + std::vector generateAccelerationProfile(const int count); + void loadThrottleCalibration(); + +}; + +} +#endif //JUMP_CONTROL_H_ diff --git a/autorally_control/src/gpsWaypoint/CMakeLists.txt b/autorally_control/src/gpsWaypoint/CMakeLists.txt new file mode 100644 index 00000000..706c653c --- /dev/null +++ b/autorally_control/src/gpsWaypoint/CMakeLists.txt @@ -0,0 +1,19 @@ +#set(CMAKE_VERBOSE_MAKEFILE on) + + +#only compile if odeint is installed (this is a workaround for now since odeint +#does not come in a version fo boost that ROS depends on yet (need boost >= 1.53) + +add_executable(gpsWaypoint gpsWaypoint.cpp) +add_dependencies(gpsWaypoint autorally_msgs_gencpp ${PROJECT_NAME}_gencfg) +target_link_libraries(gpsWaypoint ${catkin_LIBRARIES} ${Boost_LIBRARIES}) + +catkin_install_python(PROGRAMS GenerateWaypoints + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}) + +install(TARGETS + gpsWaypoint + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} + ) diff --git a/autorally_control/src/gpsWaypoint/GenerateWaypoints b/autorally_control/src/gpsWaypoint/GenerateWaypoints new file mode 100755 index 00000000..21ca21f1 --- /dev/null +++ b/autorally_control/src/gpsWaypoint/GenerateWaypoints @@ -0,0 +1,76 @@ +#!/usr/bin/env python +import rospy +from std_msgs.msg import String +from nav_msgs.msg import Odometry +from geometry_msgs.msg import PoseArray +from geometry_msgs.msg import Point +from visualization_msgs.msg import Marker + +class WaypointGen(): + + def GpsCallback(self, data): + position = data.pose.pose.position + + #print position + + if len(self.points) < 1: + print 'grabbed first position' + self.points.append(position) + self.xOff = position.x + self.yOff = position.y + + if dist2D(self.points[-1],position) > self.wptDist: + #self.points.append(position) + + self.points.append(Point(position.x,position.y,position.z)) + + rospy.loginfo('Added ' + str(position.x) + ' ' + str(position.y)) + + # Write it to a file + f = open(self.filename, 'w') + for wpt in self.points: + f.write(str(wpt.x) + ',' + str(wpt.y) + '\n') + f.close() + + wptMarker = Marker() + wptMarker.header.frame_id = "base_footprint" + wptMarker.header.stamp = rospy.Time() + wptMarker.type = Marker.SPHERE + wptMarker.id = 1 + for wpt in self.points: + #wptMarker.pose.position = wpt + wptMarker.pose.position.x = wpt.x - self.xOff + wptMarker.pose.position.y = wpt.y - self.yOff + #print str(wpt.x - self.xOff) + ' ' + str(wpt.y - self.yOff) + wptMarker.pose.position.z = 0 + wptMarker.scale.x = self.wptDist + wptMarker.scale.y = self.wptDist + wptMarker.scale.z = self.wptDist + wptMarker.color.a = 1.0 + wptMarker.color.r = 0.0 + wptMarker.color.g = 1.0 + wptMarker.color.b = 0.0 + self.markerPub.publish(wptMarker) + wptMarker.id += 1 + + + def __init__(self): + self.wptDist = rospy.get_param('~WaypointDistance', 1.5) + self.filename = rospy.get_param('~WaypointFile','waypoints.txt') + + rospy.Subscriber("~gps", Odometry, self.GpsCallback) + self.wptPub = rospy.Publisher("~waypoints", PoseArray, latch=True, queue_size=1) + self.markerPub = rospy.Publisher("~markers", Marker, queue_size=20) + self.points = [] + + while not rospy.is_shutdown(): + rospy.sleep(1.0) + +def dist2D(pt1, pt2): + #print pt1 + #print pt2 + return ((pt2.x - pt1.x)**2.0 + (pt2.y - pt1.y)**2.0)**(0.5) + +if __name__ == '__main__': + rospy.init_node('wpgenerator') + theNode = WaypointGen() \ No newline at end of file diff --git a/autorally_control/src/gpsWaypoint/gpsWaypoint.cpp b/autorally_control/src/gpsWaypoint/gpsWaypoint.cpp new file mode 100644 index 00000000..501bc35c --- /dev/null +++ b/autorally_control/src/gpsWaypoint/gpsWaypoint.cpp @@ -0,0 +1,317 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file gpsWaypoint.cpp + * @author Paul Drews + * @date January 29, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief ROS node to allow following gps waypoints + * + * @details Waypoints are read in from a configuration file. + * The waypoints are assumed to be a loop. Once each waypoint is reached, + * the controller will push it to the back of the list and move to the next. + ***********************************************/ + +#include +#include +#include "gpsWaypoint.h" + +namespace autorally_control +{ + + GpsWaypoint::GpsWaypoint() : + m_nh("~"), m_speed(0.0), m_useThetaGPS(true), m_prevTime(0.0) + { + m_nh.param("WaypointFile", m_filename, std::string("Waypoints")); + m_nh.param("WaypointRadius", m_wpRadius, 1.5); + m_nh.param("HeadingP", m_headingP, 2.0); + + m_speedSub = m_nh.subscribe("Speeds", 1, &GpsWaypoint::Speedcb, this); + m_odomSub = m_nh.subscribe("Odom", 1, &GpsWaypoint::Odomcb, this); +// m_poseSub = m_nh.subscribe("Pose", 1, &GpsWaypoint::Posecb, this); + + m_servoPub = m_nh.advertise("WPController/servoCommand", 1); + vis_pub = m_nh.advertise( "markers", 200 ); + m_maskPub = m_nh.advertise("imageMask", 1); + m_imMask.sender = "Waypoint Follower"; + m_imMask.lines.push_back(autorally_msgs::line2D()); + m_imMask.lines[0].start.x = 256; + m_imMask.lines[0].start.y = 320; + + std::ifstream wptFile; + ROS_INFO("Opening file %s", m_filename.c_str()); + wptFile.open(m_filename.c_str()); + std::string curLine; +// m_paramTimer = m_nh.createTimer(ros::Rate(1), +// &GpsWaypoint::paramCallback, this); + while(getline(wptFile, curLine)) + { + double x, y; + geometry_msgs::Point pt; + std::vector strs; + boost::split(strs, curLine, boost::is_any_of(",")); + if (strs.size() == 2) + pt.x = boost::lexical_cast(strs[0]); + pt.y = boost::lexical_cast(strs[1]); + ROS_INFO("Loaded waypoint %f %f", pt.x, pt.y); + m_wpts.push_back(pt); + } + wptFile.close(); + m_offsetX = m_wpts.front().x; + m_offsetY = m_wpts.front().y; + + dynamic_reconfigure::Server::CallbackType cb; + + cb = boost::bind(&GpsWaypoint::ConfigCallback, this, _1, _2); + m_dynServer.setCallback(cb); + ros::Duration d = ros::Duration(1.0); + d.sleep(); + PublishMarkers_track(); + } + + GpsWaypoint::~GpsWaypoint() + {} + + void GpsWaypoint::Speedcb(autorally_msgs::wheelSpeeds speeds) + { + m_lock.lock(); + m_speed = (speeds.lfSpeed + speeds.rfSpeed) / 2.0; + m_lock.unlock(); + } + + void GpsWaypoint::Odomcb(nav_msgs::Odometry position) + { + double speed; + double x, y, theta; + m_lock.lock(); + m_prevPos = m_position; + m_position = position; + speed = m_speed; + x = position.pose.pose.position.x; + y = position.pose.pose.position.y; + + // Get our heading from the message + double roll,pitch,yaw; + tf::Quaternion quat(position.pose.pose.orientation.x, + position.pose.pose.orientation.y, + position.pose.pose.orientation.z, + position.pose.pose.orientation.w); + tf::Matrix3x3(quat).getRPY(roll, pitch, yaw); + + double deltaX = x - m_prevPos.pose.pose.position.x; + double deltaY = y - m_prevPos.pose.pose.position.y; + double thetaGPS = atan2(deltaY,deltaX); + m_lock.unlock(); + + if (m_useThetaGPS) + theta = thetaGPS; + else + theta = yaw; + // Now we have all the latest data, do some maths + // Are we at the next waypoint? + double xn = m_wpts.front().x; + double yn = m_wpts.front().y; + while (GetDist(x,y,xn,yn) < m_wpRadius) + { + // Get the next wp + m_wpts.push_back(m_wpts.front()); + m_wpts.pop_front(); + xn = m_wpts.front().x; + yn = m_wpts.front().y; + //ROS_INFO("Hit a waypoint"); + } + // UTM is a ENU system + // imugps node uses a local ENU system + // so our heading is measured from the positive x axis, meaning 0 is pointing east + // and this lets a normal x-y axis system drawn on paper represent our system with x pointing up. + + double bearing = atan2(yn-y,xn-x); + double error = AngleDiff(bearing, theta); + + autorally_msgs::servoMSG servos; + servos.throttle = -5.0; + servos.frontBrake = -5.0; + servos.backBrake = -5.0; + servos.steering = Clamp(m_headingP * error,-1.0,1.0); + + servos.header.stamp = ros::Time::now(); + servos.header.frame_id = "WPController"; + m_servoPub.publish(servos); + + //m_imMask.lines[0].end.x = 256 - (100 * cos((servos.steering * PI / 2.0) + PI/2.0)); + //m_imMask.lines[0].end.y = 320 - (100 * sin((servos.steering * PI / 2.0) + PI/2.0)); + double time = ros::Time::now().toSec(); + + if (time > (m_prevTime + 0.1)) + { + m_prevTime = time; + m_imMask.lines[0].end.x = 256 - (100 * sin(servos.steering * PI / 2.0)); + m_imMask.lines[0].end.y = 320 - (100 * cos(servos.steering * PI / 2.0)); + std::cout << " Error " << error << " Steering " << servos.steering; + std::cout << "At theta " << theta << " bearing " << bearing; + std::cout << " x " << x << " y " << y << std::endl; + std::cout << " xn " << xn << " yn " << yn << std::endl; + std::cout << " dx " << deltaX<< " dy " << deltaY << std::endl; + m_maskPub.publish(m_imMask); + + PublishMarkers(x,y,theta,xn,yn); + } + + } +// void GpsWaypoint::Posecb(sensor_msgs::Imu pose) +// { +// m_lock.lock(); +// m_pose = pose; +// m_lock.unlock(); +// } +//void GpsWaypoint::paramCallback(const ros::TimerEvent& time) +//{ +// m_nh.param("HeadingP", m_headingP, 2.0); +//} + + double GpsWaypoint::GetDist(double x1, double y1, double x2, double y2) + { + return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); + } + + double GpsWaypoint::AngleDiff(double a, double b) + { + double dif = fmod(a-b + PI, 2.0*PI); + if (dif < 0) + dif += 2.0*PI; + return dif - PI; + } + + double GpsWaypoint::Clamp(double num, double min, double max) + { + if (num < min) + num = min; + if (num > max) + num = max; + return num; + } + + void GpsWaypoint::PublishMarkers(double x, double y, double yaw, double xwp, double ywp) + { + visualization_msgs::Marker marker; + marker.header.frame_id = "LocalFrame"; + marker.header.stamp = ros::Time(); + marker.ns = "gps"; + marker.id = 0; + marker.type = visualization_msgs::Marker::ARROW; + marker.action = visualization_msgs::Marker::ADD; + marker.pose.position.x = x - m_offsetX; + marker.pose.position.y = y - m_offsetY; + marker.pose.position.z = 1; + tf::Quaternion q; + q.setRPY(0.0, 0.0, (yaw )); + marker.pose.orientation.x = q.getX(); + marker.pose.orientation.y = q.getY(); + marker.pose.orientation.z = q.getZ(); + marker.pose.orientation.w = q.getW(); + marker.scale.x = 1; + marker.scale.y = 0.1; + marker.scale.z = 0.1; + marker.color.a = 1.0; + marker.color.r = 1.0; + marker.color.g = 0.0; + marker.color.b = 0.0; + vis_pub.publish( marker ); + + std::list::const_iterator iter; + iter = m_wpts.begin(); + marker.header.frame_id = "LocalFrame"; + marker.header.stamp = ros::Time(); + marker.ns = "gps"; + marker.id = 1; + marker.type = visualization_msgs::Marker::SPHERE; + marker.action = visualization_msgs::Marker::ADD; + marker.pose.position.x = iter->x - m_offsetX; + marker.pose.position.y = iter->y - m_offsetY; + marker.pose.position.z = 1; + marker.pose.orientation.x = 0; + marker.pose.orientation.y = 0; + marker.pose.orientation.z = 0; + marker.pose.orientation.w = 1; + marker.scale.x = 0.7; + marker.scale.y = 0.7; + marker.scale.z = 0.7; + marker.color.a = 1.0; + marker.color.r = 0.0; + marker.color.g = 1.0; + marker.color.b = 0.0; + vis_pub.publish( marker ); +} + void GpsWaypoint::PublishMarkers_track() + { + visualization_msgs::Marker marker; + + marker.id = 2; + std::list::const_iterator iter; + for (iter = m_wpts.begin(); iter != m_wpts.end(); ++iter) { + marker.header.frame_id = "LocalFrame"; + marker.header.stamp = ros::Time(); + marker.ns = "gps"; + marker.id ++; + marker.type = visualization_msgs::Marker::SPHERE; + marker.action = visualization_msgs::Marker::ADD; + marker.pose.position.x = iter->x - m_offsetX; + marker.pose.position.y = iter->y - m_offsetY; + marker.pose.position.z = 1; + marker.pose.orientation.x = 0; + marker.pose.orientation.y = 0; + marker.pose.orientation.z = 0; + marker.pose.orientation.w = 1; + marker.scale.x = 0.7; + marker.scale.y = 0.7; + marker.scale.z = 0.7; + marker.color.a = 0.2; + marker.color.r = 1.0; + marker.color.g = 0.0; + marker.color.b = 0.0; + vis_pub.publish( marker ); + std::cout << "Published " << marker.id << std::endl; + } + + //ROS_INFO("Publish markers at %f %f and %f %f", x, y, xwp, ywp); + } + + void GpsWaypoint::ConfigCallback(const gpsWaypoint_paramsConfig &config, uint32_t level) + { + m_headingP = config.pGain; + m_useThetaGPS = config.gpsHeading; + m_wpRadius = config.wpRadius; + std::cout << "Got a config!!" << std::endl; + } +}; + +int main (int argc, char** argv) +{ + ros::init(argc, argv, "GpsWaypoint"); + //ros::NodeHandle n; + autorally_control::GpsWaypoint wpt; + ros::spin(); +} diff --git a/autorally_control/src/gpsWaypoint/gpsWaypoint.h b/autorally_control/src/gpsWaypoint/gpsWaypoint.h new file mode 100644 index 00000000..56ebc32e --- /dev/null +++ b/autorally_control/src/gpsWaypoint/gpsWaypoint.h @@ -0,0 +1,115 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file JumpControl.h + * @author Brian Goldfain + * @date November 13, 2013 + * @copyright 2012 Georgia Institute of Technology + * @brief JumpControl class definition + * + ***********************************************/ + +#ifndef GPS_WAYPOINT_H_ +#define GPS_WAYPOINT_H_ + +#include +#include +#include + +#include // Mutex +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define PI 3.14159265358979323846264338 + +namespace autorally_control +{ + class GpsWaypoint + { + public: + GpsWaypoint(); + ~GpsWaypoint(); + private: + ros::NodeHandle m_nh; + ros::Subscriber m_speedSub; + ros::Subscriber m_odomSub; + ros::Subscriber m_poseSub; + ros::Publisher m_servoPub; + ros::Publisher vis_pub; + ros::Timer m_paramTimer; + + + std::string m_filename; + + std::list m_wpts; +// sensor_msgs::Imu m_pose; + nav_msgs::Odometry m_position; + nav_msgs::Odometry m_prevPos; + double m_speed; + double m_wpRadius; + double m_headingP; + bool m_useThetaGPS; + double m_offsetX, m_offsetY; + double m_prevTime; + + dynamic_reconfigure::Server m_dynServer; + + tf::TransformListener m_tf; + + boost::mutex m_lock; + + autorally_msgs::imageMask m_imMask; + ros::Publisher m_maskPub; ///< Publisher for steering angle commands + + void Speedcb(autorally_msgs::wheelSpeeds speeds); + void Odomcb(nav_msgs::Odometry position); + void Posecb(sensor_msgs::Imu pose); + void paramCallback(const ros::TimerEvent& time); + double GetDist(double x1, double y1, double x2, double y2); + double AngleDiff(double a, double b); + double Clamp(double num, double min, double max); + void PublishMarkers(double x, double y, double yaw, double xwp, double ywp); + void PublishMarkers_track(); + void ConfigCallback(const gpsWaypoint_paramsConfig &config, uint32_t level); + + + }; +}; +#endif diff --git a/autorally_control/src/joystick/CMakeLists.txt b/autorally_control/src/joystick/CMakeLists.txt new file mode 100644 index 00000000..ee4c76ee --- /dev/null +++ b/autorally_control/src/joystick/CMakeLists.txt @@ -0,0 +1,12 @@ +add_executable(joystickController + joystickControlMain.cpp + JoystickControl.cpp) +add_dependencies(joystickController autorally_msgs_gencpp) +target_link_libraries(joystickController ${catkin_LIBRARIES}) + +install(TARGETS + joystickController + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) diff --git a/autorally_control/src/joystick/JoystickControl.cpp b/autorally_control/src/joystick/JoystickControl.cpp new file mode 100644 index 00000000..c42ddefd --- /dev/null +++ b/autorally_control/src/joystick/JoystickControl.cpp @@ -0,0 +1,159 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file hpiController.cpp + * @author Brian Goldfain + * @date January 19, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief Brief file description + * Brief description continued. + * + * @details Detailed file description starts here. + ***********************************************/ + +#include "JoystickControl.h" + +JoystickControl::JoystickControl(): + m_throttleDamping(0.0), + m_steeringDamping(0.0), + m_throttleEnabled(true), + m_steeringEnabled(true) +{ + m_joySub = m_nh.subscribe("joy", 1, &JoystickControl::joyCallback, this); + + m_commandPub = m_nh.advertise + + ("joystick/servoCommand", 5); + m_safeSpeedPub = m_nh.advertise + + ("safeSpeed", 1); + m_servoCommand = autorally_msgs::servoMSGPtr(new autorally_msgs::servoMSG); + m_servoCommand->header.frame_id = "joystick"; + m_safeSpeed = autorally_msgs::safeSpeedPtr(new autorally_msgs::safeSpeed); + m_safeSpeed->sender = "joystick"; + m_safeSpeed->speed = 0.0; + + if(!m_nh.getParam("joystickController/throttleDamping", m_throttleDamping) || + !m_nh.getParam("joystickController/steeringDamping", m_steeringDamping) || + !m_nh.getParam("joystickController/throttleAxis", m_throttleAxis) || + !m_nh.getParam("joystickController/steeringAxis", m_steeringAxis) || + !m_nh.getParam("joystickController/safeSpeedIncButton", m_safeSpeedIncButton) || + !m_nh.getParam("joystickController/safeSpeedDecButton", m_safeSpeedDecButton) || + !m_nh.getParam("joystickController/safeSpeedZeroButton1", m_safeSpeedZeroButton1) || + !m_nh.getParam("joystickController/safeSpeedZeroButton2", m_safeSpeedZeroButton2) || + !m_nh.getParam("joystickController/throttleEnableButton", m_throttleEnableButton) || + !m_nh.getParam("joystickController/steeringEnableButton", m_steeringEnableButton) || + !m_nh.getParam("joystickController/throttleBrakePaired", m_throttleBrakePaired) || + !m_nh.getParam("joystickController/frontBrake", m_frontBrake) || + !m_nh.getParam("joystickController/brakeAxis", m_brakeAxis) ) + { + ROS_ERROR_STREAM("Couldn't get joystick control parameters"); + } + + m_safeSpeedTimer = m_nh.createTimer(ros::Rate(5), + &JoystickControl::safeSpeedCallback, + this); + +} + +JoystickControl::~JoystickControl() +{} + +void JoystickControl::joyCallback(const sensor_msgs::Joy::ConstPtr& joy) +{ + /* axes[0] is left/right of left sitck, axes[3] is up/down of right stick + * I scale the range of values from the joystick [-1,1] to the range of + * valid servo command values [0-254], and reverse the steering command so it + * is drives as expected. + */ + + if(joy->buttons[m_safeSpeedIncButton] == 1 && m_safeSpeed->speed > 0.0) + { + m_safeSpeed->speed -= 0.5; + } else if(joy->buttons[m_safeSpeedDecButton] == 1) + { + m_safeSpeed->speed += 0.5; + } else if(joy->buttons[m_safeSpeedZeroButton1] == 1 || joy->buttons[m_safeSpeedZeroButton2] == 1) + { + m_safeSpeed->speed = 0.0; + } + + //can enable/disable throttle control with left bumpers on game pad + if(joy->buttons[m_throttleEnableButton] == 1) + { + m_throttleEnabled = !m_throttleEnabled; + } + + //can enable/disable steering control with right bumpers on game pad + if(joy->buttons[m_steeringEnableButton] == 1) + { + m_steeringEnabled = !m_steeringEnabled; + } + + if(m_steeringEnabled) + { + m_servoCommand->steering = -m_steeringDamping*joy->axes[m_steeringAxis]; + } else + { + m_servoCommand->steering = -10.0; + } + + if(m_throttleEnabled) + { + + //if m_throttleBrakePaired, then throttle can be [-1,1], + //otherwise require throttle to be in [0, 1] + if(m_throttleBrakePaired) + { + m_servoCommand->throttle = m_throttleDamping*joy->axes[m_throttleAxis]; + } + else + { + m_servoCommand->throttle = std::max((double)(m_throttleDamping*joy->axes[m_throttleAxis]), 0.0); + } + + if(m_frontBrake && m_servoCommand->throttle < 0.0) + { + m_servoCommand->frontBrake = abs(m_servoCommand->throttle); + } else + { + m_servoCommand->frontBrake = 0.0; + } + } else + { + m_servoCommand->throttle = -10.0; + m_servoCommand->frontBrake = -10.0; + } + + m_servoCommand->header.stamp = ros::Time::now(); + m_commandPub.publish(m_servoCommand); +} + +void JoystickControl::safeSpeedCallback(const ros::TimerEvent& time) +{ + m_safeSpeed->header.stamp = ros::Time::now(); + m_safeSpeedPub.publish(m_safeSpeed); +} diff --git a/autorally_control/src/joystick/JoystickControl.h b/autorally_control/src/joystick/JoystickControl.h new file mode 100644 index 00000000..67423602 --- /dev/null +++ b/autorally_control/src/joystick/JoystickControl.h @@ -0,0 +1,111 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file JoystickControl.h + * @author Brian Goldfain + * @date January 29, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief Use a joystick or gamepad connected to the the computer + * to control the throttle/brake and steering commands + * + * @details This file contains the JoystickControl class + ***********************************************/ +#ifndef JOYSTICK_CONTROL_H_ +#define JOYSTICK_CONTROL_H_ + +//#include "autorally_msgs/servoControllerMSG.h" +#include +#include +#include +#include +#include + +/** + * @class JoystickControl JoystickControl.h "joystick/JoystickControl.h" + * @brief Use a joystick or gamepad connected to the computer to send out + * ServoControllerCommand messages + * + * The default configuration is for a gamepad with two joysticks. The left + * stick controlls the steering and the right stick controls the trottle. + * Make sure that ROS is able to access the input device of choice before + * running. This class is not meant to be used to freal time control, it is + * for component testing purposes and demonstration. + * + * @note in order to receive joy messages from ROS the joystick path must be + * set with [rosparam set joy_node/dev "/dev/input/js0"] if not already set. + * Also, joy must be running: [rosrun joy joy_node] + * + */ +class JoystickControl +{ + public: + /** + * Constructor registers callbacks and advertises message that will be + * published + * + */ + JoystickControl(); + ~JoystickControl(); + + /** + * Callback for receiving new joystick state data + * @see sensor_messages::joy + * @param joy the message received from ros comms + */ + void joyCallback(const sensor_msgs::Joy::ConstPtr& joy); + + void safeSpeedCallback(const ros::TimerEvent& time); + + ros::Subscriber m_joySub; ///< Channel to receive joystick state +// ros::Subscriber m_statusSub; ///< Channel to receive servo status + ros::Publisher m_commandPub; ///< Channel to publish servo commands + ros::Publisher m_safeSpeedPub; ///< Channel to publish servo commands + ros::Timer m_safeSpeedTimer; + private: + ros::NodeHandle m_nh; + + autorally_msgs::servoMSGPtr m_servoCommand; ///< command message + autorally_msgs::safeSpeedPtr m_safeSpeed; ///< command message + double m_throttleDamping; + double m_steeringDamping; + + bool m_throttleEnabled; + bool m_steeringEnabled; + bool m_throttleBrakePaired; + bool m_frontBrake; + + int m_throttleAxis; + int m_steeringAxis; + int m_brakeAxis; + int m_safeSpeedIncButton; + int m_safeSpeedDecButton; + int m_safeSpeedZeroButton1; + int m_safeSpeedZeroButton2; + int m_throttleEnableButton; + int m_steeringEnableButton; +}; + +#endif //JOYSTICK_CONTROL_H_ diff --git a/autorally_control/src/joystick/joystickControlMain.cpp b/autorally_control/src/joystick/joystickControlMain.cpp new file mode 100644 index 00000000..d78cefdd --- /dev/null +++ b/autorally_control/src/joystick/joystickControlMain.cpp @@ -0,0 +1,47 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file hpiController.cpp + * @author Brian Goldfain + * @date January 19, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief Brief file description + * Brief description continued. + * + * @details Inits joystickControl + ***********************************************/ +#include "JoystickControl.h" + +int main(int argc, char **argv) +{ + ros::init(argc, argv, "joystickController"); + + JoystickControl joystick; + + ros::spin(); + + return 0; +} diff --git a/autorally_core/CMakeLists.txt b/autorally_core/CMakeLists.txt new file mode 100644 index 00000000..c3b0ec44 --- /dev/null +++ b/autorally_core/CMakeLists.txt @@ -0,0 +1,71 @@ +cmake_minimum_required(VERSION 2.8.3) +project(autorally_core) + +find_package(catkin REQUIRED COMPONENTS + roscpp + rospy + std_msgs + sensor_msgs + geometry_msgs + nav_msgs + image_transport + pluginlib + nodelet + autorally_msgs + tf +) + +find_package(cmake_modules REQUIRED) + +catkin_python_setup() + +catkin_package( + DEPENDS libqt4-dev lm-sensors Boost + CATKIN-DEPENDS roscpp rospy std_msgs geometry_msgs sensor_msgs nav_msgs image_transport qt-ros diagnostic_updater qt_build autorally_msgs + INCLUDE_DIRS include + LIBRARIES SerialSensorInterface SafeSpeed Diagnostics RingBuffer +) + +set(BUILD_FLAGS "-std=c++11 -Wuninitialized -Wall -Wextra") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${BUILD_FLAGS}") + +include_directories(include ${catkin_INCLUDE_DIRS} ${Boost_INCLUDE_DIR}) + +add_subdirectory(src/arduino) +add_subdirectory(src/ChronyStatus) +add_subdirectory(src/Diagnostics) +add_subdirectory(src/gps) +add_subdirectory(src/ocs) +add_subdirectory(src/RingBuffer) +add_subdirectory(src/RunStop) +add_subdirectory(src/SafeSpeed) +add_subdirectory(src/SerialSensorInterface) +add_subdirectory(src/servoInterface) +add_subdirectory(src/xbee) +add_subdirectory(src/ImageRepublisher) +add_subdirectory(src/StateEstimator) + +install(TARGETS + + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) + +install(PROGRAMS + src/systemStatus/systemStatus.py + src/ChronyStatus/chronyStatus.py + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}) + +install(DIRECTORY launch/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch + FILES_MATCHING PATTERN "*.launch" PATTERN "*.machine" PATTERN "*.yaml" PATTERN "*.urdf" +) + +install(DIRECTORY include/${PROJECT_NAME}/ + DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +) + +install(FILES nodelet_plugins.xml + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +) diff --git a/autorally_core/include/autorally_core/ChronyStatus.h b/autorally_core/include/autorally_core/ChronyStatus.h new file mode 100644 index 00000000..cc310fec --- /dev/null +++ b/autorally_core/include/autorally_core/ChronyStatus.h @@ -0,0 +1,94 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file ChronyStatus.h + * @author Brian Goldfain + * @date June 6, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief ChronyStatus class definition + * + ***********************************************/ +#ifndef CHRONY_STATUS_H_ +#define CHRONY_STATUS_H_ + +#include + +#include +#include + +#include +#include + +/** + * @class ChronyStatus ChronyStatus.h + * "autorally_core/ChronyStatus.h" + * @brief Publish time synchronization diagnostic information from chrony + * + */ +class ChronyStatus : public Diagnostics +{ + + public: + /** + * @brief ChronyStatus constructor + * @param nh NodeHandle used to register stuff + * @param nodeName name of the parent process + * @param hardwareID some string to identify the corresponding hardware + * @param port serial port to connect to + * + * Initializes a node monitor the clock offset values for all clients in the + * system that are running chrony + */ + ChronyStatus(ros::NodeHandle &nh, + const std::string nodeName, + const std::string hardwareID, + const std::string port); + ~ChronyStatus(); + + private: + std::string m_masterHostname; ///< hostname of the ros master + std::string m_hostname; ///< hostname where the program is executing + ros::Timer m_updateClientsTimer; ///< timer to update clients vector + std::vector m_clients; ///< list of clients setting their time using chrony + + /** + * @brief Timer triggered callback to update the client list by asking master + * @param time information about callback execution + */ + void updateClients(const ros::TimerEvent& time); + + /** + * @brief Timer triggered callback to publish time offsets of machines in the + * system. + * @param time information about callback execution + * + * Polls all known clients of master and publishes the respective estimated + * clock offsets with respect to ROS master. + */ + void diagnosticStatus(const ros::TimerEvent& time); + +}; +#endif //CHRONY_STATUS_H_ diff --git a/autorally_core/include/autorally_core/Diagnostics.h b/autorally_core/include/autorally_core/Diagnostics.h new file mode 100644 index 00000000..a69446a5 --- /dev/null +++ b/autorally_core/include/autorally_core/Diagnostics.h @@ -0,0 +1,165 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file Diagnostics.h + * @author Brian Goldfain + * @date June 6, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief Diagnostics class definition + * + ***********************************************/ +#ifndef DIAGNOSTICS_H_ +#define DIAGNOSTICS_H_ + +#include +#include +#include + +#include +#include + +/** + * @class Diagnostics Diagnostics.h + * "Diagnostics/Diagnostics.h" + * @brief Provide hardware diagnostic capabilities + * + * Aggregates and publishes diagnostic information. Uses a ros + * diagnostic_updator as the underlying mechanism to publish data. Messages + * have a corresponding level indicated by what method is called to queue the + * message. Diagnostics are meant for hardware components only. + * @note If a diagnostic publishing frequency other than 1s is required, define + * diagnosticsFrequency double in the parameter server with desired frequency. + * This sets the publish fequency of all diagnostics in the system. + * @note If the same message is queued between diagnostics being pubished, only + * one will be included in the next diagnostics message sent. There is no + * guarantee as to the level of the message if multiple messages were queued + * with identical message bodies using different levels (ok, warn, error). + */ +class Diagnostics +{ + public: + Diagnostics(); + /** + * @brief Diagnostics constructor + * @param nh NodeHandle used to register stuff + * @param otherInfo Short string of additional info about node + * @param hardwareID some string to identify the corresponding hardware + * @param hardwareLocation how or where the hardware is connected + * + * Initializes a diagnostic_updator and sets up a timer to trigger + * callback publishing at the desired frequency (1s default). + */ + Diagnostics(const std::string otherInfo, + const std::string hardwareID, + const std::string hardwareLocation); + ~Diagnostics(); + + void init(const std::string& otherInfo, + const std::string& hardwareID, + const std::string& hardwareLocation); + /** + * @brief Send a standard diagnostic message with a key:value + * @param key the key to queue + * @param value the value to queue + */ + void diag(const std::string key, const std::string value, bool lock = true); + + /** + * @brief Send a diagnostic message with level OK + * @param msg the diagnostic message to queue + */ + void diag_ok(const std::string msg); + + /** + * @brief Send a diagnostic message with level WARN + * @param msg the diagnostic message to queue + */ + void diag_warn(const std::string msg); + + /** + * @brief Send a diagnostic message with level ERROR + * @param msg the diagnostic message to queue + */ + void diag_error(const std::string msg); + + /** + * @brief Set the overall diagnostic message to level OK + */ + void OK(); + + /** + * @brief Set the overall diagnostic message to level WARN + */ + void WARN(); + + /** + * @brief Set the overall diagnostic message to level ERROR + */ + void ERROR(); + + /** + * @brief Accumulates frequency information for a named counter + * @param name The name of the counter to increment + * + * Calling tick every time a message is published will result in the + * publishing frequencies to be displayed in diagnostics. Tick can keep track + * of and publish multiple counters at once, identified by the message name. + */ + void tick(const std::string &name); + + private: + ros::Timer m_heartbeatTimer; ///< Timer to trigger diagnostic publishing + ros::Timer m_statusTimer; /// m_diagMsgs; ///< map of pending diagnostic messages + std::map m_diags; ///< map of pending standard messages + unsigned char m_overallLevel; ///< overall status level of the message + ///< Holds tick frequency counters + std::map > > m_ticks; + + boost::mutex m_dataMutex; ///< mutex for accessing data + + /** + * @brief Timer triggered callback to force publishing of diagnostics + * @param time information about callback execution + */ + void diagUpdate(const ros::TimerEvent&); + + /** + * @brief Callback triggered to form diagnostics message + * @param stat reference to diagnostic information to be published + */ + void diagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat); + + /** + * @brief Timer triggered callback to publish a diagnostic message + * @param time information about callback execution + */ + virtual void diagnosticStatus(const ros::TimerEvent& time) = 0; +}; +#endif //DIAGNOSTICS_H_ diff --git a/autorally_core/include/autorally_core/PololuMaestro.h b/autorally_core/include/autorally_core/PololuMaestro.h new file mode 100644 index 00000000..0bcbf87a --- /dev/null +++ b/autorally_core/include/autorally_core/PololuMaestro.h @@ -0,0 +1,125 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file PololuMaestro.h + * @author Brian Goldfain + * @date January 27, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief Interface for the Pololu Micro Maestro 6 channel servo controller + * + * @details This file contains the PololuMaestro class + ***********************************************/ +#ifndef POLOLU_MAESTRO_H_ +#define POLOLU_MAESTRO_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAX_CONTROL_VALUE 254 ///< Allowable control values are [0-254] +#define SERVO_NEUTRAL_VALUE 127 ///< Middle value that puts servo in neutral +#define SERVO_HOME_POSITION 255 ///< Sends the servo to its 'home' position + +/** + * @class PololuMaestro PololuMaestro.h + * "PololuMaestro/PololuMaestro.h" + * @brief Interact with a Pololu Micro Maestro servo controller + * + * Functionality includes setting servo positions and receiving feedback as + * to their actual position. Can also retrieve errors from the controller. + * Receives commands and broadcasts status using ServoControllerMSG. This + * class is currently set up to control a steering servo connected to port + * 0, a throttle/backBrake servo connected to port 1, and a front brake + * connected to port 2. It is easily extendable to control any servo outputs + * available. The class also publishes ros diagnostic messages on the + * "diagnostics" topic. + * Steering values are [-127, 127], -127 is full left, 127 is full right. + * Throtttle/back brake values are [-127, 127] 127 is full throttle, -127 is + * full back brake. + * Front brak vales are from [0-127] 127 is full front brake. + * + * @see http://www.pololu.com/docs/0J40 for documentation of the servo + * controller protocol + * + */ +class PololuMaestro +{ + public: + /** + * @brief Constructor requires all configuration needed to connect to controller + * and properly control connected servos + * + */ + PololuMaestro(); + + ~PololuMaestro(); + + void init(ros::NodeHandle &nh, const std::string& nodeName, const std::string& port); + + /** + * @brief Sends a low level set command over serial to set the position of a servo + * + * @param channel which channel (throttle or steering) should be set + * @param target value [0-254] for position left to right in range, + * 255 to go to 'home' position + */ + void setTarget(const unsigned char channel, const unsigned char target); + + /** + * @brief Sends a low level set command over serial to set the position of a servo + * + * @param channel which channel (throttle or steering) should be set + * @param target pulse width in 1/4 ms, for example, to set the pulse width to + * 1500ms, give a target value of 1500*4=6000 + */ + void setTargetMS(const unsigned char channel, const unsigned int target); + + /** + * @brief Sends a low level get command over serial to set the position of a servo + * + * @param channel on servo controller to read from + * @return Value [0-254] of requested channel (127 is neutral) + */ + unsigned short getTarget(const unsigned char channel); + + /** + * @brief Retrieve any existing error from control board + */ + void getErrors(); + + SerialInterfaceThreaded m_serialPort; + + private: + +}; + +#endif //POLOLU_MAESTRO_H_ diff --git a/autorally_core/include/autorally_core/RingBuffer.h b/autorally_core/include/autorally_core/RingBuffer.h new file mode 100644 index 00000000..108dc641 --- /dev/null +++ b/autorally_core/include/autorally_core/RingBuffer.h @@ -0,0 +1,78 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file RingBuffer.h + * @author Brian Goldfain + * @date January 17, 2013 + * @copyright 2012 Georgia Institute of Technology + * @brief RingBuffer class definition + * + ***********************************************/ +#ifndef TIME_TAGGED_RING_BUFFER_H_ +#define TIME_TAGGED_RING_BUFFER_H_ + +#include +#include + +#include + +namespace autorally_core +{ +/** + * @class RingBuffer RingBuffer.h + * "autorally_core/RingBuffer.h" + * @brief + * + * + */ +template +class RingBuffer +{ + public: + /** + * @brief Constructor for RingBuffer + * + */ + RingBuffer(); + ~RingBuffer(); + + bool update(std::pair &newData); + double maxKey() const; + double minKey() const; + bool interpolateKey(const double value, T &interpolated) const; + bool interpolateValue(const double key, T &interpolated) const; + T linearInterp(const T &first, + const T &second, + const double& distance) const; + int size() const {return m_ringBuffer.size();} + void clear() {m_ringBuffer.clear();} + + private: + boost::circular_buffer > m_ringBuffer; +}; + +} +#endif //TIME_TAGGED_RING_BUFFER_H_ diff --git a/autorally_core/include/autorally_core/SafeSpeed.h b/autorally_core/include/autorally_core/SafeSpeed.h new file mode 100644 index 00000000..1715d2a7 --- /dev/null +++ b/autorally_core/include/autorally_core/SafeSpeed.h @@ -0,0 +1,155 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file SafeSpeed.h + * @author Brian Goldfain + * @date June 6, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief SafeSpeed class definition + * + ***********************************************/ +#ifndef SAFE_SPEED_H_ +#define SAFE_SPEED_H_ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace autorally_core +{ + +/** + * @class SafeSpeed SafeSpeed.h + * "autorally_core/SafeSpeed.h" + * @brief Given current wheel speed information, generate a maximum throttle + * servo position to not drive faster than is considered "safe" + * + * Each node can publish what it believes to be the maximum safe speed the + * vehicle can travel, and safe speed computes a throttle servo position that + * limits the velocity of the vehicle to the minimum safe speed published. If + * there are no outside nodes commanding the throttle, SafeSpeed also acts as + * a constant speed controller for the vehicle, driving it at the minimum safe + * speed it receives. + */ +class SafeSpeed : public nodelet::Nodelet +{ + /** + *@brief Internal container for received safeSpeed values + */ + struct SafeSpeedData + { + ros::Time time; + double safeSpeed; + }; + + public: + /** + * @brief Constructor for SafeSpeed + * + */ + SafeSpeed(); + ~SafeSpeed(); + + virtual void onInit(); + void init(ros::NodeHandle &nh); + + /** + * @brief Calculates the current maximum safe speed. + * + * @return double The maximum safe speed in m/s + */ + double getSafeSpeed() const; + + /** + * @brief Sets the maximum safe speed. + * + * @param maxSafeSpeed The maximum safe speed + */ + void setMaxSpeed(const double& maxSafeSpeed); + + /** + * @brief Returns the global maximum speed configured on startup + * + * @return double The maximum global safe speed in m/s + */ + double maxSpeed() const; + + /** + * @brief Calculates the current maximum safe speed. + * + * @param throttleCommand the desired throttle value (from external source) + * @return double The safeThrottleValue. It will be less than or equal to + * throttleCommand + * + * In addition to monitoring that the vehicle does not exceed the safeSpeed, + * safeThrottle can produce an alternate throttle position that drives the + * vehicle at the safeSpeed. + */ + double safeThrottle(const double& throttleCommand); + + private: + struct WheelData { + autorally_msgs::wheelSpeeds msg; + double speed; + }; + + ros::Subscriber m_safeSpeedSub; ///< Subscriber for SafeSpeed messages + ros::Subscriber m_speedSub; ///< Subscriber for current vehicle speed + std::map m_safeSpeeds; ///< SafeSpeeds + double m_safeSpeedTimeout; ///< Maximum time to consider a safeSpeed valid + double m_maxSafeSpeed; ///< Maximum speed that vehicle can go + + boost::circular_buffer m_vehicleSpeeds; + + double m_prevGoodThrottle; + bool m_safeSpeedIsInControl; + + RingBuffer m_throttleMappings; + + /** + * @brief Callback for safe speed values + * @param msg the message received from ros comms + */ + void safeSpeedCallback(const autorally_msgs::safeSpeedConstPtr& msg); + + /** + * @brief Callback for current vehicle speed information + * @param msg the message received from ros comms + */ + void wheelSpeedsCallback(const autorally_msgs::wheelSpeedsConstPtr& msg); + + void loadThrottleCalibration(ros::NodeHandle &nh); +}; + +} +#endif //SAFE_SPEED_H_ diff --git a/autorally_core/include/autorally_core/SerialCommon.h b/autorally_core/include/autorally_core/SerialCommon.h new file mode 100644 index 00000000..761e48d8 --- /dev/null +++ b/autorally_core/include/autorally_core/SerialCommon.h @@ -0,0 +1,134 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file SerialCommon.h + * @author Brian Goldfain + * @date July 22, 2013 + * @copyright 2013 Georgia Institute of Technology + * @brief SerialCommon class definition + * + ***********************************************/ +#ifndef SERIAL_COMMON_H_ +#define SERIAL_COMMON_H_ + +#include + +#include +#include + +#include + +/** + * @class SerialCommon SerialCommon.h + * "autorally_core/SerialCommon.h" + * @brief Interact with a device on the serial port + * + * Provides the ability to connect to a specified serial device at 57600 baud + * with no parity, one stop bit, 8 data bits, no flow control. Includes + * functionality to automatically accumulate incoming data by polling. The read + * data is avaiable in m_data. Automatically sets up basic diagnostics based on + * the provided constructor parameters. + * @note The serial port setting configuraiton was taken loosely from: + * http://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c + */ +class SerialCommon : public Diagnostics +{ + + public: + + SerialCommon(); + /** + * @brief SerialCommon contructor + * + * Creates a dummy interface. Sets the portID as -1, + * does not set up diagnostics + */ + SerialCommon(const std::string& portHandle, + const std::string& hardwareID, + const std::string& portPath); + + ~SerialCommon(); + + + void init(const std::string& portHandle, + const std::string& hardwareID, + const std::string& portPath); + + /** + * @brief Connects to controller with provided information + * @note if connect() fails, nothing else will work + * @return bool if connection was successful + */ + bool connect(const std::string& port, + const int baud, + const std::string parity, + const int stopBits, + const int dataBits, + const bool hardwareFlow, + const bool softwareFlow); + + /** + * @brief Pushes given data to file descriptor + * @param data information to be pushed to file descriptor + * + * @return int -1 if write failed, number of bytes written if succeeded + */ + int writePort(const std::string data) const; + + /** + * @brief Pushes given data to file descriptoor + * @param data as a series of bits to be pushed to the descriptor + * @param length the number of bytes of data to be written to the port + * + *@return int -1 if write failed. otherwise, number of bytes written + */ + int writePort(const unsigned char* data, unsigned int length) const; + + + /** + * @brief Check if connected to device + * @return bool if connected + */ + bool connected() const {return m_fd != -1;} + + /** + * @brief Get raw file descriptor for custom interaction with serial device + * @return int the raw file descriptor + */ + const int& fileDescriptor() const {return m_fd;} + + /** + * @brief get any serial settings error from connecting + * @return std::string error string + */ + const std::string& getSettingError() const {return m_settingError;} + + private: + int m_fd; ///< File descriptor of connection + std::string m_settingError; ///< Serial settings error, if exists + struct termios m_old_port_settings; +}; +#endif //SERIAL_COMMON_H_ diff --git a/autorally_core/include/autorally_core/SerialInterfaceThreaded.h b/autorally_core/include/autorally_core/SerialInterfaceThreaded.h new file mode 100644 index 00000000..5f722940 --- /dev/null +++ b/autorally_core/include/autorally_core/SerialInterfaceThreaded.h @@ -0,0 +1,217 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file SerialInterfaceThreaded.h + * @author Brian Goldfain + * @date June 6, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief SerialInterfaceThreaded class definition + * + ***********************************************/ +#ifndef SERIAL_INTERFACE_THREADED_H_ +#define SERIAL_INTERFACE_THREADED_H_ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +/** + * @class SerialInterfaceThreaded SerialInterfaceThreaded.h + * "infrastrucutre/SerialInterfaceThreaded.h" + * @brief Interact with a device on the serial port + * + * Provides the ability to open and interact with a serial device + * Includes functionality to automatically accumulate incoming data via a read + * thread that relies on select() to minimize wasted compute cycled. The read + * data is avaiable in m_data. + * @note locking operations are provided to ensure thread-safe data access, + * operations, but the user must ensure they call lock() and unlock() + */ +class SerialInterfaceThreaded : public SerialCommon +{ + + public: + std::string m_data; ///< incoming data buffer + + /** + * @brief SerialInterfaceThreaded default contructor + */ + SerialInterfaceThreaded(); + + /** + * @brief SerialInterfaceThreaded contructor + * @param nh NodeHandle used to register stuff + * @param nodeName name of the parent process + * @param hardwareID some string to identify the corresponding hardware + * @param port serial port to connect to + * @param queueData whether to automatically queue data from port + * + * Connects to the specified serial device, sets up diagnostics, starts + * polling timer if required + */ + SerialInterfaceThreaded(ros::NodeHandle& nh, + const std::string& nodeName, + const std::string& hardwareID, + const std::string& port, + const bool queueData); + ~SerialInterfaceThreaded(); + + void init(ros::NodeHandle& nh, + const std::string& nodeName, + const std::string& portHandle, + const std::string& hardwareID, + const std::string& port, + const bool queueData); + + /** + * @brief Locks internal mutex to ensure exclusive access to data + */ + void lock(); + + /** + * @brief Attempts to Lock internal mutex to ensure exclusive access to data + * @return bool If lock acquisition was successful + */ + bool tryLock(); + + /** + * @brief Unocks internal data mutex (must always be called after lock()) + */ + void unlock(); + + typedef boost::function DataCallback; + + /** + * @brief Register callback to trigger when data arrives + * @param callback the function to call that has the signature void funct() + * + * The callback is fired in the same thread as the data is read from. + */ + void registerDataCallback(DataCallback callback); + + void clearDataCallback(); + + /** + * @brief Waits (sleeps thread) until data arrives + * + * This mechanism should be used if sometheing other than the read thread + * needs to know when data has arrived. For instance, if a specific reply + * is expected right after data is sent, waitForData can be used to + * sleep the parent thread until the reply has been accumulated by the read + * thread. + * @note If no data arrives, this version of waitForData will never return + */ + void waitForData(); + + /** + * @brief Waits (sleeps thread) for up to the specified number of + milliseconds for data to arrive + * @param timeMS the maximum amount of time in ms to wait before returning + * @return bool If data was available before timeout + */ + //bool waitForData(const long& timeMS); + + /** + * @brief Writes given data to file descriptor (threadsafe) + * @param data information to be pushed to file descriptor + * + * @return int -1 if write failed, number of bytes written if succeeded + * + * Overrides SerialCommon:writePort from base class to make a it + * Thread-safe version + */ + int writePort(const std::string data); + + /** + * @brief Writes given data to file descriptor (threadsafe) + * @param data as a series of bits to be pushed to the descriptor + * @param length the number of bytes of data to be written to the port + * + *@return int -1 if write failed. otherwise, number of bytes written + * + * Overrides SerialCommon:writePort from base class to make a it + * Thread-safe version + */ + int writePort(const unsigned char* data, unsigned int length); + + /** + * @brief Tries to write given data to file descriptor (threadsafe) + * @param data information to be pushed to file descriptor + * + * @return int -1 if write failed or could not secure exclusive write access, + * otherwise number of bytes written if succeeded + * + * Uses try-lock instead of lock in SerialCommon:writePort, so it is earier + * to avoid race conditions + */ + int writePortTry(const std::string data); + + /** + * @brief Tried to write given data to file descriptor (threadsafe) + * @param data as a series of bits to be pushed to the descriptor + * @param length the number of bytes of data to be written to the port + * + * @return int -1 if write failed or could not secure exclusive write access, + * otherwise number of bytes written if succeeded + + * + * Uses try-lock instead of lock in SerialCommon:writePort, so it is earier + * to avoid race conditions + */ + int writePortTry(const unsigned char* data, unsigned int length); + + + private: + std::string m_port; ///< Serial port to connect to + bool m_settingsApplied; ///< Whether serial settings were successfully applied + boost::shared_ptr m_runThread; ///< pointer to the read thread + boost::mutex m_dataMutex; ///< mutex for accessing incoming data + boost::mutex m_writeMutex; ///< mutex for writing serial data + boost::mutex m_waitMutex; ///< mutex for thread synchronization +// boost::condition_variable m_waitCond; ///< condition variable to wait for data + DataCallback m_dataCallback; ///< Callback triggered when new data arrives + volatile bool m_alive; + /** + * @brief Function run as a thread that accumulates incoming data + */ + void run(); + + /** + * @brief Timer triggered callback to publish a diagnostic message + * @param time information about callback execution + */ + void diagnosticStatus(const ros::TimerEvent& time); +}; +#endif //SERIAL_INTERFACE_THREADED_H_ diff --git a/autorally_core/include/autorally_core/SerialSensorInterface.h b/autorally_core/include/autorally_core/SerialSensorInterface.h new file mode 100644 index 00000000..f424a67a --- /dev/null +++ b/autorally_core/include/autorally_core/SerialSensorInterface.h @@ -0,0 +1,127 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file SerialSensorInterface.h + * @author Brian Goldfain + * @date June 6, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief SerialSensorInterface class definition + * + ***********************************************/ +#ifndef SERIAL_SENSOR_INTERFACE_H_ +#define SERIAL_SENSOR_INTERFACE_H_ + +#include + +#include +#include +#include + +#include +#include + +/** + * @class SerialSensorInterface SerialSensorInterface.h + * "autorally_core/SerialSensorInterface.h" + * @brief Interact with a device on the serial port + * + * Provides the ability to connect to a specified serial device at 57600 baud + * with no parity, one stop bit, 8 data bits, no flow control. Includes + * functionality to automatically accumulate incoming data by polling. The read + * data is avaiable in m_data. Automatically sets up basic diagnostics based on + * the provided constructor parameters. + * @note The serial port setting configuraiton was taken loosely from: + * http://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c + */ +class SerialSensorInterface : public SerialCommon +{ + + public: + std::string m_data; ///< incoming data buffer + + /** + * @brief SerialSensorInterface contructor + * + * Creates a dummy interface. Sets the portID as -1, + * does not set up diagnostics + */ + SerialSensorInterface(); + + /** + * @brief SerialSensorInterface contructor + * @param nh NodeHandle used to register stuff + * @param nodeName name of the parent process + * @param hardwareID some string to identify the corresponding hardware + * @param port serial port to connect to + * @param queueData whether to automatically queue data from port + * + * Connects to the specified serial device, sets up diagnostics, starts + * polling timer if required + */ + SerialSensorInterface(ros::NodeHandle &nh, + const std::string nodeName, + const std::string hardwareID, + const std::string port, + const bool queueData); + ~SerialSensorInterface(); + + void init(ros::NodeHandle &nh, + const std::string nodeName, + const std::string portHandle, + const std::string hardwareID, + const std::string port, + const bool queueData); + + /** + * @brief Reads data from file descriptor + * @return std::string of data read. + * + * If the last character is LF it replaces it with a '\0'. + */ + std::string readPort(); + + private: + std::string m_port; ///< Serial port to connect to + bool m_settingsApplied; ///< Whether serial settings were successfully applied + bool m_queueData; ///< If data should be automatically queued from the port + ros::Time m_mostRecentData; ///< Time when the most recent data was read + ros::Timer m_serialTimer; /// + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_core/launch/autorally.launch b/autorally_core/launch/autorally.launch new file mode 100644 index 00000000..30cc50aa --- /dev/null +++ b/autorally_core/launch/autorally.launch @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_core/launch/autorally_core_manager.launch b/autorally_core/launch/autorally_core_manager.launch new file mode 100644 index 00000000..8054167e --- /dev/null +++ b/autorally_core/launch/autorally_core_manager.launch @@ -0,0 +1,7 @@ + + + + + + + diff --git a/autorally_core/launch/autorally_imu_3dm_gx4.launch b/autorally_core/launch/autorally_imu_3dm_gx4.launch new file mode 100644 index 00000000..937e49ed --- /dev/null +++ b/autorally_core/launch/autorally_imu_3dm_gx4.launch @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/autorally_core/launch/baseStation.launch b/autorally_core/launch/baseStation.launch new file mode 100644 index 00000000..a06380d6 --- /dev/null +++ b/autorally_core/launch/baseStation.launch @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/autorally_core/launch/camera.launch b/autorally_core/launch/camera.launch new file mode 100644 index 00000000..6a090566 --- /dev/null +++ b/autorally_core/launch/camera.launch @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_core/launch/cameras.launch b/autorally_core/launch/cameras.launch new file mode 100644 index 00000000..29feae10 --- /dev/null +++ b/autorally_core/launch/cameras.launch @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/autorally_core/launch/chronyStatus.launch b/autorally_core/launch/chronyStatus.launch new file mode 100644 index 00000000..4c361f56 --- /dev/null +++ b/autorally_core/launch/chronyStatus.launch @@ -0,0 +1,5 @@ + + + + + diff --git a/autorally_core/launch/gpsBase.launch b/autorally_core/launch/gpsBase.launch new file mode 100644 index 00000000..b318bbc4 --- /dev/null +++ b/autorally_core/launch/gpsBase.launch @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_core/launch/gpsRover.launch b/autorally_core/launch/gpsRover.launch new file mode 100644 index 00000000..108fe370 --- /dev/null +++ b/autorally_core/launch/gpsRover.launch @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_core/launch/hardware.machine b/autorally_core/launch/hardware.machine new file mode 100644 index 00000000..9992a497 --- /dev/null +++ b/autorally_core/launch/hardware.machine @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/autorally_core/launch/imageRepublisher.launch b/autorally_core/launch/imageRepublisher.launch new file mode 100644 index 00000000..40757b0a --- /dev/null +++ b/autorally_core/launch/imageRepublisher.launch @@ -0,0 +1,7 @@ + + + + + + + diff --git a/autorally_core/launch/ocs.launch b/autorally_core/launch/ocs.launch new file mode 100644 index 00000000..e9ffb434 --- /dev/null +++ b/autorally_core/launch/ocs.launch @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/autorally_core/launch/robot.urdf b/autorally_core/launch/robot.urdf new file mode 100644 index 00000000..769eb008 --- /dev/null +++ b/autorally_core/launch/robot.urdf @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_core/launch/runStop.launch b/autorally_core/launch/runStop.launch new file mode 100644 index 00000000..5e657e7c --- /dev/null +++ b/autorally_core/launch/runStop.launch @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_core/launch/servoInterface.launch b/autorally_core/launch/servoInterface.launch new file mode 100644 index 00000000..add6cd22 --- /dev/null +++ b/autorally_core/launch/servoInterface.launch @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_core/launch/stateEstimator.launch b/autorally_core/launch/stateEstimator.launch new file mode 100644 index 00000000..440c4a87 --- /dev/null +++ b/autorally_core/launch/stateEstimator.launch @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_core/launch/systemStatus.launch b/autorally_core/launch/systemStatus.launch new file mode 100644 index 00000000..a67c7e53 --- /dev/null +++ b/autorally_core/launch/systemStatus.launch @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/autorally_core/launch/xbeeCoordinator.launch b/autorally_core/launch/xbeeCoordinator.launch new file mode 100644 index 00000000..382b795a --- /dev/null +++ b/autorally_core/launch/xbeeCoordinator.launch @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_core/launch/xbeeNode.launch b/autorally_core/launch/xbeeNode.launch new file mode 100644 index 00000000..e1990c23 --- /dev/null +++ b/autorally_core/launch/xbeeNode.launch @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + diff --git a/autorally_core/nodelet_plugins.xml b/autorally_core/nodelet_plugins.xml new file mode 100755 index 00000000..c34433d4 --- /dev/null +++ b/autorally_core/nodelet_plugins.xml @@ -0,0 +1,31 @@ + + + + ServoInterface nodelet + + + + + + + + IMU nodelet + + + + + + + + IMU nodelet + + + + + + + + Image republisher for OCS display + + + diff --git a/autorally_core/package.xml b/autorally_core/package.xml new file mode 100644 index 00000000..9a503dfb --- /dev/null +++ b/autorally_core/package.xml @@ -0,0 +1,71 @@ + + + + autorally_core + 0.1.0 + All core software (code specific to hardware on the robot) created for the autorally project resides here + + Brian Goldfain + + Brian Goldfain + + BSD + + http://autorally.github.io + + Brian Goldfain + + catkin + + roscpp + std_msgs + sensor_msgs + geometry_msgs + nav_msgs + autorally_msgs + image_transport + diagnostic_updater + qt_build + libqt4-dev + rospy + nodelet + gps_common + cmake_modules + camera1394 + + roscpp + std_msgs + sensor_msgs + geometry_msgs + nav_msgs + autorally_msgs + image_transport + diagnostic_updater + qt_build + libqt4-dev + rospy + nodelet + gps_common + cmake_modules + camera1394 + + + + + + + diff --git a/autorally_core/setup.py b/autorally_core/setup.py new file mode 100644 index 00000000..50df9c00 --- /dev/null +++ b/autorally_core/setup.py @@ -0,0 +1,35 @@ +# Software License Agreement (BSD License) +# Copyright (c) 2013, Georgia Institute of Technology +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +from distutils.core import setup +from catkin_pkg.python_setup import generate_distutils_setup + +d = generate_distutils_setup( + packages=['systemStatus', 'ChronyStatus'], + package_dir={'': 'src/'}, + #data_files=['src/systemStatus/systemStatus.py'], + #scripts=['src/systemStatus/systemStatus.py'], + requires=['std_msgs', 'rospy', 'autorally_msgs'] +) + +setup(**d) diff --git a/autorally_core/src/ChronyStatus/CMakeLists.txt b/autorally_core/src/ChronyStatus/CMakeLists.txt new file mode 100644 index 00000000..060ca41c --- /dev/null +++ b/autorally_core/src/ChronyStatus/CMakeLists.txt @@ -0,0 +1,10 @@ +add_executable(chronyStatus chronyStatusMain.cpp ChronyStatus.cpp) +target_link_libraries(chronyStatus ${catkin_LIBRARIES} Diagnostics) +add_dependencies(chronyStatus autorally_msgs_gencpp) + +install(TARGETS + chronyStatus + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) diff --git a/autorally_core/src/ChronyStatus/ChronyStatus.cpp b/autorally_core/src/ChronyStatus/ChronyStatus.cpp new file mode 100644 index 00000000..171d8628 --- /dev/null +++ b/autorally_core/src/ChronyStatus/ChronyStatus.cpp @@ -0,0 +1,199 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file ChronyStatus.cpp + * @author Brian Goldfain + * @date June 6, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief ChronyStatus class implementation + * + ***********************************************/ + +#include +#include + +ChronyStatus::ChronyStatus(ros::NodeHandle &nh, + const std::string nodeName, + const std::string hardwareID, + const std::string port) : + Diagnostics(nodeName, hardwareID, port), + m_masterHostname(getenv("MASTER_HOSTNAME")), + m_hostname(getenv("HOSTNAME")) +{ + double updateClientListFrequency; + ros::param::param("updateClientListFrequency", + updateClientListFrequency, + 5.0); + + m_updateClientsTimer = nh.createTimer(ros::Duration(updateClientListFrequency), + &ChronyStatus::updateClients, this); +} + +ChronyStatus::~ChronyStatus() +{} + +void ChronyStatus::updateClients(const ros::TimerEvent& /*time*/) +{ + int replyStatus; + char line[150]; + char client[50]; + if(m_masterHostname != m_hostname) + { + if(system(NULL)) + { + if(system("~/ros_workspace/src/auto_rally/autorally_core/src/ChronyStatus/getClients.sh")) + { + diag_warn("system() failed"); + return; + } + + m_clients.clear(); + + std::ifstream ifs("chronyClients"); + ifs.getline(line, 150); + + sscanf(line, "%d %s", &replyStatus, client); + if(replyStatus != 200 || strcmp(client,"OK") != 0) + { + diag_error("Password not accepted"); + } else + { + ifs.getline(line, 150); + ifs.getline(line, 150); + + //parse out all the clients + while(!ifs.eof()) + { + ifs.getline(line, 150); + if(sscanf(line, "%s ", client) == 1) + { + //std::cout << client << "||" << line << std::endl; + + if(strcmp(client, "localhost") != 0) + { + m_clients.push_back(client); + } + } + } + } + } else + { + diag_warn("system() unavailable"); + } + } else + { + diag_warn("Time sync info unavailable"); + } +} + +void ChronyStatus::diagnosticStatus(const ros::TimerEvent& /*time*/) +{ + char line[150]; + char client[50]; + char clientRequest[200]; + int sys = 0; + int replyStatus; + std::vector::iterator vecIt; + + if(!m_clients.empty()) + { + if(system(NULL)) + { + sys += system("rm -rf chronySourceStats"); + + for(vecIt = m_clients.begin(); vecIt != m_clients.end(); vecIt++) + { + if(m_hostname == *vecIt) + { + sprintf(clientRequest, "chronyc sourcestats > chronySourceStats"); + } else + { + sprintf(clientRequest, + "chronyc -h %s sourcestats > chronySourceStats", + vecIt->c_str()); + } + sys += system(clientRequest); + } + + if(sys > 0) + { + diag_warn("system() failed"); + return; + } + + std::ifstream timing("chronySourceStats", std::ifstream::in); + + while(!timing.eof()) + { + timing.getline(line, 200); + sscanf(line, "%d ", &replyStatus); + if(replyStatus != 210) + { + diag_error("Could not read sourcestats"); + } else + { + timing.getline(line, 200); + timing.getline(line, 200); + char frequency[30]; + char frequencySkew[30]; + char offset[30]; + char stddev[30]; + + timing.getline(line, 200); + //std::cout << line << std::endl; + sscanf(line, "%s %*s %*s %*s %s %s %s %s", + client, frequency, frequencySkew, + offset, stddev); + + diag(client, offset); + + //float offs = atof(offset); + + /* if(offs > 1.0) + { + diag_error(client); + } else if(offs > 0.5) + { + diag_warn(client); + } else + { + diag_ok(client); + } + diag("Offset", offset); + diag("Std dev", stddev); + diag("Freq", frequency); + diag("Freq skew", frequencySkew);*/ + } + } + } else + { + diag_warn("system() unavailable"); + } + } else + { + diag_warn("No clients"); + } +} diff --git a/autorally_core/src/ChronyStatus/__init__.py b/autorally_core/src/ChronyStatus/__init__.py new file mode 100755 index 00000000..e69de29b diff --git a/autorally_core/src/ChronyStatus/chronyStatus.py b/autorally_core/src/ChronyStatus/chronyStatus.py new file mode 100755 index 00000000..d9301158 --- /dev/null +++ b/autorally_core/src/ChronyStatus/chronyStatus.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python +# Software License Agreement (BSD License) +# Copyright (c) 2013, Georgia Institute of Technology +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" +@package chronyStatus + +Gets the current state of all chrony clients. The reported value is the +predicted offset between each client and the chrony server. This program can +be run on any computer connected into the system (offloaded to OCS to save CPU +on the main computer). +""" + +import os +import socket +import sys +import roslib +import rospy +import commands +from diagnostic_msgs.msg import DiagnosticArray, DiagnosticStatus, KeyValue +from subprocess import call +from subprocess import check_output +import subprocess + +""" +@param host the hostname for the chrony server +@return clients a list of all clients using host for clock syncronization +Contacts the chrony server in the system and parses out a list of all clients +currently using it as their clock synchronization source. +""" +def getClients(host): + try: + clientsText = check_output("chronyc -h " + host + " -m 'password muri123' clients", shell=True); + + #print clients.rfind('=') + clientsText = clientsText[clientsText.rfind('=')+1:] + lines = clientsText.split('\n') + + clients = [] + for l in lines: + if len(l) and l.find('localhost'): + #print l.split()[0].rstrip('.local') + clients.append(l.split()[0].rstrip('.local')) + return clients + except subprocess.CalledProcessError as e: + return 'subprocess error:' + e.output + + +""" +@param clients list of all clients currently in the system +@param status the diagnostic message to pupulate with offset information + +Gets the offset of each client in the system and created the diagnostic message +""" +def getOffsets(clients, host, status): + status.values = [] + for c in clients: + clientName = c + if c == socket.gethostname(): + c = 'localhost' + try: + #print 'pinging', c + clientsOffset = check_output("chronyc -h " + c + " sourcestats", shell=True); + + #print clientsOffset + clientsOffset = clientsOffset[clientsOffset.rfind('=')+1:].strip() + data = clientsOffset.split('\n') + + for s in data: + splitLine = s.split() + #print 'looking for', host, 'in', splitLine + if splitLine[0] == host: + status.values.append(KeyValue(key=clientName, value=splitLine[6])) + except: + print sys.exc_info()[0] + + +if __name__ == '__main__': + rospy.init_node('chronyStatus') + pub = rospy.Publisher('/diagnostics', DiagnosticArray, queue_size=2) + array = DiagnosticArray() + status = DiagnosticStatus(name='ChronyStatus',\ + level=0,\ + message='Master:'+os.environ.get('MASTER_HOSTNAME')) + + host = os.environ.get('MASTER_HOSTNAME') + if socket.gethostname() == host: + host = 'localhost' + + array.status = [status] + + rate = rospy.Rate(0.2) + while not rospy.is_shutdown(): + + clients = getClients(host) + #print clients + if len(clients) > 0 and 'subprocess error' not in clients: + getOffsets(clients, host, status) + elif 'subprocess error' in clients: + status.values = [] + status.values.append(KeyValue(key=clients, value=chr(1)) ) + else: + status.values = [] + status.values.append(KeyValue(key='No Clients', value=chr(1)) ) + + pub.publish(array) + rate.sleep() diff --git a/autorally_core/src/ChronyStatus/chronyStatusMain.cpp b/autorally_core/src/ChronyStatus/chronyStatusMain.cpp new file mode 100644 index 00000000..1fe0d30b --- /dev/null +++ b/autorally_core/src/ChronyStatus/chronyStatusMain.cpp @@ -0,0 +1,51 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file chronyStatusMain.cpp + * @author Brian Goldfain + * @date January 29, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief Main for ChronyStatus + * + ***********************************************/ + +#include +#include + +/** + * ChronyStatus main + */ +int main(int argc, char **argv) +{ + ros::init(argc, argv, "chronyStatus"); + ros::NodeHandle nh; + + ChronyStatus chronyStatus(nh, "", getenv("MASTER_HOSTNAME"), ""); + + ros::spin(); + + return 0; +} diff --git a/autorally_core/src/ChronyStatus/getClients.sh b/autorally_core/src/ChronyStatus/getClients.sh new file mode 100755 index 00000000..05a98617 --- /dev/null +++ b/autorally_core/src/ChronyStatus/getClients.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +host=$MASTER_HOSTNAME +if [ $(hostname) == "$MASTER_HOSTNAME" ] +then + host="localhost" +fi + +chronyc -h $host < chronyClients +password muri123 +clients +EOF diff --git a/autorally_core/src/Diagnostics/CMakeLists.txt b/autorally_core/src/Diagnostics/CMakeLists.txt new file mode 100644 index 00000000..c5493753 --- /dev/null +++ b/autorally_core/src/Diagnostics/CMakeLists.txt @@ -0,0 +1,9 @@ +add_library(Diagnostics Diagnostics.cpp) +add_dependencies(Diagnostics autorally_msgs_gencpp) + +install(TARGETS + Diagnostics + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) diff --git a/autorally_core/src/Diagnostics/Diagnostics.cpp b/autorally_core/src/Diagnostics/Diagnostics.cpp new file mode 100644 index 00000000..216b4d5d --- /dev/null +++ b/autorally_core/src/Diagnostics/Diagnostics.cpp @@ -0,0 +1,202 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file Diagnostics.cpp + * @author Brian Goldfain + * @date June 6, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief Diagnostics class implementation + * + ***********************************************/ + +#include "autorally_core/Diagnostics.h" + +#include +#include +#include +#include + +Diagnostics::Diagnostics() +{} + +Diagnostics::Diagnostics(const std::string otherInfo, + const std::string hardwareID, + const std::string hardwareLocation) : + m_hardwareLocation(hardwareLocation), + m_overallLevel(diagnostic_msgs::DiagnosticStatus::OK) +{ + init(otherInfo, hardwareID, hardwareLocation); +} + +Diagnostics::~Diagnostics() +{} + + +void Diagnostics::init(const std::string& otherInfo, + const std::string& hardwareID, + const std::string& hardwareLocation) +{ + ros::NodeHandle nh; + m_hardwareLocation = hardwareLocation; + m_overallLevel = diagnostic_msgs::DiagnosticStatus::OK; + m_updater.setHardwareID(hardwareID); + m_updater.add(otherInfo, this, &Diagnostics::diagnostics); + + //can retrieve a global diagnosticsFrequency parameter if diagnostics should + //be published at a differenc frequency than 1.0 second + double diagFreq; + ros::param::param("diagnosticsFrequency", diagFreq, 1.0); + m_heartbeatTimer = nh.createTimer(ros::Duration(diagFreq), + &Diagnostics::diagUpdate, this); + + m_statusTimer = nh.createTimer(ros::Duration(diagFreq), + &Diagnostics::diagnosticStatus, this); + +} + +void Diagnostics::diag(const std::string key, const std::string value, bool lock) +{ + if (lock) m_dataMutex.lock(); + m_diags[key] = value; + if (lock) m_dataMutex.unlock(); +} + +void Diagnostics::diag_ok(const std::string msg) +{ + m_dataMutex.lock(); + m_diagMsgs[msg] = diagnostic_msgs::DiagnosticStatus::OK; + m_dataMutex.unlock(); +} + +void Diagnostics::diag_warn(const std::string msg) +{ + m_dataMutex.lock(); + m_diagMsgs[msg] = diagnostic_msgs::DiagnosticStatus::WARN; + m_dataMutex.unlock(); +} + +void Diagnostics::diag_error(const std::string msg) +{ + m_dataMutex.lock(); + m_diagMsgs[msg] = diagnostic_msgs::DiagnosticStatus::ERROR; + m_dataMutex.unlock(); +} + +void Diagnostics::diagUpdate(const ros::TimerEvent&) +{ + //force the publishing of a diagnostics array based on the desired frequency + m_updater.force_update(); +} + +void Diagnostics::OK() +{ + m_dataMutex.lock(); + m_overallLevel = diagnostic_msgs::DiagnosticStatus::OK; + m_dataMutex.unlock(); +} + +void Diagnostics::WARN() +{ + m_dataMutex.lock(); + m_overallLevel = diagnostic_msgs::DiagnosticStatus::WARN; + m_dataMutex.unlock(); +} + +void Diagnostics::ERROR() +{ + m_dataMutex.lock(); + m_overallLevel = diagnostic_msgs::DiagnosticStatus::ERROR; + m_dataMutex.unlock(); +} + +void Diagnostics::tick(const std::string &name) +{ + std::map > >::iterator mapIt; + m_dataMutex.lock(); + if( (mapIt = m_ticks.find(name)) == m_ticks.end()) + { + std::vector > toAdd; + toAdd.push_back(std::pair(0, ros::Time::now()) ); + + mapIt = m_ticks.insert(std::pair > > + (name, toAdd)).first; + } + ++mapIt->second.back().first; + m_dataMutex.unlock(); +} + +void Diagnostics::diagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat) +{ + //add current overall diagnostic level and message + stat.summary(m_overallLevel, m_hardwareLocation); + + //Frequency messages are added to diagnotics only if tick() is being called + std::map > >::iterator mapItF; + ros::Time n = ros::Time::now(); + m_dataMutex.lock(); + for( mapItF = m_ticks.begin(); mapItF != m_ticks.end(); ++mapItF) + { + //remove all tick counts older than 15 seconds + while( (n-mapItF->second.front().second).toSec() > 20.0) + { + mapItF->second.erase(mapItF->second.begin()); + } + + //sum all ticks in the window + std::vector >::const_iterator qIt; + int sum = 0; + for( qIt = mapItF->second.begin(); qIt != mapItF->second.end(); ++qIt) + { + sum += qIt->first; + } + + //add a diagnostic message with the publishing freq over the sliding window + double val = sum/(n-mapItF->second.front().second).toSec(); + if(!std::isnan(val) && !std::isinf(val)) + { //strs << sum/((n-mapItF->second.front().second).toSec()); + diag(mapItF->first + " freq(hz):", std::to_string(val), false); + } + //add new tick entry to vector + mapItF->second.push_back( std::pair(0, n)); + } + + //add all queued diganostic messages, clear the queues + std::map::iterator mapIt; + for(mapIt = m_diagMsgs.begin(); mapIt != m_diagMsgs.end(); ++mapIt) + { + stat.add(mapIt->first, mapIt->second); + } + m_diagMsgs.clear(); + + std::map::iterator mapIt2; + for(mapIt2 = m_diags.begin(); mapIt2 != m_diags.end(); ++mapIt2) + { + stat.add(mapIt2->first, mapIt2->second); + } + m_diags.clear(); + m_dataMutex.unlock(); +} diff --git a/autorally_core/src/ImageRepublisher/CMakeLists.txt b/autorally_core/src/ImageRepublisher/CMakeLists.txt new file mode 100644 index 00000000..30031ad2 --- /dev/null +++ b/autorally_core/src/ImageRepublisher/CMakeLists.txt @@ -0,0 +1,19 @@ +add_library(ImageRepublisher ImageRepublisher.cpp) +target_link_libraries(ImageRepublisher ${catkin_LIBRARIES}) +add_dependencies(ImageRepublisher autorally_msgs_gencpp) + +find_package(OpenCV) +include_directories(${OpenCV_INCLUDE_DIRS}) +target_link_libraries(ImageRepublisher ${OpenCV_LIBRARIES}) + +find_package(cv_bridge) +include_directories(${cv_bridge_INCLUDE_DIRS}) +target_link_libraries(ImageRepublisher ${cv_bridge_LIBRARIES}) + +install(TARGETS + ImageRepublisher + + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) diff --git a/autorally_core/src/ImageRepublisher/ImageRepublisher.cpp b/autorally_core/src/ImageRepublisher/ImageRepublisher.cpp new file mode 100644 index 00000000..5cd23dd0 --- /dev/null +++ b/autorally_core/src/ImageRepublisher/ImageRepublisher.cpp @@ -0,0 +1,115 @@ +#include "ImageRepublisher.h" +#include +#include +#include + +PLUGINLIB_DECLARE_CLASS(autorally_core, ImageRepublisher, autorally_core::ImageRepublisher, nodelet::Nodelet) + +namespace autorally_core +{ + +ImageRepublisher::ImageRepublisher() + : it(ros::NodeHandle()) +{ +} + +void ImageRepublisher::onInit() +{ + nh = getNodeHandle(); + it = image_transport::ImageTransport(nh); + + if(!nh.getParam(getName()+"/fps", fps) || + !nh.getParam(getName()+"/resizeHeight", resizeHeight)) + ROS_ERROR("Could not get all ImageRepublisher parameters."); + + pub = it.advertise("image_display", 100); + + sub = nh.subscribe("camera/image_raw", 100, &ImageRepublisher::imageCallback, this); +} + +void ImageRepublisher::imageCallback(const sensor_msgs::Image::ConstPtr& msg) +{ + nh.getParam(getName() + "/fps", fps); + + if( (ros::Time::now() - lastFrameTime).toSec() < (1.0 / fps) ) + return; + lastFrameTime = ros::Time::now(); + + std::string encoding = msg->encoding; + + cv::Mat dst; + + if(encoding == "mono8") + { + dst = cv::Mat(msg->height, msg->width, CV_8UC1); + copyVectorToMat(msg->data, dst); + } + else if(encoding == "mono16") + { + std::vector src_data = msg->data; + dst = cv::Mat(msg->height, msg->width, CV_8UC1); + uchar *data = dst.data; + for(size_t i = 0; i < msg->height * msg->width * 2; i += 2) + { + *(data++) = ( 255 * (src_data[i] << 8 | src_data[i+1]) ) / 65536; + } + } + else if(encoding == "bayer_bggr8") // raw8 + { + cv::Mat bayer(msg->height, msg->width, CV_8UC1); + copyVectorToMat(msg->data, bayer); + dst = cv::Mat(msg->height, msg->width, CV_8UC3); + cv::cvtColor(bayer, dst, CV_BayerRG2RGB); + } + else if(encoding == "bayer_bggr16") // raw16 + { + std::vector src_data = msg->data; + cv::Mat bayer(msg->height, msg->width, CV_8UC1); + uchar *data = bayer.data; + for(size_t i = 0; i < msg->height * msg->width * 2; i += 2) + *(data++) = ( 255 * (src_data[i] << 8 | src_data[i+1]) ) / 65536; + dst = cv::Mat(msg->height, msg->width, CV_8UC3); + cv::cvtColor(bayer, dst, CV_BayerRG2RGB); + } + else if(encoding == "rgb8") // RGB24, YUV444, YUV422, YUV411 + { + dst = cv::Mat(msg->height, msg->width, CV_8UC3); + copyVectorToMat(msg->data, dst); + copyVectorToMat(msg->data, dst); + } + else if(encoding == "bgr8") // raw8 + { + cv::Mat bayer(msg->height, msg->width, CV_8UC3); + copyVectorToMat(msg->data, bayer); + dst = cv::Mat(msg->height, msg->width, CV_8UC3); + cv::cvtColor(bayer, dst, CV_BGR2RGB); + } + else + { + ROS_INFO("Unrecognized encoding: [%s]", encoding.c_str()); + } + + float aspect_ratio = (float)dst.cols / (float)dst.rows; + + nh.getParam(getName()+"/resizeHeight", resizeHeight); + + cv::resize(dst, dst, cv::Size(aspect_ratio*resizeHeight,resizeHeight)); + + cv_bridge::CvImage cvi; + cvi.header.stamp = msg->header.stamp; + cvi.header.frame_id = "image"; + cvi.encoding = ( dst.channels() > 1 ? "rgb8" : "mono8" ); + cvi.image = dst; + + sensor_msgs::ImageConstPtr im = cvi.toImageMsg(); + pub.publish(im); +} + +void ImageRepublisher::copyVectorToMat(const std::vector &v, cv::Mat &m) +{ + auto data = m.data; + for(auto element : v) + *(data++) = element; +} + +} diff --git a/autorally_core/src/ImageRepublisher/ImageRepublisher.h b/autorally_core/src/ImageRepublisher/ImageRepublisher.h new file mode 100644 index 00000000..ba61fdd7 --- /dev/null +++ b/autorally_core/src/ImageRepublisher/ImageRepublisher.h @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include + +namespace autorally_core +{ + + class ImageRepublisher : public nodelet::Nodelet + { + public: + ImageRepublisher(); + virtual void onInit(); + protected: + void imageCallback(const sensor_msgs::Image::ConstPtr &msg); + + void copyVectorToMat(const std::vector& v, cv::Mat& m); + + ros::NodeHandle nh; + int fps; + int resizeHeight; + ros::Time lastFrameTime; + + ros::Subscriber sub; + image_transport::ImageTransport it; + image_transport::Publisher pub; + }; + +} diff --git a/autorally_core/src/RingBuffer/CMakeLists.txt b/autorally_core/src/RingBuffer/CMakeLists.txt new file mode 100644 index 00000000..2af69978 --- /dev/null +++ b/autorally_core/src/RingBuffer/CMakeLists.txt @@ -0,0 +1,9 @@ +add_library(RingBuffer RingBuffer.cpp) +target_link_libraries(RingBuffer ${Boost_LIBRARIES}) + +install(TARGETS + RingBuffer + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) diff --git a/autorally_core/src/RingBuffer/RingBuffer.cpp b/autorally_core/src/RingBuffer/RingBuffer.cpp new file mode 100644 index 00000000..4bda4967 --- /dev/null +++ b/autorally_core/src/RingBuffer/RingBuffer.cpp @@ -0,0 +1,182 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file RingBuffer.cpp + * @author Brian Goldfain + * @date January 17, 2013 + * @copyright 2012 Georgia Institute of Technology + * @brief RingBuffer class implementation + * + ***********************************************/ +#include + +namespace autorally_core +{ + +template +RingBuffer::RingBuffer(): + m_ringBuffer(50) +{ +} + +template +RingBuffer::~RingBuffer() +{ +} + +template +bool RingBuffer::update(std::pair &newData) +{ + if(m_ringBuffer.size() == 0) + { + m_ringBuffer.push_back(newData); + return true; + } + + typename boost::circular_buffer >::iterator it; + for(it = m_ringBuffer.begin(); it != m_ringBuffer.end(); it++) + { + if(newData.first < it->first) + { + m_ringBuffer.insert(it+1, newData); + return true; + } else if(newData.first == it->first)//already have entry from that time + { + return false; + } + } + m_ringBuffer.push_back(newData); + return true; +} + +template +double RingBuffer::maxKey() const +{ + return m_ringBuffer.back().first; +} + +template +double RingBuffer::minKey() const +{ + return m_ringBuffer.front().first; +} + +template +bool RingBuffer::interpolateKey(const double value, T &interpolated) const +{ + + //do not perform extrapolation + if(value < m_ringBuffer.front().second || value > m_ringBuffer.back().second) + { + return false; + } + +// std::cout << "Comparing:" << value << " to:"; + typedef typename boost::circular_buffer > buff; + for(typename buff::const_iterator buffIt = m_ringBuffer.begin()+1; + buffIt != m_ringBuffer.end(); + buffIt++) + { +// std::cout << buffIt->second << " "; + if(buffIt->second == value) + { + interpolated = buffIt->first; +// std::cout << std::endl; + return true; + }else if(buffIt->second > value) + { + interpolated = linearInterp( + (buffIt-1)->first, + buffIt->first, + (value-(buffIt-1)->second)/(buffIt->second-(buffIt-1)->second)); + + //std::cout << "Interpolating key between(" << buffIt->first << ":" << (buffIt-1)->first << + // ") for value" << value << std::endl; + return true; + } + } + std::cout << std::endl; + + return false; +} + +template +bool RingBuffer::interpolateValue(const double key, T &interpolated) const +{ + + //do not perform extrapolation + if(key < m_ringBuffer.front().first || key > m_ringBuffer.back().first) + { + return false; + } + + //std::cout << "Comparing:" << key << " to:"; + typedef typename boost::circular_buffer > buff; + for(typename buff::const_iterator buffIt = m_ringBuffer.begin()+1; + buffIt != m_ringBuffer.end(); + buffIt++) + { + //std::cout << buffIt->first << " "; + if(buffIt->first == key) + { + interpolated = buffIt->second; + //std::cout << std::endl; + return true; + }else if(buffIt->first > key) + { + interpolated = linearInterp( + (buffIt-1)->second, + buffIt->second, + (key-(buffIt-1)->first)/(buffIt->first-(buffIt-1)->first)); + //std::cout << std::endl; + return true; + } + } + std::cout << std::endl; + + return false; +} + +template +T RingBuffer::linearInterp(const T &first, const T &second, const double& distance) const +{ + T interp; + interp = first+distance*(second-first); + return interp; +} + +template <> +double RingBuffer::linearInterp(const double& first, const double& second, const double& distance) const +{ + double interp; + interp = first+distance*(second-first); + return interp; +} + +template class RingBuffer; +template class RingBuffer; +template class RingBuffer; +} diff --git a/autorally_core/src/RunStop/CMakeLists.txt b/autorally_core/src/RunStop/CMakeLists.txt new file mode 100644 index 00000000..e689dd42 --- /dev/null +++ b/autorally_core/src/RunStop/CMakeLists.txt @@ -0,0 +1,10 @@ +add_executable(runStop RunStop.cpp) +target_link_libraries(runStop ${catkin_LIBRARIES} ${Boost_LIBRARIES} SerialSensorInterface Diagnostics) +add_dependencies(runStop autorally_msgs_gencpp) + +install(TARGETS + runStop + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) diff --git a/autorally_core/src/RunStop/RunStop.cpp b/autorally_core/src/RunStop/RunStop.cpp new file mode 100644 index 00000000..f281fe9c --- /dev/null +++ b/autorally_core/src/RunStop/RunStop.cpp @@ -0,0 +1,155 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file RunStop.cpp + * @author Alex Bettadapur + * @date January 22, 2013 + * @copyright 2013 Georgia Institute of Technology + * @brief Publishes a safeSpeed message based on run stop state + * + * @details Contains RunStop class implementation + ***********************************************/ +#include +#include "RunStop.h" + +int main(int argc, char **argv) +{ + ros::init(argc, argv, "RunStop"); + ros::NodeHandle nh; + double safeSpeedDuration = 0.1; + double safeSpeedMax = 0.0; + double safeSpeedCaution = 0.0; + + std::string runStopPort; + if(!nh.getParam("runStop/port", runStopPort) || + !nh.getParam("safeSpeedMax", safeSpeedMax)|| + !nh.getParam("safeSpeedCaution", safeSpeedCaution)) + { + ROS_ERROR("Could not get all RunStop parameters"); + return -1; + } + nh.param("safeSpeedDuration", safeSpeedDuration, 0.1); + + RunStop runStop(nh, runStopPort, safeSpeedMax, safeSpeedCaution); + runStop.m_safeSpeedPub = nh.advertise("safeSpeed", 5); + + runStop.m_doWorkTimer = nh.createTimer(ros::Duration(safeSpeedDuration), + &RunStop::doWorkTimerCallback, + &runStop); + + ros::spin(); + return 0; +} + +RunStop::RunStop(ros::NodeHandle &nh, + const std::string& port, + double safeSpeedMax, + double safeSpeedCaution): + SerialSensorInterface(nh, "","RunStop", port, true), + m_safeSpeedMax(safeSpeedMax), + m_safeSpeedCaution(safeSpeedCaution), + m_state("RED") +{ + m_safeSpeedData.header.seq=0; + m_safeSpeedData.header.frame_id="RUNSTOP"; + m_safeSpeedData.sender = "RUNSTOP"; + + m_lastMessageTime = ros::Time::now() + ros::Duration(1); +} + +RunStop::~RunStop() +{} + +//leftfront, rightfront, leftback, rightback, servo, camera +bool RunStop::processData() +{ + //std::cout << "m_data:" << m_data.c_str() << std::endl; + //frame data, and parse if an entire message is waiting + int startPosition = m_data.find("#"); + if(startPosition > 0) + { + m_data.erase(0, startPosition); + } + startPosition = m_data.find("#"); + + size_t endPosition = m_data.find("\r\n"); + //std::cout << startPosition << " " << endPosition << std::endl; + if(startPosition == 0 && endPosition!=std::string::npos) + { + m_lastMessageTime = ros::Time::now(); + std::string message = m_data.substr(0,endPosition); + + //std::cout << "message:" << message.c_str() << std::endl; + int statusStart = message.find(":"); + m_state = message.substr(statusStart+1,std::string::npos); + + m_data.erase(0, endPosition+1); + return true; + } else + { + if(startPosition > 0) + { + m_data.erase(0, startPosition); + } + return false; + } +} + +void RunStop::doWorkTimerCallback(const ros::TimerEvent&) +{ + //get out all the messages + while(processData()) + { + //std::cout << "." << std::endl; + } + //std::cout << "--state--" << m_state.size() << m_state.c_str() << "--" << std::endl; + +// std::cout << "m_state:" << m_state << "euhwfuib" << std::endl; + + m_safeSpeedData.header.stamp = ros::Time::now(); + if(m_state == "GREEN") + { + m_safeSpeedData.speed = m_safeSpeedMax; + } else if(m_state == "YELLOW") + { + m_safeSpeedData.speed = m_safeSpeedCaution; + } else + { + m_safeSpeedData.speed = 0.0; + } + + //if no recent message, safespeed=0 + if((ros::Time::now()-m_lastMessageTime).toSec() > 1.0) + { + diag_error("No recent data from RUNSTOP"); + m_safeSpeedData.speed = 0.0; + } + + m_safeSpeedPub.publish(m_safeSpeedData); + tick("RUNSTOP Status"); + + +} diff --git a/autorally_core/src/RunStop/RunStop.h b/autorally_core/src/RunStop/RunStop.h new file mode 100644 index 00000000..0a754d9d --- /dev/null +++ b/autorally_core/src/RunStop/RunStop.h @@ -0,0 +1,100 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file RunStop.h + * @author Brian Goldfain + * @date May 17, 2013 + * @copyright 2012 Georgia Institute of Technology + * @brief Publishes a safeSpeed message based on run stop state + * + * @details This file contains the RunStop class definition + ***********************************************/ +#ifndef RUN_STOP +#define RUN_STOP + +#include +#include +#include +#include + +#include +#include +#include +#include + +/** + * @class RunStop RunStop.h + * "RunStop/RunStop.h" + * @brief Interacts with Arduino connected to a 4 button run stop box + * + * Provides a safeSpeed message based on the combined state of a 4-button run + * stop box. It is assumed that the three states of the run stop are: {RED, + * YELLOW, GREEN} indicating stop, caution, race, respectively. + */ +class RunStop : public SerialSensorInterface +{ + + public: + ros::Timer m_doWorkTimer; /// +* @date 5/17/2013 +* @brief the button input of the emergency stop device and outputs corresponding data. +* RED = motion disabled YELLOW = caution GREEN = motion enabled +**/ + +int initial = 0; //State starts at RED +int state = 0; +char s0[ ] = "#estopstate:RED"; +char s1[ ] = "#estopstate:YELLOW"; +char s2[ ] = "#estopstate:GREEN"; + +void setup() { + Serial.begin(57600); + pinMode(2,INPUT); + pinMode(3,INPUT); + pinMode(4,INPUT); + pinMode(5,INPUT); +} + +void loop() { + int kill = digitalRead(2); + int red = digitalRead(5); + int yellow = digitalRead(3); + int green = digitalRead(4); + + if (kill == LOW || red == LOW || initial ==0) { //Kill Switch or red button or initial state + state = 0; + initial = 1; + }else if(yellow == HIGH) { //Yellow Button + state =1; + }else if(green == HIGH){ //Green Button + state = 2; + } + + if (state == 0) { //Kill Switch or red button or initial state + Serial.println(s0); + initial = 1; + }else if(state ==1) { //Yellow Button + Serial.println(s1); + }else if(state ==2){ //Green Button + Serial.println(s2); + } + delay(50); +} diff --git a/autorally_core/src/SafeSpeed/CMakeLists.txt b/autorally_core/src/SafeSpeed/CMakeLists.txt new file mode 100644 index 00000000..1a9c6beb --- /dev/null +++ b/autorally_core/src/SafeSpeed/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(SafeSpeed SafeSpeed.cpp) +add_dependencies(SafeSpeed autorally_msgs_gencpp) +target_link_libraries(SafeSpeed ${catkin_LIBRARIES} ${Boost_LIBRARIES} RingBuffer) + +install(TARGETS + SafeSpeed + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) diff --git a/autorally_core/src/SafeSpeed/SafeSpeed.cpp b/autorally_core/src/SafeSpeed/SafeSpeed.cpp new file mode 100644 index 00000000..e5e531d7 --- /dev/null +++ b/autorally_core/src/SafeSpeed/SafeSpeed.cpp @@ -0,0 +1,227 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file SafeSpeed.cpp + * @author Brian Goldfain + * @date June 6, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief + * + ***********************************************/ + +#include + +#include + +namespace autorally_core +{ + +SafeSpeed::SafeSpeed(): + m_vehicleSpeeds(15), //keep 15 most recent speed values + m_prevGoodThrottle(0.0), + m_safeSpeedIsInControl(false) +{} + +SafeSpeed::~SafeSpeed() +{} + +void SafeSpeed::onInit() +{ +} + +void SafeSpeed::init(ros::NodeHandle &nh) +{ + m_safeSpeedSub = nh.subscribe("safeSpeed", 5, + &SafeSpeed::safeSpeedCallback, + this); + m_speedSub = nh.subscribe("wheelSpeeds", 5, + &SafeSpeed::wheelSpeedsCallback, + this); + if(!nh.getParam("safeSpeed/maxSafeSpeed", m_maxSafeSpeed) || + !nh.getParam("safeSpeed/Timeout", m_safeSpeedTimeout) ) + { + ROS_ERROR("SafeSpeed: could not get all parameters"); + } + + loadThrottleCalibration(nh); +} + +void SafeSpeed::safeSpeedCallback( + const autorally_msgs::safeSpeedConstPtr& msg) +{ + //update SafeSpeed from sender, and timstamp assosiated with it + std::map::iterator newSafeSpeed; + if( (newSafeSpeed = m_safeSpeeds.find(msg->sender)) != m_safeSpeeds.end()) + { + newSafeSpeed->second.time = msg->header.stamp; + newSafeSpeed->second.safeSpeed = msg->speed; + } else + { //if there is not yet an entry to sender, add it + SafeSpeedData toAdd; + toAdd.time = msg->header.stamp; + toAdd.safeSpeed = msg->speed; + + m_safeSpeeds.insert(std::pair( + msg->sender, toAdd)); + } +} + +double SafeSpeed::getSafeSpeed() const +{ + double safeSpeed = m_maxSafeSpeed; + std::map::const_iterator mapIt; + ros::Time now = ros::Time::now(); + + bool foundValidSafeSpeed = false; + for(mapIt = m_safeSpeeds.begin(); mapIt != m_safeSpeeds.end(); mapIt++) + { + //if the SafeSpeed is still considered valid + if( now-mapIt->second.time < ros::Duration(m_safeSpeedTimeout)) + { + safeSpeed = std::min(safeSpeed, mapIt->second.safeSpeed); + foundValidSafeSpeed = true; + } + } + + return (foundValidSafeSpeed) ? safeSpeed : -1.0; +} + +void SafeSpeed::setMaxSpeed(const double &maxSafeSpeed) +{ + m_maxSafeSpeed = maxSafeSpeed; +} + +double SafeSpeed::maxSpeed() const +{ + return m_maxSafeSpeed; +} + +void SafeSpeed::wheelSpeedsCallback(const autorally_msgs::wheelSpeedsConstPtr& msg) +{ + + WheelData toAdd; + toAdd.msg = *msg; + toAdd.speed = (msg->lfSpeed + msg->rfSpeed)/2.0; + /* Only use front wheels in case back wheels are spinning out. + * Since this is a fixed-size circular buffer, old measurements will be + * pushed out as new data arrives. + */ + m_vehicleSpeeds.push_back(toAdd); +} + +double SafeSpeed::safeThrottle(const double& throttleCommand) +{ + double safeSpeed = getSafeSpeed(); + if(safeSpeed <= 0.0 || m_vehicleSpeeds.size() < 2) + { + return 0.0; + } + + //check if safeSpeed can give up control (if it's in control) + if(m_safeSpeedIsInControl && throttleCommand < m_prevGoodThrottle) + { + m_safeSpeedIsInControl = false; + } + + double safeThrottle = 0.0; + if(!m_safeSpeedIsInControl) + { + //calculate acceleration +/* double acceleration = 0.0; + double timeDiff; + boost::circular_buffer::const_iterator vecItC = m_vehicleSpeeds.begin(); + boost::circular_buffer::const_iterator vecItP = vecItC++; + while(vecItC != m_vehicleSpeeds.end()) + { + if(vecItC->msg.header.stamp != vecItP->msg.header.stamp) + { + timeDiff = (vecItC->msg.header.stamp-vecItP->msg.header.stamp).toSec(); + acceleration += (vecItC->speed-vecItP->speed)/timeDiff; + } + vecItP = vecItC++; + } + NODELET_WARN_STREAM(" Acc:" << acceleration << " Size:" << m_vehicleSpeeds.size()); + acceleration /= m_vehicleSpeeds.size(); +*/ + //if all is good, let the throttle do whatever + //NODELET_WARN_STREAM("Speed:" << m_vehicleSpeeds.back().speed << " Acc:" << acceleration << " SafeSpeed:" << safeSpeed); + if(m_vehicleSpeeds.back().speed/*+acceleration*/ < safeSpeed) + { + safeThrottle = throttleCommand; + } else + { + m_prevGoodThrottle = throttleCommand; + m_safeSpeedIsInControl = true; + } + } + + if(m_safeSpeedIsInControl) + { + // cut throttle, act as a speed governer + + safeThrottle = 0.0; + //compute safeThrottle + //if(!m_throttleMappings.interpolateKey(safeSpeed, safeThrottle)) + //{ + // safeThrottle = 0.0; + // NODELET_WARN_STREAM( + // "SafeSpeed: couldn't interpolate a safeThrottle from safeSpeed:" + // << safeSpeed); + //} + } + + return safeThrottle; +} + +void SafeSpeed::loadThrottleCalibration(ros::NodeHandle &nh) +{ + //ros::NodeHandle nhPvt = getPrivateNodeHandle(); + XmlRpc::XmlRpcValue v; + nh.param("ServoInterface/throttleCalibration", v, v); + std::map::iterator mapIt; + for(mapIt = v.begin(); mapIt != v.end(); mapIt++) + { + if(mapIt->second.getType() == XmlRpc::XmlRpcValue::TypeDouble) + { + std::pair toAdd(std::pair( + boost::lexical_cast(mapIt->first), + static_cast(mapIt->second))); + if(!m_throttleMappings.update(toAdd)) + { + NODELET_ERROR_STREAM("SafeSpeed: Failed to add mapping " << + toAdd.first << ":" << toAdd.second); + } + } else + { + NODELET_ERROR("SafeSpeed: XmlRpc throttle calibration formatted incorrectly"); + } + } + NODELET_INFO_STREAM("SafeSpeed: Loaded " << m_throttleMappings.size() << + " throttle mappings"); +} + +} diff --git a/autorally_core/src/SerialSensorInterface/CMakeLists.txt b/autorally_core/src/SerialSensorInterface/CMakeLists.txt new file mode 100644 index 00000000..785c4340 --- /dev/null +++ b/autorally_core/src/SerialSensorInterface/CMakeLists.txt @@ -0,0 +1,11 @@ +add_library(SerialSensorInterface SerialSensorInterface.cpp SerialInterfaceThreaded.cpp SerialCommon.cpp) +target_link_libraries(SerialSensorInterface ${catkin_LIBRARIES} ${Boost_LIBRARIES}) +add_dependencies(SerialSensorInterface autorally_msgs_gencpp) + +install(TARGETS + SerialSensorInterface + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) + diff --git a/autorally_core/src/SerialSensorInterface/SerialCommon.cpp b/autorally_core/src/SerialSensorInterface/SerialCommon.cpp new file mode 100644 index 00000000..1d33ee15 --- /dev/null +++ b/autorally_core/src/SerialSensorInterface/SerialCommon.cpp @@ -0,0 +1,282 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file SerialCommon.cpp + * @author Brian Goldfain + * @date July 22, 2013 + * @copyright 2013 Georgia Institute of Technology + * @brief SerialCommon class implementation + * + ***********************************************/ +#include + +#include +#include +#include +#include + +SerialCommon::SerialCommon() : + m_fd(-1), + m_settingError("") +{} + +SerialCommon::SerialCommon(const std::string& portHandle, + const std::string& hardwareID, + const std::string& portPath) : + m_fd(-1), + m_settingError("") +{ + init(portHandle, hardwareID, portPath); +} + +SerialCommon::~SerialCommon() +{ + if(m_fd > 0) + { + std::cout << "shutting down " << m_fd << " " << close(m_fd) << std::endl; + m_fd = 0; + } +} + +void SerialCommon::init(const std::string& otherInfo, + const std::string& hardwareID, + const std::string& portPath) +{ + //init in Diagnostics + std::cout << portPath << " initializing" << std::endl; + Diagnostics::init(otherInfo, hardwareID, portPath); +} + + +bool SerialCommon::connect(const std::string& port, + const int baud, + const std::string parity, + const int stopBits, + const int dataBits, + const bool hardwareFlow, + const bool softwareFlow) +{ + std::cout << port << " connecting" << std::endl; + if (m_fd != -1 ) + { + ROS_ERROR("Already connected to %s", port.c_str()); + return false; + } + + //m_fd = open(port.c_str(), O_WRONLY | O_NOCTTY | O_NDELAY); + //ioctl(m_fd, USBDEVFS_RESET, 0); + //close(m_fd); + //std::cout << port << " reset" << std::endl; + + m_fd = open(port.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); + + //std::cout << port << " open attempted" << std::endl; + + if (m_fd == -1 ) + { + perror("Unable to open serial port"); + ROS_ERROR("Unable to open %s", port.c_str()); + diag_error("Unable to open " + port); + return false; + } else + { + struct termios port_settings; // structure to store the port settings in + memset(&port_settings, 0, sizeof(port_settings)); + //Get the current options for the port... + if(tcgetattr (m_fd, &port_settings) != 0) + { + ROS_ERROR("SerialSensorInterface: error %d from tcgetattr", errno); + diag_error("SerialSensorInterface: error from tcgetattr"); + return false; + } + //tcgetattr(m_fd, &m_old_port_settings); + //fcntl(m_fd, F_SETFL, 0); + //fcntl(m_fd, F_SETFL, FNDELAY); + //std::cout << port << " got attributes" << std::endl; + speed_t b; + switch(baud) + { + case 4800: + b = B4800; + break; + case 9600: + b = B9600; + break; + case 19200: + b = B19200; + break; + case 38400: + b = B38400; + break; + case 57600: + b = B57600; + break; + case 115200: + b = B115200; + break; + case 230400: + b = B230400; + break; + default: + ROS_ERROR("Unsupported baud:%d", baud); + m_settingError = "Unsupported baud"; + return false; + } + + // set baud rates + if(cfsetispeed(&port_settings, b) != 0 || + cfsetospeed(&port_settings, b) != 0) + { + ROS_ERROR("Could not set baud:%d", baud); + m_settingError = "Could not set baud"; + } + + // set 8N1 + if(parity == "none") + { + port_settings.c_cflag &= ~PARENB; // no parity bit + port_settings.c_cflag &= ~PARODD; // even parity + } else if(parity == "even") + { + port_settings.c_cflag |= PARENB; // enable parity + port_settings.c_cflag &= ~PARODD; // even parity + } else if(parity == "odd") + { + port_settings.c_cflag |= PARENB; // enable parity + port_settings.c_cflag |= PARODD; // odd parity + } else + { + ROS_ERROR("Unsupported parity:%s", parity.c_str()); + m_settingError = "Unsupported parity:"+parity; + return false; + } + + + if(stopBits == 1) + { + port_settings.c_cflag &= ~CSTOPB; // only one stop bit + } else if(stopBits == 2) + { + port_settings.c_cflag |= CSTOPB; // two stop bits + } else + { + ROS_ERROR("Unsupported stopBits:%d", stopBits); + m_settingError = "Unsupported stopBits"; + return false; + } + + //port_settings.c_cflag |= ~CSIZE; // clear data bit number + switch(dataBits) + { + case 5: + port_settings.c_cflag |= CS5; // set 5 data bits + break; + case 6: + port_settings.c_cflag |= CS6; // set 6 data bits + break; + case 7: + port_settings.c_cflag |= CS7; // set 7 data bits + break; + case 8: + port_settings.c_cflag |= CS8; // set 8 data bits + break; + default: + ROS_ERROR("Unsupported dataBits:%d", dataBits); + m_settingError = "Unsupported dataBits"; + return false; + } + + // hardware flow control + if(hardwareFlow) + { + port_settings.c_cflag |= CRTSCTS; + } else + { + port_settings.c_cflag &= ~CRTSCTS; + } + + // software flow control + if(softwareFlow) + { + port_settings.c_iflag |= (IXON | IXOFF | IXANY); + } else + { + port_settings.c_iflag &= ~(IXON | IXOFF | ~IXANY); //this part is important + } + + // enable reading and ignore control lines + port_settings.c_cflag |= CREAD | CLOCAL; + //set raw input mode (not canonical) + port_settings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + + port_settings.c_oflag &= ~OPOST; // disable pre-processing of input data + + port_settings.c_cc[VMIN] = 1; // wait for at least 1 character (read doesn't block) + port_settings.c_cc[VTIME] = 0; // 0.5 seconds read timeout + + //std::cout << baud << std::endl; + + //std::cout << port << " setting attributes" << std::endl; + // apply the settings to the port + tcflush(m_fd, TCIFLUSH); + + if(tcsetattr(m_fd, TCSANOW, &port_settings) == 0) + { + usleep(200000); // wait for connection to be negotiated + // found this length through experimentation + ROS_INFO("%s port configuration complete", port.c_str()); + return true; + } + } + ROS_ERROR("Could not configure %s", port.c_str()); + m_settingError = "Could not set serial port attributes"; + return false; +} + +int SerialCommon::writePort(const std::string data) const +{ + int n; + n = write(m_fd, (char*)data.c_str(), data.length()); + //std::cout<<(char*)data.c_str(); + if (n < 0) + { + //ROS_INFO("%s","write() failed!"); + return -1; + } + return n; +} + +int SerialCommon::writePort(const unsigned char* data, unsigned int length) const +{ + int n; + n=write(m_fd, data, length); + if(n < 0) + { + //ROS_INFO("%s","write() failed!"); + return -1; + } + return n; +} diff --git a/autorally_core/src/SerialSensorInterface/SerialInterfaceThreaded.cpp b/autorally_core/src/SerialSensorInterface/SerialInterfaceThreaded.cpp new file mode 100644 index 00000000..329fcee4 --- /dev/null +++ b/autorally_core/src/SerialSensorInterface/SerialInterfaceThreaded.cpp @@ -0,0 +1,285 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file SerialInterfaceThreaded.cpp + * @author Brian Goldfain + * @date June 6, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief SerialInterfaceThreaded class implementation + * + ***********************************************/ +#include + +#include + +#include + +SerialInterfaceThreaded::SerialInterfaceThreaded() : + m_port(""), + m_settingsApplied(false), + m_alive(false) +{} + +SerialInterfaceThreaded::SerialInterfaceThreaded(ros::NodeHandle& nh, + const std::string& portHandle, + const std::string& hardwareID, + const std::string& port, + const bool queueData) : + SerialCommon(portHandle, hardwareID, port), + m_port(port), + m_settingsApplied(false), + m_alive(false) +{ + init(nh, ros::this_node::getName(), portHandle, hardwareID, port, queueData); +} + +SerialInterfaceThreaded::~SerialInterfaceThreaded() +{ + /* + ** std::cout is used here instead of ROS_INFO because + ** when the destructor is called, ros::shutdown has already been executed + ** and roscore is not running. So ROS_INFO will not print any output. + ** Additionally, in the launch file the output param must be set as "screen" + ** to be able to view the std::cout outputs. + */ + + //clearDataCallback(); + + //if the serial thread isnt dead yet, wait for it to close + if(m_alive) + { + m_alive = false; + std::cout << "Joining " << m_port.c_str() << std::endl; + m_runThread->join(); + std::cout << "Joined " << m_port.c_str() << std::endl; + } + //std::cout << "Shutting down " << m_port.c_str() << " " << close(fileDescriptor()) << std::endl; +} + +void SerialInterfaceThreaded::init(ros::NodeHandle& nh, + const std::string& portName, + const std::string& portHandle, + const std::string& hardwareID, + const std::string& port, + const bool queueData) +{ + std::string parity; + int baud, stopBits, dataBits; + bool hardwareFlow, softwareFlow; + m_port = port; + + + std::string newP = portName+((portHandle.empty())?"":"/"+portHandle); + SerialCommon::init(newP, hardwareID, m_port); + + //get current node name to allow access to the serial parameters + //specific to this node + //std::string nName = nodeName;//+((portHandle.length()>0)?"/"+portHandle:""); + //std::cout << portName+((portHandle.empty())?"":"/"+portHandle) << std::endl; + + if(!nh.getParam(newP+"/serialBaud", baud) || + !nh.getParam(newP+"/serialParity", parity) || + !nh.getParam(newP+"/serialStopBits", stopBits) || + !nh.getParam(newP+"/serialDataBits", dataBits) || + !nh.getParam(newP+"/serialHardwareFlow", hardwareFlow) || + !nh.getParam(newP+"/serialSoftwareFlow", softwareFlow)) + { + ROS_ERROR("Could not get all SerialInterfaceThreaded parameters for %s", portName.c_str()); + } + + m_settingsApplied = this->connect(m_port, + baud, + parity, + stopBits, + dataBits, + hardwareFlow, + softwareFlow); + + if(queueData && m_settingsApplied) + { + //start worker in separate thread + m_alive = true; + m_runThread = boost::shared_ptr< boost::thread > + (new boost::thread(boost::bind(&SerialInterfaceThreaded::run, this))); + } +} + +void SerialInterfaceThreaded::run() +{ + fd_set rfds; + struct timeval tv; + int retval; + char data[512]; + int received; + + if(!connected()) + { + diag_error("Not connected, cannot start reading"); + return; + } + + while(m_alive) + { + /* Watch stdin (fd 0) to see when it has input. */ + FD_ZERO(&rfds); + FD_SET(fileDescriptor(), &rfds); + + /* Wait up to one seconds. */ + tv.tv_sec = 1; + tv.tv_usec = 0; + retval = select(fileDescriptor()+1, &rfds, NULL, NULL, &tv); + /* Don't rely on the value of tv now! */ + + if(retval == -1) + { + std::cout << m_port << " select() error" << std::endl; + diag_error("select() error"); + } + else if(retval) + { + /* FD_ISSET(0, &rfds) will be true. */ + if( (received = read(fileDescriptor(), &data, 512)) >= 0) + { + m_dataMutex.lock(); + m_data.append(data, received); + + m_dataMutex.unlock(); + //callback triggered within same thread + if(m_dataCallback) + { + m_dataCallback(); + } + //condition can notify (wake) other threads waiting for data +// m_waitCond.notify_all(); + } + } + else + { + diag_warn("No data within previous second"); + } + } + + //since ros is shutdown and ROS diag messages wouldnt go anywhere + std::cout << "SerialInterfaceThreaded Done Running " << fileDescriptor() << std::endl; +} + +void SerialInterfaceThreaded::lock() +{ + m_dataMutex.lock(); +} + +bool SerialInterfaceThreaded::tryLock() +{ + return m_dataMutex.try_lock(); +} + +void SerialInterfaceThreaded::unlock() +{ + m_dataMutex.unlock(); +} + +void SerialInterfaceThreaded::registerDataCallback(DataCallback callback) +{ + m_dataCallback = callback; +} + +void SerialInterfaceThreaded::clearDataCallback() +{ + m_dataCallback = NULL; +} + +//void SerialInterfaceThreaded::waitForData() +//{ +// boost::unique_lock lock(m_waitMutex); +// m_waitCond.wait(lock); +//} + +//bool SerialInterfaceThreaded::waitForData(const long& timeMS) +//{ +// boost::unique_lock lock(m_waitMutex); +// return m_waitCond.timed_wait(lock, boost::posix_time::milliseconds(timeMS)); +//} + +int SerialInterfaceThreaded::writePort(const std::string data) +{ + if(connected()) + { + boost::unique_lock lock(m_writeMutex); + return SerialCommon::writePort(data); + } + return -1; +} +int SerialInterfaceThreaded::writePort(const unsigned char* data, unsigned int length) +{ + if(connected()) + { + boost::unique_lock lock(m_writeMutex); + return SerialCommon::writePort(data, length); + } + return -1; +} + +int SerialInterfaceThreaded::writePortTry(const std::string data) +{ + if(connected()) + { + boost::unique_lock lock(m_writeMutex, boost::try_to_lock); + if(lock) + { + return SerialCommon::writePort(data); + } + } + return -1; +} + +int SerialInterfaceThreaded::writePortTry(const unsigned char* data, unsigned int length) +{ + if(connected()) + { + boost::unique_lock lock(m_writeMutex, boost::try_to_lock); + if(lock) + { + return SerialCommon::writePort(data, length); + } + } + return -1; +} + +void SerialInterfaceThreaded::diagnosticStatus(const ros::TimerEvent& /*time*/) +{ + //queue up a status messages + if(!m_settingsApplied) + { + diag_error("Serial port setting error: "+getSettingError()); + } + if(!connected()) + { + diag_error("Not connected"); + } else + { + diag_ok("Connected"); + } +} diff --git a/autorally_core/src/SerialSensorInterface/SerialSensorInterface.cpp b/autorally_core/src/SerialSensorInterface/SerialSensorInterface.cpp new file mode 100644 index 00000000..2e5ef84f --- /dev/null +++ b/autorally_core/src/SerialSensorInterface/SerialSensorInterface.cpp @@ -0,0 +1,177 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file SerialSensorInterface.cpp + * @author Brian Goldfain + * @date June 6, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief SerialSensorInterface class implementation + * + ***********************************************/ +#include + +#include + +SerialSensorInterface::SerialSensorInterface() : + m_port(""), + m_settingsApplied(false) +{} + +SerialSensorInterface::SerialSensorInterface(ros::NodeHandle &nh, + const std::string portHandle, + const std::string hardwareID, + const std::string port, + const bool queueData) : + SerialCommon(portHandle, hardwareID, port), + m_port(port), + m_settingsApplied(false), + m_queueData(queueData), + m_mostRecentData(ros::Time::now()) +{ + init(nh, ros::this_node::getName(), portHandle, hardwareID, port, queueData); +} + + + +SerialSensorInterface::~SerialSensorInterface() +{ + /* + ** std::cout is used here instead of ROS_INFO because + ** when the destructor is called, ros::shutdown has already been executed + ** and roscore is not running. So ROS_INFO will not print any output. + ** Additionally, in the launch file the output param must be set as "screen" + ** to be able to view the std::cout outputs. + */ + //std::cout << "Shutting down " << m_port.c_str() << " " << close(fileDescriptor()) << std::endl; +} + +void SerialSensorInterface::init(ros::NodeHandle &nh, + const std::string nodeName, + const std::string portHandle, + const std::string hardwareID, + const std::string port, + const bool queueData) +{ + std::string parity; + int baud, stopBits, dataBits; + bool hardwareFlow, softwareFlow; + m_port = port; + m_queueData = queueData; + + SerialCommon::init(portHandle, hardwareID, m_port); + + //get current node name to allow access to the serial parameters + //specific to this node + std::string nName = nodeName+((portHandle.length()>0)?"/"+portHandle:""); + if(!nh.getParam(nName+"/serialBaud", baud) || + !nh.getParam(nName+"/serialParity", parity) || + !nh.getParam(nName+"/serialStopBits", stopBits) || + !nh.getParam(nName+"/serialDataBits", dataBits) || + !nh.getParam(nName+"/serialHardwareFlow", hardwareFlow) || + !nh.getParam(nName+"/serialSoftwareFlow", softwareFlow)) + { + ROS_ERROR("Could not get all serialSensorInterface parameters for %s", nName.c_str()); + } + + m_settingsApplied = connect(m_port, + baud, + parity, + stopBits, + dataBits, + hardwareFlow, + softwareFlow); + + if(m_queueData && m_settingsApplied) + { + + //set timer to be able to pull 25% more data off serial port than possible + m_serialTimer = nh.createTimer(ros::Duration(1.0/((baud/100)*1.25)), + &SerialSensorInterface::pollSerial, this); + } +} + + +std::string SerialSensorInterface::readPort() +{ + char data[100]; + //get up to 100 bytes from the com port, add it to the data buffer + int received = 0; + if(connected()) + { + if( (received = read(fileDescriptor(), &data, 100)) >= 0) + { + //std::cout<<"true"; + data[received]='\0'; + if((int)data[received-1]==10) + { + data[received-1]='\0'; + received--; + } + m_data.append(std::string(data)); + m_mostRecentData = ros::Time::now(); + return std::string(data); + } + } + return std::string(); +} + +void SerialSensorInterface::pollSerial(const ros::TimerEvent& /*time*/) +{ + char data[100]; + //get up to 100 bytes from the com port, add it to the data buffer + int received = 0; + //ROS_INFO("Polling"); + if(connected()) + { + if( (received = read(fileDescriptor(), &data, 100)) >= 0) + { + //ROS_INFO("RECIEVED"); + //data[received]='\0'; + m_data.append(data, received); + m_mostRecentData = ros::Time::now(); + } + } +} + +void SerialSensorInterface::diagnosticStatus(const ros::TimerEvent& /*time*/) +{ + //queue up a status messages + if(!m_settingsApplied) + { + diag_error("Serial port setting error: "+getSettingError()); + } + + if(!connected()) + { + diag_error("Not connected"); + } else if( m_queueData && (ros::Time::now() - m_mostRecentData).toSec() > 1.0) + { + //diag_warn("No data within previous second"); + } else + { + diag_ok("Connected"); + } +} diff --git a/autorally_core/src/StateEstimator/BlockingQueue.h b/autorally_core/src/StateEstimator/BlockingQueue.h new file mode 100644 index 00000000..81e372db --- /dev/null +++ b/autorally_core/src/StateEstimator/BlockingQueue.h @@ -0,0 +1,96 @@ +/** + * @file BlockingQueue.h + * @brief Blocking queue used to parallelize feature detection and stereo matching + * @brief Automatically implements wait and notify when work is available or when queue is full + * @author Chris Beall + */ + +#pragma once + +#include +#include +#include +#include + +template +class BlockingQueue { + +private: + size_t max_size_; + std::queue queue_; + boost::mutex mutex_; + boost::condition_variable work_available_; + boost::condition_variable slot_available_; + +public: + + /// sets the maximum size of the blocking queue + BlockingQueue(size_t max_size=10) : max_size_(max_size) {} + + //push work if queue is not full, waits for the notification from pop function if queue is full + bool pushBlocking(const WorkType& element) { + boost::mutex::scoped_lock guard(mutex_); + + //checks and waits if the queue is full + //this thread would wait until a pop function is called and it notifies that a slot is available + if (queue_.size() >= max_size_) { + slot_available_.wait(guard); + } + + //store work and notify one pop function that some work is available + queue_.push(element); + work_available_.notify_one(); + return true; + } + + /// Push work if the queue is not full + bool pushNonBlocking(const WorkType& element) { + boost::mutex::scoped_lock guard(mutex_); + + // return false is queue is full and no more elements can be inserted + if (queue_.size() >= max_size_) { + return false; + } + queue_.push(element); + + // notifies one pop function that there is work available + work_available_.notify_one(); + return true; + } + + /// pops elements from the queue when work is available, waits if no work is available + WorkType popBlocking() { + boost::mutex::scoped_lock guard(mutex_); + while (queue_.empty() == true) { + //puts the thread on wait if there is no work available + //this thread would wait until a push function is called and it notifies that work is available + work_available_.wait(guard); + } + + WorkType element = queue_.front(); + queue_.pop(); + + //notifies one push thread that there is a slot available to store future work + slot_available_.notify_one(); + return element; + } + + /// pops elements from the queue when work is available, returns nothing otherwise + boost::optional popNonBlocking() { + boost::mutex::scoped_lock guard(mutex_); + if (queue_.empty() == true) { + return boost::optional(); + } + + WorkType element = queue_.front(); + queue_.pop(); + + //notifies one push thread that there is a slot available to store future work + slot_available_.notify_one(); + return boost::optional(element); + } + + size_t size() const { return queue_.size(); } + size_t max_size() const { return max_size_; } + +}; diff --git a/autorally_core/src/StateEstimator/CMakeLists.txt b/autorally_core/src/StateEstimator/CMakeLists.txt new file mode 100644 index 00000000..d3fb52c5 --- /dev/null +++ b/autorally_core/src/StateEstimator/CMakeLists.txt @@ -0,0 +1,17 @@ +find_package(Boost REQUIRED) +find_package(Eigen REQUIRED) + +include_directories(include ${catkin_INCLUDE_DIRS} ${Boost_INCLUDE_DIR} ${Eigen_INCLUDE_DIRS}) + +find_package(GTSAM) +if(GTSAM_FOUND) +include_directories(include + ${catkin_INCLUDE_DIRS} + "/usr/local/include") +add_executable(imuGpsEstimator IMU_GPS.cpp) +target_link_libraries(imuGpsEstimator ${catkin_LIBRARIES} ${ROS_LIBRARIES} /usr/local/lib/libgtsam.so /usr/lib/libtbb.so /usr/lib/libtbbmalloc.so /usr/local/lib/libGeographic.so Diagnostics) +install(TARGETS imuGpsEstimator + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}) +endif() diff --git a/autorally_core/src/StateEstimator/IMU_GPS.cpp b/autorally_core/src/StateEstimator/IMU_GPS.cpp new file mode 100644 index 00000000..08648ff7 --- /dev/null +++ b/autorally_core/src/StateEstimator/IMU_GPS.cpp @@ -0,0 +1,522 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file gpsWaypoint.cpp + * @author Paul Drews + * @date January 29, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief ROS node to allow following gps waypoints + * + * @details Waypoints are read in from a configuration file. + * The waypoints are assumed to be a loop. Once each waypoint is reached, + * the controller will push it to the back of the list and move to the next. + ***********************************************/ + + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "IMU_GPS.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +// Convenience for named keys +using symbol_shorthand::X; +using symbol_shorthand::V; +using symbol_shorthand::B; + +namespace autorally_core +{ + + Imu_Gps::Imu_Gps() : + m_nh("~"), + m_gotFirstFix(false), + m_biasKey(0), + m_poseVelKey(0), + m_lastImuTgps(0.0), + m_lastImuT(0.0), + m_imuQPrevTime(0), + m_gpsOptQ(40), + m_ImuOptQ(400), + m_maxQSize(0), + m_gpsCounter(0), + Diagnostics("ImuGpsEstimator", "", "") + { + double accSigma, gyroSigma; + m_nh.param("InitialYaw", m_initialYaw, 5); + m_nh.param("InitialRotationNoise", m_initialRotationNoise, 1.0); + m_nh.param("InitialVelocityNoise", m_initialVelNoise, 0.1); + m_nh.param("InitialBiasNoiseAcc", m_initialBiasNoiseAcc, 1e-1); + m_nh.param("InitialBiasNoiseGyro", m_initialBiasNoiseGyro, 1e-2); + m_nh.param("AccelerometerSigma", accSigma, 6.0e-2); + m_nh.param("GyroSigma", gyroSigma, 2.0e-2); + m_nh.param("AccelBiasSigma", m_AccelBiasSigma, 2.0e-4); + m_nh.param("GyroBiasSigma", m_GyroBiasSigma, 3.0e-5); + m_nh.param("GPSSigma", m_gpsSigma, 0.07); + m_nh.param("SensorTransformX", m_sensorX, 0.0); + m_nh.param("SensorTransformY", m_sensorY, 0.0); + m_nh.param("SensorTransformZ", m_sensorZ, 0.0); + m_nh.param("SensorXAngle", m_sensorXAngle, 0); + m_nh.param("SensorYAngle", m_sensorYAngle, 0); + m_nh.param("SensorZAngle", m_sensorZAngle, 0); + m_nh.param("CarXAngle", m_carXAngle, 0); + m_nh.param("CarYAngle", m_carYAngle, 0); + m_nh.param("CarZAngle", m_carZAngle, 0); + m_nh.param("GpsSkip", m_gpsSkip, 5); + m_nh.param("Gravity", m_gravityMagnitude, 9.8); + //Limit to about 0.9g +// m_nh.param("MaxGPSAccel", m_accelLimit, 9.0); + m_nh.param("InvertX", m_invertx, false); + m_nh.param("InvertY", m_inverty, false); + m_nh.param("InvertZ", m_invertz, false); + m_nh.param("Imudt", m_imuDt, 1.0/200.0); + + + + bool fixedInitialPose; + double initialRoll, intialPitch, initialYaw; + + m_nh.param("FixedInitialPose", fixedInitialPose, false); + m_nh.param("initialRoll", initialRoll, 0); + m_nh.param("intialPitch", intialPitch, 0); + m_nh.param("initialYaw", initialYaw, 0); + + + std::cout << "InitialYaw " << m_initialYaw << "\n" + << "InitialRotationNoise " << m_initialRotationNoise << "\n" + << "InitialVelocityNoise " << m_initialVelNoise << "\n" + << "InitialBiasNoiseAcc " << m_initialBiasNoiseAcc << "\n" + << "InitialBiasNoiseGyro " << m_initialBiasNoiseGyro << "\n" + << "AccelerometerSigma " << accSigma << "\n" + << "GyroSigma " << gyroSigma << "\n" + << "AccelBiasSigma " << m_AccelBiasSigma << "\n" + << "GyroBiasSigma " << m_GyroBiasSigma << "\n" + << "GPSSigma " << m_gpsSigma << "\n" + << "SensorTransformX " << m_sensorX << "\n" + << "SensorTransformY " << m_sensorY << "\n" + << "SensorTransformZ " << m_sensorZ << "\n" + << "SensorXAngle " << m_sensorXAngle << "\n" + << "SensorYAngle " << m_sensorYAngle << "\n" + << "SensorZAngle " << m_sensorZAngle << "\n" + << "CarXAngle " << m_carXAngle << "\n" + << "CarYAngle " << m_carYAngle << "\n" + << "CarZAngle " << m_carZAngle << "\n" + << "GpsSkip " << m_gpsSkip << "\n" + << "Gravity " << m_gravityMagnitude << "\n"; + + // Use an ENU frame + m_preintegrationParams = PreintegrationParams::MakeSharedU(m_gravityMagnitude); + m_preintegrationParams->accelerometerCovariance = accSigma * I_3x3; + m_preintegrationParams->gyroscopeCovariance = gyroSigma * I_3x3; + m_preintegrationParams->integrationCovariance = 1e-5 * I_3x3; + + Vector biases((Vector(6) << 0, 0, 0, 0, 0, 0).finished()); + m_optimizedBias = imuBias::ConstantBias(biases); + m_previousBias = imuBias::ConstantBias(biases); + m_imuPredictor = boost::make_shared(m_preintegrationParams,m_optimizedBias); + + m_prevTime = ros::TIME_MIN; + m_optimizedTime = 0; + + imu_3dm_gx4::FilterOutputConstPtr ip; + if (!fixedInitialPose) { + while (!ip) + { + ROS_WARN("Waiting for valid initial pose"); + ip = ros::topic::waitForMessage("filter", m_nh, ros::Duration(15)); + } + m_initialPose = *ip; + } + else { + ROS_WARN("Using fixed initial pose"); + Rot3 initialRotation = Rot3::Ypr(initialYaw, intialPitch, initialRoll); + m_initialPose.orientation.w = initialRotation.quaternion()[0]; + m_initialPose.orientation.x = initialRotation.quaternion()[1]; + m_initialPose.orientation.y = initialRotation.quaternion()[2]; + m_initialPose.orientation.z = initialRotation.quaternion()[3]; + m_initialPose.bias.x = 0; + m_initialPose.bias.y = 0; + m_initialPose.bias.z = 0; + + } + + Rot3 initRot(Quaternion(m_initialPose.orientation.w, m_initialPose.orientation.x, m_initialPose.orientation.y, m_initialPose.orientation.z)); +// std::cout << "Rotation yaw: " << initRot.yaw() << " pitch: " << initRot.pitch() << " roll: " << initRot.roll() << std::endl; + + m_bodyPSensor = Pose3(Rot3::RzRyRx(m_sensorXAngle, m_sensorYAngle, m_sensorZAngle), + //m_bodyPSensor = Pose3(Rot3::RzRyRx(0, 0, 0), + Point3(m_sensorX, m_sensorY, m_sensorZ)); + m_carENUPcarNED = Pose3(Rot3::RzRyRx(m_carXAngle, m_carYAngle, m_carZAngle), Point3()); + + m_bodyPSensor.print("Body pose\n"); + m_carENUPcarNED.print("CarBodyPose\n"); + + m_posePub = m_nh.advertise("pose", 1); +// m_gpsPosePub = m_nh.advertise("pose_gps", 1); + m_biasAccPub = m_nh.advertise("bias_acc", 1); + m_biasGyroPub = m_nh.advertise("bias_gyro", 1); +// m_anglePub = m_nh.advertise("angle_est", 1); +// m_imuAnglePub = m_nh.advertise("angle_imu", 1); + m_timePub = m_nh.advertise("time_delays", 1); + + + m_gravity << 0, 0, m_gravityMagnitude; // Define gravity + m_omegaCoriolis << 0, 0, 0; + + ISAM2Params params; + params.factorization = ISAM2Params::QR; + m_isam = new ISAM2(params); + + m_prevVel = (Vector(3) << 0.0,0.0,0.0).finished(); + + // prior on the first pose + priorNoisePose = noiseModel::Diagonal::Sigmas( + (Vector(6) << m_initialRotationNoise, m_initialRotationNoise, 3*m_initialRotationNoise, + m_gpsSigma, m_gpsSigma, m_gpsSigma).finished()); + // add to solver and values + + // Add velocity prior + priorNoiseVel = noiseModel::Diagonal::Sigmas( + (Vector(3) << m_initialVelNoise, m_initialVelNoise, m_initialVelNoise).finished()); + + // Add bias prior + priorNoiseBias = noiseModel::Diagonal::Sigmas( + (Vector(6) << m_initialBiasNoiseAcc, + m_initialBiasNoiseAcc, + m_initialBiasNoiseAcc, + m_initialBiasNoiseGyro, + m_initialBiasNoiseGyro, + m_initialBiasNoiseGyro).finished()); + + sigma_acc_bias_c << m_AccelBiasSigma, m_AccelBiasSigma, m_AccelBiasSigma; + sigma_gyro_bias_c << m_GyroBiasSigma, m_GyroBiasSigma, m_GyroBiasSigma; + + noiseModelBetweenbias_sigma = (Vector(6) << sigma_acc_bias_c, sigma_gyro_bias_c).finished(); + noiseModelBetweenbias = noiseModel::Diagonal::Sigmas((noiseModelBetweenbias_sigma)); + + m_gpsSub = m_nh.subscribe("gps", 300, &Imu_Gps::GpsCb, this); + m_imuSub = m_nh.subscribe("imu", 600, &Imu_Gps::ImuCb, this); + + boost::thread optimizer(&Imu_Gps::GpsHelper,this); + + } + + Imu_Gps::~Imu_Gps() + {} + + void Imu_Gps::GpsCb(sensor_msgs::NavSatFixConstPtr fix) + { + if (!m_gpsOptQ.pushNonBlocking(fix)) + { + ROS_WARN("Dropping a GPS measurement due to full queue!!"); + } +// m_gpsPtr = fix; +// m_curGpsNumber ++; + return; + } + + void Imu_Gps::GetAccGyro(sensor_msgs::ImuConstPtr imu, Vector3 &acc, Vector3 &gyro) + { + double accx, accy, accz; + if (m_invertx) accx = -imu->linear_acceleration.x; + else accx = imu->linear_acceleration.x; + if (m_inverty) accy = -imu->linear_acceleration.y; + else accy = imu->linear_acceleration.y; + if (m_invertz) accz = -imu->linear_acceleration.z; + else accz = imu->linear_acceleration.z; + acc = Vector3(accx, accy, accz); + + double gx, gy, gz; + if (m_invertx) gx = -imu->angular_velocity.x; + else gx = imu->angular_velocity.x; + if (m_inverty) gy = -imu->angular_velocity.y; + else gy = imu->angular_velocity.y; + if (m_invertz) gz = -imu->angular_velocity.z; + else gz = imu->angular_velocity.z; + + gyro = Vector3(gx, gy, gz); + } + + void Imu_Gps::GpsHelper() + { + // Kick off the thread, and wait for our GPS measurements to come streaming in + while (ros::ok()) + { + sensor_msgs::NavSatFixConstPtr fix = m_gpsOptQ.popBlocking(); + ++m_gpsCounter; + if (m_gpsCounter > m_gpsSkip) m_gpsCounter = 0; + else continue; + + ros::WallTime tstart = ros::WallTime::now(); + if (!m_gotFirstFix) + { + NonlinearFactorGraph newFactors; + Values newVariables; + m_gotFirstFix = true; + m_enu.Reset(fix->latitude, fix->longitude, fix->altitude); + // ROS_WARN("Reset local origin to %f %f %f", fix->latitude, fix->longitude, fix->altitude); + // Add prior factors on pose, vel and bias + Rot3 initialOrientation = Rot3::Quaternion(m_initialPose.orientation.w, + m_initialPose.orientation.x, + m_initialPose.orientation.y, + m_initialPose.orientation.z); + //m_bodyPSensor.rotation() * + std::cout << "Initial orientation" << std::endl; + std::cout << m_bodyPSensor.rotation() * initialOrientation * m_carENUPcarNED.rotation() << std::endl; + Pose3 x0(m_bodyPSensor.rotation() * initialOrientation * m_carENUPcarNED.rotation(), + Point3(0, 0, 0)); /// We always start at the origin of m_enu + m_prevPose = x0; + PriorFactor priorPose(X(0), x0, priorNoisePose); + newFactors.add(priorPose); + PriorFactor priorVel(V(0), Vector3(0, 0, 0), priorNoiseVel); + newFactors.add(priorVel); + Vector biases((Vector(6) << 0, 0, 0, m_initialPose.bias.x, + -m_initialPose.bias.y, -m_initialPose.bias.z).finished()); + // std::cout << "Initial Biases\n" << biases << std::endl; + m_previousBias = imuBias::ConstantBias(biases); + PriorFactor priorBias(B(0), imuBias::ConstantBias(biases), priorNoiseBias); + newFactors.add(priorBias); + // add prior values on pose, vel and bias + newVariables.insert(X(0), x0); + newVariables.insert(V(0), Vector3(0, 0, 0)); + newVariables.insert(B(0), imuBias::ConstantBias(biases)); + + m_isam->update(newFactors, newVariables); + //Read IMU measurements up to the first GPS measurement + m_lastIMU = m_ImuOptQ.popBlocking(); + //If we only pop one, we need some dt + m_lastImuTgps = m_lastIMU->header.stamp.toSec() - 0.005; + while(m_lastIMU->header.stamp.toSec() < fix->header.stamp.toSec()) + { + m_lastImuTgps = m_lastIMU->header.stamp.toSec(); + m_lastIMU = m_ImuOptQ.popBlocking(); + } + } + else + { + NonlinearFactorGraph newFactors; + Values newVariables; + double E, N, U; + m_enu.Forward(fix->latitude, fix->longitude, fix->altitude, E, N, U); + double D = -U; // We want to work in NED + + PreintegratedImuMeasurements pre_int_data(m_preintegrationParams, m_previousBias); + + while(m_lastIMU->header.stamp.toSec() < fix->header.stamp.toSec()) + { + Vector3 acc, gyro; + GetAccGyro(m_lastIMU, acc, gyro); + double imuDT = m_lastIMU->header.stamp.toSec() - m_lastImuTgps; + m_lastImuTgps = m_lastIMU->header.stamp.toSec(); + pre_int_data.integrateMeasurement(acc, gyro, imuDT); + m_lastIMU = m_ImuOptQ.popBlocking(); + } + + ImuFactor imuFactor(X(m_poseVelKey), V(m_poseVelKey), X(m_poseVelKey+1), V(m_poseVelKey+1), B(m_biasKey), + pre_int_data); + + newFactors.add(imuFactor); + newFactors.add(BetweenFactor(B(m_biasKey), B(m_biasKey+1), imuBias::ConstantBias(), + noiseModel::Diagonal::Sigmas( sqrt(pre_int_data.deltaTij()) * noiseModelBetweenbias_sigma))); + + // Predict forward to get an initialization for the pose and velocity + NavState curNavState(m_prevPose, m_prevVel); + NavState nextNavState = pre_int_data.predict(curNavState, m_previousBias); + + SharedDiagonal gpsNoise = noiseModel::Diagonal::Sigmas(Vector3(m_gpsSigma, m_gpsSigma, 3.0 * m_gpsSigma)); + + GPSFactor gpsFactor(X(m_poseVelKey+1), Point3(E, N, U), gpsNoise); + newFactors.add(gpsFactor); + + newVariables.insert(X(m_poseVelKey+1), nextNavState.pose()); + newVariables.insert(V(m_poseVelKey+1), nextNavState.v()); + newVariables.insert(B(m_biasKey+1), m_previousBias); + + m_isam->update(newFactors, newVariables); + m_prevPose = m_isam->calculateEstimate(X(m_poseVelKey+1)); + m_prevVel = m_isam->calculateEstimate(V(m_poseVelKey+1)); + m_previousBias = m_isam->calculateEstimate(B(m_biasKey+1)); + //std::cout << m_isam->marginalCovariance(X(m_poseVelKey+1)) << std::endl << std::endl; + + diag_ok("Still ok!"); + + { + boost::mutex::scoped_lock guard(m_optimizedStateMutex); + m_optimizedState = NavState(m_prevPose, m_prevVel); + m_optimizedBias = m_previousBias; + m_optimizedTime = fix->header.stamp.toSec(); + } + + nav_msgs::Odometry poseNew; + poseNew.header.stamp = fix->header.stamp; + Vector3 rpy = m_prevPose.rotation().rpy(); +// ROS_INFO("time: %f\tr: %f p: %f y: %f", (ros::WallTime::now() - tstart).toSec(), rpy[0], rpy[1], rpy[2]); + + geometry_msgs::Point ptAcc; + ptAcc.x = m_previousBias.vector()[0]; + ptAcc.y = m_previousBias.vector()[1]; + ptAcc.z = m_previousBias.vector()[2]; + + geometry_msgs::Point ptGyro; + ptGyro.x = m_previousBias.vector()[3]; + ptGyro.y = m_previousBias.vector()[4]; + ptGyro.z = m_previousBias.vector()[5]; + + m_biasAccPub.publish(ptAcc); + m_biasGyroPub.publish(ptGyro); + + m_biasKey ++; + m_poseVelKey ++; + } + } + } + + void Imu_Gps::ImuCb(sensor_msgs::ImuConstPtr imu) + { + double dt = imu->header.stamp.toSec() - m_lastImuT; + m_lastImuT = imu->header.stamp.toSec(); + ros::Time before = ros::Time::now(); + // Push the IMU measurement to the optimization thread + int qSize = m_ImuOptQ.size(); + if (qSize > m_maxQSize) + { + m_maxQSize = qSize; +// ROS_WARN("Queue size %d", m_maxQSize); + } + if (!m_ImuOptQ.pushNonBlocking(imu)) + { + ROS_WARN("Dropping an IMU measurement due to full queue!!"); + } + // Each time we get an imu measurement, calculate the incremental pose from the last GTSAM pose + m_imuMeasurements.push_back(imu); + //Grab the most current optimized state + double optimizedTime; + NavState optimizedState; + imuBias::ConstantBias optimizedBias; + { + boost::mutex::scoped_lock guard(m_optimizedStateMutex); + optimizedState = m_optimizedState; + optimizedBias = m_optimizedBias; + optimizedTime = m_optimizedTime; + } + if (optimizedTime == 0) return; + + bool newMeasurements = false; + int numImuDiscarded = 0; + while (!m_imuMeasurements.empty() && (m_imuMeasurements.front()->header.stamp.toSec() < optimizedTime)) + { + m_imuMeasurements.pop_front(); + newMeasurements = true; + numImuDiscarded ++; + } + + if(newMeasurements) + { + //We need to reset integration and iterate through all our IMU measurements + m_imuPredictor->resetIntegration(); + int numMeasurements = 0; + for (auto it=m_imuMeasurements.begin(); it!=m_imuMeasurements.end(); ++it) + { + double dt = m_imuQPrevTime - (*it)->header.stamp.toSec(); + m_imuQPrevTime = (*it)->header.stamp.toSec(); + Vector3 acc, gyro; + GetAccGyro(*it, acc, gyro); + m_imuPredictor->integrateMeasurement(acc, gyro, m_imuDt); + numMeasurements++; + } +// ROS_INFO("Resetting Integration, %d measurements integrated, %d discarded", numMeasurements, numImuDiscarded); + } + else + { + //Just need to add the newest measurement, no new optimized pose + Vector3 acc, gyro; + GetAccGyro(imu, acc, gyro); + m_imuPredictor->integrateMeasurement(acc, gyro, dt);//m_bodyPSensor); + } + NavState currentPose = m_imuPredictor->predict(optimizedState, optimizedBias); + nav_msgs::Odometry poseNew; + poseNew.header.stamp = imu->header.stamp; + + Vector4 q = currentPose.quaternion().coeffs(); + poseNew.pose.pose.orientation.x = q[0]; + poseNew.pose.pose.orientation.y = q[1]; + poseNew.pose.pose.orientation.z = q[2]; + poseNew.pose.pose.orientation.w = q[3]; + + poseNew.pose.pose.position.x = currentPose.position().x(); + poseNew.pose.pose.position.y = currentPose.position().y(); + poseNew.pose.pose.position.z = currentPose.position().z(); + + poseNew.twist.twist.linear.x = currentPose.velocity().x(); + poseNew.twist.twist.linear.y = currentPose.velocity().y(); + poseNew.twist.twist.linear.z = currentPose.velocity().z(); + + poseNew.child_frame_id = "base_link"; + poseNew.header.frame_id = "odom"; + + m_posePub.publish(poseNew); + + ros::Time after = ros::Time::now(); + geometry_msgs::Point delays; + delays.x = imu->header.stamp.toSec(); + delays.y = (ros::Time::now() - imu->header.stamp).toSec(); + delays.z = imu->header.stamp.toSec() - optimizedTime; + m_timePub.publish(delays); + return; + } + + void Imu_Gps::diagnosticStatus(const ros::TimerEvent& /*time*/) + { + //Don't do anything + //diag_info("Test"); + } + +}; + +int main (int argc, char** argv) +{ + ros::init(argc, argv, "stateEstimator"); + //ros::NodeHandle n; + autorally_core::Imu_Gps wpt; + ros::spin(); +} diff --git a/autorally_core/src/StateEstimator/IMU_GPS.h b/autorally_core/src/StateEstimator/IMU_GPS.h new file mode 100644 index 00000000..d2801bd7 --- /dev/null +++ b/autorally_core/src/StateEstimator/IMU_GPS.h @@ -0,0 +1,159 @@ + +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file JumpControl.h + * @author Brian Goldfain + * @date November 13, 2013 + * @copyright 2012 Georgia Institute of Technology + * @brief JumpControl class definition + * + ***********************************************/ + +#ifndef IMU_GPS_H_ +#define IMU_GPS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "autorally_core/Diagnostics.h" +#include "BlockingQueue.h" + +#include +#include +#include +#include +#include +#include +#include + +#define PI 3.14159265358979323846264338 + +using namespace gtsam; +using namespace GeographicLib; + +namespace autorally_core +{ + class Imu_Gps : public Diagnostics + { + public: + Imu_Gps(); + ~Imu_Gps(); + ros::NodeHandle m_nh; + ros::Subscriber m_gpsSub, m_imuSub; + ros::Publisher m_posePub; + ros::Publisher m_biasAccPub, m_biasGyroPub; +// ros::Publisher m_anglePub, m_imuAnglePub; + ros::Publisher m_timePub; + + ros::Time m_prevTime; + ros::Time m_lastImuTime; + ros::Time m_overlimitTime; + + long m_biasKey, m_poseVelKey; + + double m_initialYaw; + double m_lastImuT, m_lastImuTgps, m_imuQPrevTime; + double m_initialRotationNoise, m_initialTransNoise, m_initialVelNoise; + double m_initialBiasNoiseAcc, m_initialBiasNoiseGyro; + double m_AccelBiasSigma, m_GyroBiasSigma; + double m_gpsSigma, m_gravityMagnitude; + double m_sensorX, m_sensorY, m_sensorZ; + double m_sensorXAngle, m_sensorYAngle, m_sensorZAngle; + double m_carXAngle, m_carYAngle, m_carZAngle; + + int m_gpsSkip, m_gpsCounter; + int m_maxQSize; + + BlockingQueue m_gpsOptQ; + BlockingQueue m_ImuOptQ; + boost::mutex m_optimizedStateMutex; + NavState m_optimizedState; + double m_optimizedTime; + boost::shared_ptr m_imuPredictor; + double m_imuDt; + imuBias::ConstantBias m_optimizedBias, m_previousBias; + sensor_msgs::ImuConstPtr m_lastIMU; + boost::shared_ptr m_preintegrationParams; + + std::list m_imuMeasurements, m_imuGrav; + imu_3dm_gx4::FilterOutput m_initialPose; + + Vector3 m_gravity; + Vector3 m_omegaCoriolis; + Vector3 m_prevVel; + Pose3 m_prevPose; + Pose3 m_bodyPSensor, m_carENUPcarNED; + + LocalCartesian m_enu; /// Object to put lat/lon coordinates into local cartesian + bool m_gotFirstFix; + bool m_invertx, m_inverty, m_invertz; + + SharedDiagonal priorNoisePose; + SharedDiagonal priorNoiseVel; + SharedDiagonal priorNoiseBias; + + Vector3 sigma_acc_bias_c; + Vector3 sigma_gyro_bias_c; + + Vector noiseModelBetweenbias_sigma; + SharedDiagonal noiseModelBetweenbias; + + ISAM2 *m_isam; + + void GpsCb(sensor_msgs::NavSatFixConstPtr fix); + void ImuCb(sensor_msgs::ImuConstPtr imu); + void FilterCb(imu_3dm_gx4::FilterOutputConstPtr fix); + void GpsHelper(); + void diagnosticStatus(const ros::TimerEvent& time); + + void GetAccGyro(sensor_msgs::ImuConstPtr imu, Vector3 &acc, Vector3 &gyro); + }; +}; + +#endif /* IMU_GPS_H_ */ diff --git a/autorally_core/src/arduino/ArduinoOnboard.cpp b/autorally_core/src/arduino/ArduinoOnboard.cpp new file mode 100644 index 00000000..b2b24237 --- /dev/null +++ b/autorally_core/src/arduino/ArduinoOnboard.cpp @@ -0,0 +1,352 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file ArduinoOnboard.cpp + * @author Brian Goldfain + * @date January 22, 2014 + * @copyright 2014 Georgia Institute of Technology + * @brief Brief file description + * Brief description continued. + * + * @details Contains ArdionoOnboard class implementation + ***********************************************/ +#include "ArduinoOnboard.h" + +#include + +#include + +#include + +PLUGINLIB_DECLARE_CLASS(autorally_core, ArduinoOnboard, autorally_core::ArduinoOnboard, nodelet::Nodelet) + +namespace autorally_core +{ + +ArduinoOnboard::ArduinoOnboard(): + m_lfSum(0.0), + m_rfSum(0.0), + m_lbSum(0.0), + m_rbSum(0.0) +{} + +ArduinoOnboard::~ArduinoOnboard() +{ + +} + +void ArduinoOnboard::onInit() +{ + ros::NodeHandle nh = getNodeHandle(); + m_nhPvt = getPrivateNodeHandle(); + + m_lastTime = ros::Time::now(); + std::string port; + + if(!m_nhPvt.getParam("port", port) || + !m_nhPvt.getParam("numMovingAverageValues", m_numMovingAverageValues) || + !m_nhPvt.getParam("wheelDiameter", m_wheelDiameter) || + !m_nhPvt.getParam("triggerFPS", m_triggerFPS) || + !m_nhPvt.getParam("srvBatteryCrit", srvBatteryCrit) || + !m_nhPvt.getParam("srvBatteryLow", srvBatteryLow) || + !m_nhPvt.getParam("camBatteryCrit", camBatteryCrit) || + !m_nhPvt.getParam("camBatteryLow", camBatteryLow) || + !m_nhPvt.getParam("lfRotationEnabled", m_lfEnabled) || + !m_nhPvt.getParam("rfRotationEnabled", m_rfEnabled) || + !m_nhPvt.getParam("lbRotationEnabled", m_lbEnabled) || + !m_nhPvt.getParam("rbRotationEnabled", m_rbEnabled) ) + { + ROS_ERROR("ArduinoOnboard: Could not get all arduinoOnboard parameters"); + } + + m_wheelSpeedPub = nh.advertise + ("wheelSpeeds", 1); + + m_servoPub = nh.advertise ("RC", 1); + + m_port.init(m_nhPvt, getName(), "", "ArduinoOnboard", port, true); + m_port.registerDataCallback( + boost::bind(&ArduinoOnboard::arduinoDataCallback, this)); + + loadServoParams(); +} + +void ArduinoOnboard::arduinoDataCallback() +{ + std::string msg; + +// These are super expensive on the jetson +// m_nhPvt.getParam("srvBatteryCrit", srvBatteryCrit); +// m_nhPvt.getParam("srvBatteryLow", srvBatteryLow); +// m_nhPvt.getParam("camBatteryCrit", camBatteryCrit); +// m_nhPvt.getParam("camBatteryLow", camBatteryLow); + + while(findMessage(msg)) + { + //allocate new wheelSpeeds message + autorally_msgs::wheelSpeedsPtr wheelSpeeds(new autorally_msgs::wheelSpeeds); + wheelSpeeds->header.stamp = ros::Time::now(); + + boost::char_separator seps(":,\n"); + tokenizer tok(msg, seps); + tokenizer::iterator it=tok.begin(); + + //allocate new servo message for RC servoCommand + autorally_msgs::servoMSGPtr servos(new autorally_msgs::servoMSG); + servos->header.frame_id = "RC"; + servos->backBrake = -5.0; + servos->frontBrake = -5.0; + + double lf, rf, lb, rb; + bool wheels = false; + //bool servo = false; + //bool camera = false; + bool rc = false; + + while(it!=tok.end()) + { + if(*it == "wheels") + { + if(++it == tok.end()) break; + lf = atof(it->c_str()); + + if(++it == tok.end()) break; + rf = atof(it->c_str()); + + if(++it == tok.end()) break; + lb = atof(it->c_str()); + + if(++it == tok.end()) break; + rb = atof(it->c_str()); + + wheels = true; + //} else if(*it == "servo") + //{ + // if(++it == tok.end()) break; + // m_port.diag("Servo Battery Voltage", *it); + // servo = true; + //} else if(*it == "camera") + //{ + // if(++it == tok.end()) break; + // m_port.diag("Camera Battery Voltage", *it); + // camera = true; + } else if(*it == "rc") + { + if(++it == tok.end()) break; + servos->throttle = atof(it->c_str()); + + if(++it == tok.end()) break; + servos->steering = atof(it->c_str()); + rc = true; + } else + { + NODELET_ERROR("ArduinoOnboard: Bad token %s", it->c_str()); + m_port.diag_warn("ArduinoOnboard got a bad token"); + } + + if(it!=tok.end()) + { + ++it; + } + } + if(!(wheels && rc)) + { + NODELET_ERROR("ArduinoOnboard: Incomplete packet %d %d", wheels, rc); + m_port.diag_warn("ArduinoOnboard: Incomplete packet"); + } + + if(isnan(lf)) lf = 0.0; + if(isnan(lb)) lb = 0.0; + if(isnan(rf)) rf = 0.0; + if(isnan(rb)) rb = 0.0; + + wheelSpeeds->lfSpeed = (lf)*m_wheelDiameter*PI; + wheelSpeeds->lbSpeed = (lb)*m_wheelDiameter*PI; + wheelSpeeds->rfSpeed = (rf)*m_wheelDiameter*PI; + wheelSpeeds->rbSpeed = (rb)*m_wheelDiameter*PI; + + //check if one of the front rotation sensors is disabled + if(m_lfEnabled && !m_rfEnabled) + { + wheelSpeeds->rfSpeed = wheelSpeeds->lfSpeed; + } else if(!m_lfEnabled && m_rfEnabled) + { + wheelSpeeds->lfSpeed = wheelSpeeds->rfSpeed; + } + + //check if one of the back rotation sensors is disabled + if(m_lbEnabled && !m_rbEnabled) + { + wheelSpeeds->rbSpeed = wheelSpeeds->lbSpeed; + } else if(!m_lbEnabled && m_rbEnabled) + { + wheelSpeeds->lbSpeed = wheelSpeeds->rbSpeed; + } + + //Calculate servo commands + //Raw data from arduino is in units of 500 ns. + servos->throttle /= 2.0; + servos->steering /= 2.0; + std::map::const_iterator mapIt; + + if( (mapIt = m_servoSettings.find("steering")) != m_servoSettings.end()) + { + if(servos->steering > mapIt->second.center) + { + servos->steering = (servos->steering - mapIt->second.center) / (mapIt->second.max-mapIt->second.center); + if (servos->steering > 1.0) + servos->steering = 1.0; + } else if(servos->steering < mapIt->second.center) + { + servos->steering = (servos->steering-mapIt->second.center)/(mapIt->second.center-mapIt->second.min); + if (servos->steering < -1.0) + servos->steering = -1.0; + } else + { + servos->steering = 0.0; + } + + if(mapIt->second.reverse) + { + servos->steering = -servos->steering; + } + } + if( (mapIt = m_servoSettings.find("throttle")) != m_servoSettings.end()) + { + if(servos->throttle > mapIt->second.center) + { + servos->throttle = (servos->throttle - mapIt->second.center) / (mapIt->second.max-mapIt->second.center); + if (servos->throttle > 1.0) + servos->throttle = 1.0; + } else if(servos->throttle < mapIt->second.center) + { + servos->throttle = (servos->throttle-mapIt->second.center)/(mapIt->second.center-mapIt->second.min); + if (servos->throttle < -1.0) + servos->throttle = -1.0; + } else + { + servos->throttle = 0.0; + } + + if(mapIt->second.reverse) + { + servos->throttle = -servos->throttle; + } + } + + + servos->header.stamp = ros::Time::now(); + + if (m_lastTime + ros::Duration(2.0) > ros::Time::now()) { + m_lastTime = ros::Time::now(); + //set FPS + int newFPS = 0; + m_nhPvt.getParam("triggerFPS", newFPS); + if(newFPS != m_triggerFPS) + { + m_triggerFPS = newFPS; + m_port.lock(); + m_port.writePort("#fps:" + std::to_string(m_triggerFPS) + "\r\n"); + m_port.unlock(); + } + } + + //publish data + m_wheelSpeedPub.publish(wheelSpeeds); + m_servoPub.publish(servos); + m_port.tick("arduinoData"); + m_port.diag("Triggering FPS", std::to_string(m_triggerFPS)); + } +} + +bool ArduinoOnboard::findMessage(std::string& msg) +{ + m_port.lock(); + if(m_port.m_data.size() > 10) + { + //make sure data is framed + if(m_port.m_data[0] != '#') + { + size_t start = m_port.m_data.find("#"); + m_port.m_data.erase(0, start); + } + + //try to pull out a full message + size_t end = m_port.m_data.find("\r\n"); + if(end != std::string::npos) + { + //std::cout << "Looking at^" << m_port.m_data << "^" << std::endl; + //remove # at beginning and trailing \r\n before further processing + msg = m_port.m_data.substr(1,end-1); + //erase through \r\n at end of message + m_port.m_data.erase(0,end+2); + m_port.unlock(); + return true; + } + } + m_port.unlock(); + return false; +} + +void ArduinoOnboard::loadServoParams() +{ + //read in servo settings + ros::NodeHandle nhPvt = getPrivateNodeHandle(); + XmlRpc::XmlRpcValue v; + nhPvt.param("servos", v, v); + if(v.getType() == XmlRpc::XmlRpcValue::TypeStruct) + { + XmlRpc::XmlRpcValue servoInfo; + ServoSettings toAdd; + for(int i = 0; i < v.size(); i++) + { + servoInfo = v[boost::lexical_cast(i)]; + + if(servoInfo.getType() == XmlRpc::XmlRpcValue::TypeStruct && + servoInfo.size() == 5) + { + toAdd.center = static_cast(servoInfo["center"]); + toAdd.min = static_cast(servoInfo["min"]); + toAdd.max = static_cast(servoInfo["max"]); + toAdd.range = toAdd.max-toAdd.min; + toAdd.port = i; + toAdd.reverse = static_cast(servoInfo["reverse"]); + m_servoSettings[servoInfo["name"]] = toAdd; + } else + { + NODELET_ERROR("ServoInterface: XmlRpc servo settings formatted incorrectly"); + } + } + } else + { + NODELET_ERROR("ServoInterface: Couldn't retreive servo settings"); + } + NODELET_INFO("ServoInterface: Loaded %u servos", m_servoSettings.size()); + +} + + +} diff --git a/autorally_core/src/arduino/ArduinoOnboard.h b/autorally_core/src/arduino/ArduinoOnboard.h new file mode 100644 index 00000000..06381f47 --- /dev/null +++ b/autorally_core/src/arduino/ArduinoOnboard.h @@ -0,0 +1,158 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file ArduinoOnboard.h + * @author Brian Goldfain + * @date January 22, 2014 + * @copyright 2014 Georgia Institute of Technology + * @brief + * + * @details This file contains the ArduinoOnboard class + ***********************************************/ + +#ifndef Arduino_Onboard +#define Arduino_Onboard + +#define PI 3.141592653589793238462; + +#include +#include +#include +//#include +#include +#include +#include + +#include +//#include + +#include +#include + +namespace autorally_core +{ + +/** + * @class ArduinoOnboard ArduinoOnboard.h + * "ArduinoOnboard/ArduinoOnboard.h" + * @brief Interacts with the onboard Arduino card + * + * The Arduino card publishes data on startup. This class + * publishes that data as an arduinoData message. + */ +class ArduinoOnboard : public nodelet::Nodelet +{ + + public: + /** + * @brief Constructor requires all configuration needed to connect to arduino + * + */ + ArduinoOnboard(); + + ~ArduinoOnboard(); + + void onInit(); + + private: + ros::NodeHandle m_nhPvt; + + ros::Publisher m_arduinoPub; /// m_lf; + //boost::circular_buffer m_rf; + //boost::circular_buffer m_lb; + //boost::circular_buffer m_rb; + + bool m_lfEnabled; + bool m_rfEnabled; + bool m_lbEnabled; + bool m_rbEnabled; + + typedef boost::tokenizer > tokenizer; + + /** + * @brief Process incoming data stream to pull out complete message strings + * @return bool if a complete message string was found and processed + */ + void arduinoDataCallback(); + bool findMessage(std::string& msg); + void loadServoParams(); + + struct ServoSettings + { + unsigned short center; ///< calibrated zero of servo in us + unsigned short min; ///< calibrated minimum of servo in us (left) + unsigned short max; ///< calibrated maximum of servo in us (right) + unsigned short range; ///< range of servo signal (max-min) + unsigned char port; ///< port on servo controller + bool reverse; ///< if the servo should be reversed + + // center should be (min+max)/2 + ServoSettings(): + center(1500), + min(1050), + max(1950), + range(max-min), + port(0), + reverse(false) + {} + }; + + std::map m_servoSettings; +}; + +} + +#endif //Arduino_Onboard diff --git a/autorally_core/src/arduino/CMakeLists.txt b/autorally_core/src/arduino/CMakeLists.txt new file mode 100644 index 00000000..3b521426 --- /dev/null +++ b/autorally_core/src/arduino/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(ArduinoOnboard ArduinoOnboard.cpp) +target_link_libraries(ArduinoOnboard ${catkin_LIBRARIES} SerialSensorInterface Diagnostics) +add_dependencies(ArduinoOnboard autorally_msgs_gencpp) + +install(TARGETS + ArduinoOnboard + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) diff --git a/autorally_core/src/arduino/arduinoOnboard/arduinoOnboard.ino b/autorally_core/src/arduino/arduinoOnboard/arduinoOnboard.ino new file mode 100644 index 00000000..fd87cf7b --- /dev/null +++ b/autorally_core/src/arduino/arduinoOnboard/arduinoOnboard.ino @@ -0,0 +1,357 @@ + + +/********************************************** + * @file arduinoDataSerial,ino + * @author Alex Bettadapur + * @date January 22, 2013 + * @copyright 2013 Georgia Institute of Technology + * @brief Communicates with sensors connected to Arduino + * + * @details Same function as the arduinoData.ino file, except modified + * to transfer data over serial. This program + * is meant to run on an Arduino Mega. It collects data + * from 4 Hall Effect sensors to measure wheel rotation + * and the voltage of the onboard data packs and publishes + * all data in one arduinoData message. + * This program also handles triggering the cameras. + ***********************************************/ + +#include +#include + +#define MAX_MEASUREMENT_AGE 400 ///< Zero the reading at 400 ms + +int triggerPin = 40; +int triggerFPS = 40; + +float analogVoltageScaler0; ///< Scale the analog reading 0-1024 to 0-5 volts, value from ADC specs +float analogVoltageScaler1; ///< Scale the analog reading 0-1024 to 0-5 volts, value from ADC specs + +volatile int rpscount0; ///< Counts the ticks from the Hall Effect sensor 0 +volatile int rpscount1; ///< Counts the ticks from the Hall Effect sensor 1 +volatile int rpscount2; ///< Counts the ticks from the Hall Effect sensor 2 +volatile int rpscount3; ///< Counts the ticks from the Hall Effect sensor 3 + +volatile unsigned long w0period; ///< Total period of wheel0 +unsigned long w0prevtimer; ///< Previous timer value of wheel0 +volatile unsigned long w0updatetime; ///< Last update time for wheel0 +volatile unsigned long w1period; ///< Total period of wheel0 +unsigned long w1prevtimer; ///< Previous timer value of wheel0 +volatile unsigned long w1updatetime; ///< Last update time for wheel0 +volatile unsigned long w2period; ///< Total period of wheel0 +unsigned long w2prevtimer; ///< Previous timer value of wheel0 +volatile unsigned long w2updatetime; ///< Last update time for wheel0 +volatile unsigned long w3period; ///< Total period of wheel0 +unsigned long w3prevtimer; ///< Previous timer value of wheel0 +volatile unsigned long w3updatetime; ///< Last update time for wheel0 + +volatile unsigned int rc_risingEdge4; ///< Record the rising edge of rc signal on IC4 +volatile unsigned int rc_width4; ///< Record the pulse width of the rc signal on IC4 +volatile unsigned int rc_risingEdge5; ///< Record the rising edge time of rc signal on IC5 +volatile unsigned int rc_width5; ///< Record the pulse width of the rc signal on IC5 + +int pulsesPerRevolution = 6; ///< Number of magnets on each wheel +//int frontPulsesPerRevolution = 6; +float divisor = 0.0; ///< Divisor calculated to turn absolute pulse count into rps +float divisorFront=0.0; +float dataPublishPeriod = 14.0;///< Period (in ms) for publishing arduinoData messages, 70hz +unsigned long time; ///< Time that the last message was published +unsigned long diagTime; ///< Time that the last diagnostic message was published +unsigned long elapsed; ///< Calculated elapsed time since last transmission +unsigned long diagElapsed; ///< Calculated elapsed time since last transmission +int counter=0; + +/*ros::NodeHandle nh; ///< Nodehandle to publish data into system +autorally_core::arduinoData msg; ///< Sensor data message to publish +diagnostic_msgs::DiagnosticArray diag; ///< Diagnostics message to publish +diagnostic_msgs::DiagnosticStatus stat; ///< Diagnostic status to publish +diagnostic_msgs::KeyValue info; ///< Diagnostics key value pair +ros::Publisher publisher("arduinoData", &msg); ///< ArduinoData publisher +ros::Publisher diagPublisher("diagnostics", &diag); ///< ArduinoData publisher*/ + +/** +* @brief Sets up all parameters, attaches interrupts, and initializes rosserial objects +*/ +void setup() +{ + pinMode(triggerPin, OUTPUT); + configureTriggerTimers(); + + pinMode(18, INPUT); + pinMode(19, INPUT); + pinMode(20, INPUT); + pinMode(21, INPUT); + digitalWrite(18,HIGH); + digitalWrite(19,HIGH); + digitalWrite(20,HIGH); + digitalWrite(21,HIGH); + + configureRcInput(); + + time = 0; + //attach all interrupts for rpm sensors + attachInterrupt(2, int0, RISING); + attachInterrupt(3, int1, RISING); + attachInterrupt(4, int2, RISING); + attachInterrupt(5, int3, RISING); + + rpscount0 = 0; + rpscount1 = 0; + rpscount2 = 0; + rpscount3 = 0; + + w0period = 0; ///< Total period of wheel0 + w0prevtimer = 0; ///< Previous timer value of wheel0 + w0updatetime = 0; ///< Last update time for wheel0 + w1period = 0; ///< Total period of wheel0 + w1prevtimer = 0; ///< Previous timer value of wheel0 + w1updatetime = 0; ///< Last update time for wheel0 + w2period = 0; ///< Total period of wheel0 + w2prevtimer = 0; ///< Previous timer value of wheel0 + w2updatetime = 0; ///< Last update time for wheel0 + w3period = 0; ///< Total period of wheel0 + w3prevtimer = 0; ///< Previous timer value of wheel0 + w3updatetime = 0; ///< Last update time for wheel0 + + + Serial.begin(115200); + + + //R1 0.96 KOhm + //R2 1.99 KOhm + analogVoltageScaler0 = 0.0049*(2.95/1.99); + + //R1 2.18 KOhm + //R2 5.07 KOhm + analogVoltageScaler1 = 0.0049*(7.25/2.18); + +} + +/** +* @brief Main body of program, gathers and publishes sensor data. +*/ +void loop() +{ + if(Serial.available() && Serial.read() == '#') + { + char buffer[10]; + int numBytesRead = Serial.readBytesUntil(':', buffer, 10); + if(numBytesRead < 10) + buffer[numBytesRead] = '\0'; + if(strcmp(buffer, "fps") == 0) + { + triggerFPS = Serial.parseInt(); + configureTriggerTimers(); + } + } + elapsed = millis()-time; + if(elapsed >= dataPublishPeriod) + { + counter++; + time = millis(); + //divisor = (pulsesPerRevolution*(elapsed/1000.0)); + //divisorFront = (frontPulsesPerRevolution*(elapsed/1000.0)); + + float leftFront, rightFront, leftBack, rightBack; + + getrps(leftFront, rightFront, leftBack, rightBack); + + //float servoVoltage = analogRead(0)*analogVoltageScaler0; + //float cameraVoltage = analogRead(1)*analogVoltageScaler1; + + Serial.print("#wheels:"); + Serial.print(leftFront,3); + Serial.print(","); + Serial.print(rightFront,3); + Serial.print(","); + Serial.print(leftBack,3); + Serial.print(","); + Serial.print(rightBack,3); + Serial.print("\n"); + + //Serial.print("servo:"); + //Serial.print(servoVoltage,2); + //Serial.print("\n"); + + //Serial.print("camera:"); + //Serial.print(cameraVoltage,2); + //Serial.print("\n"); + + Serial.print("rc:"); + Serial.print(rc_width4); + Serial.print(","); + Serial.println(rc_width5); + } + +} + +/** + * @brief Configures the ATmega's timers for the desired camera frame rate + * @note See http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts for details. + */ +void configureTriggerTimers() +{ + cli(); //disable global interrupts + TCCR3A=0; //shut off timers + TCCR3B = 0; //shut off timers + int cnt = (int)(1.0/((2.0*triggerFPS)*0.000016) - 1.0); //compute new overflow value. 2FPS to turn bit on and off at twice the framerate + OCR3A = cnt; //set the compare register to this computed overflow value + TCCR3B|=(1< + * @date November 5, 2013 + * @copyright 2013 Georgia Institute of Technology + * @brief Implementation of GPSHemisphere class + * + ***********************************************/ +#include "GPSHemisphere.h" + +#include + +#include +#include + +#include +#include +#include +#include + +/** + * This GPS Interface program currently using the hemisphere + * GPS R320 pr P303 Receivers. + */ +int main(int argc, char **argv) +{ + ros::init(argc, argv, "gpsBase"); + ros::NodeHandle nh; + + GPSHemisphere gpsInterface(nh); + + ros::spin(); + + return 0; +} + +void printMessage(const char* message, int size) +{ + for (int i = 0; i < size; i++) + { + printf("%x ", message[i]&0xFF ); + } + printf("\n"); +} +void printMessage(const std::string &message) +{ + printMessage(message.c_str(), message.size()); +} + +GPSHemisphere::GPSHemisphere(ros::NodeHandle &nh): + m_previousCovTime(ros::Time::now()), + m_mostRecentRTK(ros::Time::now()), + m_rtkEnabled(true) +{ + std::string nodeName = ros::this_node::getName(); + std::string mode; + std::string portPathA = ""; + std::string portPathB = ""; + + //default values reasonable for a crappy gps + nh.param(nodeName+"/accuracyRTK", m_accuracyRTK, 0.02); + nh.param(nodeName+"/accuracyWAAS", m_accuracyWAAS, 0.6); + nh.param(nodeName+"/accuracyAutonomous", m_accuracyAutonomous, 2.5); + nh.param(nodeName+"/gpsTimeOffset", m_gpsTimeOffset, 0.0); + nh.param(nodeName+"/utcSource", m_utcSource, "GPZDA"); + nh.param(nodeName+"/showGsv", m_showGsv, "false"); + + + if(!nh.getParam(nodeName+"/mode", mode) || + !nh.getParam(nodeName+"/primaryPort/portPath", portPathA) || + !nh.getParam(nodeName+"/correctionPort/portPath", portPathB) || + !nh.getParam(nodeName+"/statusPositionSource", m_statusPositionSource) ) + { + ROS_ERROR("GPSHemisphere: could not find mode or portPaths"); + } + { + if(mode == "base") + { + m_navSatFix.header.frame_id = "gpsBase"; + + m_rtkCorrection.layout.data_offset = 0; + m_rtkCorrection.layout.dim.push_back(std_msgs::MultiArrayDimension()); + m_timeUTC.source = "gps"; + + /* Have to init serial ports after publishers are connected otherwise + * if a message is received from serial before the associated publisher + * is connected, an exception occurs and the node crashes. + */ + m_portA.init(nh, nodeName, "primaryPort", "Hemisphere R320", portPathA, true); + m_portB.init(nh, nodeName, "correctionPort", "Hemisphere R320", portPathB, true); + + m_rtcm3Pub = nh.advertise("gpsBaseRTCM3", 5); + m_statusPub = nh.advertise("gpsBaseStatus", 5); + m_utcPub = nh.advertise("utc", 5); + + m_rtkStatusTimer = nh.createTimer(ros::Duration(1.0), + &GPSHemisphere::rtkStatusCallback, + this); + + m_portA.registerDataCallback( + boost::bind(&GPSHemisphere::gpsInfoCallback, this)); + m_portB.registerDataCallback( + boost::bind(&GPSHemisphere::rtcmDataCallback, this)); + + // m_refLocTimer = nh.createTimer(ros::Duration(60.0), +// &GPSHemisphere::updateReferenceLocationCallback, +// this); + } else if(mode == "rover") + { + /*rover gets base location through RTK corrections, updating ref location + * is not needed + */ + m_navSatFix.header.frame_id = "gpsRover"; + + /* Have to init serial ports after publishers are connected otherwise + * if a message is received from serial before the associated publisher + * is connected, an exception occurs and the node crashes. + */ + m_portA.init(nh, nodeName, "primaryPort", "Hemisphere p303", portPathA, true); + m_portB.init(nh, nodeName, "correctionPort", "Hemisphere p303", portPathB, false); + + m_statusPub = nh.advertise("gpsRoverStatus", 5); + + m_rtcm3Sub = nh.subscribe("gpsBaseRTCM3", 5, + &GPSHemisphere::rtcmCorrectionCallback, + this); + m_portA.registerDataCallback( + boost::bind(&GPSHemisphere::gpsInfoCallback, this)); + } else + { + ROS_ERROR("GPSHemisphere: unrecognized mode of operation:%s", mode.c_str()); + } + } + + if(!m_portA.connected() || !m_portB.connected()) + { + ROS_ERROR("GPSHemisphere: one of the serial ports isn't open, stuff might not work"); + } + + m_navSatFix.status.status = sensor_msgs::NavSatStatus::STATUS_NO_FIX; + m_navSatFix.status.service = sensor_msgs::NavSatStatus::SERVICE_GPS; + m_navSatFix.latitude = 0.0; + m_navSatFix.longitude = 0.0; + m_navSatFix.altitude = 0.0; + m_navSatFix.position_covariance_type = + sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN; + //set real high covariances for now + m_navSatFix.position_covariance[0] = 99999; + m_navSatFix.position_covariance[4] = 99999; + m_navSatFix.position_covariance[8] = 99999; + + + time_t t = time(NULL); + tm* timePtr = gmtime(&t); + + //since this is only done once, the published utc time messages will not + //be correct if the code is run overnight receiving GPGSA or GPGGA for timing + m_secondsToToday = 360*24*(timePtr->tm_year); +} + +GPSHemisphere::~GPSHemisphere() +{ + +} + + +void GPSHemisphere::gpsInfoCallback() +{ + std::string msg(""); + m_portA.lock(); + + //make sure data is framed (we expect only NMEA 0183 messages here) + if(!m_portA.m_data.empty()) + { + if(m_portA.m_data[0] != '$') + { + size_t start = m_portA.m_data.find("$"); + m_portA.m_data.erase(0, start); + } + + size_t end = m_portA.m_data.find("\r\n"); + if(end != std::string::npos) + { + //remove $ at beginning and trailing \r\n before further processing + msg = m_portA.m_data.substr(1,end-1); + //erase through \r\n at end of message + m_portA.m_data.erase(0,end+2); + } + } + m_portA.unlock(); + + //if a complete message was found, process it + if(!msg.empty()) + { + processGPSMessage(msg); + } +} + +void GPSHemisphere::rtcmDataCallback() +{ + m_portB.lock(); + + if(m_portB.m_data.size() > 6) + { + //make sure data is framed + if((m_portB.m_data[0]&0xff) != 0xd3) + { + std::string s; + s.push_back(0xd3); + s.push_back(0x00); + size_t start = m_portB.m_data.find(s); + //ROS_WARN_STREAM("Not Framed"); + //std::cout << "Discarding:" << m_portB.m_data.substr(0, start).size() << + // " Leading with:" << (unsigned int)(m_portB.m_data[0]&0xff) << std::endl; + //printMessage(m_portB.m_data); + m_portB.m_data.erase(0, start); + } + + //process if there is enough data to read the header and message type + if(m_portB.m_data.length() > 6) + { + /*RTCM 3.0 frame structure: + bits 0 - 7 - header + bits 8 - 13 - reserved + bits 14 - 23 - message length + bits 24 - 23+length - message + bits 24+length - 24+length+23 - 24 bit bit CRC + + first 6 bits of message body are message type, + total frame size (bytes): message length + 6 + */ + unsigned int len = (unsigned int)((((unsigned int)m_portB.m_data[1])&0x03)>>8) + + (unsigned int)(((m_portB.m_data[2])&0xff)) + 6; + unsigned int type = (unsigned int)(((m_portB.m_data[3])&0xff)<<4) + + (unsigned int)(((m_portB.m_data[4])&0xf0)>>4); + + /*printf("%x %x %x %x %x\n", m_portB.m_data[0]&0xff, + m_portB.m_data[1]&0xff, + m_portB.m_data[2]&0xff, + m_portB.m_data[3]&0xff, + m_portB.m_data[4]&0xff);*/ + + if(m_portB.m_data.size() >= len && ((type > 1000 && type < 1030) || (type > 4087 && type <= 4096))) + { + //printMessage(m_portB.m_data); + //ROS_WARN_STREAM("Buffer len:" << m_portB.m_data.length() << + // " Payload len:" << len << " msg type:" << type); + //record type of message seen in diagnostics + try + { + m_portB.tick("RTCM3.0 type "+boost::lexical_cast(type)); + + //fill in structure to send message + m_rtkCorrection.layout.dim.front().label = "RTCM3.0 " + + boost::lexical_cast(type); + + m_rtkCorrection.layout.dim.front().size = len; + m_rtkCorrection.layout.dim.front().stride = 1*(len); + m_rtkCorrection.data.resize(len); + memcpy(&m_rtkCorrection.data[0], &m_portB.m_data[0], len); + + m_rtcm3Pub.publish(m_rtkCorrection); + } catch(const boost::bad_lexical_cast &) + { + ROS_ERROR_STREAM("GPSHemisphere failed RTCM3.0 type lexical cast:" << type); + m_portB.diag_warn("GPSHemisphere failed RTCM3.0 type lexical cast"); + } + + m_portB.m_data.erase(0,len); + //std::cout << "\t new B Len:" << m_portB.m_data.length() << std::endl; + } else if(m_portB.m_data.size() >= len) + { + m_portB.m_data.erase(0,len); + ROS_WARN_STREAM("GPSHemisphere:: unknown RTCM3.0 message type:" << type << " of length:" << len); + m_portB.diag_warn("GPSHemisphere:: unknown " + m_rtkCorrection.layout.dim.front().label); + } + + } + } + + m_portB.unlock(); + +} + +void GPSHemisphere::rtcmCorrectionCallback(const std_msgs::ByteMultiArray& msg) +{ + m_portB.tick("Incoming Correction Data"); + m_mostRecentRTK = ros::Time::now(); + m_portB.writePort( reinterpret_cast(&msg.data[0]), + msg.layout.dim[0].size); +} + +void GPSHemisphere::processGPSMessage(std::string& msg) +{ + if(msg.length() == 0) + { + ROS_WARN("GPSHemisphere: recieved empty message."); + return; + } + std::vector tokens; + boost::split(tokens, msg, boost::is_any_of(",*")); + + std::string msgType = tokens[0]; + + if(msgType == "GPGGA") + { + if(tokens.size() < 15) + { + ROS_WARN("GPSHemisphere: %s wrong token count %lu", msgType.c_str(), tokens.size()); + return; + } + m_portA.tick(msgType); + + if(msgType != m_statusPositionSource) + { + ROS_WARN("GPSHemisphere: using %s for fix data, ignoring %s", + m_statusPositionSource.c_str(), + msgType.c_str()); + return; + } + + if( atoi(tokens[1].c_str()) == 0) + { + m_navSatFix.latitude = 0.0; + m_navSatFix.longitude = 0.0; + m_navSatFix.altitude = 0.0; + m_navSatFix.header.stamp = ros::Time::now(); + m_portA.diag(msgType + " UTC HHMMSS.SS:", "-"); + m_portA.diag(msgType + " quality:", processQuality("0")); + m_portA.diag(msgType + " # of satellites:", "0"); + m_portA.diag(msgType + " HDOP:", "-"); + m_portA.diag(msgType + " diff correction age (s):", "-"); + m_portA.diag(msgType + " diff ref station ID:", "-"); + } else + { + processUTC(tokens[1], msgType); + m_portA.diag(msgType + " UTC HHMMSS.SS:", tokens[1].c_str()); + m_navSatFix.latitude = processLatitude(tokens[2],tokens[3]); + m_navSatFix.longitude = processLongitude(tokens[4],tokens[5]); + m_portA.diag(msgType + " quality:", processQuality(tokens[6])); + m_portA.diag(msgType + " # of satellites:", tokens[7].c_str()); + m_portA.diag(msgType + " HDOP:", tokens[8].c_str()); + + m_navSatFix.altitude = processAltitude(tokens[9], tokens[10], tokens[11], tokens[12]); + + //quality token + if(tokens[6] != "0" && tokens[6] != "1") + { + if(tokens.size() < 15) + { + ROS_WARN("GPSHemisphere: wrong token count 3 in: %s", msg.c_str()); + return; + } + m_portA.diag(msgType + " diff correction age (s):", tokens[13].c_str()); + m_portA.diag(msgType + " diff ref station ID:", tokens[14].c_str()); + } else + { + m_portA.diag(msgType + " diff correction age (s):", "-"); + m_portA.diag(msgType + " diff ref station ID:", "-"); + } + double messageTime = GetUTC(tokens[1]); + m_navSatFix.header.stamp = ros::Time(((double)((int)(ros::Time::now().toSec() + m_gpsTimeOffset) / 86400) * 86400) + messageTime + m_gpsTimeOffset); + //std::cout << (double)((int)(ros::Time::now().toSec() + m_gpsTimeOffset) / 86400) << "Week" << messageTime << time << std::endl; + //std::cout << (ros::Time::now().toSec()) << std::endl; + } + double messageAge = m_navSatFix.header.stamp.toSec() - ros::Time::now().toSec(); + // Abandon our timestamp if its too far off + if (messageAge > 1.0 || messageAge < -1.0){ + m_navSatFix.header.stamp = ros::Time::now(); + ROS_ERROR("GPS message too old! %f seconds", messageAge); + } + + try + { + m_portA.diag("GPS Message Age (s)", (boost::lexical_cast(messageAge)).c_str()); + } catch(const boost::bad_lexical_cast &) + { + ROS_ERROR_STREAM("GPSHemisphere failed GPS message age lexical cast"); + m_portB.diag_warn("GPSHemisphere failed GPS message age lexical cast"); + } + + m_statusPub.publish(m_navSatFix); + m_portA.tick("Publishing navSatFix"); + } else if(msgType == "GPGNS") + { + if(tokens.size() < 15) + { + ROS_WARN("GPSHemisphere: %s wrong token count %lu", msgType.c_str(), tokens.size()); + return; + } + m_portA.tick(msgType); + + if(msgType != m_statusPositionSource) + { + ROS_WARN("GPSHemisphere: using %s for fix data, ignoring %s", + m_statusPositionSource.c_str(), + msgType.c_str()); + return; + } + + if( atoi(tokens[1].c_str()) == 0) + { + m_navSatFix.latitude = 0.0; + m_navSatFix.longitude = 0.0; + m_navSatFix.altitude = 0.0; + m_navSatFix.header.stamp = ros::Time::now(); + m_portA.diag(msgType + " UTC HHMMSS.SS:", "-"); + m_portA.diag(msgType + " GPS mode indicator:", "no fix"); + m_portA.diag(msgType + " GLONASS mode indicator:", "no fix"); + m_portA.diag(msgType + " # of satellites:", "0"); + m_portA.diag(msgType + " HDOP:", "-"); + m_portA.diag(msgType + " diff correction age (s):", "-"); + m_portA.diag(msgType + " diff ref station ID:", "-"); + m_portA.ERROR(); + //navigational status should be unsafe when no fix + if(tokens[13] == "U") + { + m_portA.diag(msgType + " Navigational status:", "U - unsafe"); + } else + { + m_portA.diag(msgType + "Unknown no fix navigational status:", tokens[13]); + } + } else + { + processUTC(tokens[1], msgType); + m_portA.diag(msgType + " UTC HHMMSS.SS:", tokens[1].c_str()); + m_navSatFix.latitude = processLatitude(tokens[2],tokens[3]); + m_navSatFix.longitude = processLongitude(tokens[4],tokens[5]); + + if(tokens[6].size() >= 1) + { + m_portA.diag(msgType + " GPS mode indicator:", processMode(tokens[6].substr(0,1))); + } + if(tokens[6].size() == 2) + { + m_portA.diag(msgType + " GLONASS mode indicator:", processMode(tokens[6].substr(1,1))); + } + + m_portA.diag(msgType + " # of satellites:", tokens[7].c_str()); + m_portA.diag(msgType + " HDOP:", tokens[8].c_str()); + + try + { + m_navSatFix.altitude = boost::lexical_cast(tokens[9]) + + boost::lexical_cast(tokens[10]); + } catch(const boost::bad_lexical_cast &) + { + m_portA.diag_error("GPSHemisphere::GPGNS bad altitude lexical cast"); + ROS_ERROR("GPSHemisphere::GPGNS bad altitude lexical cast"); + } + + if((tokens[6][0] == 'D' || + tokens[6][0] == 'P' || + tokens[6][0] == 'R' || + tokens[6][0] == 'F' || + tokens[6][1] == 'D' || + tokens[6][1] == 'P' || + tokens[6][1] == 'R' || + tokens[6][1] == 'F') ) + { + m_portA.diag(msgType + " diff correction age (s):", tokens[11].c_str()); + m_portA.diag(msgType + " diff ref station ID:", tokens[12].c_str()); + }else + { + m_portA.diag(msgType + " diff correction age (s):", "-"); + m_portA.diag(msgType + " diff ref station ID:", "-"); + } + + if(tokens[13] == "S") + { + m_portA.diag(msgType + " Navigational status:", "S - safe"); + } else if(tokens[13] == "C") + { + m_portA.diag(msgType + " Navigational status:", "C - caution"); + } else if(tokens[13] == "U") + { + m_portA.diag(msgType + " Navigational status:", "U - unsafe"); + } else if(tokens[13] == "V") + { + m_portA.diag(msgType + " Navigational status:", "V - not valid"); + } else + { + m_portA.diag(msgType + "Unknown Navigational status:", tokens[13]); + } + + double messageTime = GetUTC(tokens[1]); + m_navSatFix.header.stamp = ros::Time(((double)((int)(ros::Time::now().toSec() + m_gpsTimeOffset) / 86400) * 86400) + messageTime + m_gpsTimeOffset); + //std::cout << (double)((int)(ros::Time::now().toSec() + m_gpsTimeOffset) / 86400) << "Week" << messageTime << time << std::endl; + //std::cout << (ros::Time::now().toSec()) << std::endl; + } + double messageAge = m_navSatFix.header.stamp.toSec() - ros::Time::now().toSec(); + // Abandon our timestamp if its too far off + if (messageAge > 1.0 || messageAge < -1.0) + { + m_navSatFix.header.stamp = ros::Time::now(); + ROS_ERROR("GPS message too old! %f seconds", messageAge); + } + + try + { + m_portA.diag("GPS Message Age (s)", (boost::lexical_cast(messageAge)).c_str()); + } catch(const boost::bad_lexical_cast &) + { + ROS_ERROR_STREAM("GPSHemisphere failed GPS message age lexical cast"); + m_portB.diag_warn("GPSHemisphere failed GPS message age lexical cast"); + } + + m_statusPub.publish(m_navSatFix); + m_portA.tick("Publishing navSatFix"); + } else if(msgType == ">JRTK") + { + if(tokens.size() < 2) + { + ROS_WARN("GPSHemisphere: wrong token count 4 in: %s", msg.c_str()); + return; + } + if(tokens[1] == "6") + { + if(tokens.size() < 5) + { + ROS_WARN("GPSHemisphere: wrong token count 5 in: %s", msg.c_str()); + return; + } + std::string timeToGo = tokens[2]; + int readyTransmit = atoi(tokens[3].c_str()); + int transmitting = atoi(tokens[4].c_str()); + + if(transmitting > 0) + { + m_portB.diag("RTK Corrections:", "transmitting"); + m_portB.diag("RTK Fix:", "SBAS"); + m_portB.OK(); + } else if(readyTransmit > 0) + { + m_portB.diag("RTK Corrections:", "ready to transmit"); + m_portB.diag("RTK Fix:", "SBAS"); + m_portB.OK(); + } else + { + m_portB.diag("RTK Corrections:", timeToGo + " seconds until ready"); + if(atoi(timeToGo.c_str()) == 299) + { + m_portB.diag("RTK Fix:", "none"); + m_portB.ERROR(); + } else + { + m_portB.diag("RTK Fix:", "unaugmented"); + m_portB.WARN(); + } + } + } else if(tokens[1] == "1") + { + //ignore since its a reply + } + } + else if(msgType == "GPGSA" || + msgType == "GLGSA" || + msgType == "GNGSA") + { + if(tokens.size() < 20) + { + ROS_WARN("GPSHemisphere: %s too few tokens %lu", msgType.c_str(), tokens.size()); + return; + } + std::string gnssId; + if(tokens[18] == "1") + { + gnssId = " GPS"; + } else if(tokens[18] == "2") + { + gnssId = " GLONASS"; + } else + { + gnssId = " unknown gnssId: " + tokens[18]; + } + m_portA.tick(msgType + gnssId); + + if( (ros::Time::now()-m_previousCovTime).toSec() > 5.0) + { + m_navSatFix.position_covariance_type = + sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN; + } + + //only use this if there isn't a better source of covariance information + //and the fix is valid + int satsInUse = 0; + std::string sats; + for(int i = 3; i < 15; i++) + { + if(!tokens[i].empty()) + { + ++satsInUse; + sats += tokens[i]; + sats += " "; + } + } + m_portA.diag(msgType + gnssId + " # satellites used:", std::to_string(satsInUse)); + if(satsInUse > 0) + { + m_portA.diag(msgType + gnssId + " satellites used:", sats); + } + m_portA.diag(msgType + gnssId + " PDOP-HDOP-VDOP", + tokens[15]+"-"+tokens[16]+"-"+tokens[17]); + + if(m_navSatFix.position_covariance_type <= + sensor_msgs::NavSatFix::COVARIANCE_TYPE_APPROXIMATED && + atof(tokens[2].c_str()) > 1) + { + //choose ideal measurmenet error based on fix type + double multiplier = m_accuracyRTK; + if(m_navSatFix.status.status <= sensor_msgs::NavSatStatus::STATUS_FIX) + { + multiplier = m_accuracyAutonomous; + } else if(m_navSatFix.status.status <= sensor_msgs::NavSatStatus::STATUS_SBAS_FIX) + { + multiplier = m_accuracyWAAS; + } + + //use DOP*ideal measurement error for std dev estimates + //HDOP used for lat and lon + + try + { + double val = boost::lexical_cast(tokens[4])*multiplier; + m_navSatFix.position_covariance[0] = val*val; + m_navSatFix.position_covariance[4] = val*val; + //VDOP + //val = boost::lexical_cast(tokens[5])*multiplier; + val = boost::lexical_cast(tokens[5])*multiplier; + m_navSatFix.position_covariance[8] = val*val; + + m_navSatFix.position_covariance_type = + sensor_msgs::NavSatFix::COVARIANCE_TYPE_APPROXIMATED; + m_previousCovTime = ros::Time::now(); + } catch(const boost::bad_lexical_cast &) + { + m_portA.diag_error("GPSHemisphere: process of GSA msg cause bad lexical cast for:" + + msgType); + ROS_ERROR_STREAM("GPSHemisphere::process " << msgType << " caused bad lexical cast failed"); + } + } + + } else if(msgType == "GPGST") + { + if(tokens.size() < 9) + { + ROS_WARN("GPSHemisphere: GPGST partial token count: %lu", tokens.size()); + return; + } + + m_portA.tick("GPGST"); + + if( (ros::Time::now()-m_previousCovTime).toSec() > 5.0) + { + m_navSatFix.position_covariance_type = + sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN; + } + + //check to see better variance source is available, and the message has data + if(m_navSatFix.position_covariance_type <= + sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN && + atof(tokens[1].c_str()) > 100) + { + if(tokens.size() < 9) + { + ROS_WARN("GPSHemisphere: wrong token count 7 in: %s", msg.c_str()); + return; + } + //UTC time + processUTC(tokens[1], msgType); + //Token 2 = RMS of std dev of range inputs + //Token 3 = Standard deviation of semi-major axis of error ellipse, meters + //Token 4 = Standard deviation of semi-minor axis of error ellipse, meters + //Token 5 = Error in semi major axis origination, in decimal degrees, true north + + //Std dev of latitude error, in meters + try + { + if(!tokens[6].empty()) + { + double val = boost::lexical_cast(tokens[6]); + m_navSatFix.position_covariance[0] = val*val; + //Std dev of longitude error, in meters + val = boost::lexical_cast(tokens[7]); + m_navSatFix.position_covariance[4] = val*val; + //Std dev of altitude error, in meters + val = boost::lexical_cast(tokens[8]); + m_navSatFix.position_covariance[8] = val*val; + + m_navSatFix.position_covariance_type = + sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN; + m_previousCovTime = ros::Time::now(); + } + } catch(const boost::bad_lexical_cast &) + { + m_portA.diag_error("GPSHemisphere: process GPGST bad lexical cast"); + ROS_ERROR("GPSHemisphere: process GPGST bad lexical cast"); + } + } + } else if(msgType == "GPVTG") //course over ground/ground speed + { + m_portA.tick("GPVTG"); + } else if(msgType == "GPZDA") //detailed UTC time information + { + if(tokens.size() < 2) + { + ROS_WARN("GPSHemisphere: wrong token count 8 in: %s", msg.c_str()); + return; + } + m_portA.tick("GPZDA"); + processUTC(tokens[1], "GPZDA"); + //Token 1 = UTC + //Token 2 = UTC day + //Token 3 = UTC month + //Token 4 = UTC year + //Token 5 = Local zone hours + //Token 6 = Local zone minutes + } else if(msgType == "$PSAT") + { + if(tokens.size() < 2) + { + ROS_WARN("GPSHemisphere: wrong token count 9 in: %s", msg.c_str()); + return; + } + m_portA.tick("$PSAT"); + if(tokens[1] == "RTKSTAT") + { + } else if(tokens[1] == "RTKPROG") + { + } + } else if(msgType == "GPGSV" || + msgType == "GLGSV") + { + if(tokens.size() < 5) //Minimum message with no satelite info in it. + { + ROS_WARN("GPSHemisphere: wrong token count 10 in: %s", msg.c_str()); + return; + } + + try + { + int totalMessages = boost::lexical_cast(tokens[1]); + int messageNumber = boost::lexical_cast(tokens[2]); + + if(m_showGsv) + { + char channel[20]; + // Iterate through all of the satellites + for (size_t i = 4; i <= (tokens.size() - 6); i+=4) + { + std::string diagnosticMessage; + diagnosticMessage += " SS: "; + diagnosticMessage += tokens[i+3]; + if (tokens[i+3]=="") diagnosticMessage += "NA"; + diagnosticMessage += " EL: "; + diagnosticMessage += tokens[i+1]; + diagnosticMessage += " AZ: "; + diagnosticMessage += tokens[i+2]; + diagnosticMessage += " Num: "; + diagnosticMessage += tokens[i]; + std::string diagnosticLabel = msgType; + diagnosticLabel += " channel "; + snprintf(channel,20,"%lu",(messageNumber*4) + ((i-4)/4)); + diagnosticLabel += std::string(channel); + m_portA.diag(diagnosticLabel,diagnosticMessage); + } + } + + if(messageNumber == totalMessages) + { + //We got complete info + m_portA.tick(msgType); + } + } catch(const boost::bad_lexical_cast &) + { + m_portA.diag_error("GPSHemisphere: process GSV failed"); + ROS_ERROR_STREAM("GPSHemisphere: process " << msgType << " failed"); + } + + } else if(msgType == "GPGNS" || + msgType == "GLGNS" || + msgType == "GNGNS") + { + m_portA.tick(msgType); + }else + { + ROS_WARN("GPSHemisphere: received unknown message type:%s", msgType.c_str()); + } + +} + +std::string GPSHemisphere::processQuality(const std::string& qual) +{ + m_navSatFix.status.service = sensor_msgs::NavSatStatus::SERVICE_GPS + + sensor_msgs::NavSatStatus::SERVICE_GLONASS; + if(qual == "0") + { + m_portA.ERROR(); + m_navSatFix.status.status = sensor_msgs::NavSatStatus::STATUS_NO_FIX; + return "0 - no position"; + } else if(qual == "1") + { + m_portA.WARN(); + m_navSatFix.status.status = sensor_msgs::NavSatStatus::STATUS_FIX; + return "1 - undifferentially corrected"; + } else if(qual == "2") + { + m_portA.OK(); + m_navSatFix.status.status = sensor_msgs::NavSatStatus::STATUS_SBAS_FIX; + return "2 - differentially corrected"; + } else if(qual == "4") + { + m_portA.OK(); + m_navSatFix.status.status = sensor_msgs::NavSatStatus::STATUS_GBAS_FIX; + return "4 - RTK fixed integer converged"; + } else if(qual == "5") + { + m_portA.OK(); + m_navSatFix.status.status = sensor_msgs::NavSatStatus::STATUS_GBAS_FIX; + return "5 - RTK float converged"; + } else + { + return qual + " - unknown"; + } +} + +std::string GPSHemisphere::processMode(const std::string& modeIndicator) +{ + m_navSatFix.status.service = sensor_msgs::NavSatStatus::SERVICE_GPS + + sensor_msgs::NavSatStatus::SERVICE_GLONASS; + if(modeIndicator == "N") + { + m_portA.ERROR(); + m_navSatFix.status.status = sensor_msgs::NavSatStatus::STATUS_NO_FIX; + return "N - no fix"; + } else if(modeIndicator == "A") + { + m_portA.WARN(); + m_navSatFix.status.status = sensor_msgs::NavSatStatus::STATUS_FIX; + return "A - autonomous (undifferentially corrected)"; + } else if(modeIndicator == "D") + { + m_portA.OK(); + m_navSatFix.status.status = sensor_msgs::NavSatStatus::STATUS_SBAS_FIX; + return "D - differentially corrected"; + } else if(modeIndicator == "P") + { + m_portA.OK(); + m_navSatFix.status.status = sensor_msgs::NavSatStatus::STATUS_SBAS_FIX; + return "P - precise fix"; + } else if(modeIndicator == "R") + { + m_portA.OK(); + m_navSatFix.status.status = sensor_msgs::NavSatStatus::STATUS_GBAS_FIX; + return "R - RTK fixed integer converged"; + } else if(modeIndicator == "F") + { + m_portA.OK(); + m_navSatFix.status.status = sensor_msgs::NavSatStatus::STATUS_GBAS_FIX; + return "F - RTK float converged"; + } else if(modeIndicator == "E") + { + m_portA.WARN(); + m_navSatFix.status.status = sensor_msgs::NavSatStatus::STATUS_FIX; + return "E - dead reckoning"; + } else + { + return modeIndicator + " - unknown"; + } +} + +double GPSHemisphere::processLatitude(const std::string& lat, + const std::string& latInd) +{ + //std::cout << "lat " << lat << std::endl; + + try + { + if(latInd == "N") + { + return boost::lexical_cast(lat.substr(0,2))+ + boost::lexical_cast(lat.substr(2))/60.0; + } else + { + return -(boost::lexical_cast(lat.substr(0,2))+ + boost::lexical_cast(lat.substr(2))/60.0); + } + } catch(const boost::bad_lexical_cast &) + { + m_portA.diag_error("GPSHemisphere::processLatitude bad lexical cast"); + ROS_ERROR("GPSHemisphere::processLatitude bad lexical cast"); + } + return 0.0; +} +double GPSHemisphere::processLongitude(const std::string& lon, + const std::string& lonInd) +{ + //std::cout << "lon " << lon << std::endl; + + try + { + if(lonInd == "E") + { + return boost::lexical_cast(lon.substr(0,3))+ + boost::lexical_cast(lon.substr(3))/60.0; + } else + { + return -(boost::lexical_cast(lon.substr(0,3))+ + boost::lexical_cast(lon.substr(3))/60.0); + } + } catch(const boost::bad_lexical_cast &) + { + m_portA.diag_error("GPSHemisphere::processLongitude bad lexical cast"); + ROS_ERROR("GPSHemisphere::processLongitude bad lexical cast"); + } + return 0.0; + +} +double GPSHemisphere::processAltitude(const std::string& antAlt, + const std::string& antAltUnits, + const std::string& geodSep, + const std::string& geodSepUnits) +{ + if(antAltUnits == "M" && geodSepUnits == "M") + { + try + { + return boost::lexical_cast(antAlt) + + boost::lexical_cast(geodSep); + } catch(const boost::bad_lexical_cast &) + { + m_portA.diag_error("GPSHemisphere::processAltitude bad lexical cast"); + ROS_ERROR("GPSHemisphere::processAltitude bad lexical cast"); + } + } else + { + m_portA.diag_error("GPSHemisphere: unsupported altitude units: Altitude in " + + antAltUnits + ". Geoidal Seperation in " + geodSepUnits + + ". Expected 'M' for both."); + } + return 0.0; +} + +void GPSHemisphere::processUTC(const std::string& utc, const std::string& source) +{ + if(m_utcSource == source) + { + m_timeUTC.header.stamp = ros::Time::now(); + + try + { + int sec = boost::lexical_cast(utc.substr(0,2))*360 + + boost::lexical_cast(utc.substr(2,2))*60 + + boost::lexical_cast(utc.substr(4,2)); + int nsec = boost::lexical_cast(utc.substr(7,2))*1000000000; + m_timeUTC.time_ref = ros::Time(sec+m_secondsToToday, nsec); + + m_utcPub.publish(m_timeUTC); + } catch(const boost::bad_lexical_cast &) + { + m_portA.diag_error("GPSHemisphere::processUTC bad lexical cast"); + ROS_ERROR("GPSHemisphere::processUTC bad lexical cast"); + } + } +} + +double GPSHemisphere::GetUTC(const std::string& utc) +{ + m_timeUTC.header.stamp = ros::Time::now(); + try + { + int sec = boost::lexical_cast(utc.substr(0,2))*3600 + + boost::lexical_cast(utc.substr(2,2))*60 + + boost::lexical_cast(utc.substr(4,2)); + double dsec = (float)(boost::lexical_cast(utc.substr(7,2)))/100.0; + return (double)sec + dsec; + } catch(const boost::bad_lexical_cast &) + { + m_portA.diag_error("GPSHemisphere::getUTC bad lexical cast"); + ROS_ERROR("GPSHemisphere::getUTC bad lexical cast"); + return 0.0; + } +} + +void GPSHemisphere::rtkStatusCallback(const ros::TimerEvent&) +{ + //query the current RTK transmission status + unsigned char cmd[10] = "$JRTK,6\r\n"; + m_portA.writePort(cmd,10); + + //if there are no recent RTK corrections, switch to satellite augmentation +// if((ros::Time::now()-m_mostRecentRTK).toSec() > 120 && m_rtkEnabled) +// { +// unsigned char mode[14] = "$JDIFF,WAAS\r\n"; +// m_portA.writePort(cmd,14); +// m_rtkEnabled = false; +// m_portA.diag_ok("Switching to WAAS corrections"); +// } else if((ros::Time::now()-m_mostRecentRTK).toSec() < 5 && !m_rtkEnabled) +// { +// unsigned char mode[16] = "$JDIFF,BEACON\r\n"; +// m_portA.writePort(cmd,16); +// m_rtkEnabled = true; +// m_portA.diag_ok("Switching to RTK corrections"); +// } +} + +void GPSHemisphere::updateReferenceLocationCallback(const ros::TimerEvent&) +{ + //if the unit has augmented position data, update the current reference + //location + if(m_navSatFix.status.status > sensor_msgs::NavSatStatus::STATUS_FIX) + { + unsigned char cmd[12] = "$JRTK,1,P\r\n"; + m_portA.writePort(cmd, 12); + } + return; +} diff --git a/autorally_core/src/gps/GPSHemisphere.h b/autorally_core/src/gps/GPSHemisphere.h new file mode 100644 index 00000000..c5346e0f --- /dev/null +++ b/autorally_core/src/gps/GPSHemisphere.h @@ -0,0 +1,222 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file GPSHemisphere.h + * @author Brian Goldfain + * @date November 5, 2013 + * @copyright 2013 Georgia Institute of Technology + * @brief GPSHemisphere class definition + * + ***********************************************/ +#ifndef GPS_HEMISPHERE_H_ +#define GPS_HEMISPHERE_H_ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +/** + * @class GPSHemisphere GPSHemisphere.h + * "autorally_core/GPSHemisphere.h" + * @brief Interact with a hemisphere R320 GPS Base station + * + * Interacts with a RTK-compatible GPS base station, specifically the + * Hemisphere R320. The main porpose of the base station is to send RTK + * corrections to other GPS devices onboard running robot. Additionally, + * position data for the base station is published. The position data is + * received in the form of NMEA 0183 messages, and the corrections are RTCM 3.0 + * + * @note It is assumed that the device is already configured to stream GPGGA + * messages on portA and the correction data on portB. See the wiki pages for + * additional GPS setup information. + * + * @note Covariance types in navSat message are explained here: + * http://answers.ros.org/question/10310/calculate-navsatfix-covariance/ + * + * Useful Commands: + * Base: + * $jmode,base,yes - put in base mode + * $jasc,rtcm3,1 - enable rtcm3 corrections + * $JRTK,5,1 - start correction data stream + * Rover: + * $JDIFF,BEACON - enable local RTCM corrections + * $JDIFF,WAAS - diable local RTCM corrections + * Both: + * $JSAVE - save current configuration + * $japp - use to confirm sbasrtkb program? + * $JRTK,6 - use to check if rtk ready + * $JRTK,1,P - set receiver reference coordinates to current position + * $JRTK,1 - get receiver reference position + * $JASC,GPGGA,20 - get gpgga message at 20hz + * $JASC,GPGSA,1 - get gpgsa message at 1hz + * $JASC,GPGST,1 - get gpgst message at 1hz + * + * + */ + + +class GPSHemisphere +{ + + public: + /** + * Constructor reads connection information for each port and connects to the + * Hemisphere GPS R320, and performs other initialization. + * @param nh NodeHandle + + */ + GPSHemisphere(ros::NodeHandle &nh); + + ~GPSHemisphere(); + + /** + * @brief Timer triggered callback to request RTK status from base station + * @param time information about callback execution + */ + void rtkStatusCallback(const ros::TimerEvent& /*time*/); + + /** + * @brief Timer triggered callback to update the device reference location + * @param time information about callback execution + * + * This may be periodically needed for the base station?????? + */ + void updateReferenceLocationCallback(const ros::TimerEvent& /*time*/); + + private: + ros::Timer m_rtkStatusTimer; /// + * @date October 18, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief + **/ +#include "DiagnosticsEntry.hpp" + +DiagnosticsEntry::DiagnosticsEntry() +{ + QStringList header; + header << "Name" << "Hardware ID" << "Message" << "Count"; + m_model.setColumnCount(4); + m_model.setHorizontalHeaderLabels(header); +} + +DiagnosticsEntry::~DiagnosticsEntry() { + +} + +void DiagnosticsEntry::newSender(const diagnostic_msgs::DiagnosticStatus& msg) +{ + QList newSender; + newSender << new QStandardItem(msg.name.c_str()); + newSender << new QStandardItem(msg.hardware_id.c_str()); + newSender << new QStandardItem(msg.message.c_str()); + newSender << new QStandardItem("0"); + + newSender[NAMECOL]->setEditable(false); + newSender[HWIDCOL]->setEditable(false); + newSender[MSGCOL]->setEditable(false); + newSender[COUNTCOL]->setEditable(false); + m_model.appendRow(newSender); +} + +void DiagnosticsEntry::newKeyValue(QStandardItem* parent, const diagnostic_msgs::KeyValue& msg) +{ + QList newMessage; + newMessage << new QStandardItem(msg.key.c_str()); + + QBrush color = colorFromLevel(msg.value[0]); + if(color == Qt::white) + { + newMessage << new QStandardItem(msg.value.c_str()); + } else + { + newMessage << new QStandardItem("0.000"); + newMessage[VALCOL]->setData(QVariant(ros::Time::now().toSec())); + newMessage[KEYCOL]->setBackground(color); + } + //newMessage << new QStandardItem("1"); + newMessage << new QStandardItem(); + newMessage << new QStandardItem(); + + newMessage[KEYCOL]->setEditable(false); + newMessage[VALCOL]->setEditable(false); + newMessage[TIMECOL]->setEditable(false); + newMessage[COUNTCOL]->setEditable(false); + + parent->appendRow(newMessage); +} + +void DiagnosticsEntry::update(const diagnostic_msgs::DiagnosticArray& msg) +{ + //go through each DiagnosticStatus in the array + std::vector::const_iterator diagIt; + for(diagIt = msg.status.begin(); diagIt != msg.status.end(); diagIt++) + { + //ROS_INFO("Looking at %s", diagIt->name.c_str()); + //find the entry in the diagnostics model, otherwise add a new one + QList items = m_model.findItems(diagIt->name.c_str()); + if(items.isEmpty() && diagIt->message != "Node starting up") + { + //add new item for the sender + newSender(*diagIt); + items = m_model.findItems( diagIt->name.c_str() ); + } + + if(items.size() == 1) + { + if(diagIt->hardware_id == m_model.item(items.front()->index().row(),1)->text().toStdString()) + { + m_model.item(items.front()->index().row(),2)->setText(diagIt->message.c_str()); + items.front()->setData(diagIt->level); + + for(const auto value : diagIt->values) + { + updateKeyValue(items.front(), value); + } + } + else + { + newSender(*diagIt); + update(msg); + } + } + else if(!diagIt->hardware_id.empty()) + { + bool foundMatch = false; + for( auto item : items) + { + if(diagIt->hardware_id == m_model.item(item->index().row(),1)->text().toStdString()) + { + foundMatch = true; + m_model.item(item->index().row(),2)->setText(diagIt->message.c_str()); + item->setData(diagIt->level); + + for(const auto value : diagIt->values) + { + updateKeyValue(item, value); + } + } + } + if(!foundMatch) + { + newSender(*diagIt); + update(msg); + } + } else { + ROS_WARN_STREAM("DiagnosticsEntry: No hardware ID in Diagnostics message: " << diagIt->name << " but multiple diagnostic entries present."); + } + } +} + +void DiagnosticsEntry::updateKeyValue(QStandardItem* diagMsg, + const diagnostic_msgs::KeyValue& data) +{ + QBrush color; + //int count; + double time; + bool found = false; + //bool ok = false; + //QString num; + + //update the message just received + for(int i = 0; i < diagMsg->rowCount(); i++) + { + if(diagMsg->child(i)->text().toStdString() == data.key) + { + //ROS_INFO("%s -%s-", data.key.c_str(), data.value.c_str()); + found = true; + if(data.value.empty()) + { + color = QBrush(Qt::white); + } else + { + color = colorFromLevel(data.value[0]); + } + + //if its a normal diagnostic message set the text to the value, + //otherwise it is an auto_rally diagnostic that has a level associated + if(color == Qt::white) + { + diagMsg->child(i,1)->setText(data.value.c_str()); + } else + { + diagMsg->child(i,0)->setBackground(color); + time = ros::Time::now().toSec(); + diagMsg->child(i,1)->setData(QVariant(time)); + } + + //count = diagMsg->child(i,2)->text().toInt(&ok) + 1; + //ROS_INFO("count %d", count); + + //if(ok && diagMsg->child(i,2)) + //{ + //num.setNum(count); + //ROS_INFO("%s", diagMsg->child(i,2)->text().toStdString().c_str()); + //ROS_INFO("num [%s]", QString::number(count).toStdString().c_str()); + //diagMsg->child(i,2)->setText(QString::number(count)); + //ROS_INFO("after"); + //} else + //{ + // ROS_ERROR("Bad conversion"); + //} + //ROS_INFO("end count %d", count); + } + } + //ROS_INFO("updateKeyValue halfway"); + //if it is a new message from the sender, add it + if(!found) + { + newKeyValue(diagMsg, data); + //set the number of messages for the sender + m_model.item(diagMsg->index().row(),3)-> + setText(QString::number(diagMsg->rowCount())); + } + diagMsg->setBackground(highestPriorityColor(diagMsg)); + //ROS_INFO("updateKeyValue done"); +} + +QBrush DiagnosticsEntry::colorFromLevel(unsigned char level) +{ + switch(level) + { + case 0 : + return Qt::green; + case 1 : + return Qt::yellow; + case 2 : + return Qt::red; + default : + return Qt::white; + } +} + +QBrush DiagnosticsEntry::highestPriorityColor(QStandardItem* item) +{ + bool foundGreen = false; + bool foundYellow = false; + + QBrush toReturn(Qt::white); + if(item->data().isValid()) + { + toReturn = colorFromLevel(item->data().toChar().toAscii()); + } + else if(!item->hasChildren()) + { + return QBrush(Qt::white); + } + + for(int i = 0; i < item->rowCount(); i++) + { + + if(item->child(i)->background().color() == Qt::red || + toReturn.color() == Qt::red) + { + return QBrush(Qt::red); + } + + if(item->child(i)->background().color() == Qt::yellow || + toReturn.color() == Qt::yellow) + { + foundYellow = true; + } else if(item->child(i)->background().color() == Qt::green) + { + foundGreen = true; + } + } + + if(foundYellow) + { + toReturn = Qt::yellow; + } else if(foundGreen) + { + toReturn = Qt::green; + } + + return toReturn; +} + +void DiagnosticsEntry::diagModelDoubleClicked(const QModelIndex& index) +{ + if(index.parent().isValid()) + { + //remove the row that was clicked on + QStandardItem* parent = m_model.itemFromIndex(index.parent()); + parent->removeRow(index.row()); + parent->setBackground(highestPriorityColor(parent)); + + //set number of messages for parent entry + QStandardItem* entry = m_model.item(parent->index().row(),3); + entry->setText(QString::number(parent->rowCount())); + } +} + +void DiagnosticsEntry::clearStaleDiag() +{ + QStandardItem* node; + + //go through each nodes diagnostics messages + for(int i = 0; i < m_model.rowCount(); i++) + { + node = m_model.item(i); + + //go through each message + for(int j = 0; j < node->rowCount();) + { + if(node->child(j,1)->background() == Qt::magenta) + { + //remove that entry by index + diagModelDoubleClicked(node->child(j,1)->index()); + } else + { + /*only increment the index if there was nothing removed, otherwise + the second of two stale messages in a row will be skipped + */ + j++; + } + } + } +} + +void DiagnosticsEntry::updateTimes() +{ + double time; + QStandardItem* node; + QStandardItem* child1; + bool anyStale = false; + + for(int i = 0; i < m_model.rowCount(); i++) + { + if( (node = m_model.item(i)) == 0) + { + ROS_ERROR("Invalid Parent Node"); + } else + { + anyStale = false; + for(int j = 0; j < node->rowCount(); j++) + { + //only update the times if the model has time data associated with it + //this allows non auto_rally diagnostic messages to be not colored + if( (child1 = node->child(j,1)) != 0 && + node->child(j,2) != 0 && + child1->data().isValid()) + { + time = ros::Time::now().toSec()-child1->data().toDouble(); + + //consider message stale if a new one has not been received for a while, + //color part of it magenta as well as part of the parent + if(time > 5*m_diagnosticFrequency) + { + child1->setBackground(Qt::magenta); + anyStale = true; + } + else + { + child1->setBackground(node->child(j,2)->background()); + } + + child1->setText(QString::number(time, 'g', 4)); + } else //there are no key-value pairs with priority, reset bkgnd color + { + m_model.item(i,1)->setBackground(m_model.item(i,2)->background()); + } + } + + if(anyStale) + { + m_model.item(i,1)->setBackground(Qt::magenta); + } else + { + m_model.item(i,1)->setBackground(m_model.item(i,2)->background()); + } + } + } +} diff --git a/autorally_core/src/ocs/DiagnosticsEntry.hpp b/autorally_core/src/ocs/DiagnosticsEntry.hpp new file mode 100644 index 00000000..edf122ea --- /dev/null +++ b/autorally_core/src/ocs/DiagnosticsEntry.hpp @@ -0,0 +1,126 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file DiagnosticsEntry.hpp + * @author Brian Goldfain + * @date October 18, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief + * + * @details + ***********************************************/ +#ifndef DIAGNOSTICS_ENTRY_HPP_ +#define DIAGNOSTICS_ENTRY_HPP_ + +#include +#include +#include + +#include +#include +#include + +/** + * @class DiagnosticsEntry DiagnosticsEntry.hpp "ocs/DiagnosticsEntry.hpp" + * @brief + */ +class DiagnosticsEntry : public QObject { + Q_OBJECT +public: + + /** + * @brief Constructor, just initializes internal variables + * + */ + DiagnosticsEntry(); + virtual ~DiagnosticsEntry(); + + + void update(const diagnostic_msgs::DiagnosticArray& msg); + + + QStandardItemModel* model() {return &m_model;} + + + void setDiagnosticFrequency(const double diagFreq) {m_diagnosticFrequency = diagFreq;} + + /** + * @brief Generates new entry for a sender (node) of diagnostics messages + * @param level the message level to covnert to a color + * @return QBrush the translated color (ERROR=red, WARN=yellow, OK=green) + */ + QBrush colorFromLevel(unsigned char level); + +public slots: + /** + * @brief Slot Indicates that an item in the diagnostics view was double clicked + * @param index The location in the model that was clicked + */ + void diagModelDoubleClicked(const QModelIndex& index); + + /** + * @brief Remove all stale diagnostic messages + */ + void clearStaleDiag(); + + /** + * @brief Update the time since last message received for all elements in OCS + */ + void updateTimes(); + +private: + enum DataIndexes { NAMECOL = 0, + HWIDCOL = 1, + MSGCOL = 2, + COUNTCOL = 3}; + enum KeyValIndexes { KEYCOL = 0, + VALCOL = 1, + TIMECOL = 2}; + + QStandardItemModel m_model; /// WARN > OK) + */ + QBrush highestPriorityColor(QStandardItem* item); +}; + +#endif /* DIAGNOSTICS_ENTRY_HPP_ */ diff --git a/autorally_core/src/ocs/ImageMaskEntry.cpp b/autorally_core/src/ocs/ImageMaskEntry.cpp new file mode 100644 index 00000000..d6192806 --- /dev/null +++ b/autorally_core/src/ocs/ImageMaskEntry.cpp @@ -0,0 +1,105 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/** + * @file ImageMaskEntry.cpp + * @author Brian Goldfain + * @date October 18, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief + **/ +#include "ImageMaskEntry.hpp" + +ImageMaskEntry::ImageMaskEntry() +{ + m_model.setColumnCount(2); +} + +ImageMaskEntry::~ImageMaskEntry() { +} + +void ImageMaskEntry::newEntry(const autorally_msgs::imageMask& mask) +{ + QStandardItem* newEntry = new QStandardItem(mask.sender.c_str()); + newEntry->setEditable(false); + newEntry->setCheckable(true); + newEntry->setCheckState(Qt::Checked); + newEntry->setBackground(generateColor()); + + newEntry->setChild(PROW,NAMECOL, new QStandardItem("Points:")); + newEntry->setChild(PROW,DATACOL, + new QStandardItem(QString::number(mask.points.size()) )); + newEntry->setChild(LROW,NAMECOL, new QStandardItem("Lines:")); + newEntry->setChild(LROW,DATACOL, + new QStandardItem(QString::number(mask.lines.size()) )); + newEntry->setChild(RROW,NAMECOL, new QStandardItem("ROIs:")); + newEntry->setChild(RROW,DATACOL, + new QStandardItem(QString::number(mask.rois.size()))); + m_model.appendRow(newEntry); +} + +bool ImageMaskEntry::update(const autorally_msgs::imageMask& mask) +{ + QList items = m_model.findItems(mask.sender.c_str()); + if(items.empty()) + { + newEntry(mask); + m_masks.insert(std::pair(mask.sender, mask)); + + } else if(items.size() == 1) + { + m_masks[mask.sender] = mask; + items[0]->child(PROW,DATACOL)->setText(QString::number(mask.points.size())); + items[0]->child(LROW,DATACOL)->setText(QString::number(mask.lines.size())); + items[0]->child(RROW,DATACOL)->setText(QString::number(mask.rois.size())); + } else + { + ROS_ERROR("Something is wrong with the imageMaskModel!"); + } + return true; +} + +const autorally_msgs::imageMask& ImageMaskEntry::mask(const std::string& maskName) const +{ + return m_masks.find(maskName)->second; +} + +const QStandardItem* ImageMaskEntry::itemFromName(const std::string& itemName) const +{ + QList items = m_model.findItems(itemName.c_str()); + if(items.size() == 1) + { + return items[0]; + } + return NULL; +} + +const QColor ImageMaskEntry::generateColor() +{ + //pick a random color from + //{Qt::red, Qt::green, Qt::blue, Qt::cyan, Qt::magenta, Qt::yellow} + int c = rand()%6; + return Qt::GlobalColor(7+c); +} diff --git a/autorally_core/src/ocs/ImageMaskEntry.hpp b/autorally_core/src/ocs/ImageMaskEntry.hpp new file mode 100644 index 00000000..069ab03f --- /dev/null +++ b/autorally_core/src/ocs/ImageMaskEntry.hpp @@ -0,0 +1,80 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file ImageMaskEntry.hpp + * @author Brian Goldfain + * @date October 18, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief + * + * @details + ***********************************************/ +#ifndef IMAGE_MASK_ENTRY_HPP_ +#define IMAGE_MASK_ENTRY_HPP_ + +#include +#include +#include + +#include +#include +#include + +/** + * @class ImageMaskEntry ImageMaskEntry.hpp "ocs/ImageMaskEntry.hpp" + * @brief + */ +class ImageMaskEntry { +public: + + std::map m_masks; + + /** + * @brief Constructor, just initializes internal variables + * + */ + ImageMaskEntry(); + virtual ~ImageMaskEntry(); + bool update(const autorally_msgs::imageMask& mask); + const autorally_msgs::imageMask& mask(const std::string &maskName) const; + const QStandardItem* itemFromName(const std::string& itemName) const; + QStandardItemModel* model() {return &m_model;} + bool maskChecked(); + +private: + enum DataIndexes { NAMECOL = 0, + DATACOL = 1, + PROW = 0, + LROW = 1, + RROW = 2 }; + + QStandardItemModel m_model; /// + * @date March 2, 2012 + * @copyright {2012 Georgia Institute of Technology} + * @brief Main for the ocs GUI + **/ +/***************************************************************************** +** Includes +*****************************************************************************/ + +#include +#include +#include "main_window.hpp" + +/***************************************************************************** +** Main +*****************************************************************************/ + +int main(int argc, char **argv) { + + QApplication app(argc, argv); + MainWindow w(argc,argv); + w.show(); + app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); + int result = app.exec(); + + return result; +} diff --git a/autorally_core/src/ocs/main_window.cpp b/autorally_core/src/ocs/main_window.cpp new file mode 100644 index 00000000..9f0c7e32 --- /dev/null +++ b/autorally_core/src/ocs/main_window.cpp @@ -0,0 +1,591 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/** + * @file main_window.cpp + * @author Brian Goldfain + * @date March 2, 2012 + * @copyright 2013 Georgia Institute of Technology + * @brief Implementation for the qt-based ocs gui. + **/ +#include +#include +#include +#include "main_window.hpp" +#include + +using namespace Qt; + +MainWindow::MainWindow(int argc, char** argv, QWidget *parent) + : QMainWindow(parent) + , qnode(argc,argv) +{ + m_savingImages = false; + m_saveOneImage = 0; + + // Calling this incidentally connects all ui's triggers to on_...() callbacks in this class. + ui.setupUi(this); + // qApp is a global variable for the application + QObject::connect(ui.actionAbout_Qt, SIGNAL(triggered(bool)), qApp, SLOT(aboutQt())); + + ReadSettings(); + setWindowIcon(QIcon(":/doc/car_logo.png")); + + QObject::connect(&qnode, SIGNAL(rosShutdown()), this, SLOT(close())); + + ui.diagMsgsTreeView->setModel(qnode.diagnosticModel()); + ui.diagMsgsTreeView->header()->setResizeMode(QHeaderView::ResizeToContents); + + ui.safeSpeedTreeView->setModel(qnode.safeSpeedModel()); + ui.safeSpeedTreeView->header()->setResizeMode(QHeaderView::ResizeToContents); + + ui.imageMaskTreeView->setModel(qnode.imageMaskModel()); + ui.imageMaskTreeView->header()->setResizeMode(QHeaderView::ResizeToContents); + + + QObject::connect(ui.motionControlButton, SIGNAL(clicked(bool)), + this, SLOT(enableMotion(bool))); + QObject::connect(ui.safeSpeedSetButton, SIGNAL(clicked(bool)), + this, SLOT(setSafeSpeed(bool))); +// QObject::connect(ui.steeringControlSlider, SIGNAL(valueChanged(int)), +// this, SLOT(setSteering(int))); +// QObject::connect(ui.throttleControlSlider, SIGNAL(valueChanged(int)), +// this, SLOT(setThrottle(int))); +// QObject::connect(ui.frontBrakeControlSlider, SIGNAL(valueChanged(int)), +// this, SLOT(setFrontBrake(int))); +// QObject::connect(ui.backBrakeControlSlider, SIGNAL(valueChanged(int)), +// this, SLOT(setBackBrake(int))); + QObject::connect(ui.tab_manager, SIGNAL(currentChanged(int)), + this, SLOT(currentTabChanged(int))); + + QObject::connect(&qnode, SIGNAL(newWheelSpeeds( + const autorally_msgs::wheelSpeedsConstPtr&)), + this, SLOT(updateWheelSpeeds( + const autorally_msgs::wheelSpeedsConstPtr&))); + //QObject::connect(&qnode, SIGNAL(newArduinoData( + // const autorally_msgs::arduinoDataConstPtr&)), + // this, SLOT(updateArduinoData( + // const autorally_msgs::arduinoDataConstPtr&))); + QObject::connect(&qnode, SIGNAL(newServoData( + const autorally_msgs::servoMSGConstPtr&)), + this, SLOT(updateServoData( + const autorally_msgs::servoMSGConstPtr&))); + QObject::connect(&qnode, SIGNAL(newImage1()), + this, SLOT(updateImage1())); + QObject::connect(&qnode, SIGNAL(newImage2()), + this, SLOT(updateImage2())); + + QObject::connect(ui.controlButton, SIGNAL(clicked(const bool)), + this, SLOT(setControl(const bool))); + QObject::connect(ui.clearStaleDiagButton, SIGNAL(released()), + &qnode.m_diagModel, SLOT(clearStaleDiag())); + QObject::connect(ui.diagMsgsTreeView, + SIGNAL(doubleClicked(const QModelIndex&)), + &qnode.m_diagModel, SLOT(diagModelDoubleClicked(const QModelIndex&))); + QObject::connect(ui.safeSpeedTreeView, + SIGNAL(doubleClicked(const QModelIndex&)), + &qnode, SLOT(safeSpeedModelDoubleClicked(const QModelIndex&))); + + QObject::connect(&m_updateTimeBoxesTimer, SIGNAL(timeout()), + this, SLOT(updateTimeBoxes())); + QObject::connect(&m_diagTimeTimer, SIGNAL(timeout()), + &qnode, SLOT(updateTimes())); + QObject::connect(&m_diagTimeTimer, SIGNAL(timeout()), + &qnode.m_diagModel, SLOT(updateTimes())); + QObject::connect(&m_servoCommandTimer, SIGNAL(timeout()), + this, SLOT(sendServoCommand())); + + m_diagTimeTimer.start(75); + m_updateTimeBoxesTimer.start(100); +// m_servoCommandTimer.start(100); + + ui.motionControlButton->setStyleSheet("QPushButton:checked{background-color: \ + red;} QPushButton:!checked{background-color: green;}"); + + m_progrssBarLevelStyleSheets[0] = "QProgressBar { \ + text-align: center;\ + } \ + QProgressBar::chunk { \ + background-color: green;\ + border-radius: 5px; }"; + m_progrssBarLevelStyleSheets[1] = "QProgressBar { \ + text-align: center;\ + } \ + QProgressBar::chunk { \ + background-color: yellow;\ + border-radius: 5px; }"; + m_progrssBarLevelStyleSheets[2] = "QProgressBar { \ + text-align: center;\ + } \ + QProgressBar::chunk { \ + background-color: red;\ + border-radius: 5px; }"; + + ui.throttleBar->setFormat("Throttle: %v"); + ui.backBrakeBar->setFormat("Back Brake: %v"); + ui.frontBrakeBar->setFormat("Front Brake: %v"); + m_servoCommand.header.frame_id = "OCS"; + m_servoCommand.steering = -5.0; + m_servoCommand.throttle = -5.0; + m_servoCommand.frontBrake = -5.0; + m_servoCommand.backBrake = -5.0; + //automatically connect into ROS system on startup + qnode.init(); + m_startTime = ros::Time::now(); + + ui.tab_manager->setCurrentIndex(0); + currentTabChanged(0); + + ui.imageTopics_comboBox->setEditable(false); + on_imageTopicsRefresh_button_clicked(); + ui.saveImagesPath_lineEdit->setText(tr("/media/data/").append(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss"))); +} + +MainWindow::~MainWindow() {} + +void MainWindow::updateWheelSpeeds(const autorally_msgs::wheelSpeedsConstPtr& msg) +{ + QString text; + text.sprintf("%.2f", (msg->lfSpeed+msg->rfSpeed)/2.0); + ui.speedLabel->setText(text); + + text.sprintf("%.2f", msg->lfSpeed); + ui.wheelRPS_fl->setText(text); + text.sprintf("%.2f", msg->rfSpeed); + ui.wheelRPS_fr->setText(text); + text.sprintf("%.2f", msg->lbSpeed); + ui.wheelRPS_bl->setText(text); + text.sprintf("%.2f", msg->rbSpeed); + ui.wheelRPS_br->setText(text); + +} + +/* +void MainWindow::updateArduinoData( + const autorally_msgs::arduinoDataConstPtr& msg) +{ + QString text; + text.sprintf("%.2f", msg->leftFrontHallEffect); + ui.wheelRPS_fl->setText(text); + text.sprintf("%.2f", msg->rightFrontHallEffect); + ui.wheelRPS_fr->setText(text); + text.sprintf("%.2f", msg->leftBackHallEffect); + ui.wheelRPS_bl->setText(text); + text.sprintf("%.2f", msg->rightBackHallEffect); + ui.wheelRPS_br->setText(text); +} +*/ + +void MainWindow::updateServoData(const autorally_msgs::servoMSGConstPtr& msg) +{ +// { +// if(msg->throttle >= 0) +// ui.throttleBar->setValue(100*msg->throttle); +// ui.backBrakeBar->setValue(0); +// } else +// { +// ui.throttleBar->setValue(0); +// ui.backBrakeBar->setValue(-msg->throttle); +// } + + ui.steeringSlider->setValue(100*msg->steering); + ui.throttleBar->setValue(100*msg->throttle); + ui.frontBrakeBar->setValue(100*msg->frontBrake); + ui.backBrakeBar->setValue(100*msg->backBrake); + ui.safeSpeedLabel->setNum(msg->safeSpeed); +} + +void MainWindow::on_actionAbout_triggered() { + QMessageBox::about(this, tr("About ..."),tr("

Auto-Rally OCS 0.10

Copyright (2013) C Georgia Institute of Technology

Remote Operator Control Station for communicate with Auto-Rally vehicles

")); +} + +void MainWindow::on_imageTopicsRefresh_button_clicked() { + std::vector topics; + qnode.getImageTopics(topics); + ui.imageTopics_comboBox->clear(); + ui.imageTopics_comboBox_2->clear(); + ui.imageTopics_comboBox->addItem("None"); + ui.imageTopics_comboBox_2->addItem("None"); + for(size_t i = 0; i < topics.size(); i++) + { + ui.imageTopics_comboBox->addItem(topics[i].c_str()); + ui.imageTopics_comboBox_2->addItem(topics[i].c_str()); + } +} + +void MainWindow::on_pushButton_saveLeft_clicked() { + m_saveOneImage = 1; +} + +void MainWindow::on_pushButton_saveRight_clicked() { + m_saveOneImage = 2; +} + +void MainWindow::on_saveImages_button_clicked() { + ui.saveImagesPath_lineEdit->setEnabled(!ui.saveImages_button->isChecked()); + m_savingImages = ui.saveImages_button->isChecked(); +} + +void MainWindow::on_imageTopics_comboBox_currentIndexChanged(int index) +{ + qnode.switchImageTopic(0, ui.imageTopics_comboBox->itemText(index).toStdString()); +} + +void MainWindow::on_imageTopics_comboBox_2_currentIndexChanged(int index) +{ + qnode.switchImageTopic(1, ui.imageTopics_comboBox_2->itemText(index).toStdString()); +} + +void MainWindow::ReadSettings() { + QSettings settings("Qt-Ros Package", "ocs"); + restoreGeometry(settings.value("geometry").toByteArray()); + restoreState(settings.value("windowState").toByteArray()); +} + +void MainWindow::WriteSettings() { + QSettings settings("Qt-Ros Package", "ocs"); + settings.setValue("geometry", saveGeometry()); + settings.setValue("windowState", saveState()); +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + WriteSettings(); + QMainWindow::closeEvent(event); +} + +void MainWindow::enableMotion(const bool check) +{ + if(check) + { + //ui.safeSpeedValueBox->setEnabled(true); + ui.safeSpeedSetButton->setEnabled(true); + ui.motionControlButton->setText("Enable Motion"); + qnode.setSafeSpeed(0.0); + } else + { + //ui.safeSpeedValueBox->setEnabled(false); + ui.safeSpeedSetButton->setEnabled(false); + ui.motionControlButton->setText("STOP"); + setSafeSpeed(ui.safeSpeedSetButton->isChecked()); + } +} + +void MainWindow::setSafeSpeed(const bool check) +{ + if(check) + { + ui.safeSpeedValueBox->setEnabled(false); + if(!ui.motionControlButton->isChecked()) + { + qnode.setSafeSpeed(ui.safeSpeedValueBox->value()); + } + } else + { + ui.safeSpeedValueBox->setEnabled(true); + if(!ui.motionControlButton->isChecked()) + { + qnode.setSafeSpeed(25.0); + } + } +} + +void MainWindow::setControl(bool check) +{ + if(check) + { + m_servoCommandTimer.start(100); + } else + { + m_servoCommandTimer.stop(); + } + //m_sendServoCommand = check; +} + +void MainWindow::sendServoCommand() +{ +// if(ui.steeringControlEnable->checkState() == Qt::Checked) +// { +// m_servoCommand.steering = val/100.0; +// qnode.servoControl(m_servoCommand); +// } else +// { +// m_servoCommand.steering = -5.0; +// } + + if(ui.steeringControlEnable->checkState() == Qt::Checked) + { + m_servoCommand.steering = ui.steeringControlSlider->value()/100.0; + qnode.servoControl(m_servoCommand); + } else + { + m_servoCommand.steering = -5.0; + } + + if(ui.throttleControlEnable->checkState() == Qt::Checked) + { + m_servoCommand.throttle = ui.throttleControlSlider->value()/100.0; + qnode.servoControl(m_servoCommand); + } else + { + m_servoCommand.throttle = -5.0; + } + + if(ui.frontBrakeControlEnable->checkState() == Qt::Checked) + { + m_servoCommand.frontBrake = ui.frontBrakeControlSlider->value()/100.0; + qnode.servoControl(m_servoCommand); + } else + { + m_servoCommand.frontBrake = -5.0; + } + + if(ui.backBrakeControlEnable->checkState() == Qt::Checked) + { + m_servoCommand.backBrake = ui.backBrakeControlSlider->value()/100.0; + qnode.servoControl(m_servoCommand); + } else + { + m_servoCommand.backBrake = -5.0; + } + + qnode.servoControl(m_servoCommand); +} + +void MainWindow::setSteering(const int val) +{ + if(ui.steeringControlEnable->checkState() == Qt::Checked) + { + m_servoCommand.steering = val/100.0; + qnode.servoControl(m_servoCommand); + } else + { + m_servoCommand.steering = -5.0; + } +} + +void MainWindow::setThrottle(const int val) +{ + if(ui.throttleControlEnable->checkState() == Qt::Checked) + { + m_servoCommand.throttle = val/100.0; + qnode.servoControl(m_servoCommand); + } else + { + m_servoCommand.throttle = -5.0; + } +} + +void MainWindow::setFrontBrake(const int val) +{ + if(ui.frontBrakeControlEnable->checkState() == Qt::Checked) + { + m_servoCommand.frontBrake = val/100.0; + qnode.servoControl(m_servoCommand); + } else + { + m_servoCommand.frontBrake = -5.0; + } +} + +void MainWindow::setBackBrake(const int val) +{ + if(ui.backBrakeControlEnable->checkState() == Qt::Checked) + { + m_servoCommand.backBrake = val/100.0; + qnode.servoControl(m_servoCommand); + } else + { + m_servoCommand.backBrake = -5.0; + } +} + +void MainWindow::updateTimeBoxes() +{ + ros::Time time = ros::Time::now(); + ui.timeSpinBox->setValue(time.toSec()); + ui.elapsedSpinBox->setValue( (time-m_startTime).toSec()); + //ROS_INFO("%f",(time-m_startTime).toSec()); +} + +void MainWindow::currentTabChanged(const int /*index*/) +{ + qnode.m_currentTabText = + ui.tab_manager->tabText(ui.tab_manager->currentIndex()).toStdString(); +} + +void MainWindow::updateImage1() +{ + pthread_mutex_lock(&qnode.m_imageMutex); + QPainter painter(&qnode.m_firewireImage1); + + std::map::const_iterator mapIt; + for(mapIt = qnode.m_imMaskModel.m_masks.begin(); + mapIt != qnode.m_imMaskModel.m_masks.end(); + mapIt++) + { + const QStandardItem* item = qnode.m_imMaskModel.itemFromName(mapIt->second.sender); + if(item) + { + if(item->checkState() == Qt::Checked) + { + QPen pen(item->background().color()); + pen.setWidth(4); + painter.setPen(pen); + + std::vector::const_iterator pointIt; + for(pointIt = mapIt->second.points.begin(); + pointIt != mapIt->second.points.end(); + pointIt++) + { + painter.drawPoint(pointIt->x, pointIt->y); + } + + std::vector::const_iterator vecIt; + for(vecIt = mapIt->second.lines.begin(); + vecIt != mapIt->second.lines.end(); + vecIt++) + { + painter.drawLine(vecIt->start.x, vecIt->start.y, vecIt->end.x, vecIt->end.y); + } + + std::vector::const_iterator rectIt; + for(rectIt = mapIt->second.rois.begin(); + rectIt != mapIt->second.rois.end(); + rectIt++) + { + painter.drawRect(rectIt->x_offset, rectIt->y_offset, rectIt->width, rectIt->height); + } + } + } + } + + painter.end(); + //set image + if(qnode.m_currentTabText == "Video") + { + ui.cameraLabel->setPixmap(qnode.m_firewireImage1.scaled(240,240, Qt::KeepAspectRatio)); + } + + if(m_savingImages || m_saveOneImage == 1) + { + QDir().mkpath(ui.saveImagesPath_lineEdit->text().append(ui.imageTopics_comboBox->currentText())); + QString path = ui.saveImagesPath_lineEdit->text().append(ui.imageTopics_comboBox->currentText()).append(QDateTime::currentDateTime().toString("/yyyy-MM-dd-hh-mm-ss-zzz")).append(".png"); + if(!qnode.m_firewireImage1.save(path)) + { + std::cout << "Failed to save image to " << path.toStdString().c_str() << std::endl; + } + m_saveOneImage = 0; + } + + pthread_mutex_unlock(&qnode.m_imageMutex); +} + +void MainWindow::updateImage2() +{ + pthread_mutex_lock(&qnode.m_imageMutex); + QPainter painter(&qnode.m_firewireImage2); + + std::map::const_iterator mapIt; + for(mapIt = qnode.m_imMaskModel.m_masks.begin(); + mapIt != qnode.m_imMaskModel.m_masks.end(); + mapIt++) + { + const QStandardItem* item = qnode.m_imMaskModel.itemFromName(mapIt->second.sender); + if(item) + { + if(item->checkState() == Qt::Checked) + { + QPen pen(item->background().color()); + pen.setWidth(4); + painter.setPen(pen); + + std::vector::const_iterator pointIt; + for(pointIt = mapIt->second.points.begin(); + pointIt != mapIt->second.points.end(); + pointIt++) + { + painter.drawPoint(pointIt->x, pointIt->y); + } + + std::vector::const_iterator vecIt; + for(vecIt = mapIt->second.lines.begin(); + vecIt != mapIt->second.lines.end(); + vecIt++) + { + painter.drawLine(vecIt->start.x, vecIt->start.y, vecIt->end.x, vecIt->end.y); + } + + std::vector::const_iterator rectIt; + for(rectIt = mapIt->second.rois.begin(); + rectIt != mapIt->second.rois.end(); + rectIt++) + { + painter.drawRect(rectIt->x_offset, rectIt->y_offset, rectIt->width, rectIt->height); + } + } + } + } + + painter.end(); + //set image + if(qnode.m_currentTabText == "Video") + { + ui.cameraLabel_2->setPixmap(qnode.m_firewireImage2.scaled(240,240, Qt::KeepAspectRatio)); + } + + if(m_savingImages || m_saveOneImage == 2) + { + QDir().mkpath(ui.saveImagesPath_lineEdit->text().append(ui.imageTopics_comboBox->currentText())); + QString path = ui.saveImagesPath_lineEdit->text().append(ui.imageTopics_comboBox->currentText()).append(QDateTime::currentDateTime().toString("/yyyy-MM-dd-hh-mm-ss-zzz")).append(".png"); + if(!qnode.m_firewireImage2.save(path)) + { + std::cout << "Failed to save image to " << path.toStdString().c_str() << std::endl; + } + m_saveOneImage = 0; + } + + pthread_mutex_unlock(&qnode.m_imageMutex); +} + +template +unsigned char MainWindow::levelFromParams(const T warnVal, const T critVal, const T val) const +{ + unsigned char level = 0; + //std::cout << warnVal << " " << critVal << " " << val << std::endl; + if(critVal > warnVal) + { + if(val >= warnVal) ++level; + if(val >= critVal) ++level; + } + else if (warnVal > critVal) + { + if(val <= warnVal) ++level; + if(val <= critVal) ++level; + } + + return level; +} + diff --git a/autorally_core/src/ocs/main_window.hpp b/autorally_core/src/ocs/main_window.hpp new file mode 100644 index 00000000..da40c893 --- /dev/null +++ b/autorally_core/src/ocs/main_window.hpp @@ -0,0 +1,184 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file main_window.hpp + * @author Brian Goldfain + * @date March 3, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief QT Based OCS main window + * + * @details This file contains the MainWindow class that utilizes main_window.ui + * to generate an Operator Control Station (OCS) GUI. The GUI provides a window + * into various ROS messages and the ability to disable vehicle motion using the + * safeSpeed message. This class was built from a template generated by qt-ros + ***********************************************/ +#ifndef MAIN_WINDOW_H +#define MAIN_WINDOW_H + +#include +#include +#include "ui_main_window.h" +#include "qnode.hpp" + +/** + * @class MainWindow main_window.hpp "ocs/main_window.hpp" + * @brief Operator Control Station GUI developed in QT + * @note this code grows orgnaically (its dirty) + */ +class MainWindow : public QMainWindow { +Q_OBJECT + +public: + MainWindow(int argc, char** argv, QWidget *parent = 0); + ~MainWindow(); + + void ReadSettings(); // Load up qt program settings at startup + void WriteSettings(); // Save qt program settings when closing + + void closeEvent(QCloseEvent *event); // Overloaded function + +public slots: + /** + * @brief Slot for OCS menu action + */ + void on_actionAbout_triggered(); + + void on_imageTopicsRefresh_button_clicked(); + + void on_saveImages_button_clicked(); + + void on_imageTopics_comboBox_currentIndexChanged(int index); + + void on_imageTopics_comboBox_2_currentIndexChanged(int index); + + void on_pushButton_saveLeft_clicked(); + void on_pushButton_saveRight_clicked(); + + /** + * @brief Slot that is activated when the enableMotion button is presses + * @param check The state of the button + */ + void enableMotion(const bool check); + + /** + * @brief Slot that is activated when the user wants to send a safeSpeed + * @param check The state of the button + */ + void setSafeSpeed(const bool check); + + /** + * @brief Slot used to trigger display updates + */ + void updateTimeBoxes(); + + //void updateLoggingView(); // no idea why this can't connect automatically + + /** + * @brief Update OCS with the new wheelSpeeds + * @param msg The new wheelSpeeds + */ + void updateWheelSpeeds(const autorally_msgs::wheelSpeedsConstPtr& msg); + + /** + * @brief Update OCS with new Arduino data + * @param msg new data + */ + //void updateArduinoData(const autorally_msgs::arduinoDataConstPtr& msg); + + /** + * @brief Update OCS with new servo data + * @param msg The new servo data + */ + void updateServoData(const autorally_msgs::servoMSGConstPtr& msg); + + void setControl(bool check); + void sendServoCommand(); + + /** + * @brief Desired steering value has been changed + * @param val The new steering value + */ + void setSteering(const int val); + + /** + * @brief Desired throttle value has been changed + * @param val The new throttle value + */ + void setThrottle(const int val); + + /** + * @brief Desired front brake value has been changed + * @param val The new front brake value + */ + void setFrontBrake(const int val); + + /** + * @brief Desired back brake value has been changed + * @param val The new back brake value + */ + void setBackBrake(const int val); + + void currentTabChanged(const int index); + + void updateImage1(); + void updateImage2(); + +private: + Ui::MainWindowDesign ui; ///> Design file for the GUI + QNode qnode; ///> Provides access to the ROS system + ros::Time m_startTime; ///> Time OCS started + autorally_msgs::servoMSG m_servoCommand; ///> servoInterfaceCommand message + QTimer m_diagTimeTimer; ///> Timer to trigger color updates + QTimer m_updateTimeBoxesTimer; ///> Timer to update displayed elapsed time + QTimer m_servoCommandTimer; ///< Timer for sending servo command messages + std::string m_progrssBarLevelStyleSheets[3]; ///> List of style sheets for the QProgressBars + bool m_savingImages; + int m_saveOneImage; + + /** + * @brief Computes a status based on a value and 2 thresholds + * @param warnVal Threshold value to be considered abnormal + * @param critVal Threshold value to be considered critical + * @param val + * @return level 0=OK, 1=WARN, 2=ERROR. Follows the levels from ros diagnostics + * + * Computes the status of a given state variable given warning and critical + * thresholds for that value. The level computed follows those in + * ros::diagnostic_msgs::DiagnosticStatus. Can handle values that are critical + * when high such as temp and values that are critical when low such as battery + */ + template + unsigned char levelFromParams(const T warnVal, const T critVal, const T val) const; + + /** + * @brief Slot indicating if the OCS wants to control the car + * @param msg the desired servo positions commanded by the OCS + */ + void setControl(autorally_msgs::servoMSG& msg); +}; + +#endif // ocs_MAIN_WINDOW_H diff --git a/autorally_core/src/ocs/main_window.ui b/autorally_core/src/ocs/main_window.ui new file mode 100644 index 00000000..31a7ec3c --- /dev/null +++ b/autorally_core/src/ocs/main_window.ui @@ -0,0 +1,1126 @@ + + + MainWindowDesign + + + + 0 + 0 + 1041 + 691 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Auto-Rally OCS + + + + :/doc/car_logo.png:/doc/car_logo.png + + + + + + + + + + true + + + Current wall time + + + true + + + true + + + QAbstractSpinBox::NoButtons + + + 5 + + + 2000000000.000000000000000 + + + + + + + System Time: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Elapsed Time: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + OCS up time + + + true + + + QAbstractSpinBox::NoButtons + + + 5 + + + 2000000000.000000000000000 + + + + + + + + 0 + 1 + + + + + 0 + 0 + + + + + 16777215 + 1677215 + + + + + + + 1 + + + + System Info + + + + + + + 0 + 0 + + + + Safe Speed + + + + + + + 0 + 0 + + + + Current safe speeds published + + + false + + + true + + + QAbstractItemView::NoSelection + + + true + + + true + + + false + + + + + + + + + + + 0 + 5 + + + + Diagnostic Messages + + + + + + + 0 + 5 + + + + + 0 + 0 + + + + Diagnostic Messages + + + QFrame::StyledPanel + + + false + + + true + + + QAbstractItemView::NoSelection + + + true + + + true + + + false + + + + + + + Clear Stale Messages + + + + + + + + + + + Video + + + + + + + + + 0 + 0 + + + + + 27 + 27 + + + + + + + + :/images/camera.png:/images/camera.png + + + true + + + + + + + + + + + + + + 0 + 0 + + + + + 27 + 27 + + + + + + + + :/images/camera.png:/images/camera.png + + + true + + + + + + + + 320 + 240 + + + + QFrame::Box + + + No Data + + + Qt::AlignCenter + + + + + + + + 320 + 240 + + + + QFrame::Box + + + No Data + + + Qt::AlignCenter + + + + + + + Refresh + + + + + + + + + + + + + + Start Saving + + + true + + + false + + + + + + + + + Image Masks + + + + + + QAbstractItemView::NoSelection + + + true + + + + + + + + + + + Control + + + + + + + + Steering + + + Qt::AlignCenter + + + + + + + -100 + + + 100 + + + 0 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 50 + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Control + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Throttle + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + -100 + + + 100 + + + 0 + + + Qt::Vertical + + + QSlider::TicksBothSides + + + 50 + + + + + + + + + + + + + + + + + + Front Brake + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + -100 + + + 100 + + + Qt::Vertical + + + QSlider::TicksBothSides + + + 50 + + + + + + + + + + + + + + + + + + Back Brake + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + -100 + + + 100 + + + Qt::Vertical + + + QSlider::TicksBothSides + + + 50 + + + + + + + Qt::LeftToRight + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + 0 + 0 + 1041 + 25 + + + + + &App + + + + + + + + + + + + + + + 0 + 0 + + + + + 352 + 644 + + + + + 524287 + 650 + + + + QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable + + + Qt::RightDockWidgetArea + + + Command Panel + + + 2 + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Vehicle Information + + + + + + QFrame::StyledPanel + + + 0.0 + + + Qt::AlignCenter + + + + + + + Current Vhicle Speed + + + Speed (m/s) + + + + + + + SafeSpeed from servoInterface + + + SafeSpeed + + + + + + + QFrame::StyledPanel + + + 0.0 + + + Qt::AlignCenter + + + + + + + QFrame::StyledPanel + + + 0.0 + + + Qt::AlignCenter + + + + + + + QFrame::StyledPanel + + + 0.0 + + + Qt::AlignCenter + + + + + + + QFrame::StyledPanel + + + 0.0 + + + Qt::AlignCenter + + + + + + + QFrame::StyledPanel + + + 0.0 + + + Qt::AlignCenter + + + + + + + -100 + + + 100 + + + 0 + + + true + + + Qt::Vertical + + + Throttle + + + + + + + 100 + + + 0 + + + true + + + Qt::Vertical + + + Back Brake + + + + + + + 0 + + + 100 + + + 0 + + + true + + + Qt::Vertical + + + Front Brake + + + + + + + Steering + + + + + + + false + + + -100 + + + 100 + + + 0 + + + 0 + + + Qt::Horizontal + + + QSlider::TicksBothSides + + + 50 + + + + + + + Wheel RPS + + + + + + + + + + Vehicle Control + + + + + + SafeSpeed control + + + SafeSpeed + + + + + + + true + + + SafeSpeed control + + + m/s + + + + + + + SafeSpeed control + + + Set + + + true + + + false + + + false + + + + + + + + 0 + 0 + + + + + 0 + 70 + + + + + + + Software E-Stop + + + true + + + Enable Motion + + + true + + + true + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + Quit OCS + + + Quit + + + + + + + + + &Quit + + + Ctrl+Q + + + Qt::ApplicationShortcut + + + + + &Preferences + + + + + &About + + + + + About &Qt + + + + + + + + + action_Quit + triggered() + MainWindowDesign + close() + + + -1 + -1 + + + 399 + 299 + + + + + quit_button + clicked() + MainWindowDesign + close() + + + 859 + 552 + + + 469 + 299 + + + + + diff --git a/autorally_core/src/ocs/qnode.cpp b/autorally_core/src/ocs/qnode.cpp new file mode 100644 index 00000000..87d1fa2e --- /dev/null +++ b/autorally_core/src/ocs/qnode.cpp @@ -0,0 +1,405 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/** + * @file qnode.cpp + * @author Brian Goldfain + * @date March 2, 2012 + * @brief Implementation of ROS components for ocs gui. + **/ +#include +#include +#include "qnode.hpp" +#include +#include + +QNode::QNode(int argc, char** argv ) : + m_currentTabText(""), + m_firewireImage1(320,320), + m_firewireImage2(320,320), + init_argc(argc), + init_argv(argv) +{ + //register my data types so I can pass them around in signals and slots + qRegisterMetaType + ("autorally_msgs::safeSpeedConstPtr"); + qRegisterMetaType + ("autorally_msgs::wheelSpeedsConstPtr"); + qRegisterMetaType + ("autorally_msgs::servoMSGConstPtr"); + qRegisterMetaType + ("diagnostic_msgs::DiagnosticStatus"); + pthread_mutex_init(&m_imageMutex, NULL); +} + +QNode::~QNode() { + if(ros::isStarted()) + { + ros::shutdown(); // explicitly needed since we use ros::start(); + ros::waitForShutdown(); + } + wait(); +} + +bool QNode::init() { + ros::init(init_argc,init_argv,"ocs"); + if ( ! ros::master::check() ) { + return false; + } + + m_nh = new ros::NodeHandle; + + // Add your ros communications here. + safeSpeed_publisher = m_nh->advertise + ("safeSpeed", 1); + servoCommandPub = m_nh->advertise + ("OCS/servoCommand", 1); + + //vehicleSpeed_subscriber = n.subscribe("vehicleSpeed", 5, + // &QNode::vehicleSpeedCallback, + // this); + safeSpeed_subscriber = m_nh->subscribe("safeSpeed", 5, + &QNode::safeSpeedCallback, + this); + wheelSpeeds_subscriber = m_nh->subscribe("wheelSpeeds", 1, + &QNode::wheelSpeedsCallback, + this); + diagStatus_subscriber = m_nh->subscribe("diagnostics", 10, + &QNode::diagStatusCallback, + this); + servoStatus_subscriber = m_nh->subscribe("servoStatus", 1, + &QNode::newServoMSG, + this); + imageMask_subscriber = m_nh->subscribe("imageMask", 10, + &QNode::imageMaskCallback, + this); + + m_safeSpeedTimer = m_nh->createTimer(ros::Duration(0.1), &QNode::ssTimerCallback, this); +// m_servoCommandTimer = n.createTimer(ros::Duration(0.1), &QNode::ssTimerCallback, this); +// m_servoCommandTimer.stop(); + + m_safeSpeed.header.seq = 0; + m_safeSpeed.sender = "OCS"; + + QStringList header; + header << "Sender" << "Value (m/s)" << "Time since last message"; + m_safeSpeedModel.setColumnCount(3); + m_safeSpeedModel.setHorizontalHeaderLabels(header); + + double diagFreq; + ros::param::param("diagnosticsFrequency", diagFreq, 1.0); + ros::param::param("safeSpeed/Timeout", m_safeSpeedTimeout, 5.0); + + m_diagModel.setDiagnosticFrequency(diagFreq); + + start(); + return true; +} + +void QNode::ssTimerCallback(const ros::TimerEvent&) +{ + m_safeSpeed.header.stamp = ros::Time::now(); + safeSpeed_publisher.publish(m_safeSpeed); +} + +void QNode::run() { + ros::spin(); + + std::cout << "Ros shutdown, proceeding to close the gui." << std::endl; + emit rosShutdown(); //used to signal the gui to shutdown (useful to roslaunch) +} + +//void QNode::vehicleSpeedCallback(const autorally_msgs::vehicleSpeedConstPtr& msg) +//{ +// emit newVehicleSpeed(msg); +//} + +void QNode::safeSpeedCallback(const autorally_msgs::safeSpeedConstPtr& msg) +{ + QList items = m_safeSpeedModel.findItems( + QString::fromStdString(msg->sender) ); + if(items.isEmpty()) + { + //add new item for the sender + m_safeSpeedModel.appendRow(generateNewSafeSpeed(msg)); + items = m_safeSpeedModel.findItems( QString::fromStdString(msg->sender) ); + } + + if(items.size() == 1) + { + //update the safeSpeed + m_safeSpeedModel.item(items.front()->index().row(),1)-> + setText(QString::number(msg->speed, 'g', 4)); + m_safeSpeedModel.item(items.front()->index().row(),2)-> + setData(QVariant(msg->header.stamp.toSec())); + } else //found more than one sender with the same name + { + ROS_ERROR("Something is wrong with the OCS safeSpeedModel!!!!!"); + } +} + +void QNode::safeSpeedModelDoubleClicked(const QModelIndex& index) +{ + m_safeSpeedModel.removeRows(index.row(), 1); +} + +void QNode::wheelSpeedsCallback(const autorally_msgs::wheelSpeedsConstPtr& msg) +{ + emit newWheelSpeeds(msg); +} + +void QNode::newServoMSG(const autorally_msgs::servoMSGConstPtr& msg) +{ + emit newServoData(msg); +} + +void QNode::setSafeSpeed(const double& speed) +{ + m_safeSpeed.speed = speed; +} + +void QNode::diagStatusCallback(const diagnostic_msgs::DiagnosticArray& msg) +{ + m_diagModel.update(msg); +} + + +void QNode::servoControl(autorally_msgs::servoMSG& msg) +{ +// if(m_sendServoCommand) + { + msg.header.stamp = ros::Time::now(); + servoCommandPub.publish(msg); + } +} + +QList QNode::generateNewSafeSpeed( + const autorally_msgs::safeSpeedConstPtr& msg) +{ + QList newSafeSpeed; + newSafeSpeed << new QStandardItem(msg->sender.c_str()); + newSafeSpeed << new QStandardItem(QString::number(msg->speed, 'g', 4)); + newSafeSpeed << new QStandardItem("0.000"); + + newSafeSpeed[0]->setEditable(false); + newSafeSpeed[1]->setEditable(false); + newSafeSpeed[2]->setEditable(false); + newSafeSpeed[2]->setData(QVariant(msg->header.stamp.toSec())); + + return newSafeSpeed; +} + +void QNode::updateTimes() +{ + double time; + QStandardItem* node; + + if(m_currentTabText == "System Info") + { + for(int i = 0; i < m_safeSpeedModel.rowCount(); i++) + { + if( (node = m_safeSpeedModel.item(i,2)) == 0 || !node->data().isValid()) + { + ROS_ERROR("Invalid safespeed child"); + } else + { + time = ros::Time::now().toSec()-node->data().toDouble(); + node->setText(QString::number(time, 'g', 4)); + //set colors for stale + if(time > m_safeSpeedTimeout) + { + node->setBackground(Qt::magenta); + } else + { + node->setBackground(m_safeSpeedModel.item(i,1)->background()); + } + } + } + } +} + +void QNode::imageMaskCallback(const autorally_msgs::imageMask& msg) +{ + m_imMaskModel.update(msg); +} + +void QNode::imageCallback1(const sensor_msgs::ImageConstPtr& msg) +{ + QImage::Format format = QImage::Format_Indexed8; + unsigned char *newData = 0; + if(msg->encoding == "bgr8") { + format = QImage::Format_RGB888; + newData = convertBGRtoRGB(&msg->data[0], msg->step * msg->height); + } + if(msg->encoding == "rgb8") + format = QImage::Format_RGB888; + if(msg->encoding == "mono16") + ROS_WARN("The OCS does not currently support 16bpp images. This image topic will not render correctly."); + QImage img(msg->encoding == "bgr8" ? newData : &msg->data[0], + msg->width, + msg->height, + msg->step, + format); + + if(!pthread_mutex_trylock(&m_imageMutex)) + { + if(m_firewireImage1.convertFromImage(img)) + { + emit newImage1(); + } + pthread_mutex_unlock(&m_imageMutex); + } + if(newData != 0) + delete newData; +} + +void QNode::imageCallback2(const sensor_msgs::ImageConstPtr& msg) +{ + QImage::Format format = QImage::Format_Indexed8; + unsigned char *newData = 0; + if(msg->encoding == "bgr8") { + format = QImage::Format_RGB888; + newData = convertBGRtoRGB(&msg->data[0], msg->step * msg->height); + } + if(msg->encoding == "rgb8") + format = QImage::Format_RGB888; + if(msg->encoding == "mono16") + ROS_WARN("The OCS does not currently support 16bpp images. This image topic will not render correctly."); + QImage img(msg->encoding == "bgr8" ? newData : &msg->data[0], + msg->width, + msg->height, + msg->step, + format); + + if(!pthread_mutex_trylock(&m_imageMutex)) + { + if(m_firewireImage2.convertFromImage(img)) + { + emit newImage2(); + } + pthread_mutex_unlock(&m_imageMutex); + } + if(newData != 0) + delete newData; +} + +unsigned char* QNode::convertBGRtoRGB(const unsigned char* data, int size) { + unsigned char* newData = new unsigned char[size]; + for(int i = 0; i < size; i+=3){ + // Swap R & B channels + char tmp = data[i]; + newData[i] = data[i+2]; + newData[i+2] = tmp; + // Copy G channel directly + newData[i+1] = data[i+1]; + } + return newData; +} + +void QNode::getImageTopics(std::vector& topics) +{ + /* + * Largely copied from rqt_image_view/image_view.cpp + */ + ros::master::V_TopicInfo topic_info; + ros::master::getTopics(topic_info); + + // get declared transports + QList transports; + image_transport::ImageTransport it(*m_nh); + std::vector declared = it.getDeclaredTransports(); + for (std::vector::const_iterator it = declared.begin(); it != declared.end(); it++) + { + //qDebug("ImageView::updateTopicList() declared transport '%s'", it->c_str()); + QString transport = it->c_str(); + + // strip prefix from transport name + QString prefix = "image_transport/"; + if (transport.startsWith(prefix)) + { + transport = transport.mid(prefix.length()); + } + transports.append(transport); + } + + QSet all_topics; + for (ros::master::V_TopicInfo::const_iterator it = topic_info.begin(); it != topic_info.end(); it++) + { + all_topics.insert(it->name.c_str()); + } + + for (ros::master::V_TopicInfo::const_iterator it = topic_info.begin(); it != topic_info.end(); it++) + { + if (it->datatype == "sensor_msgs/Image") + { + QString topic = it->name.c_str(); + + topics.push_back(topic.toStdString()); + + for (QList::const_iterator jt = transports.begin(); jt != transports.end(); jt++) + { + if (all_topics.contains(topic + "/" + *jt)) + { + QString sub = topic + " " + *jt; + topics.push_back(sub.toStdString()); + } + } + } + if (it->datatype == "sensor_msgs/CompressedImage") + { + QString topic = it->name.c_str(); + int index = topic.lastIndexOf("/"); + if (index != -1) + { + topic.replace(index, 1, " "); + topics.push_back(topic.toStdString()); + } + } + } +} + +void QNode::switchImageTopic(int subscriber, std::string name) +{ + image_transport::Subscriber& sub = subscriber ? images_subscriber_2 : images_subscriber; + void (QNode::*callback)(const sensor_msgs::ImageConstPtr& msg) = subscriber ? &QNode::imageCallback2 : &QNode::imageCallback1; + if(sub.getTopic() != name) + { + sub.shutdown(); + if(name != "None") + { + image_transport::ImageTransport it(*m_nh); + if(find(name.begin(), name.end(), ' ') == name.end()) + { + sub = it.subscribe(name, 1, callback,this); + } + else + { + std::string base = name.substr(0,name.find(' ')); + std::string param = name.substr(name.find(' ')+1, name.length()-name.find(' ')); + sub = it.subscribe(base, 1,callback,this,param); + } + } + } +} diff --git a/autorally_core/src/ocs/qnode.hpp b/autorally_core/src/ocs/qnode.hpp new file mode 100644 index 00000000..7f28eff5 --- /dev/null +++ b/autorally_core/src/ocs/qnode.hpp @@ -0,0 +1,272 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file qnode.hpp + * @author Brian Goldfain + * @date March 3, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief ROS backend for OCS + * + * @details This file contains the QNode class that implements the ROS backend + * for the operator control station passing messages from and to the rest of the + * nodes in the system. + ***********************************************/ +#ifndef QNODE_HPP_ +#define QNODE_HPP_ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include "ImageMaskEntry.hpp" +#include "DiagnosticsEntry.hpp" + +/** + * @class QNode qnode.hpp "ocs/qnode.hpp" + * @brief ROS backend for OCS + * + * QNode is ROS the backend for the Operator Control Station (OCS) that + * receives and sends all pertinent ROS messages. The class also handles + * updating the models used by the tree views in the OCS to display data. + * Updating many of the individual text boxes is passed back to OCS through + * signals. + * @note this code grows orgnaically (its dirty) + */ +class QNode : public QThread { + Q_OBJECT +public: + + std::string m_currentTabText; + QPixmap m_firewireImage1; + QPixmap m_firewireImage2; + + DiagnosticsEntry m_diagModel; + ImageMaskEntry m_imMaskModel; + pthread_mutex_t m_imageMutex; + + /** + * @brief Constructor, just initializes internal variables + * + */ + QNode(int argc, char** argv ); + virtual ~QNode(); + + /** + * @brief Publishes and subscribes to all necessary ROS information, sets up + * view headers. + * @note init() muse be called prior to run() for proper setup + */ + bool init(); + + /** + * @brief Main loop for program + * + * Call run() after setup is complete to start listening/publishing ROS + * messages. This function will not return until the ROS system is shut down. + */ + void run(); + + //QStringListModel* loggingModel() { return &logging_model; } + /** + * @brief Accessor for the QStandardItemModel holding diagnostic messages + * @return QStandardItemModel* Pointer to the model + */ + QStandardItemModel* diagnosticModel() { return m_diagModel.model(); } + + /** + * @brief Accessor for the QStandardItemModel holding safeSpeed messages + * @return QStandardItemModel* Pointer to the model + */ + QStandardItemModel* safeSpeedModel() { return &m_safeSpeedModel; } + + /** + * @brief Accessor for the QStandardItemModel holding image masks + * @return QStandardItemModel* Pointer to the model + */ + QStandardItemModel* imageMaskModel() { return m_imMaskModel.model(); } + + /** + * @brief Callback for new vehicleSpeed messages + * @param msg The new vehicle speed + */ + void wheelSpeedsCallback(const autorally_msgs::wheelSpeedsConstPtr& msg); + + /** + * @brief Callback for new safeSpeed messages + * @param msg The new vehicle speed + */ + void safeSpeedCallback(const autorally_msgs::safeSpeedConstPtr& msg); + + /** + * @brief Callback for new wheelSpeeds messages + * @param msg The new wheelSpeeds + */ + //void wheelSpeedsCallback(const autorally_msgs::wheelSpeedsConstPtr& msg); + + /** + * @brief Callback for new servoInterfaceStatus messages + * @param msg The new servoInterfaceStatus message + */ + void newServoMSG(const autorally_msgs::servoMSGConstPtr& msg); + + /** + * @brief Callback for new diagnostics messages + * @param msg the new diagnostic message + */ + void diagStatusCallback(const diagnostic_msgs::DiagnosticArray& msg); + + /** + * @brief Callback for new imageMask messages + * @param msg The new imageMask + */ + void imageMaskCallback(const autorally_msgs::imageMask& msg); + + /** + * @brief Slot indicating the OCS safeSpeed has been updated + * @param speed new value + */ + void setSafeSpeed(const double& speed); + + /** + * @brief Slot the desired servoInterfaceControl message data to send + * @param msg the control values from the OCS + */ + void servoControl(autorally_msgs::servoMSG& msg); + + void getImageTopics(std::vector& topics); + + void switchImageTopic(int subscriber, std::string name); + +signals: + + /** + * @brief Signal that the ROS system has shut down + */ + void rosShutdown(); + + /** + * @brief Signal for the OCS to update vehicleSpeed display + * @param msg The new value + */ + void newWheelSpeeds(const autorally_msgs::wheelSpeedsConstPtr& msg); + + /** + * @brief Signal for the OCS to update data from the arduino + * @param msg The new data + */ + //void newWheelSpeeds(const autorally_msgs::wheelSpeedsConstPtr& msg); + + /** + * @brief Signal for the OCS to update servo information + * @param msg The new data + */ + void newServoData(const autorally_msgs::servoMSGConstPtr& msg); + + void newImage1(); + void newImage2(); + +public slots: + + /** + * @brief Update the time since last message received for all elements in OCS + */ + void updateTimes(); + + /** + * @brief Callback for a user click on a safeSPeed entry + * @param index the index for the item clicked + */ + void safeSpeedModelDoubleClicked(const QModelIndex& index); + +private: + int init_argc; ///< Command line parameter count + char** init_argv; ///< Command line parameters + + ros::NodeHandle *m_nh; + + ros::Timer m_safeSpeedTimer; ///< Timer for sending safeSpeed messages + ros::Publisher safeSpeed_publisher; ///< Publisher for safeSpeed + ros::Publisher servoCommandPub; ///< Publishe for servoInterfaceCommand + + ros::Subscriber wheelSpeeds_subscriber; ///< Subscriber for wheelSpeeds + ros::Subscriber safeSpeed_subscriber; ///< Subscriber for safeSpeed + //ros::Subscriber wheelSpeeds_subscriber; ///< Subscriber for wheelSpeeds + ros::Subscriber diagStatus_subscriber; ///< Subscriber for diagnostics + ros::Subscriber servoStatus_subscriber; ///< Subscriber for servoInterfaceStatus + ros::Subscriber imageMask_subscriber; ///< Subscriber for imageMask + image_transport::Subscriber images_subscriber; ///< Subscriber for images + image_transport::Subscriber images_subscriber_2; ///< Subscriber for images + + autorally_msgs::safeSpeed m_safeSpeed; ///< SafeSpeed message OCS can send + + QStandardItemModel m_safeSpeedModel; ///< Model holding safeSpeed messages + + double m_safeSpeedTimeout; + + void ssTimerCallback(const ros::TimerEvent&); ///< Callback to publish safeSpeed + void updateTimeBoxesCallback(const ros::TimerEvent&); ///< Callbak to update time displays + + /** + * @brief Generates new entry for a safe speed message + */ + QList generateNewSafeSpeed( + const autorally_msgs::safeSpeedConstPtr& msg); + + /** + * @brief Callback for new image messages + * @param msg The new image data + */ + void imageCallback1(const sensor_msgs::ImageConstPtr& msg); + void imageCallback2(const sensor_msgs::ImageConstPtr& msg); + + /** + * @brief Swaps the first and third channel of the given image data. + * @param data The original image data + * @param size The size of the data buffer + * @return A pointer to the new data. Don't forget to delete it when you're done. + */ + unsigned char* convertBGRtoRGB(const unsigned char* data, int size); + +}; + +#endif /* QNODE_HPP_ */ diff --git a/autorally_core/src/ocs/resources/images.qrc b/autorally_core/src/ocs/resources/images.qrc new file mode 100644 index 00000000..7c93a56a --- /dev/null +++ b/autorally_core/src/ocs/resources/images.qrc @@ -0,0 +1,7 @@ + + + images/icon.png + images/car_logo.png + images/camera.png + + diff --git a/autorally_core/src/ocs/resources/images.qrc.depends b/autorally_core/src/ocs/resources/images.qrc.depends new file mode 100644 index 00000000..eb4c565c --- /dev/null +++ b/autorally_core/src/ocs/resources/images.qrc.depends @@ -0,0 +1,8 @@ + + + images/icon.png + + + images/car_logo.png + + diff --git a/autorally_core/src/ocs/resources/images/camera.png b/autorally_core/src/ocs/resources/images/camera.png new file mode 100644 index 0000000000000000000000000000000000000000..fbf1ed90a25832709f7f035d93fbe05dc13f698b GIT binary patch literal 5145 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 Ef;vI38vp;v|tC@M{ zowq#w`9077zh8L!Ti;Y!-db*Em2bX&^E-I`khanY|MvX-r!V0p^5GlawAnoU_ss{t z`#0<<`{ecS`%h*S_1XgVwg219&giG!eB-sz{pF#$dC}+o-Ds;>hrN08)$jUD!1n(4 z6}JUE&*P|bH)bqvDf6~hS#U$tg6HnU|DT@eoHIal$|4md7C1j7o0+wAcfU6_JZck} zS!-Ug+zMqSI~p4sH=Lgfp5L>c7Y4l6TaHf;co7&FscH(?NS`-(?6`I9+-tpi57^M5 zZX53#wB-1djRrmIZLYK6+-93Uf4+5gc3MYAhuan}UK}Vdmks%sJ^n>8pb($f94zEM zZ?p0B&u!gm5C8mU*1dPXd6P42aSJEYR+_{5=FLijVVkP1wEWeV+eCHDve~SSkB{5* z^t6?hmRf6Tt2H$>+1ua#c57*A5mU~SO1?G*|4tZCz(gesO6GGG3q~zafTF3C%^o=5 zJ@S*E+5jrI0eDaV&bN-PoyTfxg&GM%wp!EB_W%s#jEajRUp`WGc7 zC09a<%BP=x+MavvIorK^xApe+S}vEfdGqGk#*G{8vdb>B<;$1T_{+Jm?4jEFR2LHOyeB8Z+^6lz$P7cwHHgB|<8((2K+> z9N6pax#vFH@ylP?^GI&gD_BE$g;_djC76_|Xw>5INkiDpgIvK#$h;D^aL@wL5}T^2 zwcB?e!X`yuJm;xz(&@BCImZhxykPg-bB{gx=%da|tz5a%-uJ%u*_+<D4 zOG?}pz#L6hR@f_HrHC@0i7I6^9759LRK1$SP5HI zO@s9gPuMJOqOz{RW>JS+FksQLO7lv~(TaaQ(wUu|H9s1<{`%{U=*XUb{&{=op@-}T zKlp(S4-b2{-g>JoTD0hQ!id*J1G>liy!mzQ0fPa_N49#O``91Z{BWra9Nur?NEWTg zTL{}8$iO8CEF%>r3=IWKEv-Zm4&|a{Hi}8fVs2Jmavhe_-LJMhgau znl&^uWaI>v&*yDyY|NUQo9)Dj6P8S3*3h2z_I8_@nXzY|ebzBT&RUR&rw0 z!Xp#b8LPpz4?|=p^bWKr;k`0wJO%bXWEoylC8d_CD7O_?USXTx|9duP)k+)6q-->k zv=I9%t81-cPNR!*#DoHolHiqaIP7u*gTN}AEv*XK-De}BK-dFP!jU-;bTKKHt5LD6vfcX>Wu(>Z(OZ~xwgcJH?; zOpKDMOfF-IeA2RE&vJn|wu*pf zQT)NoV87*48E5a~L`q_Sh_6>kyEYM7pOqo&7=16s=vDS!zCsR}1kJ9!_FCJrWsBW? z_uV+2*Jqqx4H!vmAHDbf^!2sCdY@!VyCRGw#-s6z#}4>oh~4?Q57HR1e)p#_8}pIiUU?|s(> z6A2qhr>v#E#zuw`HcO0OJ*Uk^F-7^RQY){hvZ~5Tt01flLl6-q8YX1}e#k(uWHx8V z$ZFH%3LRv#Z7t2{22K_el*#3ha?D9G%a*c2h~La6U|Yd`=gH*oDMTh0;yrfA@&z;? zm$um~LXh*Ut*y;PMam0E&g_d{{G$EpSHBVi_~rQ>=Y;_t5*9$}9)IdFyX)D zWZB~Lss-nT0V2M}kMFn9qx2-Siwtf5d zS#52tZM4dtqYON4fOR}T{&R^ekc};xx8TCf&F&j zg%{ecUAyc%-}#RH+2?LQuPSg}7@#}uI(XRo>Cf(g7|$2l~-QrvQ_sb{|Ma_koNuWe;=(m;+P;Cukf+0eV%iy0sMkj zT4D!}AF>&+BP$~kD#7PWP1ptN*WlVC7EI=Cc5K{+M}}>tZ^}X(Q;83mOeqQrSzUd- z?cKZAcHv9j_SU!Bq9qIM;jIq=TfEylpT6L{G2p)Ye`US>y*wPS0cIu*z!t^X_Vo4I zY$|D;^E>Rop@U??5nHihg{@w_+GB3YyL)Z# z3ww~{N;2k%-T0ojBgs{k!U=ER_7q81+9IVfYiMk?vhphH?&-7KOx)(qnPaP#EVubB z?Y3>tUW=31O_NpU`LDaL+YZ1S2}A?OZF}Zv`{*sVI1}n_<{bZXUKl`f<86O#hlPY( z<^s=7e5c>6*b9IO${}$fn}|=l3^oE&1Q);MEpKtqvBE@!l5==?g^4mX8h%8gELF!W zT)5EvW^!`U4jw#cHPzL&lWVS8v&vdKnk<=^u^k6ru=vEd<)#ugr=bNi7`HtKyYNK; ztEHCE!ZtQFX{qrEcdeDnm)g+ughNZEfr2(vR}i)&?bLPl9X#NzS$TfK)APa%Nl+p= zYaS@4Vskx|{DS;}7}QG!+Oc4PU4s3e-`VkEoGuBMQ&#LQ2PjMto0Ad$Tpv*4T!N)>$%@uu;IgNf?qOx|-iP&tBNO+YX`~Fo3&1_v5@|#X=ng z3&<3S_)368NTHNL;D`f<589Piz0va6W&vc9`g$CqjuVl^01Zh!Xr(hpdavUoor;XE zy6P$`kPp-m^>pD#xBl`McHpTeEd=h=6i-{t(4>`j4_bNOkX?uAxpvK3i*Y}B2wPKA zW#d!hcF)iM$&PR@34GA{3)k4H<;#G?OB|9aG!?koC3D9KgLVJsW1JTaP&v>iBARaj zLPa7#n;{8H5ec=C#da=S;Ou=pHDEtu6@kSB-x&*1kmSoeO-)TXR8tUxKsD8TW96k5 z$6R@nW7L;tEHX1?a}xM~@e>xCNLx9z=eD|fTU%Cb9slKz?dI-d_IzKL-TUB!_UvO% zT1{n@J+tizyYZ%X*ffk?NxRGV#F&j@o}>*jiSkK1cIq0@0P28^+Pb zre~}nk+HfNG$4gv;k*-r!#42blh*O*lUCYTZEM=vt@);#Y#Gjd+tbfjKj+)WdE4jB zbtvoHmNthYB{*LxO!fi3iRtOhwN+KF$aF55aL!FoKhAite}Fm+j`w6KG7nQkOc73C zSVu>Pi+bcA|7NZSD+NS=a^D)jj z1L8b{q95e|BDn0kIN)o59-@k9M+EnY?@PQp_LQg8XK9HNwI`li$VMnstf^D8a%S!aNZ_~WNPZFtO0GCLKvp=y_SW*E#;L~ z#=S(jR+@kzL=;wy9M^)5^0qQF%&3k|l#iESjmK1$P zP4%^gTH3^(ee{%;TO?LtIdYO|(AO;IRL5P3kW+3?TMgeQF_&4I!K7&g`jcb=&&N3D z3{cdf=tUB*q3B-(b)N-SGbBxdiM3A*(D&L-WroiLX^~8jh_BztU-;3I9HodAOAr}x z>M%qL0bff1!~)99mV=_9K-RK~?IH3gFh!)Q+VVtZS)!;saCikw4#K#KNT~(TphzG@ z9U^HN%v}R!ig?-;`*rWEge0f2KpJ8RqHe-K_;A}*{h#WGZ0;2k&+tAa$KmaDEX>Ir0@w6B!!_Kj7t#W zo{yn>Jg4KC?c0GJKq|4oA;Lh(dX@7m1%3VLg!p7U%lL_RxGh@;Oiu&FplZ5l89>(i{nee zFw#NR6o@1^!l$ODCbysZ9OvTwIW<9`nx2R&B8u=DdUeF*z3&&4ObN?beZg|fO(h$( z+A<0zn4fHVn$Bs#(;1M>QLC)VTYlxWZ?pn)2@ViiwpIbW4GdXXRhb2laL_wy$*q>=eG1575;G@aw>8bNdg=r+ zYa_!atf#w+%3Oox5S%)qqQ-^>hpLW`Pp+@8Cy6|V$R4fONP!= zu<~#fA!el=?eDW-c@xnJE$$jbI-maYzqLI_x7#QG z=-=C3lB=eMMmsSuY;AMeZE9i$jUj2{xb~K6x+$itvu!R7!PO25PtgQcMe}71g(4x$P&F_{fZU})h$=0NLCom=_dnoWcim>bJvZZ=F+g=xnHa^*Dl=**fszk6 z)fD;Kpk%55j9GyX5ZoM(qcLNcoj95h9ESlJYn@X|NIQ(Q6TVi(I3vZC)DV6lX{F(L zw6|1PI+3+rY;$d6gEdiHQFla!a4`b|ckkL`zyJF;a}OEoKH6ss7B004`c6ye*f_HP zsHNi*wz#v|jvm}=qeH`Pj#&lKl8Qp3b8IQUthH=*IjH^uD!(CYa6W=KQjkOcAe7L`irl;*e<>53aciOQ&)xr;*m!lam`u+ z-XuH{3?-3OGH>Js3p+dP0ua=P?*A43>7@eAseaErprQdCz<7GoSra3zddl6q6XwVjkkI zfKCG`ri@IKPSL@^QJd3LM^sdx%-Mr)0ZJ$VWDC+!8f>r~ySr@B@_AN8VSWHclvh+b z$hr#0`|h{h{yum>J^ zfVxHA=FXpokgT;0mtUS((3!4?lG~Kw6J{o-Z2xo5d&|~b5KxI#KJRSD85uB}OPWvo zG_zTvB`;k}#J}@f-|!S(zT+M5aP8jyjri!Hv_PA0dK8|jALz56{j4jx_mB3Y=7g*? z?WW4AEL)ibvZkrZBO?x0)0%h~!qXK^DKkj(t_5gUlqLjeakQj8cWAHGF1*fmAKedp z{E3x+0Pa@o1t_z=UC-OGBVG1afAN=?r@4f|dDm5~dT$pIj+}3#LMst4HF;vhF1Y*( z8#!{&CKEJx(N?qmA|{2by1-TR)VcA(3%l*%haalA^oq;vf(tIN%QjwQhYlUG2k*O= z(74`foZsPuRL>|af3@R`%y72&XUZB~E z$$XU@BOjB%=BI!og7p5tpW{QIrohwzFKFAJdDi~&FaF9ZK}{nlt2QZCa;D63b^xRmxj_2lEWkN%+zYu7oy zanaf}b~pV?H@y4Z-u#7&0%t>f(dUc|&_U_}Es*+$P<2Oqu$6(`yS;~hai2|%j=MGv zwR`(XmmmAfW~#=j;)a+ayZOEEea|^OowtQjpg(4bQf6kwQIXZx7AM*_#RCpcx9Bo3J>Xdh^-{K+%hp0zLB@daz52eqc*r75k-WJ_Si{+=VY zeBL4($xYd}|L>i)die_b<=ywtDYxHRDALrzq!^4-51pE}^xRcs(94!Cwl(Y4+E2dw zkG6BiGgeo<$yyugEU{p|-GAS&?3Pa~a*uH~T5v{(JTcfucX<&tbXV!=_MZB|kG$u% zK55ICwWtm>5nmH0d{>oRrVw*N?a$2AX6B>HRJhnFimQz#1Y?cbj zlrc7(U?^5^iCoO;Th>~0+Z8aT14j*3pKs^*`IgUA;zL-d1mZt%-xmA$tsl3QY9*mN z?$j{>61!o;M!V;y|AZrFk_g%IB=E^|XvPAxekB@(ZArdU)&-%*DAQ;j!uluzJGR*d(py1xwD3pt{rn(2{wLRd#&uVf(}P ze$X~wc{Q350y}Dh(9|8sPll)$H-Ua`e&f~lr=R{~>pFH6<}oAZP?z;GS$x5QMRwu( z4X%N!qhkS`e01y)DpwLjOb!oOJKs;A=qEqG>@r>UYJ9;MX6o<1^0#)3I`|sSTT!2J z$g$-wEdymZoBQYU8jAVnBGi7&C#uQ-gVmps9Q;d9#5pKncn@Lks&*P z-JAj0tR#^sr_d24^i*NH4QDq>qSOYV1qUoArXHhdc64Nv-X8k=iPP&FX-`pADjFi* z1|bEO$kTG3lUDE>^#IMOt^tG_B703klnOHBD4DHh!caa8H`zbkx6@Xyz05xR;g4Y2 z8XS-oC2COspb>LR{}fB2)6{$)eBge28C&aQ zq4~F;M#bOy@z-X~U_7wACoL1==RLgL+y2Poc66ZEI@YeV`sItPvKgeXtHeOJVvX4ZH_|LPAzw$34`w+1Ti`tysRwCdNrF$pso)=Ws7- z?hV-}k(9dkzWxv2w8LmqGm+MxFf&M98~5IOuVaMTDK!;}#Y4`h4Znc_9+Mj4+hfy- z^#_0Ts2%;;R%@!PvF61KZQXvc`ry5qN~Ii*N90iecL`x0N-21RFa;+F1+gSNXmOr^?5GmD3Y?~9(UcP!hB;3uxP2-4 zMj4;=KEiPY?C*ux;b0lqO?$CbaZYt3Sky}l80;IdmiCw6N8+M|y>i2sS( zB^#I7Pk#I(Le~NNlTZD3+q~&*Kp@Pt9h$I>7q3Md=)Nc?BtAI=t1CSH=}+%*k>64r zwDKH9OAtN7cM&Cb3Oe5Pu6G6WEdShinGcvrC#;fGzcE<3;fsIwSKcLa7ui~6jx4HC z(=pe26BG7>CmymvRI>~T#Zp)~Aejn*fQ%$j3=toxmkEIMFoo(E-s$ z>kkn>hm+59-dVuF0&vI14Hw$n_B!k8K48y0^^h%HvH}PqLclOeC&p9u&Ud`mF<@|D z)LL2_{8PEtLcu+yt0UA?m6JbHn0=g9Mndg~S~2DC)XDL8fA@FZ=FOXJ{rdI4RTEyu z01-cp4USTF3L>Ffz{@XcTV$)T-@6a&v`6;rv>^(AB3xg8k41y@BFwUG7EUw+!81HL zK9JA`Vv7MBSBh3(KO6xH)OiC)y+=7x#|2>2G(~rXkdkg~%BDp`g|rzSwzj&i_~1U# zc@>ky0KICcB}Q!|1qdCVnRHM>kb+NgHiKWNgRoLHb45@vs-@5sv`@qrRFf7DybYE8h5ZricGpxmH_`0 zqjVZ&rq1MK*5P2f7lCF^m!dY=_y9goFpQ6VsRKknpYG$b z%Pw=dgr;aQKiNBdv5=QBU}}6~{mt)vpZ)uP_etxR$E=dax4FLgEPz+Cob?_!VPSN_ zn!**fxUIt$AU*5mwIKcUe>xKspkPvre&mcr9FNw)GR#3#63j8K?F8xfoRm`#*YYT^ zLDN+Q;Q6qHOpJ)<%#AdF_euzrBltchi?|0dJ8Gs%;VWk88Oo(Gzv+v0#pLFf-IhM(nx*+w~}g zmb<=l7kGTin&=dOJP;V0Eh3W4)a639jNTpZ=y3}l-fQK@k6HLwuZ52FTeSOx&AU}T2hq|vMl-%lcS5eo2{r6aRP69W_O?BP1a}Qx<6IHPLk?P~b@{K^)wb*$uyP8+W@jCOnc( zZ{M-)sr8RN`GozC+irKgJ74|kS6y_nV%c&RVYsGMw4i_u46FUSs-898nyi%zw4_;n zjASg3kyK*g@upKSDj6!y0r-bIziv%n@=;Z;j_$QOR!^zGF+UBm*xK4`2L_J;3G`8q zB?@Azpf{%kn>sRZ!fyTWN9=#x{%7{K8{cXd($k}53OYMGK?JJpM?dH9eT%qvVg(-5ambbNf2r(zi#Fe^>qCg-wGe)5w*(ED6h zc3oYKW1`NRgt1{oa1c{nbDEf_KwFc)Kk$JMxN|=I@WZxk+cuY!iQw84O=*^=H1_73 zZ+-zdX0`l*3PO$njnU|ayYBjq_xm4szr~S~FMR1QFeL?h19Q1nELvh?;2m+={HkNs zObfll-txw4>z>E=4|M$)3*f%rnoptX}3v6BA{&sGqOatWd4sMK_5GT7mG9{^Q=`TOYA2 zKef@m_3dw3Q_CE?Zrz*hzzh4aXWjOxfBkO>y{c^C1ya2hx+IN|ym-eS{@HMXdx!p4YH>Z|H(w3`XpU;CEbdh^Y!pm?8s z^bbF1Q`BP{$Ol?kx=g-cFKiPB zp9n-^j));lSO}@-cFBp-j^Nz&DdqcW_bBKZb6 zVEKoho*q+0F{~8}8)?tjwevY7BE?z{vv&0OQCB*A`ji(vabNeQ%|PsZ zjsfoZxRESAP#Lh8l_z@Br1F1mFx@u5VkDlrMg&g)OSmNMs;jOl3bKCup<6y4U~}i$ zH`wJZZus?L{OK3*D4sN4yxJm?JWPflWZfKnBUXY0mO-`X-XVI zJ(EY}F9!J4PY+O4zSb>=aJZ-2 zGH63k$SC(K^ALi-P8+cQ!gM_LMKF;vBQuzeS)dL1CP`$tpQ8MQ^I#gahH7T(Q{N~6 zQh7k?lI%GweW37Cgcl=3aK}iZKd<4VfBffW#a;lwMR^=eE`KfK*O;M`{d0`a_t8kD zb&pNi_aAtaT7UvG2!aEa+0YQ)<0md6f)X&7TtTv+x7Pt@TDp>-ax#vkLqW$phU)8~ zHNss--FyQPR-I~UgV!QY%8Uy~yNk9NJHKKTVKY7`h!&>sC1KP}L`z~`xDlK)#U4zD z!qyy6NJ&W*3?X0$&ashEGU?=mEm=wpn~C4G6lX?;<8*{naa;tcM}1(7CZapY1s^ax zI>dc5MR#lfA@Jy$cx_7?{6+@ocF!~bM3H_71M$PWDgyF{-iI&?E^`Dga@mmc84!=} z3J_5lbU}z}p4x&KL%tyf+B|GcAVVn2}jqU6go_{+(%2b}B7{ zi15f~popjA^}QIPcwFzb!j_h*mt7Tpq|7uyr-poh(=d+F@1${l_^5O0y@r4O)88v( zy!N^)?a0wVGV5&d++bBYUdfuSt@A4SQ8=lnMtOn!$u*nafXAw^lCkDwO3YVeY>VBtvVumVHB7}}F z!{KXTCcRh8ts#Q@jMjCuX`K4{;(oML4A*aUuevv#D+th7L2HVR(>8>@g* z4Ir5yUs2Q6YaM6J03U{x^A4Z^{sW@*FMm(i=p-JesF2WSN{;R-?bmuha*o=s+OV9O zoT0vxlq-4Bd!INuPS=tEoH&uNm8(}d4G^J3JP}{t>o@*;p8?u`>c&AV9@6M06N>TW zL`5O0c*u0%#*GzwW=vfS<<+>p~98bajC(V$2fe7zR6U-n*Q+BDOD2%hLqE|;f z{CaH!eXOU|Tu`p&8whlhDe!H*Bu|V`E+Mv=p&obxFHg-gOT?1H=SHO}^y& z@AZg|;3r@G_sSoH_b5b_AdHQ$;unmQgV%L+EgdTcrKl20K-34-N^Y}Z?b_E)eeUP1 z7$8FE;WSiimn1nytR0RCMW%=uLL?=bl4KE5gpKyu=2&V5e{8#sZe_kZ~$sM#j169cEu(kx969WU| zws_$hmzx|p((9J5sR6Q)7Nk!G5$Xnf*Sp^1pYk=oo)rToCMLZ>KqftO3JI4KN^<<6 z_xhxmT`MVStHiFVb8SEUH6oZ8B4Us6K$2WBM++y(@k-L98G2YT=2R)yHDs?P1paq2 zHHwflb5l$Z)AYTVrDJ8w{d@Eoq|Y*&%5X~rVSuC_Bfqc$A!+|4A!(YW(-vW(m_dmt z)U$T?bU7192gHs;Tm%&1^eRWINJI`?njyl=+{ko^i0V?1Pv~HE+~Msbj=++9 zX^)PT=@C&QX^GaN(|3|~-JgU* zrcmGe4A5uYmzd(7f!R5+a$0Q&DrS>Y+&6{u(gFbj_vvNbd28#cK{WSLJv(f--1 zoSKnqxK43qsF*DCbhhKH7;yRJm(%e2aFM7GEkZ?0CP@#c2UE+4h@=Nr@}lqb>LZFm zC-q*$ngZa{_adG)NwG9Q60QAuI5Aqnk(D@@#qBSaf(!4ZL5Jf%LE!_lst_)vA{0dfN9|kJ#>OSHi zZq*Y0)eUcD<@YvVl4V2(EF6U(=^R9M1b#0?gYKrz@XxE(fWe_YudDYsZ6RRnNVvkc zByA`05*li8YPo39+38`m6$+ZFMAtJ9taTVf>r(!P*fbR;+ApxdTag`fgZ3cZ?osc3XYEH-dX=r$J*``}&VB#QZ+_GHxl1p-)I~$Owtvkt%l}zmLGj_V zH*~Cr#q$U?A^LP$>ufsSkWFH8(o~KzBw2)br5;_<5n5Zwcts>Z6JgAd2(Ql`iJQkh zNvH}Q>YmmFKt&@-AP!B`o?taZNn{R89;4*^j9#@gO-&7JJ&g9?Fp6QRPjH|3zC+im zh$5{J0mUpuQ_>Xe_rDjxbYFgwDdtFPa^Qts4gAQX_Jf_B(W`rgP^b+DI zr>#a@F+zii0A)%3U^9ZBS1%6|CRig+?@zwKii>VVxE%8lSoM&SrKUyA!jJ^>#uhJL z09-%_+6@#z0wv=5gi;P6qKasGFNxNB?NdT097=>2A^pfrOw&F|zRsoN^s<}DznPd!mQam2~ADd7VuM|%q^fY&pD|%`T9V$nW$)hp_ z%3C}kOZuT)nt_p~=Y=xZ$rJKt25gG!KnxZ2t){k|%1kR2^J843xF)_I7M*GnL}gJ> zwnSV}EUZnUuKN&Wb-Ztn^j?(K(D(YSVp?%Vs-olcs?R!3-$}*9Rdwh}T@-u2nsEkZ zymTrYFnxmK>l+$Q*q{9I6+|>W5HD=c?akTvOsT7K_w}D34pf{J#Xe}|87QkNd_k=k>uf*dxogyPuJfYRZ7O&th|FkUNufeTiR^DQ~ z{}3Tl@oyd~I}=ePzRuo3aAj>GmiFm85m-Znlig9KCuWE_`p$pVF+KzIUTWcg7Bi(X zaxzLp6d#KTN?Lp*QNMYm;}tU?J9WSd<`j%SPID>K%su9g67sBFdl}xgnFjz4C7#K$ zCF!9UADgiedRc~t$6Pm;;L#+Ta0@-Gh(uasg(%ntec|r!oFo51R4u~(@={iHBKGz8 z9K|pXp>9+WnL)xFq`Dvvt+0tD52wX|;-BY`p%!68ND*E{6QPwgis-T_`mAf~y*A$q zYo8=uztQi-Fum%t&rp5V@j6aSQI;se>w6uqOz_o?SHys9hHl*;m6GWJ))S~;#nk7? zN(Sg^0*;*CMq^E#o55X)hw#d1SB|kFUIVxUu7f|G$E)PL_+YLl;^bWxLP%c}qt3z( z`s-~OAk-ZFifJ}US(bz%MQ?mEON$%{LI_nU4OOwS6AQ(mebKUJCw;1{sHiIm6yarN z#0U{d(y4l?h$M}W#4C`11K?Ku$5J5ePJH1guh3E2Bb(13h6#(?$K_Rt#EZn85OP2q*&BVY!%^M*o4=X z0a8=S$p^3yOWcBv<%wkr5ZYtIuDMy;9IVV4$x_%v1%-?$lV-jX(Lg*kg)k5akdpTI z$N5WdStrfDiIJ_A*^v+MwN1nlF~tBeLKa6x}mKp|8uzNHLv zr|T$e0TW?u1KDG3zG)Fb!~|`pnh`NTo6Loru>63=>4Y!dqkK?tLYj!K^N4X`urx>4 zQlpX5XC(?M)4kepMh57F`CJ&{v-Vhl#r-1-_#1-s|Ixge&Giu@_92y0V{AIot)@%t zl~YT|%d41Ce83_Dini75gt-BhN(s2hUP3MCGl3B-V}|L;xfFYrgdxq^Hff@z6vt)? zmD~q#W`PI>2CGHdC!~ljB8f15XwcHoX?XM_~$&+>lqoKM58=b5ukk;QLSUG8CG9~2wrF&t6OmMXaP&9 za+8u|A{zeTts9ammvOl^3f@EFVpYEwaj2y^z|0Cj3dghp91=d^{^}=_0w{2?SOkfJ z9-5YhJm6E95>}XGBB1H}07>e^)zY{kjHFYgGZ9GlA;w5LRfBY19iwwN&gHDYQCiBd=e zA7-cdM}*gRTC71gs7<~jM*%=7t$J4!PC5-BsZwEpBM3Qh*$`F4*XGbUey3U5X_7Kc zf5|Fu)?j}S^A;$e1u!A#6?;a&K3?K8oD z@4n!l)A#FlVys^MuvQV!D_J_lKd1ltiWpElScHpjW+{#b)EllLBIhw1lkviK;`{ZE z_$RHO?52pXioFO_lzcHku~0EH4M25GlXt`i*boEq5E-^Xe2#@_nzmW=Dom@FlZOGJ zJkFgkRF}$R$wxvkjQC#H6w$>1ZIXJu`dT2O>mEg5U()p(4PV;z>c7{1&T%bTvPHk+ kH#-P%H%Ri&)%eD-uYK$J` + * @date January 19, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief Implementation of PololuMaestro class + * + ***********************************************/ + +#include + +PololuMaestro::PololuMaestro() +{} + +PololuMaestro::~PololuMaestro() +{} + +void PololuMaestro::init(ros::NodeHandle &nh, + const std::string& nodeName, + const std::string& port) +{ + m_serialPort.init(nh, nodeName, "", "PololuMaestro", port, false); +} + +void PololuMaestro::setTarget(const unsigned char channel, const unsigned char target) +{ + unsigned char command[3]; + + command[0] = 0xFF; // Command byte: Set Target. + command[1] = channel; // First data byte holds channel number. + command[2] = target; // Target position + + //ROS_INFO("Sending %d %d %d", command[0], command[1], command[2]); + + if(m_serialPort.writePort(command, 3) != 3) + { + //ROS_ERROR("Failed to set state"); + m_serialPort.diag_error("Failed to set state"); + } +} + +void PololuMaestro::setTargetMS(const unsigned char channel, const unsigned int target) +{ + unsigned char command[4]; + + command[0] = 0x84; // Command byte: Set Target. + command[1] = channel; // First data byte holds channel number. + command[2] = target&0x7F; // Target position low + command[3] = (target>>7) & 0x7F; // Target position high + + //ROS_INFO("Sending %d %d %d", command[0], command[1], command[2]); + + if(m_serialPort.writePort(command, 4) != 4) + { + //ROS_ERROR("Failed to set state"); + m_serialPort.diag_error("Failed to set state"); + } +} + +unsigned short PololuMaestro::getTarget(unsigned char channel) +{ + unsigned char command[2]; + unsigned char reply[2]; + + command[0] = 0x90; // Command byte: Get Position. + command[1] = channel; // First data byte holds channel number. + + if(m_serialPort.writePort(command, 2) != 2) + { + //ROS_ERROR("Failed to request state"); + //perror("Pololu: Serial Write error"); + m_serialPort.diag_error("Failed to request state"); + return 0; + } + + usleep(10); + int r = 0; + if( (r = read(m_serialPort.fileDescriptor(), &reply, 2)) != 2) + { + m_serialPort.diag_error("Error getting channel"); + //ROS_ERROR("Error getting channel %d : %d", channel, r); + } + + return reply[0] + (reply[1]<<8); +} + +void PololuMaestro::getErrors() +{ + unsigned char command = 0xA1; + unsigned char reply[2]; + for(int i = 0; i<20; i++) + { + reply[i] = 0; + } + + if(m_serialPort.writePort(&command, 1) != 1) + { + ROS_ERROR("PololuMaestro::getErrors: Failed to get errors"); + return; + } + + if( read(m_serialPort.fileDescriptor(), &reply, 2) != 2) + { + ROS_ERROR("Error reading errors"); + m_serialPort.diag_error("Error reading errors"); + } + + ROS_ERROR("Error message:%c %c", reply[0], reply[1]); +} diff --git a/autorally_core/src/servoInterface/servoInterface.cpp b/autorally_core/src/servoInterface/servoInterface.cpp new file mode 100644 index 00000000..01ebda6c --- /dev/null +++ b/autorally_core/src/servoInterface/servoInterface.cpp @@ -0,0 +1,415 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file servoInterface.cpp + * @author Brian Goldfain + * @date January 29, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief ROS Interface Node for controlling servos + * Brief description continued. + * + * @details Detailed file description starts here. + ***********************************************/ + +#include +#include +#include "servoInterface.h" + +PLUGINLIB_DECLARE_CLASS(autorally_core, ServoInterface, autorally_core::ServoInterface, nodelet::Nodelet) + +namespace autorally_core +{ + +ServoInterface::~ServoInterface() +{} + +void ServoInterface::onInit() +{ + ros::NodeHandle nh = getNodeHandle(); + ros::NodeHandle nhPvt = getPrivateNodeHandle(); + std::string port; + if(!nh.getParam(getName()+"/port", port)) + { + NODELET_ERROR("ServoInterface: could not get servo interface port"); + } + + loadServoParams(); + loadServoCommandPriorities(); + + m_maestro.init(nh, getName(), port); + m_ss.init(nh); + + double servoCommandRate = 0.0; + if(!nhPvt.getParam("servoCommandRate", servoCommandRate) || + !nhPvt.getParam("throttleBrakeCoupled", m_brakeSetup.coupledWithThrottle) || + !nhPvt.getParam("servoCommandMaxAge", m_servoCommandMaxAge)) + { + NODELET_ERROR_STREAM(getName() << " could not get all startup params"); + } + + for (auto& mapIt : m_servoCommandMsgs) + { + ros::Subscriber sub = nh.subscribe(mapIt.first+"/servoCommand", 2, + &ServoInterface::servoMSGCallback, this); + m_servoSub[mapIt.first] = sub; + NODELET_INFO_STREAM("ServoInterface: subscribed to srv cmd:" << mapIt.first+"/servoCommand"); + } + + m_speedCommandSub = nh.subscribe("vehicleSpeedCommand", 2, + &ServoInterface::speedCallback, this); + + //m_servoStatusTimer = nh.createTimer(ros::Rate(servoStatusPubRate), + // &ServoInterface::servoStatusTimerCallback, this); + m_throttleTimer = nh.createTimer(ros::Rate(servoCommandRate), + &ServoInterface::setServos, this); + + m_servoMSGPub = nh.advertise + ("servoStatus", 2); + + //m_servoMSGStatus = autorally_msgs::servoMSGPtr(new autorally_msgs::servoMSG); + //m_servoMSGStatus->header.frame_id = "servoController"; +} + +void ServoInterface::servoMSGCallback( + const autorally_msgs::servoMSGConstPtr& msg) +{ + std::map::iterator mapIt; + if((mapIt = m_servoCommandMsgs.find(msg->header.frame_id)) == m_servoCommandMsgs.end()) + { + NODELET_ERROR_STREAM("ServoInterface: Unknown controller " << + msg->header.frame_id << + " attempting to control servos, please add entry " << + " to servoCommandPriorities.yaml"); + } else + { + mapIt->second = *msg; + + } +} + +void ServoInterface::setServos(const ros::TimerEvent&) +{ + bool throttleFound = false; + bool frontBrakeFound = false; + bool backBrakeFound = false; + bool steeringFound = false; + double throttle = -10.0; + double frontBrake = -10.0; + double backBrake = -10.0; + double steering = -10.0; + + //find highest priority (lowest priority value) command message for each servo + //across all currently valid servo commands + ros::Time currentTime = ros::Time::now(); + + std::vector::const_iterator vecIt; + for(vecIt = m_servoCommandPriorities.begin(); + vecIt != m_servoCommandPriorities.end(); + vecIt++) + { + if( currentTime-m_servoCommandMsgs[vecIt->id].header.stamp < + ros::Duration(m_servoCommandMaxAge)) + { + if(!throttleFound && + m_servoCommandMsgs[vecIt->id].throttle <= 1.0 && + m_servoCommandMsgs[vecIt->id].throttle >= -1.0) + { + throttleFound = true; + throttle = m_servoCommandMsgs[vecIt->id].throttle; + } + + if(!steeringFound && + m_servoCommandMsgs[vecIt->id].steering <= 1.0 && + m_servoCommandMsgs[vecIt->id].steering >= -1.0) + { + steeringFound = true; + steering = m_servoCommandMsgs[vecIt->id].steering; + } + + if(!frontBrakeFound && + m_servoCommandMsgs[vecIt->id].frontBrake <= 1.0 && + m_servoCommandMsgs[vecIt->id].frontBrake >= -1.0) + { + frontBrakeFound = true; + frontBrake = m_servoCommandMsgs[vecIt->id].frontBrake; + } + + if(!backBrakeFound && + m_servoCommandMsgs[vecIt->id].backBrake <= 1.0 && + m_servoCommandMsgs[vecIt->id].backBrake >= -1.0) + { + backBrakeFound = true; + backBrake = m_servoCommandMsgs[vecIt->id].backBrake; + } + } + } + + autorally_msgs::servoMSGPtr servoStatus(new autorally_msgs::servoMSG); + + //only set servos if a valid command value was found + if(throttleFound) + { + double safeThrottle = m_ss.safeThrottle(throttle); + //NODELET_INFO_STREAM("safeThrottle:" << safeThrottle << " throttle:" << throttle); + if(safeThrottle != throttle) + { + m_maestro.m_serialPort.diag("in control", "safeThrottle"); + } else + { + m_maestro.m_serialPort.diag("in control", "servoCommand"); + } + + //if theres no brake with the throttle, throttle cant go negative + if(!m_brakeSetup.coupledWithThrottle) + { + safeThrottle = std::max(safeThrottle, 0.0); + } + setServo("throttle", safeThrottle); + servoStatus->throttle = safeThrottle; + } + + if(steeringFound) + { + setServo("steering", steering); + servoStatus->steering = steering; + } else + { + servoStatus->steering = -10.0; + } + + if(frontBrakeFound && m_brakeSetup.independentFront) + { + setServo("frontBrake", std::max(frontBrake, 0.0)); + servoStatus->frontBrake = std::max(frontBrake, 0.0); + } else + { + servoStatus->frontBrake = -10.0; + } + if(backBrakeFound && m_brakeSetup.independentBack) + { + setServo("backBrake", std::max(backBrake, 0.0)); + servoStatus->backBrake = std::max(backBrake, 0.0); + } else + { + servoStatus->backBrake = -10.0; + } + + servoStatus->header.stamp = ros::Time::now(); + servoStatus->header.frame_id = "servoController"; + m_servoMSGPub.publish(servoStatus); + m_maestro.m_serialPort.tick("servoStatus"); +} + +bool ServoInterface::setServo(const std::string& channel, const double target) +{ + if(target > 1.0 || target < -1.0) + { + return false; + NODELET_WARN_STREAM("Servo value " << target << + " for channel " << channel << + " out of [-1,1] range"); + } + + std::map::const_iterator mapIt; + double pos = target; + if( (mapIt = m_servoSettings.find(channel)) != m_servoSettings.end()) + { + if(mapIt->second.reverse) + { + pos = -pos; + } + + if(pos > 0.0) + { + pos = mapIt->second.center+pos*(mapIt->second.max-mapIt->second.center); + } else if(pos < 0.0) + { + pos = mapIt->second.center+pos*(mapIt->second.center-mapIt->second.min); + } else + { + pos = mapIt->second.center; + } + unsigned int val = static_cast(pos*4); + m_maestro.setTargetMS(mapIt->second.port, val); + return true; + } + +// m_maestro.diag_error("Servo does not exist:"+channel); + return false; +} + +bool ServoInterface::getServo(const std::string& channel, double& position) +{ + std::map::const_iterator mapIt; + unsigned short val; + if( (mapIt = m_servoSettings.find(channel)) != m_servoSettings.end()) + { + val = m_maestro.getTarget(mapIt->second.port); + position = (double)val/4.0; + + if(position > mapIt->second.center) + { + position = (position-mapIt->second.center)/(mapIt->second.max-mapIt->second.center); + } else if(position < mapIt->second.center) + { + position = (position-mapIt->second.center)/(mapIt->second.center-mapIt->second.min); + } else + { + position = 0.0; + } + + if(mapIt->second.reverse) + { + position = -position; + } +// std::cout << "got channel (" << (int)mapIt->second.port << ") val:" << val << " pos:" << position << std::endl; + return true; + //TODO: handle reverse + } + m_maestro.m_serialPort.diag_error("Servo does not exist:"+channel); + return false; +} + +/* +void ServoInterface::servoStatusTimerCallback(const ros::TimerEvent&) +{ + populateStatusMessage(m_servoMSGStatus); + m_servoMSGStatus->header.stamp = ros::Time::now(); + m_servoMSGPub.publish(m_servoMSGStatus); + m_maestro.m_serialPort.tick("servoStatus"); +} + +void ServoInterface::populateStatusMessage(autorally_msgs::servoMSGPtr& status) +{ + if( (status->safeSpeed = m_ss.getSafeSpeed()) == -1.0) + { + NODELET_ERROR("No valid safeSpeed"); + m_maestro.m_serialPort.diag_error("NO valid safeSpeed"); + } + + double position; + if(getServo("steering", position)) + { + status->steering = position; + } + if(getServo("throttle", position)) + { + status->throttle = position; + } + if(getServo("frontBrake", position)) + { + status->frontBrake = position; + } + if(getServo("backBrake", position)) + { + status->backBrake = position; + } +} +*/ + +void ServoInterface::loadServoParams() +{ + //read in servo settings + ros::NodeHandle nhPvt = getPrivateNodeHandle(); + XmlRpc::XmlRpcValue v; + nhPvt.param("servos", v, v); + if(v.getType() == XmlRpc::XmlRpcValue::TypeStruct) + { + XmlRpc::XmlRpcValue servoInfo; + ServoSettings toAdd; + for(int i = 0; i < v.size(); i++) + { + servoInfo = v[boost::lexical_cast(i)]; + + if(servoInfo.getType() == XmlRpc::XmlRpcValue::TypeStruct && + servoInfo.size() == 5) + { + toAdd.center = static_cast(servoInfo["center"]); + toAdd.min = static_cast(servoInfo["min"]); + toAdd.max = static_cast(servoInfo["max"]); + toAdd.range = toAdd.max-toAdd.min; + toAdd.port = i; + toAdd.reverse = static_cast(servoInfo["reverse"]); + m_servoSettings[servoInfo["name"]] = toAdd; + } else + { + NODELET_ERROR("ServoInterface: XmlRpc servo settings formatted incorrectly"); + } + } + } else + { + NODELET_ERROR("ServoInterface: Couldn't retreive servo settings"); + } + NODELET_INFO("ServoInterface: Loaded %lu servos", m_servoSettings.size()); + + if(m_servoSettings.find("frontBrake") != m_servoSettings.end()) + { + m_brakeSetup.independentFront = true; + } + if(m_servoSettings.find("backBrake") != m_servoSettings.end()) + { + m_brakeSetup.independentBack = true; + } +} + +void ServoInterface::loadServoCommandPriorities() +{ + ros::NodeHandle nhPvt = getPrivateNodeHandle(); + XmlRpc::XmlRpcValue v; + nhPvt.param("servoCommandProirities", v, v); + std::map::iterator mapIt; + for(mapIt = v.begin(); mapIt != v.end(); mapIt++) + { + if(mapIt->second.getType() == XmlRpc::XmlRpcValue::TypeInt) + { + //add entry in priority queue and command map + priorityEntry toAdd; + toAdd.id = mapIt->first; + toAdd.priority = static_cast(mapIt->second); + m_servoCommandPriorities.push_back(toAdd); + m_servoCommandMsgs[mapIt->first] = autorally_msgs::servoMSG(); + + } else + { + NODELET_ERROR("ServoInterface: XmlRpc servo command priorities formatted incorrectly"); + } + } + std::sort(m_servoCommandPriorities.begin(), + m_servoCommandPriorities.end(), + priorityComparator()); + + std::vector::const_iterator vecIt; + for(vecIt = m_servoCommandPriorities.begin(); + vecIt != m_servoCommandPriorities.end(); + vecIt++) + { + NODELET_INFO_STREAM("ServoInterface: ServoCommand ID:Priorities:" << vecIt->id << ":" << vecIt->priority); + } + NODELET_INFO_STREAM("ServoInterface: Loaded " << + m_servoCommandPriorities.size() << " servo commanders"); +} + +} diff --git a/autorally_core/src/servoInterface/servoInterface.h b/autorally_core/src/servoInterface/servoInterface.h new file mode 100644 index 00000000..65085188 --- /dev/null +++ b/autorally_core/src/servoInterface/servoInterface.h @@ -0,0 +1,173 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file servoInterface.h + * @author Brian Goldfain + * @date July 10, 2013 + * @copyright 2013 Georgia Institute of Technology + * @brief Interface for servo controller + * + * @details This file contains the ServoInterface class + ***********************************************/ +#ifndef SERVO_INTERFACE_H_ +#define SERVO_INTERFACE_H_ + +#include +#include +#include + +#include +#include +#include +#include + +//#include +#include +#include +#include +#include +//#include + +namespace autorally_core +{ + +class ServoInterface : public nodelet::Nodelet +{ + public: + struct BrakeSetup { + bool coupledWithThrottle; + bool independentFront; + bool independentBack; + }; + + struct ServoSettings + { + unsigned short center; ///< calibrated zero of servo in us + unsigned short min; ///< calibrated minimum of servo in us (left) + unsigned short max; ///< calibrated maximum of servo in us (right) + unsigned short range; ///< range of servo signal (max-min) + unsigned char port; ///< port on servo controller + bool reverse; ///< if the servo should be reversed + + // center should be (min+max)/2 + ServoSettings(): + center(1500), + min(1050), + max(1950), + range(max-min), + port(0), + reverse(false) + {} + }; + + ~ServoInterface(); + + virtual void onInit(); + + private: + std::map m_servoSub; + ros::Subscriber m_speedCommandSub; +// ros::Subscriber m_irDataSub; + ros::Publisher m_servoMSGPub; /// m_servoSettings; + BrakeSetup m_brakeSetup; + double m_servoCommandMaxAge; +// std::string m_steeringCommander; +// std::string m_throttleCommander; + + struct priorityEntry + { + std::string id; + int priority; + }; + + struct priorityComparator + { + bool operator() (const priorityEntry& a, const priorityEntry& b) + { + return a.priority < b.priority; + } + }; + + std::map m_servoCommandMsgs; + std::vector m_servoCommandPriorities; + + /** + * @brief Timer triggered callback to publish a servoInterfaceStatus message + * @param time information about callback execution + */ + //void servoStatusTimerCallback(const ros::TimerEvent& time); + + /** + * @brief Callback for receiving control messages + * @see autorally_core::servoMSG + * @param msg the message received from ros comms + */ + void servoMSGCallback(const autorally_msgs::servoMSGConstPtr& msg); + + /** + * @brief Callback for receiving speed command messages + * @param msg the message received from ros comms + */ + void speedCallback(const std_msgs::Float64ConstPtr& msg) + {m_speedCommand = msg->data;} + + /** + * @brief Time triggered callback to set position of throttle servo + * @param time information about callback firing + */ + void setServos(const ros::TimerEvent& time); + + /** + * @brief Retrieves servo positiona from control board and scales them to 0-254 + */ + void populateStatusMessage(autorally_msgs::servoMSGPtr& status); + + /** + * @brief + * + * @param channel which channel (throttle or steering) should be set + * @param target value to set channel to (-100.0 to 100.0) + */ + bool setServo(const std::string &channel, const double target); + bool getServo(const std::string &channel, double& position); + + void loadServoParams(); + void loadServoCommandPriorities(); +}; + +}//end infratructure +#endif //SERVO_INTERFACE_H_ diff --git a/autorally_core/src/servoInterface/servoInterfaceMain.cpp b/autorally_core/src/servoInterface/servoInterfaceMain.cpp new file mode 100644 index 00000000..08b20b12 --- /dev/null +++ b/autorally_core/src/servoInterface/servoInterfaceMain.cpp @@ -0,0 +1,62 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file servoInterface.cpp + * @author Brian Goldfain + * @date January 29, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief ROS Interface Node for controlling servos + * Brief description continued. + * + * @details Detailed file description starts here. + ***********************************************/ +#include "servoInterface.h" + +/** + * The basic servoIntterface program currently using the PololuMicroMaestro + * servo controller. + */ +int main(int argc, char **argv) +{ + ros::init(argc, argv, "servoInterface"); +// ros::NodeHandle nh; + + //retrieve all needed from the paramter server +// std::string port; + +// if(!nh.getParam("servoInterface/port", port)) +// { +// ROS_ERROR("Could not get all servo interface port"); +// return -1; +// } + + autorally_core::ServoInterface servoInterface; + servoInterface.onInit(); + + ros::spin(); + + return 0; +} diff --git a/autorally_core/src/systemStatus/__init__.py b/autorally_core/src/systemStatus/__init__.py new file mode 100755 index 00000000..e69de29b diff --git a/autorally_core/src/systemStatus/systemStatus.py b/autorally_core/src/systemStatus/systemStatus.py new file mode 100755 index 00000000..8f6b9e4e --- /dev/null +++ b/autorally_core/src/systemStatus/systemStatus.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python +# Software License Agreement (BSD License) +# Copyright (c) 2013, Georgia Institute of Technology +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## @package systemStatus +# Gets the wireless signal strength, power status, and CPU temperature. This information is published in the form of ROS messages. +# + +#import roslib; roslib.load_manifest('autorally_msgs') +import rospy +import commands +import subprocess +import signal +import sys +from std_msgs.msg import String +from diagnostic_msgs.msg import DiagnosticArray, DiagnosticStatus, KeyValue + +running = True + +def signal_handler(signal, frame): + print('SystemStatus: SIGINT detected.') + running = False + +## WirelessStatus. +# +# Uses iwconfig to retrieve wireless signal strength and then publishes it. +class WirelessStatus: + ## Initializes wirelessSignalStatusMSG + def __init__(self): + self.linkQuality = 0 + self.maxQuality = 0 + ## Retrieves wireless signal strength and stores it in the MSG format. + def getValues(self): + outputString = commands.getoutput("sudo iwconfig | grep 'Link Quality='") + linkQualityLocation = outputString.find("Link Quality=") + if linkQualityLocation >= 0 and outputString[linkQualityLocation+13:linkQualityLocation+15].isdigit() and outputString[linkQualityLocation+16:linkQualityLocation+18].isdigit(): + self.linkQuality = int(outputString[linkQualityLocation+13:linkQualityLocation+15]) + self.maxQuality = int(outputString[linkQualityLocation+16:linkQualityLocation+18]) + +## PowerStatus. +# +# Uses acpi to retrieve battery status and then publishes it. +class PowerStatus: + ## Initializes powerStatusMSG + def __init__(self): + self.percentage = 0 + self.valid = True + ## Retrieves battery status and stores it in the MSG format. + def getValues(self): + outputString = commands.getoutput("acpi") + if outputString == "No support for device type: power_supply": + self.valid = False + else: + self.valid = True + percentageLocation = outputString.find("%") + if percentageLocation >= 0: + self.percentage = int(outputString[percentageLocation-2:pPubercentageLocation]) + +## M4ATXPowerStatus +# +# Uses M4API to check compute box battery status and power supply diagnostics +class M4ATXPowerStatus: + def __init__(self): + self.percentage = 0 + self.VIN = 0 + self.V33 = 0 + self.V5 = 0 + self.V12 = 0 + self.temp = 0 + self.valid = True + def getValues(self): + if not self.valid: + return + try: + output = subprocess.check_output("sudo m4ctl", shell=True) + except subprocess.CalledProcessError, e: + self.valid = False + if e.returncode is 127: + print "m4ctl gave error code 127" + else : + print "Unknown error code from m4ctl: ", e.returncode + else: + for line in output.split("\n"): + tokens = line.split("\t") + if len(tokens) is 2: + if tokens[0] == "VIN:": + self.valid = True + self.VIN = float(tokens[1]) + # Battery max voltage 25, fully depleted 19, 6 volt span + self.percentage = min( 100, ( ( float(tokens[1]) - 19 ) / 6.0 ) * 100) + if tokens[0] == "33V:": + self.valid = True + self.V33 = float(tokens[1]) + if tokens[0] == "5V:": + self.valid = True + self.V5 = float(tokens[1]) + if tokens[0] == "12V:": + self.valid = True + self.V12 = float(tokens[1]) + if tokens[0] == "TEMP:": + self.valid = True + self.temp = float(tokens[1]) + +## TempStatus. +# +# Uses sensors to retrieve CPU temperature and then publishes it. +class TempStatus: + ## Initializes tempStatusMSG + def __init__(self): + self.cpuTemp = 0 + self.fanSpeed = 0 + ## Retrieves CPU temperature and fan speed and stores it in the MSG format. + def getValues(self): + outputString = commands.getoutput("sensors | grep \"Core 0:\"") + cpuTempLocation = outputString.find("+") + if cpuTempLocation >= 0: + try: + self.cpuTemp1 = float(outputString[cpuTempLocation+1:cpuTempLocation+5]) + except ValueError: + self.cpuTemp1 = -1.0 + else: + self.cpuTemp1 = 0.0 + outputString = commands.getoutput("sensors | grep \"Core 1:\"") + cpuTempLocation = outputString.find("+") + if cpuTempLocation >= 0: + try: + self.cpuTemp2 = float(outputString[cpuTempLocation+1:cpuTempLocation+5]) + except ValueError: + self.cpuTemp2 = -1.0 + else: + self.cpuTemp2 = 0.0 + outputString = commands.getoutput("sensors | grep \"Core 2:\"") + cpuTempLocation = outputString.find("+") + if cpuTempLocation >= 0: + try: + self.cpuTemp3 = float(outputString[cpuTempLocation+1:cpuTempLocation+5]) + except ValueError: + self.cpuTemp3 = -1.0 + else: + self.cpuTemp3 = 0.0 + outputString = commands.getoutput("sensors | grep \"Core 3:\"") + cpuTempLocation = outputString.find("+") + if cpuTempLocation >= 0: + try: + self.cpuTemp4 = float(outputString[cpuTempLocation+1:cpuTempLocation+5]) + except ValueError: + self.cpuTemp4 = -1.0 + else: + self.cpuTemp4 = 0.0 + self.cpuTemp = max(self.cpuTemp1, self.cpuTemp2, self.cpuTemp3, self.cpuTemp4) + outputString = commands.getoutput("sensors | grep \"fan2:\"") + try: + self.fanSpeed = float(outputString[23:27]) + except ValueError: + self.fanSpeed = -1.0 + +if __name__ == '__main__': + signal.signal(signal.SIGINT, signal_handler) + + rospy.init_node('systemStatus') + pub = rospy.Publisher('/diagnostics', DiagnosticArray, queue_size=1) + array = DiagnosticArray() + status = DiagnosticStatus(name='SystemStatus',\ + level=0,\ + message='System Status') + + array.status = [status] + + if not rospy.has_param('/systemStatus/cpuTempHigh') or\ + not rospy.has_param('/systemStatus/cpuTempCrit') or\ + not rospy.has_param('/systemStatus/batteryLow') or\ + not rospy.has_param('/systemStatus/batteryCrit') or\ + not rospy.has_param('/systemStatus/wirelessLow') or\ + not rospy.has_param('/systemStatus/wirelessCrit'): + rospy.logerr("Could not get all SystemStatus parameters"); + + wirelessStatusPublisher = WirelessStatus() + powerStatusPublisher = PowerStatus() + tempStatusPublisher = TempStatus() + powerSupplyHandler = M4ATXPowerStatus() + + rate = rospy.Rate(0.5) #1Hz + while not rospy.is_shutdown() and running: + status.values = [] + + wirelessStatusPublisher.getValues() + powerStatusPublisher.getValues() + tempStatusPublisher.getValues() + powerSupplyHandler.getValues() + + if powerStatusPublisher.valid: + status.values.append(KeyValue(key='Laptop Battery Level', value=str(powerStatusPublisher.percentage))) + if powerStatusPublisher.percentage <= rospy.get_param('/systemStatus/batteryCrit'): + status.values.append(KeyValue(key='BATTERY CRITICALLY LOW', value=chr(2))) + elif powerStatusPublisher.percentage <= rospy.get_param('/systemStatus/batteryLow'): + status.values.append(KeyValue(key='BATTERY LOW', value=chr(1))) + + if powerSupplyHandler.valid: + status.values.append(KeyValue(key='Battery Level', value=str(powerSupplyHandler.percentage))) + if powerSupplyHandler.percentage <= rospy.get_param('/systemStatus/batteryCrit'): + status.values.append(KeyValue(key='BATTERY CRITICALLY LOW', value=chr(2))) + elif powerSupplyHandler.percentage <= rospy.get_param('/systemStatus/batteryLow'): + status.values.append(KeyValue(key='BATTERY LOW', value=chr(1))) + status.values.append(KeyValue(key='VIN', value=str(powerSupplyHandler.VIN))) + status.values.append(KeyValue(key='3.3v Rail', value=str(powerSupplyHandler.V33))) + status.values.append(KeyValue(key='5v Rail', value=str(powerSupplyHandler.V5))) + status.values.append(KeyValue(key='12v Rail', value=str(powerSupplyHandler.V12))) + status.values.append(KeyValue(key='Power Supply Temp', value=str(powerSupplyHandler.temp))) + + status.values.append(KeyValue(key='CPU Temp', value=str(tempStatusPublisher.cpuTemp))) + if tempStatusPublisher.cpuTemp >= rospy.get_param('/systemStatus/cpuTempCrit'): + status.values.append(KeyValue(key='CPU CRITICALLY HOT', value=chr(2))) + elif tempStatusPublisher.cpuTemp >= rospy.get_param('/systemStatus/cpuTempHigh'): + status.values.append(KeyValue(key='CPU HOT', value=chr(1))) + status.values.append(KeyValue(key='Fan Speed', value=str(tempStatusPublisher.fanSpeed))) + + # WiFi status is not currently published by our driver + status.values.append(KeyValue(key='WiFi Quality', value=str(wirelessStatusPublisher.linkQuality))) + status.values.append(KeyValue(key='WiFi Max Quality', value=str(wirelessStatusPublisher.maxQuality))) + if wirelessStatusPublisher.linkQuality <= rospy.get_param('/systemStatus/wirelessCrit'): + status.values.append(KeyValue(key='WiFi CRITICALLY WEAK', value=chr(2))) + elif wirelessStatusPublisher.linkQuality <= rospy.get_param('/systemStatus/wirelessLow'): + status.values.append(KeyValue(key='WiFi WEAK', value=chr(1))) + pub.publish(array) + rate.sleep() + print("SystemStatus: Shutting down"); diff --git a/autorally_core/src/xbee/CMakeLists.txt b/autorally_core/src/xbee/CMakeLists.txt new file mode 100644 index 00000000..e7e28c12 --- /dev/null +++ b/autorally_core/src/xbee/CMakeLists.txt @@ -0,0 +1,13 @@ +add_executable(xbeeCoordinator XbeeCoordinator.cpp XbeeInterface.cpp) +target_link_libraries(xbeeCoordinator ${catkin_LIBRARIES} ${Boost_LIBRARIES} SerialSensorInterface Diagnostics) +add_executable(xbeeNode XbeeNode.cpp XbeeInterface.cpp) +target_link_libraries(xbeeNode ${catkin_LIBRARIES} ${Boost_LIBRARIES} SerialSensorInterface Diagnostics) + +install(TARGETS + xbeeCoordinator + xbeeNode + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) + diff --git a/autorally_core/src/xbee/XbeeCoordinator.cpp b/autorally_core/src/xbee/XbeeCoordinator.cpp new file mode 100644 index 00000000..c30a8273 --- /dev/null +++ b/autorally_core/src/xbee/XbeeCoordinator.cpp @@ -0,0 +1,207 @@ +#include "XbeeCoordinator.h" +#include + +int main(int argc, char **argv) +{ + ros::init(argc, argv, "xbeeCoordinator"); + ros::NodeHandle nh; + + std::string xbeePort; + if(!nh.getParam("xbeeCoordinator/port", xbeePort)) + { + ROS_ERROR("Could not get xbeeCoordinator port name, will exit"); + return -1; + } + + XbeeCoordinator coordinator(nh, xbeePort); + + ros::spin(); + return 0; +} + +XbeeCoordinator::XbeeCoordinator(ros::NodeHandle &nh, const std::string& port): + m_xbee(nh, port) +{ + m_xbee.registerReceiveMessageCallback(boost::bind(&XbeeCoordinator::processXbeeMessage, this, _1, _2, _3, _4) ); + + m_safeSpeedSubscriber = nh.subscribe("safeSpeed", 1, + &XbeeCoordinator::safeSpeedCallback, + this); + m_baseStationRTKSubscriber = nh.subscribe("gpsBaseRTCM3", 1, + &XbeeCoordinator::gpsCorrectionsCallback, + this); +} + +XbeeCoordinator::~XbeeCoordinator() +{} + +void XbeeCoordinator::processXbeeMessage(const std::string& sender, + const std::string& /*networkAddress*/, + const std::string& data, + const bool /*broadcast*/) +{ + std::string msg = data.substr(0,2); + ROS_DEBUG_STREAM("Xbee: rf message from" << sender << ":" << data); + if(msg == "HI") + { + ROS_INFO_STREAM("New Xbee in system: " << sender); + RobotState toAdd(sender, data.substr(2)); + m_robotInfos[sender] = toAdd; + //give 5 extra seconds to complete startup before the node is stale + m_robotInfos[sender].lastHeartbeat = ros::Time::now()+ros::Duration(5); + std::string sendData = "AK " + m_xbee.getAddress(); + m_xbee.sendTransmitPacket(sendData, sender); + } else if(msg == "ST") + { + m_robotInfos[sender].lastHeartbeat = ros::Time::now(); + } else if(msg == "AK") + { + ROS_ERROR("XbeeCoordinator: Received AK message, there may be another\ + coordinator with address %s", sender.c_str()); + } else if (msg == "OD") + { + if(data.length() == 62) + { + processXbeeOdom(data, sender); + } + else + ROS_ERROR("XbeeNode: Received incorrect length(%d) odom message \"%s\"", (int)data.length(),data.c_str()); + } else + { + ROS_ERROR("XbeeCoordinator: Received unknown message %s", msg.c_str()); + } +} + +void XbeeCoordinator::safeSpeedCallback(const autorally_msgs::safeSpeedConstPtr& msg) +{ + std::ostringstream ss; + ss << std::fixed << std::setprecision(2); + ss << msg->speed; + + std::string sendData = "SS " + msg->sender + " " + ss.str(); + m_xbee.sendTransmitPacket(sendData); + //ROS_INFO(sendData.c_str()); + + ros::Time now = ros::Time::now(); + std::map::const_iterator mapIt; + //if state has not been received from a node in > 2 seconds, send a + //safeSpeed = 0.0 to that node (overriding the broadcast safeSpeed), + //regardless of what overall system safeSpeed is + for(mapIt = m_robotInfos.begin(); mapIt != m_robotInfos.end(); mapIt++) + { + if( (now-mapIt->second.lastHeartbeat).toSec() > 5.0) + { + ROS_WARN("No recent heartbeat from %s", mapIt->first.c_str()); + sendData = "SS " + msg->sender + " 0.00"; + m_xbee.sendTransmitPacket(sendData, mapIt->second.address); + } + } + +} + +void XbeeCoordinator::gpsCorrectionsCallback(const std_msgs::ByteMultiArray::ConstPtr& correction) +{ + //xbee packet has max len of 72 bytes + //size_t bytesSent = 0; + std::string correctionSubstr; + int numMsgs = 2 + (correction->data.size()-1)/67; + int msgNum = 1; + + //send a header packet with identifier, msg count, label from the MultiByteArray + std::string msgHeader = "GC " + boost::lexical_cast(numMsgs); + //ROS_INFO_STREAM("Sending gps correction len " << correction->data.size() << + // " in " << numMsgs << " xbee packets"); + //ROS_INFO_STREAM(msgHeader + boost::lexical_cast(msgNum) + + // correction->layout.dim.front().label); + if(correction->layout.dim.front().label.size() < 67) + { + if(m_xbee.sendTransmitPacket(msgHeader + + boost::lexical_cast(msgNum) + + correction->layout.dim.front().label) ) + { + msgNum++; + std::vector msgBody; + + while(msgNum <= numMsgs) + { + //msg payload is 67 bytes of data appended + //correctionSubstr.clear(); + msgBody.clear(); + msgBody.push_back('G'); + msgBody.push_back('C'); + msgBody.push_back(' '); + msgBody.push_back(boost::lexical_cast(numMsgs)); + msgBody.push_back(boost::lexical_cast(msgNum)); + + for(int i = (msgNum-2)*67; i < std::min((msgNum-1)*67, correction->data.size()); i++) + { + msgBody.push_back(correction->data[i]); + } + + //ROS_INFO_STREAM(msgHeader + std::to_string(msgNum) << + // " positions " << (msgNum-2)*67 << ":" << + // std::min((msgNum-1)*67, correction->data.size())); + + if(!m_xbee.sendTransmitPacket(msgBody)) + { + ROS_ERROR_STREAM("XbeeCoordinator: transmit of gps correction packet " << msgNum << "/" << + numMsgs << " failed"); + } else + + msgNum++; + } + } else + { + ROS_ERROR("XbeeCoordinator gps correction header transmit failed"); + } + } else + { + ROS_WARN_STREAM("Xbee: ByteMultiArray label " << correction->layout.dim.front().label << " will be clipped to 67 bytes"); + } +} + +double XbeeCoordinator::unscaleAndClip(int number, double range, double resolution) +{ + return ((double)number * resolution) - range; +} + +void XbeeCoordinator::processXbeeOdom(const std::string& message, const std::string& sender) +{ + //ROS_WARN_STREAM("Received:" << message << " from:" << sender); + nav_msgs::OdometryPtr odom(new nav_msgs::Odometry); + + odom->pose.pose.position.x = unscaleAndClip(atoi(message.substr(3,5).c_str()), 500, 0.01); + odom->pose.pose.position.y = unscaleAndClip(atoi(message.substr(8,5).c_str()), 500, 0.01); + odom->pose.pose.position.z = unscaleAndClip(atoi(message.substr(13,5).c_str()), 500, 0.01); + odom->twist.twist.linear.x = unscaleAndClip(atoi(message.substr(18,4).c_str()), 50, 0.01); + odom->twist.twist.linear.y = unscaleAndClip(atoi(message.substr(22,4).c_str()), 50, 0.01); + odom->twist.twist.linear.z = unscaleAndClip(atoi(message.substr(26,4).c_str()), 50, 0.01); + odom->pose.pose.orientation.x = unscaleAndClip(atoi(message.substr(30,8).c_str()), 1, 0.0000001); + odom->pose.pose.orientation.y = unscaleAndClip(atoi(message.substr(38,8).c_str()), 1, 0.0000001); + odom->pose.pose.orientation.z = unscaleAndClip(atoi(message.substr(46,8).c_str()), 1, 0.0000001); + odom->pose.pose.orientation.w = unscaleAndClip(atoi(message.substr(54,8).c_str()), 1, 0.0000001); + /*ROS_WARN("[%f %f %f][%f %f %f][%f %f %f %f]", + odom->pose.pose.position.x, + odom->pose.pose.position.y, + odom->pose.pose.position.z, + odom->twist.twist.linear.x, + odom->twist.twist.linear.y, + odom->twist.twist.linear.z, + odom->pose.pose.orientation.x, + odom->pose.pose.orientation.y, + odom->pose.pose.orientation.z, + odom->pose.pose.orientation.w); + */ + + if(!m_recOdomPublishers[sender]) + { + ros::NodeHandle nh; + m_recOdomPublishers[sender] = nh.advertise + ("/pose_estimate_"+sender, 1); + + } + odom->header.stamp = ros::Time::now(); + odom->child_frame_id = sender; + m_xbee.m_port.tick("/pose_estimate_"+sender); + m_recOdomPublishers[sender].publish(odom); +} \ No newline at end of file diff --git a/autorally_core/src/xbee/XbeeCoordinator.h b/autorally_core/src/xbee/XbeeCoordinator.h new file mode 100644 index 00000000..861a03d6 --- /dev/null +++ b/autorally_core/src/xbee/XbeeCoordinator.h @@ -0,0 +1,112 @@ +/********************************************** + * @file XbeeCoordinator.h + * @author Brian Goldfain + * @date May 17, 2013 + * @copyright 2012 Georgia Institute of Technology + * @brief + * + * @details This file contains the XbeeCoordinator class definition + ***********************************************/ + +#include "XbeeInterface.h" + +#include +#include +#include + #include + +/** + * @class XbeeCoordinator XbeeCoordinator.h + * "xbee/XbeeCoordinator.h" + * @brief Publishes ROS messages from a Coordinator xbee into system + * + * XbeeCoordinator is designed to send periodic information to any XbeeNodes within + * range. It gives us the ability to send information to multiple robot while each + * independant ROS systems. The current information sent from the coordinator is + * a safeSpeed message based on the state of the runStop and gps corrections as + * RTCM3 messages for RTK-enabled gps devices on each robot to use. + * + */ +class XbeeCoordinator +{ + struct RobotState + { + std::string address; + std::string name; + double velocity; + ros::Time lastHeartbeat; + + RobotState() + {} + + RobotState(const std::string& _address, const std::string& _name): + velocity(-1.0) + { + address = _address; + name = _name; + } + + RobotState(RobotState const& copy): + address(copy.address), + name(copy.name), + velocity(copy.velocity), + lastHeartbeat(copy.lastHeartbeat) + {} + + RobotState& operator=(RobotState const& copy) + { + address = copy.address; + name = copy.name; + velocity = copy.velocity; + lastHeartbeat = copy.lastHeartbeat; + return *this; + } + + void update(const std::string& /*msg*/) + { + lastHeartbeat = ros::Time::now(); + } + }; + + public: + + XbeeCoordinator(ros::NodeHandle &nh, const std::string& port); + ~XbeeCoordinator(); + + private: + + XbeeInterface m_xbee; ///< Xbee object that manages sending/receiving data + std::map m_robotInfos; ///< Info for all XbeeCoordinators in system + ros::Subscriber m_safeSpeedSubscriber; ///< Subscriber for safeSpeed + ros::Subscriber m_baseStationRTKSubscriber; ///< Subscriber for RTK corrections + + std::map m_recOdomPublishers; + + /** + * @brief Parse a message received over USB from xbee + * @param sender identifier for xbee that sent message + * @param networkAddress address of the originating xbee network + * @param data message payload + * @param broadcast if the message was targeted or broadcast + * + */ + void processXbeeMessage(const std::string &sender, + const std::string &networkAddress, + const std::string &data, + const bool broadcast); + + /** + * @brief Callback for new safeSpeed messages + * @param msg The new vehicle speed + */ + void safeSpeedCallback(const autorally_msgs::safeSpeedConstPtr& msg); + + /** + * @brief Broadcast RTK correction messages to all XbeeCoordinator + * @param correction RTCM3.0 RTK correction message to be broadcast + */ + void gpsCorrectionsCallback(const std_msgs::ByteMultiArray::ConstPtr& correction); + + double unscaleAndClip(int number, double range, double resolution); + void processXbeeOdom(const std::string& message, const std::string& sender); +}; diff --git a/autorally_core/src/xbee/XbeeInterface.cpp b/autorally_core/src/xbee/XbeeInterface.cpp new file mode 100644 index 00000000..2ce083f4 --- /dev/null +++ b/autorally_core/src/xbee/XbeeInterface.cpp @@ -0,0 +1,556 @@ +/* API MODE STUFF +FRAME: + 0x7E | MSB|LSB | API SPEC STRUCTURE = X | checksum + +Modem Status 0x8A - Reset Status + +AT Command 0x08 - Send AT Command. cmdData contains two command characters + X=0x08 | Arbitrary Byte | command | param | + +AT Command - Queue Parameter Value 0x09 + Same, but nothing is applied until AC( apply changes) is issued + +AT Command Response 0x88 + Response from module. X = 0x88 | CommandType | 0...3 (OK, Err, bad cmd, bad prm)| option value + +Remote Command Request 0x17 + Same, but remote to another Xbee + +Remote Command Response 0x97 + Same, but remote to another Xbee + +Transmit Request + 0x10 + Here is what we want! Used to send messages to other xbees + X= 0x10 | Arbitrary Byte | 64 bit address (0x000000000000FFFF for all) | 16 bit address| 0 | 0 | 54 byte message + + +Explicit Addressing Command Frame 0x11 + More specific way of sending transmissions. Probably dont need + +Transmit Status 0x8B + Auto response after transmission + +Receive Packet (AO=0) 0x90 + What UART spits out when a packet is recieved + X= 0x90|64 bit sender|16 bit sender | 0x01,0x02 (options) | data + +Explicit Rx Indicator (AO=1) 0x91 + Explicit setting. Probably will not need +*/ +#include "XbeeInterface.h" +#include +#include + +XbeeInterface::XbeeInterface(ros::NodeHandle &nh, const std::string& port): + m_nh(nh), + m_bytesReceived(0), + m_bytesTransmitted(0) +{ + std::string frameID; + std::string diagInfo; + std::string nName = ros::this_node::getName(); + if(!nh.getParam(nName+"/frameID", frameID) || + !nh.getParam(nName+"/diagnosticInfo", diagInfo) ) + { + ROS_ERROR("Could not get all xbee parameters for %s", nName.c_str()); + } + + //Create function pointers to call based on what type of message is + m_apiFrameFunctions[(char)0x88] = &XbeeInterface::processATCommandResponse; + m_apiFrameFunctions[(char)0x97] = &XbeeInterface::processRemoteATCommandResponse; + m_apiFrameFunctions[(char)0x8B] = &XbeeInterface::processTransmitStatus; + m_apiFrameFunctions[(char)0x90] = &XbeeInterface::processReceivePacket; + + m_frameID = hexToString(&frameID[0])[0]; + + m_diagTimer = nh.createTimer(ros::Duration(1.0), + &XbeeInterface::diagUpdate, + this); + m_diagInfoTimer = nh.createTimer(ros::Duration(4.0), + &XbeeInterface::diagInfoRequest, + this); + + //create vector of all periodically update diagnostic info + size_t space; + while( (space = diagInfo.find_first_of(" ")) != std::string::npos) + { + m_diagCommands[diagInfo.substr(0, space)] = "-"; + diagInfo.erase(0, space+1); + } + m_diagCommands[diagInfo.substr(0, space)] = "-"; + + m_port.init(nh, ros::this_node::getName(), "", "Xbee Pro 900", port, true); + m_port.registerDataCallback( + boost::bind(&XbeeInterface::xbeeDataCallback, this)); + + + if(!m_port.connected()) + { + ROS_ERROR("The serial port isn't open, stuff might not work"); + m_port.diag_error("The serial port isn't open, stuff might not work"); + } +} + +XbeeInterface::~XbeeInterface() +{} + +void XbeeInterface::registerReceiveMessageCallback( + boost::function callback) +{ + m_receiveMessageCallback = callback; +} + +bool XbeeInterface::sendCommandPacket(const std::string &command, const std::string ¶m) +{ + + int length = 0; + unsigned char apiFrame[9]; + if(param.size() == 0 && command.size() == 2) + { + length = 8; + apiFrame[2]=0x04; + } else if(param.size() == 1 && command.size() == 2) + { + length = 9; + apiFrame[2]=0x05; + apiFrame[7]=param[0]; + } else + { + ROS_ERROR("Xbee: could not generate command packet, command:%s param:%s", + command.c_str(), + param.c_str()); + return false; + } + + apiFrame[0]=0x7E; + apiFrame[1]=0x00; + apiFrame[3]=0x08; //AT command + apiFrame[4]=m_frameID; //frame id + apiFrame[5]=command[0];//0x41; + apiFrame[6]=command[1];//0x50; + + apiFrame[length-1] = computeChecksum(apiFrame); + return (m_port.writePort(apiFrame, length) != -1); +} + +void XbeeInterface::xbeeDataCallback() +{ + m_port.lock(); + size_t startPosition = m_port.m_data.find("~"); + if(startPosition == 0 && m_port.m_data.length() >= 3) + { + int size = (m_port.m_data[1]<<8)|m_port.m_data[2]; + size_t totalSize = size+4; + + if(m_port.m_data.length() >= totalSize) + { + std::string msgToAdd = m_port.m_data.substr(3, size); + + unsigned char checksum = computeChecksum(m_port.m_data.substr(0, totalSize)); + if(checksum == (unsigned char)(m_port.m_data[totalSize-1]&0xFF)) + { + //call appropritate callback + if(m_apiFrameFunctions.find(msgToAdd[0]&0xFF) != m_apiFrameFunctions.end()) + { + if(!m_apiFrameFunctions[msgToAdd[0]&0xFF](this, msgToAdd)) + { + m_port.diag_error("Xbee: error processing message:" + msgToAdd); + ROS_ERROR("Xbee: error processing message:%s", stringToHex(msgToAdd).c_str()); + } + } else + { + m_port.diag_error("Unrecognized xbee message type"); + ROS_ERROR_STREAM("Unrecognized xbee message type:" << (int)(msgToAdd[0]&0xFF)); + } + //append incoming message to vector, stripped of + //start delimiter, length, checksum + m_port.m_data.erase(0, totalSize); + m_port.unlock(); + return; + } else + { + m_port.diag_error("Xbee: computed checksum does not match message checksum"); + ROS_ERROR("Xbee: computed checksum %x does not match message checksum %x", + checksum, + m_port.m_data[totalSize-1]&0xFF); + } + m_port.m_data.erase(0, totalSize); + + } + + } else if(startPosition != std::string::npos) + { + m_port.m_data.erase(0, startPosition); + } + m_port.unlock(); +} + +bool XbeeInterface::processATCommandResponse(const std::string &message) +{ + if( message[0] == (char)0x88 && //AT command reply byte + message[1] == m_frameID) //frameid + { + if(message[4] != (char)0x00)//Check no error code + { + ROS_ERROR("Xbee: %s error code:%x", message.c_str(), message[4] ); + m_port.diag_error("Xbee: " + message + " error code:" + message[4]); + } else + { + std::string command = message.substr(2, 2); + std::string value = message.substr(5, message.length()-5); + + std::map::iterator mapIt; + if( (mapIt = m_diagCommands.find(command)) != m_diagCommands.end()) + { + if(command == "NI") + { + mapIt->second = value; + } else + { + mapIt->second = stringToHex(value); + } + } else + { + m_port.diag_warn("Received unknown diagnostic command: " + command); + } + return true; + } + } + return false; +} + +bool XbeeInterface::processRemoteATCommandResponse(const std::string &message) +{ + if( message[0] == (char)0x97 && //AT command reply byte + message[1] == m_frameID) //frameid + { + if(message[15] != (char)0x00)//Check no error code + { + ROS_ERROR("Xbee: %s error code:%d", message.c_str(), message[4] ); + m_port.diag_error(message + " error code:" + message[4]); + } else + { + std::string responder = message.substr(3, 8); + std::string responderNetwork = message.substr(11, 2); + std::string command = message.substr(13, 2); + if(message.size() > 16) + { + std::string value = message.substr(15, message.length()-16); + } + + return true; + } + } + return false; + +} + +bool XbeeInterface::processTransmitStatus(const std::string &message) +{ + //check the message is an AT command reply for the desired command + if( message[0] == (char)0x8B && //AT command reply byte + message[1] == m_frameID ) //frameid + { + ROS_DEBUG_STREAM("Xbee: transmit status:" << message << ":" << stringToHex(message)); + if(message[5] != (char)0x00) + { + ROS_WARN("Xbee: transmit error (likely wrong address):%x", message[5]); + m_port.diag_warn("Xbee: transmit error (likely wrong address):" + message[5]); + } + return true; + } + return false; +} + +bool XbeeInterface::processReceivePacket(const std::string &message) +{ + ROS_DEBUG_STREAM("Xbee: received Packet:" << stringToHex(message)); + m_bytesReceived += message.size()+6; + if(message[0] == (char)0x90) + { + std::string sender = message.substr(1, 8); + std::string responderNetwork = message.substr(9, 2); + std::string packetType = message.substr(11, 1); + std::string data = message.substr(12); + + if(m_receiveMessageCallback) + { + m_receiveMessageCallback(stringToHex(sender), + responderNetwork, + data, + (packetType[0]==(char)0x02)); + return true; + } + } + return false; +} + +bool XbeeInterface::sendTransmitPacket(const std::string &message, + const std::string &destAddress, + const std::string &networkAddress) +{ + if(message.size() > 72) + { + ROS_ERROR("Xbee: Transmit packet length %ld too long (max 72)", message.size()); + return false; + } + if(destAddress.size() != 16) + { + ROS_ERROR("Xbee: Destination address %s length %ld != 16", + destAddress.c_str(), + destAddress.size()); + return false; + } + if(networkAddress.size() != 4) + { + ROS_ERROR("Xbee: Network address %s length %ld != 4", + networkAddress.c_str(), + networkAddress.size()); + return false; + } + + int payloadSize = message.size() + 14; + int totalSize = payloadSize + 4; + unsigned char buff[totalSize]; + + buff[0] = 0x7E; //frame delimiter + buff[1]=0x00; + buff[2]=static_cast(payloadSize); + buff[3]=0x10; //Transmit command + buff[4]=m_frameID; //Random selection + + //5-12 64bit address + std::string converted = hexToString(destAddress); + for(size_t i = 0; i < converted.size(); i++) + { + buff[5+i] = converted[i]; + } + converted = hexToString(networkAddress); + buff[13] = converted[0]; + buff[14] = converted[1]; + + buff[15]=0x00; //broadcast radius set to 0 + buff[16] = 0x00; //multicast set to 0 (unicast) + + for(size_t i = 0; i < message.size(); i++) + { + buff[17+i] = message[i]; + } + + buff[totalSize-1] = computeChecksum(buff); + + ROS_DEBUG_STREAM("Xbee: Sending:" << message << " with checksum:" << (int)buff[totalSize-1] << " to:" << destAddress << + " in network:" << networkAddress); + + if(m_port.writePort(buff, totalSize) >= 0) + { + m_bytesTransmitted += totalSize; + return true; + } + + ROS_WARN("Xbee: Writing Message to port failed"); + return false; +} + +bool XbeeInterface::sendTransmitPacket(const std::vector &message, + const std::string &destAddress, + const std::string &networkAddress) +{ + if(message.size() > 72) + { + ROS_ERROR("Xbee: Transmit packet length %ld too long (max 72)", message.size()); + return false; + } + if(destAddress.size() != 16) + { + ROS_ERROR("Xbee: Destination address %s length %ld != 16", + destAddress.c_str(), + destAddress.size()); + return false; + } + if(networkAddress.size() != 4) + { + ROS_ERROR("Xbee: Network address %s length %ld != 4", + networkAddress.c_str(), + networkAddress.size()); + return false; + } + + int payloadSize = message.size() + 14; + int totalSize = payloadSize + 4; + unsigned char buff[totalSize]; + + buff[0] = 0x7E; //frame delimiter + buff[1]=0x00; + buff[2]=static_cast(payloadSize); + buff[3]=0x10; //Transmit command + buff[4]=m_frameID; //Random selection + + //5-12 64bit address + std::string converted = hexToString(destAddress); + for(u_int i = 0; i < converted.size(); i++) + { + buff[5+i] = converted[i]; + } + converted = hexToString(networkAddress); + buff[13] = converted[0]; + buff[14] = converted[1]; + + buff[15]=0x00; //broadcast radius set to 0 + buff[16] = 0x00; //multicast set to 0 (unicast) + + std::memcpy(&buff[17], &message.front(), message.size()); + + buff[totalSize-1] = computeChecksum(buff); + + ROS_DEBUG_STREAM("Xbee: Sending " << message.size() << " bytes to:" << destAddress << + " in network:" << networkAddress); + + if(m_port.writePort(buff, totalSize) >= 0) + { + m_bytesTransmitted += totalSize; + return true; + } + + ROS_WARN("Xbee: Writing Message to port failed"); + return false; +} + +unsigned char XbeeInterface::computeChecksum(const std::string &msg) +{ + return computeChecksum(reinterpret_cast(msg.data())); +} + +unsigned char XbeeInterface::computeChecksum(const unsigned char *msg) +{ + int len = (msg[1]<<8)|msg[2]; + int totalLen = len + 4; + int sum = 0; + + for(int i = 3; i <= totalLen-2; i++) + { + sum += msg[i]&0xFF; + } + return 0xFF-(sum&0xFF); +} + +void XbeeInterface::diagInfoRequest(const ros::TimerEvent& /*time*/) +{ + std::map::const_iterator mapIt; + for(mapIt = m_diagCommands.begin(); mapIt != m_diagCommands.end(); mapIt++) + { + sendCommandPacket(mapIt->first); + } +} + +void XbeeInterface::diagUpdate(const ros::TimerEvent& /*time*/) +{ + m_port.diag("Transmit bandwidth B/s", std::to_string(m_bytesTransmitted)); + m_port.diag("Receive bandwidth B/s", std::to_string(m_bytesReceived)); + m_bytesTransmitted = 0; + m_bytesReceived = 0; + + std::map::const_iterator mapIt; + for(mapIt = m_diagCommands.begin(); mapIt != m_diagCommands.end(); mapIt++) + { + m_port.diag(mapIt->first, mapIt->second); + } +} + +std::string XbeeInterface::stringToHex(const std::string& input) +{ + static const char* const lut = "0123456789ABCDEF"; + size_t len = input.length(); + + std::string output; + output.reserve(2 * len); + for (size_t i = 0; i < len; ++i) + { + const unsigned char c = input[i]; + output.push_back(lut[c >> 4]); + output.push_back(lut[c & 15]); + } + return output; +} + +std::string XbeeInterface::hexToString(const std::string& input) +{ + static const char* const lut = "0123456789ABCDEF"; + size_t len = input.length(); + + std::string output; + output.reserve(len / 2); + for (size_t i = 0; i < len; i += 2) + { + char a = input[i]; + const char* p = std::lower_bound(lut, lut + 16, a); + if (*p != a) + { + ROS_ERROR("Xbee: hexToString Invalid hex digit:%x", a); + m_port.diag_error("Xbee: hexToString Invalid hex digit:" + a); + } + + char b = input[i + 1]; + const char* q = std::lower_bound(lut, lut + 16, b); + if (*q != b) + { + ROS_ERROR("Xbee: hexToString Invalid hex digit:%x", b); + m_port.diag_error("Xbee: hexToString Invalid hex digit:" + b); + } + output.push_back(((p - lut) << 4) | (q - lut)); + } + return output; +} + +std::string XbeeInterface::hexCharToString(const std::vector& input) +{ + static const char* const lut = "0123456789ABCDEF"; + int length = 2*input.size(); + std::string toReturn(length, 0x00); //allocate space in string + + for(size_t i = 0; i < input.size(); i++) + { + toReturn[2*i+1] = lut[(input[i]&0x0F)]; + toReturn[2*i] = lut[((input[i]>>4)&0x0F)]; + //ROS_ERROR_STREAM("Converted:" << (int)input[i] << " to:" << toReturn.substr(2*i,2)); + } + + return toReturn; +} + +std::vector XbeeInterface::stringToHexChar(const std::string& input) +{ + std::vector toReturn(input.size()/2); + if(input.size()%2 == 0) + { + for(size_t i = 0; i < input.size()/2; i++) + { + std::istringstream buffer(input.substr(i*2,2)); + int p; + buffer >> std::hex >> p; + toReturn[i] = (signed char)p; + } + } else + { + ROS_ERROR_STREAM("Xbee: stringToHexChar input string odd length, can't convert to hex"); + } + return toReturn; +} + +void XbeeInterface::printMessage(const std::string &message) +{ + printMessage(message.c_str(), message.size()); +} + +void XbeeInterface::printMessage(const char* message, int size) +{ + for (int i = 0; i < size; i++) + { + printf("%x ", message[i]&0xFF ); + } + printf("\n"); +} \ No newline at end of file diff --git a/autorally_core/src/xbee/XbeeInterface.h b/autorally_core/src/xbee/XbeeInterface.h new file mode 100644 index 00000000..98c7ca48 --- /dev/null +++ b/autorally_core/src/xbee/XbeeInterface.h @@ -0,0 +1,262 @@ +/********************************************** + * @file XbeeInterface.h + * @author Brian Goldfain + * @date May 17, 2013 + * @copyright 2012 Georgia Institute of Technology + * @brief Interface for Xbee Pro 900 in API mode + * + * @details This file contains the XbeeInterface class definition + ***********************************************/ +#ifndef XBEE_INTERFACE +#define XBEE_INTERFACE + +#include +#include +#include +#include +#include +#include +#include + +/** + * @class XbeeInterface XbeeInterface.h + * "xbee/XbeeInterface.h" + * @brief Interact with an Xbee in API mode + * + * Implements an interface for Xbee modules that supports api mode. The Xbee + * api specification is mostly implemented. You can send broadcast or targeted + * messages to any other Xbee in the network. You can also get and set any of + * the Xbee parameters available in AT mode. This uses SerialSensorInterface + * to send and receieve Xbee data over USB. There are also startup Xbee params + * that can be verified, as well as params that can be updated periodically in + * the diagnostic information. These data items are set in the launch files. + * + * @todo Make return statuses and such more visible outside of this class + */ +class XbeeInterface +{ + public: + SerialInterfaceThreaded m_port; + + boost::function m_receiveMessageCallback; + + /** + * @brief XbeeInterface constructor + * @param nh NodeHandle used to register stuff + * @param port name of the xbee + * + * Connects to the specified serial device, sets up diagnostics, starts + * polling timers, verifies startup configuration of Xbee + */ + XbeeInterface(ros::NodeHandle &nh, const std::string& port); + ~XbeeInterface(); + + /** + * @brief Set a function pointer to call to process a newly received message + * @param callback a boost::function to save and be call to process messages + * + * The function set to be triggered must accept 3 const std::string, for the + * information given in addition to the received message. + */ + void registerReceiveMessageCallback( + boost::function callback); + + /** + * @brief Get the network address of the Xbee it is connected to. + * @return std::string the network address of this Xbee + * + * The network address is a concatenation of the AT commands SH and SL, which + * are retreived and verified on startup (serial number high byte, serial + * number low byte) + */ + std::string getAddress() {return m_diagCommands["SH"]+m_diagCommands["SL"];} + + /** + * @brief Get the Node Identifier parameter for the connected Xbee + * @return std::string the ASCII string node identifier of the Xbee + * + * The node identifier is a user configurable ASCII string used to identify + * a particular xbee node in a more user-firendly manner than serial number + */ + std::string getNodeIdentifier() {return m_diagCommands["NI"];} + + /** + * @brief Send an arbitrary data packet up to 72 bytes over RF + * @param message data that should be sent over the network + * @param destAddress the address of the Xbee the message should be sent to + * @param networkAddress the network address that the destination node is on + * @return bool whether the message was sent out or not + * + * Send message over RF using the Transmit Request Xbee API command. If + * networkAddress is not specified, it defaults to any. If no destination + * address is specified, the message is sent out as a broadcast, which is + * then received by all Xbees in the network. + */ + bool sendTransmitPacket(const std::string &message, + const std::string &destAddress = "000000000000FFFF", + const std::string &networkAddress = "FFFE"); + + bool sendTransmitPacket(const std::vector &message, + const std::string &destAddress = "000000000000FFFF", + const std::string &networkAddress = "FFFE"); + + /** + * @brief Prints the char buffer as hex data to std::out + * @param message the message to be printed + * @param size the size of the message to be printed + */ + void printMessage(const char* message, int size); + + /** + * @brief Converts raw hex data to a more friendly std::string (ASCII + * character) representation + * @param input std::vector of characters to be converted + * @return std::string converted data + * @note this function does the same thing as hexToString below, but takes different input + * + * A vector with character values [0x00, 0x05, 0xFF] would be converted to: + * "0005FF" + */ + std::string hexCharToString(const std::vector& input); + +/** + * @brief Converts a string of hex data in ASCII format to its actual hex values + * @param input string to be converted + * @return std::vector converted data + * @note this is similar to the below function stringToHex + * + * A string "0005FF" would be converted to the character sequence: + * [0x00, 0x05, 0xFF] + */ + std::vector stringToHexChar(const std::string& input); + + private: + ros::NodeHandle m_nh; ///< local copy of the nodeHandle for timer starting + char m_frameID; ///< default frameID used in Xbee messages if none specified + ///< Set of Xbee AT commands to request periodically for diagnostic info + std::map m_diagCommands; + /** Map of functions to call within XbeeInterface based on what type of + * message is received from the Xbee. + */ + std::map > m_apiFrameFunctions; + + ///< Complete messages from Xbee that have been received, but not yet processed + std::vector m_unparsedMessages; + ros::Timer m_diagTimer; ///< timer to send out diagnostic info + ros::Timer m_diagInfoTimer; ///< timer to request diagnostic info from Xbee + int m_bytesReceived; + int m_bytesTransmitted; + + /** + * @brief Callback triggered by SerialInterfaceThreaded when USB data is available + */ + void xbeeDataCallback(); + + /** + * @brief Sends an AT command to the Xbee in api form + * @param command the AT command to send to the Xbee + * @param param value to set the param to, if setting (not needed to query) + * @return bool whether the packet was successfully send to the Xbee + * + * This same function is used to query and set params on the Xbee. The only + * difference is that to set a parameter, specify the value to set it to. + */ + bool sendCommandPacket(const std::string& command, + const std::string ¶m = ""); + + /** + * @brief Processes an AT command response received from Xbee + * @return bool whether the message was processed without errors + * + */ + bool processATCommandResponse(const std::string& command); + + /** + * @brief Processes a remote AT command response received from Xbee + * @return bool whether the message was processed without errors + * + */ + bool processRemoteATCommandResponse(const std::string& command); + + /** + * @brief Processes a transmit status response received from Xbee + * @return bool whether the message was processed without errors + * + */ + bool processTransmitStatus(const std::string& command); + + /** + * @brief Processes a receive packet response received from Xbee + * @return bool whether the message was processed without errors + * + */ + bool processReceivePacket(const std::string& message); + + /** + * @brief Computes checksum of Xbee message in std::string format + * @param msg the complete message to compute the checksum over + * @return unsigned char the checksum value + * + */ + unsigned char computeChecksum(const std::string& msg); + + /** + * @brief Computes checksum of Xbee message in char buffer format + * @param msg the complete message to compute the checksum over + * @return unsigned char the checksum value + * + * Computes checksum as per Xbee API specification by summing all data frame + * bytes, the subtracting the least significant byte of the sum from 0xFF + */ + unsigned char computeChecksum(const unsigned char* msg); + + /** + * @brief Update diagnostic information for this node + * @param time the timer event info + */ + void diagUpdate(const ros::TimerEvent& time); + + /** + * @brief Request diagnostic AT commands from Xbee + * @param time the timer event info + */ + void diagInfoRequest(const ros::TimerEvent& time); + + /** + * @brief Converts raw hex data to a more friendly std::string (ASCII + * character) representation + * @param input string to be converted + * @return std::string converted data + * @note this was taken from http://stackoverflow.com/questions/3381614/c-convert-string-to-hexadecimal-and-vice-versa + * + * A string with character values [0x00, 0x05, 0xFF] would be converted to: + * "0005FF" + */ + std::string stringToHex(const std::string& input); + + /** + * @brief Converts a string of hex data in ASCII format to its actual hex values + * @param input string to be converted + * @return std::string converted data + * @note this was taken from http://stackoverflow.com/questions/3381614/c-convert-string-to-hexadecimal-and-vice-versa + * + * A string "0005FF" would be converted to the character sequence: + * [0x00, 0x05, 0xFF] + */ + std::string hexToString(const std::string& input); + + /** + * @brief Prints the Xbee API packet as hex data to std::out + * @param message the message to be printed + */ + void printMessage(const std::string& message); +}; + +#endif //XBEE_INTERFACE \ No newline at end of file diff --git a/autorally_core/src/xbee/XbeeNode.cpp b/autorally_core/src/xbee/XbeeNode.cpp new file mode 100644 index 00000000..1d8d6c99 --- /dev/null +++ b/autorally_core/src/xbee/XbeeNode.cpp @@ -0,0 +1,343 @@ +/********************************************** + * @file XbeeNode.cpp + * @author Brian Goldfain + * @date May 17, 2013 + * @copyright 2012 Georgia Institute of Technology + * @brief + * + * @details This file contains the XbeeNode class implementation + ***********************************************/ + +#include "XbeeNode.h" +#include + +int main(int argc, char **argv) +{ + + ros::init(argc, argv, "xbeeNode"); + ros::NodeHandle nh; + + std::string xbeePort; + + if(!nh.getParam("xbeeNode/port", xbeePort)) + { + ROS_ERROR("Could not get xbeeNode parameters"); + return -1; + } + + XbeeNode coordinator(nh, xbeePort); + + ros::spin(); + return 0; +} + +XbeeNode::XbeeNode(ros::NodeHandle &nh, const std::string& port): + m_xbee(nh, port), + m_nh(nh), + m_lastSafeSpeed(0), + m_lastTargetedSafeSpeed(0), + m_coordinatorAddress(""), + m_prevGpsMsgNum(0) +{ + std::string nName = ros::this_node::getName(); + int transmitPositionRate; + if(!nh.getParam(nName+"/transmitPositionRate", transmitPositionRate)) + { + ROS_ERROR("Could not get all xbee parameters for %s", nName.c_str()); + } + + m_xbee.registerReceiveMessageCallback(boost::bind(&XbeeNode::processXbeeMessage, this, _1, _2, _3, _4) ); + + m_safeSpeedPublisher = nh.advertise + ("safeSpeed", 1); + m_gpsRTCM3Publisher = nh.advertise + ("gpsBaseRTCM3", 3); + + m_xbeeHeartbeatTimer = nh.createTimer(ros::Duration(0.5), + &XbeeNode::xbeeHeartbeatState, + this); + m_hiTimer = m_nh.createTimer(ros::Duration(1.0), + &XbeeNode::sendHi, + this); + + if(transmitPositionRate > 0) + { + m_transmitPositionTimer = m_nh.createTimer(ros::Duration(1.0/transmitPositionRate), + &XbeeNode::transmitPosition, + this); + m_poseSubscriber = nh.subscribe("pose_estimate", 1, + &XbeeNode::odomCallback, + this); + } + //until a safeSpeed is received from rf, it will publish safespeeds + //with this name + m_safeSpeed.sender = "XbeeNode"; + m_safeSpeed.speed = 0.0; + + +} + +XbeeNode::~XbeeNode() +{} + +void XbeeNode::sendHi(const ros::TimerEvent& /*time*/) +{ + if(m_coordinatorAddress.size() == 0 || m_coordinatorAddress == "--") + { + + std::string sendData = "HI " + m_xbee.getNodeIdentifier(); + //std::cout << "SENDING:" << sendData << std::endl; + + m_xbee.sendTransmitPacket(sendData); + } else + { + m_hiTimer.stop(); + m_stateTimer = m_nh.createTimer(ros::Duration(1.0), + &XbeeNode::sendState, + this); + } +} + +void XbeeNode::sendState(const ros::TimerEvent& /*time*/) +{ + std::string sendData = "ST 0.5"; + m_xbee.sendTransmitPacket(sendData, m_coordinatorAddress); +} + +void XbeeNode::xbeeHeartbeatState(const ros::TimerEvent& /*time*/) +{ + if( (ros::Time::now()-m_lastSafeSpeed).toSec() > 1.0) + { + m_safeSpeed.sender = "XbeeNode(No safeSpeed data from RF)"; + m_safeSpeed.speed = 0.0; + m_safeSpeed.header.stamp = ros::Time::now(); + m_safeSpeedPublisher.publish(m_safeSpeed); + } +} + +void XbeeNode::processXbeeMessage(const std::string& sender, + const std::string& /*networkAddress*/, + const std::string& data, + const bool broadcast) +{ + std::stringstream ss(data); + std::string msg; + ss >> msg; + //ROS_INFO_STREAM("Xbee NODE receive:" << data << " -" << msg << "-" << m_coordinatorAddress); + if(msg == "AK") + { + ss >> m_coordinatorAddress; + } + else if(sender == m_coordinatorAddress) + { + if(msg == "SS") + { + m_lastSafeSpeed = ros::Time::now(); + if(!broadcast) + { + m_lastTargetedSafeSpeed = m_lastSafeSpeed; + } + + //if I'm receiving targeted xbee safeSpeed messages, ignore broadcast xbee + //safeSpeed messages + std::string speed = "0.00"; + double timeDiff = (m_lastSafeSpeed-m_lastTargetedSafeSpeed).toSec(); + if( timeDiff <= 1.0 && !broadcast) + { + ss >> m_safeSpeed.sender >> speed; + m_safeSpeed.speed = boost::lexical_cast(speed); + m_safeSpeed.header.stamp = m_lastTargetedSafeSpeed; + m_safeSpeedPublisher.publish(m_safeSpeed); + } else if(broadcast) + { + ss >> m_safeSpeed.sender >> speed; + m_safeSpeed.speed = boost::lexical_cast(speed); + m_safeSpeed.header.stamp = m_lastSafeSpeed; + m_safeSpeedPublisher.publish(m_safeSpeed); + } else + { + ROS_ERROR("XbeeNode: something wrong with safeSpeed received over xbee"); + } + + } else if(msg == "GC") + { + ++m_prevGpsMsgNum; + /*if(m_prevGpsMsgNum==1) + { + ROS_INFO_STREAM(data[3] << " " << boost::lexical_cast(data[4]) << " " << + m_prevGpsMsgNum << ":" << data.substr(5)); + } else + { + ROS_INFO_STREAM(data[3] << " " << boost::lexical_cast(data[4]) << " " << + m_prevGpsMsgNum << ":" << std::to_string(data.size())); + }*/ + + + if(boost::lexical_cast(data[4]) == m_prevGpsMsgNum) + { + if(m_prevGpsMsgNum == 1) + { + m_msgLabel = data.substr(5); + m_gpsString.clear(); + } else + { + m_gpsString += data.substr(5); + } + //ROS_INFO_STREAM("GPS correction " << m_prevGpsMsgNum << ":" << m_gpsCorrection); + //m_gpsCorrection += data.substr(4); + } else + { + ROS_ERROR_STREAM("XbeeNode: received gps correction number:" << data[4] << + " out of order, expected:" << m_prevGpsMsgNum); + m_prevGpsMsgNum = 0; + //m_gpsCorrection->data.clear(); + } + + if(data[4] == data[3] && m_prevGpsMsgNum != 0) + { + ROS_DEBUG_STREAM("Rec'd complete GPS correction, " << m_gpsString.size() << " bytes in " << + m_prevGpsMsgNum << " xbee packets"); + + //allocate new message, fill it in + std_msgs::ByteMultiArrayPtr m_gpsCorrection(new std_msgs::ByteMultiArray); + + m_gpsCorrection->layout.dim.push_back(std_msgs::MultiArrayDimension()); + m_gpsCorrection->layout.dim.front().label = m_msgLabel; + + + for(size_t i = 0; i < m_gpsString.size(); i++) + { + m_gpsCorrection->data.push_back(m_gpsString[i]); + } + + //publish correction into ros + m_gpsCorrection->layout.dim.front().size = m_gpsCorrection->data.size(); + m_gpsCorrection->layout.dim.front().stride = m_gpsCorrection->data.size(); + m_gpsRTCM3Publisher.publish(m_gpsCorrection); + m_xbee.m_port.tick("RTCM3 correction"); + m_prevGpsMsgNum = 0; + //m_gpsCorrection->data.clear(); + } + } else if (msg == "OD") + { + if(data.length() == 62) + { + processXbeeOdom(data, sender); + } + else + ROS_ERROR("XbeeNode: Received incorrect length(%d) odom message \"%s\"", (int)data.length(),data.c_str()); + } else + { + ROS_ERROR("XbeeNode: Received unknown message \"%s\"", msg.c_str()); + } + } +} +void XbeeNode::odomCallback(const nav_msgs::OdometryConstPtr& odom) +{ + m_odometry = *odom; +} + +void XbeeNode::transmitPosition(const ros::TimerEvent& /*time*/) +{ + if(m_odometry.header.stamp > m_lastXbeeOdomTransmit) + { + char temp[16]; + std::string data; + data += "OD "; + sprintf(temp, "%5i", scaleAndClip(m_odometry.pose.pose.position.x, 500, 0.01)); + data += temp; + sprintf(temp, "%5i", scaleAndClip(m_odometry.pose.pose.position.y, 500, 0.01)); + data += temp; + sprintf(temp, "%5i", scaleAndClip(m_odometry.pose.pose.position.z, 500, 0.01)); + data += temp; + sprintf(temp, "%4i", scaleAndClip(m_odometry.twist.twist.linear.x, 50, 0.01)); + data += temp; + sprintf(temp, "%4i", scaleAndClip(m_odometry.twist.twist.linear.y, 50, 0.01)); + data += temp; + sprintf(temp, "%4i", scaleAndClip(m_odometry.twist.twist.linear.z, 50, 0.01)); + data += temp; + + sprintf(temp, "%8i", scaleAndClip(m_odometry.pose.pose.orientation.x, 1, 0.0000001)); + data += temp; + sprintf(temp, "%8i", scaleAndClip(m_odometry.pose.pose.orientation.y, 1, 0.0000001)); + data += temp; + sprintf(temp, "%8i", scaleAndClip(m_odometry.pose.pose.orientation.z, 1, 0.0000001)); + data += temp; + sprintf(temp, "%8i", scaleAndClip(m_odometry.pose.pose.orientation.w, 1, 0.0000001)); + data += temp; + + /*ROS_WARN("[%f %f %f][%f %f %f][%f %f %f %f]", + m_odometry.pose.pose.position.x, + m_odometry.pose.pose.position.y, + m_odometry.pose.pose.position.z, + m_odometry.twist.twist.linear.x, + m_odometry.twist.twist.linear.y, + m_odometry.twist.twist.linear.z, + m_odometry.pose.pose.orientation.x, + m_odometry.pose.pose.orientation.y, + m_odometry.pose.pose.orientation.z, + m_odometry.pose.pose.orientation.w); + */ + //ROS_WARN_STREAM("Sending position:" << data); + m_xbee.sendTransmitPacket(data); + m_xbee.m_port.tick("Transmitting pose over Xbee"); + m_lastXbeeOdomTransmit = m_odometry.header.stamp; + } +} + + +int XbeeNode::scaleAndClip(double number, double range, double resolution) +{ + double scaled = (number + range) / resolution; + if (scaled >= ((2.0*range)/resolution)) + scaled = 2.0*range / resolution; + if (scaled < 0) + scaled = 0; + return (int)scaled; +} + +double XbeeNode::unscaleAndClip(int number, double range, double resolution) +{ + return ((double)number * resolution) - range; +} + +void XbeeNode::processXbeeOdom(const std::string& message, const std::string& sender) +{ + //ROS_WARN_STREAM("Received:" << message << " from:" << sender); + nav_msgs::OdometryPtr odom(new nav_msgs::Odometry); + + odom->pose.pose.position.x = unscaleAndClip(atoi(message.substr(3,5).c_str()), 500, 0.01); + odom->pose.pose.position.y = unscaleAndClip(atoi(message.substr(8,5).c_str()), 500, 0.01); + odom->pose.pose.position.z = unscaleAndClip(atoi(message.substr(13,5).c_str()), 500, 0.01); + odom->twist.twist.linear.x = unscaleAndClip(atoi(message.substr(18,4).c_str()), 50, 0.01); + odom->twist.twist.linear.y = unscaleAndClip(atoi(message.substr(22,4).c_str()), 50, 0.01); + odom->twist.twist.linear.z = unscaleAndClip(atoi(message.substr(26,4).c_str()), 50, 0.01); + odom->pose.pose.orientation.x = unscaleAndClip(atoi(message.substr(30,8).c_str()), 1, 0.0000001); + odom->pose.pose.orientation.y = unscaleAndClip(atoi(message.substr(38,8).c_str()), 1, 0.0000001); + odom->pose.pose.orientation.z = unscaleAndClip(atoi(message.substr(46,8).c_str()), 1, 0.0000001); + odom->pose.pose.orientation.w = unscaleAndClip(atoi(message.substr(54,8).c_str()), 1, 0.0000001); + /*ROS_WARN("[%f %f %f][%f %f %f][%f %f %f %f]", + odom->pose.pose.position.x, + odom->pose.pose.position.y, + odom->pose.pose.position.z, + odom->twist.twist.linear.x, + odom->twist.twist.linear.y, + odom->twist.twist.linear.z, + odom->pose.pose.orientation.x, + odom->pose.pose.orientation.y, + odom->pose.pose.orientation.z, + odom->pose.pose.orientation.w); + */ + + if(!m_recOdomPublishers[sender]) + { + ros::NodeHandle nh; + m_recOdomPublishers[sender] = nh.advertise + ("/pose_estimate_"+sender, 1); + + } + odom->header.stamp = ros::Time::now(); + odom->child_frame_id = sender; + m_xbee.m_port.tick("/pose_estimate_"+sender); + m_recOdomPublishers[sender].publish(odom); +} \ No newline at end of file diff --git a/autorally_core/src/xbee/XbeeNode.h b/autorally_core/src/xbee/XbeeNode.h new file mode 100644 index 00000000..120bf556 --- /dev/null +++ b/autorally_core/src/xbee/XbeeNode.h @@ -0,0 +1,104 @@ +/********************************************** + * @file XbeeNode.h + * @author Brian Goldfain + * @date May 17, 2013 + * @copyright 2012 Georgia Institute of Technology + * @brief + * + * @details This file contains the XbeeNode class definition + ***********************************************/ + +#include "XbeeInterface.h" + +#include +#include +#include +#include + +/** + * @class XbeeNode XbeeNode.h + * "xbee/XbeeNode.h" + * @brief Publishes ROS messages from a Coordinator xbee into system + * + * XbeeNode is designed to allow an alternate wireless communication channel than wifi, + * and receive messages from a central coordinator that can send important information + * to multiple robots at the same time. The current data sent over Xbee is a safeSpeed + * message from the runStop as well as RTK correction data from the gps base station. + * Also, each node commicates it's current status to coordinator. + * + * @todo Make return statuses and such more visible outside of this class + * @todo Maybe add more information to message to coordinator? + * (current speed, heading, gps location) + */ +class XbeeNode +{ + public: + + XbeeNode(ros::NodeHandle &nh, const std::string& port); + ~XbeeNode(); + + private: + XbeeInterface m_xbee; ///< Xbee object, handles communication with device + ros::NodeHandle m_nh; ///< local copy + ros::Publisher m_safeSpeedPublisher; ///< Subscriber for safeSpeed + ros::Publisher m_gpsRTCM3Publisher; ///< Publisher for RTK correction data from xbee + ros::Subscriber m_poseSubscriber; ///< + ///< publishers for odomoetry msgs received over xbee + std::map m_recOdomPublishers; + ros::Timer m_hiTimer; ///< Startup timer to register with coordinator + ros::Timer m_stateTimer; ///< timer to send heartbeat to xbee coordinator + ros::Timer m_xbeeHeartbeatTimer; ///< timer to publish safeSpeed into system + ros::Timer m_transmitPositionTimer; ///< timer to publish safeSpeed into system + ros::Time m_lastSafeSpeed; ///< Last receive time of safeSpeed over xbee + ros::Time m_lastTargetedSafeSpeed; ///< last targeted safeSPeed from coordinator + ros::Time m_lastXbeeOdomTransmit; ///< last targeted safeSPeed from coordinator + + + std::string m_coordinatorAddress; ///< Xbee addess of coordinator + autorally_msgs::safeSpeed m_safeSpeed; ///< SafeSpeed message to send + std::string m_msgLabel; ///< RTCM3 message header from xbee + std::string m_gpsString; ///< buffer to store incoming message data as packets arrive + int m_prevGpsMsgNum; ///< sequence number for received message + nav_msgs::Odometry m_odometry; + /** + * @brief Send startup information to xbee coordinator and wait for confirmation + * @param time timer information + * + */ + void sendHi(const ros::TimerEvent& time); + + /** + * @brief Periodically send state information to xbee coordinator + * @param time timer information + * + */ + void sendState(const ros::TimerEvent& time); + + /** + * @brief Update ROS system on state of incoming data from xbee + * @param time timer information + * + * Sends error safeSpeed message if no data is being received from xbee + */ + void xbeeHeartbeatState(const ros::TimerEvent& time); + + + /** + * @brief Parse a message received over USB from xbee + * @param sender identifier for xbee that sent message + * @param networkAddress address of the originating xbee network + * @param data message payload + * @param broadcast if the message was targeted or broadcast + * + */ + void processXbeeMessage(const std::string &sender, + const std::string &networkAddress, + const std::string &data, + const bool broadcast); + + void odomCallback(const nav_msgs::OdometryConstPtr& odom); + void transmitPosition(const ros::TimerEvent& time); + int scaleAndClip(double number, double range, double resolution); + double unscaleAndClip(int number, double range, double resolution); + void processXbeeOdom(const std::string& message,const std::string& sender); +}; diff --git a/autorally_core/test/CMakeLists.txt b/autorally_core/test/CMakeLists.txt new file mode 100644 index 00000000..5b0cec89 --- /dev/null +++ b/autorally_core/test/CMakeLists.txt @@ -0,0 +1,9 @@ +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") +rosbuild_add_gtest(test/diagnosticsTest diagnosticsTest.cpp) +target_link_libraries(test/diagnosticsTest Diagnostics) + +rosbuild_add_gtest(test/serialSensorInterfaceTest serialSensorInterfaceTest.cpp) +target_link_libraries(test/serialSensorInterfaceTest SerialSensorInterface Diagnostics) + +rosbuild_add_gtest(test/pololuMicroMaestroTest pololuMicroMaestroTest.cpp) +target_link_libraries(test/pololuMicroMaestroTest PololuMicroMaestro SerialSensorInterface Diagnostics) diff --git a/autorally_core/test/diagnosticsTest.cpp b/autorally_core/test/diagnosticsTest.cpp new file mode 100644 index 00000000..92697287 --- /dev/null +++ b/autorally_core/test/diagnosticsTest.cpp @@ -0,0 +1,259 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file diagnosticsTest.cpp + * @author Brian Goldfain + * @date August 21, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief Unit tests for Diagnostics + * + ***********************************************/ +#include + +/* This is an ugly line included simply so that I can verify that function calls + * with no return values can be tested without subscribing to the ROS messages + * they trigger. + */ +#define private public +#include + +#include +#include + +/** + * @class DiagnosticsTest + * @brief Wrapper class for SerialSensorInterface for unit testing purposes + * + * @see Diagnostics + * + */ +class DiagnosticsTest : public Diagnostics +{ + public: + DiagnosticsTest(ros::NodeHandle &nh) : + Diagnostics(nh, "nodeName", "hardwareID", "hardwareLocation") + {} + + void diagnosticStatus(const ros::TimerEvent& time) + {} + // virtual void TearDown() {} +}; + +/** + * @test Diagnostics initialization unit test + * + */ +TEST(DagnosticsBasic, initialization) +{ + ros::NodeHandle nh; + DiagnosticsTest a(nh); + + EXPECT_EQ(a.m_name, "nodeName"); + EXPECT_EQ(a.m_hardwareLocation, "hardwareLocation"); +} + +/** + * @test Diagnostics unit test covering the control of the overall level of a + * diagnostics message + */ +TEST(DagnosticsTest, overallLevel) +{ + ros::NodeHandle nh; + DiagnosticsTest a(nh); + + //set overall level + EXPECT_EQ(a.m_overallLevel, diagnostic_msgs::DiagnosticStatus::OK); + a.WARN(); + EXPECT_EQ(a.m_overallLevel, diagnostic_msgs::DiagnosticStatus::WARN); + a.ERROR(); + EXPECT_EQ(a.m_overallLevel, diagnostic_msgs::DiagnosticStatus::ERROR); + + //force diagnostic publication + ros::TimerEvent s; + a.diagUpdate(s); + + //check overall status is unchanged, then change it + EXPECT_EQ(a.m_overallLevel, diagnostic_msgs::DiagnosticStatus::ERROR); + a.OK(); + EXPECT_EQ(a.m_overallLevel, diagnostic_msgs::DiagnosticStatus::OK); +} + +/** + * @test Diagnostics unit test covering messages added with status OK + * + */ +TEST(DagnosticsTest, okMessages) +{ + + ros::NodeHandle nh; + DiagnosticsTest a(nh); + + EXPECT_TRUE(a.m_diagMsgs.empty()); + a.diag_ok("check"); + EXPECT_EQ(a.m_diagMsgs.size(), 1); + EXPECT_EQ(a.m_diagMsgs["check"], diagnostic_msgs::DiagnosticStatus::OK); + + //force diagnostic message to be sent + ros::TimerEvent s; + a.diagUpdate(s); + + //make sure queue is now empty + EXPECT_TRUE(a.m_diagMsgs.empty()); +} + +/** + * @test Diagnostics unit test covering messages added with status WARN + * + */ +TEST(DagnosticsTest, warnMessages) +{ + ros::NodeHandle nh; + DiagnosticsTest a(nh); + + EXPECT_TRUE(a.m_diagMsgs.empty()); + a.diag_warn("checkWARN"); + EXPECT_EQ(a.m_diagMsgs.size(), 1); + EXPECT_EQ(a.m_diagMsgs["checkWARN"], diagnostic_msgs::DiagnosticStatus::WARN); + + //force diagnostic message to be sent + ros::TimerEvent s; + a.diagUpdate(s); + + //make sure queue is now empty + EXPECT_TRUE(a.m_diagMsgs.empty()); +} + +/** + * @test Diagnostics unit test covering messages added with status ERROR + * + */ +TEST(DagnosticsTest, errorMessages) +{ + ros::NodeHandle nh; + DiagnosticsTest a(nh); + + EXPECT_TRUE(a.m_diagMsgs.empty()); + a.diag_error("12232"); + EXPECT_EQ(a.m_diagMsgs.size(), 1); + EXPECT_EQ(a.m_diagMsgs["12232"], diagnostic_msgs::DiagnosticStatus::ERROR); + + //force diagnostic message to be sent + ros::TimerEvent s; + a.diagUpdate(s); + + //make sure queue is now empty + EXPECT_TRUE(a.m_diagMsgs.empty()); +} + +/** + * @test Diagnostics unit test covering messages involving key value pairs of + * type std::string + */ +TEST(DagnosticsTest, stringMessages) +{ + ros::NodeHandle nh; + DiagnosticsTest a(nh); + + EXPECT_TRUE(a.m_diags.empty()); + a.diag("key", "value"); + EXPECT_EQ(a.m_diags.size(), 1); + EXPECT_EQ(a.m_diags["key"], "value"); + + a.diag("!#(<:""", "@$($@&*^$@"); + EXPECT_EQ(a.m_diags.size(), 2); + EXPECT_EQ(a.m_diags["!#(<:"""], "@$($@&*^$@"); + + //force diagnostic message to be sent + ros::TimerEvent s; + a.diagUpdate(s); + + //make sure queue is now empty + EXPECT_TRUE(a.m_diags.empty()); +} + +/** + * @test Diagnostics unit test covering the correct behavior when multiple + * messages are added of each type ( [msg,level] and [key,value]) + */ +TEST(DagnosticsTest, multipleLevels) +{ + ros::NodeHandle nh; + DiagnosticsTest a(nh); + + EXPECT_TRUE(a.m_diagMsgs.empty()); + a.diag_warn("warn"); + a.diag_ok("ok"); + a.diag_error("error"); + a.diag("blah","junk"); + a.diag("xawfe","junk"); + + EXPECT_EQ(a.m_diagMsgs.size(), 3); + EXPECT_EQ(a.m_diags.size(), 2); + //force diagnostic message to be sent + ros::TimerEvent s; + a.diagUpdate(s); + + //make sure queue is now empty + EXPECT_TRUE(a.m_diagMsgs.empty()); + EXPECT_TRUE(a.m_diags.empty()); +} + +/** + * @test Diagnostics unit test covering the behavior when multiple messagges + * with the same msg or key are added, only the most recent is maintained + */ +TEST(DagnosticsTest, mostRecentLevel) +{ + ros::NodeHandle nh; + DiagnosticsTest a(nh); + + EXPECT_TRUE(a.m_diagMsgs.empty()); + a.diag_error("test"); + EXPECT_EQ(a.m_diagMsgs.size(), 1); + EXPECT_EQ(a.m_diagMsgs["test"], diagnostic_msgs::DiagnosticStatus::ERROR); + + a.diag_ok("test"); + EXPECT_EQ(a.m_diagMsgs.size(), 1); + EXPECT_EQ(a.m_diagMsgs["test"], diagnostic_msgs::DiagnosticStatus::OK); + + a.diag_warn("test"); + EXPECT_EQ(a.m_diagMsgs.size(), 1); + EXPECT_EQ(a.m_diagMsgs["test"], diagnostic_msgs::DiagnosticStatus::WARN); + + a.diag("key","old"); + a.diag("key","new"); + EXPECT_EQ(a.m_diags.size(), 1); + EXPECT_EQ(a.m_diags["key"], "new"); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + + ros::init(argc, argv, "diagnostics_validation"); + + return RUN_ALL_TESTS(); +} diff --git a/autorally_core/test/pololuMicroMaestroTest.cpp b/autorally_core/test/pololuMicroMaestroTest.cpp new file mode 100644 index 00000000..3528bec1 --- /dev/null +++ b/autorally_core/test/pololuMicroMaestroTest.cpp @@ -0,0 +1,60 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file pololuMicroMaestroTest.cpp + * @author Brian Goldfain + * @date August 21, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief Unit tests for PololuMicroMaestro + * + ***********************************************/ +#include + +/* This is an ugly line included simply so that I can verify that function calls + * with no return values can be tested without subscribing to the ROS messages + * they trigger. + */ +#define private public +#include "infrastructure/PololuMicroMaestro.h" + +/** + * @test PololuMicroMaestro initialization unit test (empty) + * + */ +TEST(PololuMicroMaestroBasic, initialization) +{ + ros::NodeHandle nh; + +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + + ros::init(argc, argv, "pololuMicroMaestro_validation"); + + return RUN_ALL_TESTS(); +} diff --git a/autorally_core/test/serialSensorInterfaceTest.cpp b/autorally_core/test/serialSensorInterfaceTest.cpp new file mode 100644 index 00000000..e192c05c --- /dev/null +++ b/autorally_core/test/serialSensorInterfaceTest.cpp @@ -0,0 +1,108 @@ +/* +* Software License Agreement (BSD License) +* Copyright (c) 2013, Georgia Institute of Technology +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/********************************************** + * @file serialSensorInterfaceTest.cpp + * @author Brian Goldfain + * @date August 21, 2012 + * @copyright 2012 Georgia Institute of Technology + * @brief Unit tests for SerialSensorInterface + * + ***********************************************/ +#include + +#include + +/* This is an ugly line included simply so that I can verify that function calls + * with no return values can be tested without subscribing to the ROS messages + * they trigger. + */ +#define private public +#include "infrastructure/SerialSensorInterface.h" + +/** + * @class SerialSensorInterfaceTest + * @brief Wrapper class for SerialSensorInterface for unit testing purposes + * + * @see SerialSensorInterface + * + */ +class SerialSensorInterfaceTest : public SerialSensorInterface +{ + public: + SerialSensorInterfaceTest(ros::NodeHandle &nh, + const std::string &port, + const bool queueData) : + SerialSensorInterface(nh, "nodeName", "hardwareID", port, queueData) + { + } + // virtual void TearDown() {} +}; + + +/** + * @test SerialSensorInterface initialization unit test + * + */ +TEST(SerialSensorInterfaceBasic, initialization) +{ + ros::NodeHandle nh; + SerialSensorInterfaceTest a(nh, "portBlah", false); + + EXPECT_EQ(a.m_port, "portBlah"); + EXPECT_EQ(a.fileDescriptor(), -1); + EXPECT_FALSE(a.connected()); + EXPECT_EQ(a.m_data.size(), 0); +} + +/** + * @test SerialSensorInterface with no queuing unit test (empty b/c there is no + * serial port simulation) + */ +TEST(SerialSensorInterfaceTest, noQueueData) +{ + ros::NodeHandle nh; + SerialSensorInterfaceTest a(nh, "portBlah", false); +} + +/** + * @test SerialSensorInterface with data queuing initialization unit test + * (empty b/c there is no serial port simulation) + * + */ +TEST(SerialSensorInterfaceTest, queueData) +{ + ros::NodeHandle nh; + SerialSensorInterfaceTest a(nh, "portBlah", true); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + + ros::init(argc, argv, "serialSensorInterface_validation"); + + return RUN_ALL_TESTS(); +} diff --git a/autorally_description/CMakeLists.txt b/autorally_description/CMakeLists.txt new file mode 100644 index 00000000..6b332e08 --- /dev/null +++ b/autorally_description/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 2.8.3) +project(autorally_description) +find_package(catkin REQUIRED) +catkin_package() + +install(DIRECTORY launch/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch + FILES_MATCHING PATTERN "*.launch" PATTERN "*.machine" PATTERN "*.yaml" PATTERN "*.urdf" +) + +install(DIRECTORY urdf/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/urdf + FILES_MATCHING PATTERN "*.dae" PATTERN "*.stl" PATTERN "*.xacro" PATTERN "*.yaml" PATTERN "*.urdf" +) diff --git a/autorally_description/LICENSE.md b/autorally_description/LICENSE.md new file mode 100644 index 00000000..37ec93a1 --- /dev/null +++ b/autorally_description/LICENSE.md @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/autorally_description/launch/autoRallyPlatform.launch b/autorally_description/launch/autoRallyPlatform.launch new file mode 100644 index 00000000..96d5ddf5 --- /dev/null +++ b/autorally_description/launch/autoRallyPlatform.launch @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + diff --git a/autorally_description/launch/autoRallyPlatformRviz.launch b/autorally_description/launch/autoRallyPlatformRviz.launch new file mode 100644 index 00000000..2099c4c3 --- /dev/null +++ b/autorally_description/launch/autoRallyPlatformRviz.launch @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_description/launch/rviz.launch b/autorally_description/launch/rviz.launch new file mode 100644 index 00000000..f6a01a16 --- /dev/null +++ b/autorally_description/launch/rviz.launch @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/autorally_description/package.xml b/autorally_description/package.xml new file mode 100644 index 00000000..e20d462f --- /dev/null +++ b/autorally_description/package.xml @@ -0,0 +1,41 @@ + + + + autorally_description + 0.1.0 + + autorally_description contains the description (3D model, + kinematics, mass, etc.) of the AutoRally platform and other models + associated with the test track. This was developed from + ackermann_vehicle_description. + + + Brian Goldfain + BSD + + Brian Goldfain + + http://autorally.github.io + + catkin + + joint_state_publisher + robot_state_publisher + rviz + xacro + + diff --git a/autorally_description/urdf/autoRallyPlatform.stl b/autorally_description/urdf/autoRallyPlatform.stl new file mode 100644 index 0000000000000000000000000000000000000000..598f0748e12cd94c3a69a326ddc5e1682f2ef236 GIT binary patch literal 353984 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%0DgNT=`IOU9(|c(!$ZG6bnCf3j}ow|DdU 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�Q_27Gu&u%l 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 E3e;;F( z7p3rNuSmSO|32lepNl}LN(*xtbvBF^YwqN_LIU$cTFe9Mfu%xPB!u5$?a{RZ6;J=O zRHg-m6d(>}Eo)?0H%hFBNeC%Gw0>64sMFW^AB2zs#L)-Mjf4X+|3L^TKzz#A&Ztm0 z`acLE1&E-nosEG$QU5^*DL_=*;A6}f!{6>{c{_JQ_UDv^6d_WDPbDw~ ziF)J4(5vm)n)VxA-OMwRuD!$d!B`5?|9?c-kYL&*V&gY7dn0t~Nukd!-YJ49NO2|e>9kWS{_f4W~V=c zJ*7uu{Yn47BLo8HK}b8Cx%1c3e($)CoESDp#uOxu*6nGG%^N}wzvJy=;>Rjl>-U$* z{!{(rp&mUA&!ZvK{X{%Psh}<0j5#Gj=>(bYi{^bS-Je1NQ>nTdj4Q_3u`*A4E_mC5X zS{Bq+9xWlak7*(=uh_z<8aIp%)7DdzQjaz7I2X|yW~8_4bas>uP1>lqoV52wLF8z@R;Yf{nZ z)pR)RwUqg?v$S?nt(&2}Z1l+^4~ng7{CV^p3NNz<}Y zp;T~z7b)xOMbQ;?I58#nwd8Ac6uHCNa&mInkQGIh2_5EMS^TQmeTWcEUn6703hvfUTQcl$uajGS$m?FkVlJS$5LvJ zcG9+5JVl!A8Z@huob|~8vMVl7Ab3fhKOIGXZ5B_FX6uiXGf5r0?j}yZ5E)aDD0%N# zO5=H>Xs0f`eRxGQNX{~4EoqTssGQ}{ixh8vCw;Iio}yI0_b*Zw_>ZFVTX14i^QFmI zKTRX8mkyUZ-OpppS`kO9gvV2qDv>L%;l9mDX9N+&sx%Av2z{x#FB^#++d>bYN%Je}L4k2p3$^>VNN{wt$?~etReX{X{4NWR!c)qiKOjn$5WJQezB!d z|6UZml8+OcGnP<89TkYwC0Z_$u7lB|WdyBODW0NKOv?_&yAF}`Xzu^V*n2=lk-T4^ zV^+*Li#g}K!gSlMf*B(Uf+*$y2qGY;j5+5VF(6_>5HK-SMVZC8=A6Tt)0)$(9!B<- zzxRLV?Kz&ahrV~JyQ;eCtNVpE7*%doATC#ODzh!)RjpYcK4j7uEwN0jhA3rXA3m>l zh;}58!O&vrk+kw}%-XN3#_*n_$;07ul~RkwNMnwuH!WN8 zV|T}D$s-NMly!qh#mcLc;Kb3=yh7BcWzG1B%n@33i@`X)%bh&1#wgWx1WI!kQC0iZ z<&CnA)67c^#f2gQW2TJcbqGm0Ao0|2-1g&pLV~;wvHpV)z-)ALStXH^} zAWB}ZqWmXV>*Rl=TzxiBV&J-hY;mHeA=Z!0la(2RH}27HjP^Aq zRzuXRi>`cbaEKO@W-zKY*-WyJJFcvc8LoCK)RuRf7ODl$6|vxes-LYT|95AYmT9ZO z=-_W5&f}AnrI-CxoPCJGIcBmH313AC?jUJ%lTtd`UYiFK$ z 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 EAFfwK + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + transmission_interface/SimpleTransmission + + EffortJointInterface + + + + EffortJointInterface + 1 + + + + + + + + + + + + + + + + + transmission_interface/SimpleTransmission + + EffortJointInterface + + + + EffortJointInterface + 1 + + + + + + + + + + + + + + + + + + + + + + + + + transmission_interface/SimpleTransmission + + EffortJointInterface + + + + EffortJointInterface + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + 0.000000001 + 0.2 + 1e+10 + 10 + 0.01 + 0.005 + + + + + + + + 0.7 + 0.75 + + + + + + + + + + + + + + + + + + + + + + transmission_interface/SimpleTransmission + + EffortJointInterface + + + + + EffortJointInterface + 1 + + + + + + + + + + + + + + + + + + + + + + + + Gazebo/Grey + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gazebo/Grey + 0.2 + 0.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30.0 + + 0 0.07 0 0 0 0 + 1.3962634 + + 1280 + 1024 + R8G8B8 + + + 0.02 + 300 + + + gaussian + 0.0 + 0.009 + + + + 0.02 -0.07 0 0 0 0 + 3.0 + + 1280 + 1024 + R8G8B8 + + + 0.02 + 300 + + + gaussian + 0.0 + 0.009 + + + + true + 60.0 + camera + image_raw + camera_info + left_camera_optical_frame + + 0.14 + + + + + + + + + + 30.0 + + 1.3962634 + + 1280 + 1024 + R8G8B8 + + + 0.02 + 50 + + + gaussian + + 0.0 + 0.007 + + + + true + 0.0 + camera_side + image_raw + camera_info + side_camera_link + 0.07 + + + + + + + + + + + + + + + + + /autorally_platform + gazebo_ros_control/DefaultRobotHWSim + + + + /autorally_platform + /imu/calibrate + 200.0 + imu_link + imu_link + imu + 0 0 0 + 0 0 0 + 0.00000001 + 0.00000001 0.00000001 0.00000001 + 0.00000001 0.00000001 0.00000001 + 0.00000001 0.00000001 0.00000001 + 0.0 0.0 0.0 + 0.0 0.0 0.0 + 0.0 0.0 0.0 + 0.0 0.0 0.0 + 0.0 0.0 0.0 + 0.0 0.0 0.0 + + + + 20.0 + base_link + base_link + gpsRoverStatus + fix_velocity + 33.774497 + -84.405001 + 309.0 + 0.001 0.001 0.001 + 0.0001 0.0001 0.0001 + 0 0 0 + 0.005 0.005 0.05 + + + + + + diff --git a/autorally_description/urdf/autoRallyPlatformFrontWheel.stl b/autorally_description/urdf/autoRallyPlatformFrontWheel.stl new file mode 100755 index 0000000000000000000000000000000000000000..7884f6c80acbe4d6097a24aa312fd1c17c1a5b68 GIT binary patch literal 244984 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 literal 0 HcmV?d00001 diff --git a/autorally_description/urdf/autoRallyPlatformRearWheel.stl b/autorally_description/urdf/autoRallyPlatformRearWheel.stl new file mode 100755 index 0000000000000000000000000000000000000000..9503f33b563b94ac14796b993873d3b14b99c337 GIT binary patch literal 244784 zcmb512fSTV+W)T-Eg~fID#0kZCvq6QCfu`kh~5SXK@cV+N|Xda+D3FSGD^&lD7l#E zM7`Xzmu`sYqKq~Zbw=;6!T(v$S?FXa4uY$F`s6d)C^kKI^ylUVEP*yKTGX zpnY~5gef>o~ntk{F z->0jOUp#qf_g*QE-Ix!*Py4i;dxJk;F1>y4&iTQDN&ZsWzHn{ZphM%P6*=s97FPs%`^FrJ^dAt1W9ZO0)_2zx)ZoAx|1if%xh?f`NDqs7Djq?Qq*1mq%{ccGY+w?9a z=!Nq_TzLO_`6qvG(KH_JaZUQ4J=>L_7tRau*^R%=XMVI({@dMOYu&2HCF$vxKB)w~ za9)Uy-&;Qa%X0f@8W)Z{D}DK!=arxr&I_^4$&2PYZZ}-g7}mFKhhx*^h}V^%7tRYY z?~@Ozt4|!MY5aTc@6(mvc~=Q~;k*!i-g~lo@9jtDkL)|Hb;>52q_6J#p%V1Mc_H5Y z>c;9TubiN1?DKxFwD%MLR)StQFT~Y@ jH;mQ6wW{-OJ{p5;%Un)T_oEPHA?{}>} z{`P57gV(k0{dsG0__%MBpcl>yF=FCU)j{`7%D;Hw@aBEa+##9!*YA{|7tRZD>C@-7 z-!Nv15bw`k{`{$x|2+DAEmw6q#d#roE0=*suUsruBj|+skF-_M?`Q%o*^ul=|q&_OXKK#{49XP8&df~hfQs)(4 z=TaZdQqRs>3B7P$2x(Up->!Tb(w3aHM0(-85Yl!lzU@xfuBBPptFzWlFPs-b`bXmX zhfhQLgtHz+FPs-b`e5Swpo|P9>37b0ExmAF2=Z>D$gm272MV5Hgk|HkQcv z;cWDw7tRYI<5l9vE1!mpQO-s&1&?*c_CyT zOl%&MxzE|mNiUoiLgw1U&$YgEWqx%wJJSp2g^>9?vH4u)aA&ary>MO#i82yI8P1{? zdP)3X=Y^2iC-Je5&y_?nE<{U?UN|p=#8-)ruRI}fl=J@$5t7j<&ew?+?-_n8_XNFg zzMd;3LQa&R7tRY2uDs&Y2v@5Fy>MQLP`XNl5_KV3@+IwQA1(QM^5=yJHK;_WH6`eU z^FoAHqC{vJO3(}Eg$OON((Rs0n?vhUf?hZ;L}=|5KRbsOt^~bs-V?PRmH4s>y+{dq z;k*!`*D4WusuJ|Vc_G5cphOrAl%N;R3lT;iCBlfK1if%xh%mw_5k@s7=!Nq_gi$mJ z(UKo`m7rG`QT=%#!bq)Ygwa_Edf~hfVK$I7G+OfWhZ6J(Gebxt%s84xm}Qip7tTu> zVOC47`l`qEVJ1_8UN|pAm^n3#Fk31?FPs-5%+AS#?b@5ejI0E`a9)TI0VH#(w>O7b zUkQ5QybuyC`6wgtQAUU?l%N;R3n9^xk7R`Sx^IYHYPqUKHU8K~OFkyj<04w}SDuN* z$5%?w3+HQT_=wE6lG&2FkKv3kI>q_gb@-?++5M?q{FVDSQ3-nCybvL>Or9Q-`O@{V zs1o$Tc_BjdYBlKNT_xxxbz|p+2obWR(NvOp_AzxWSMb7lAwm>xEz!sAO3+K%n4K3Q zMEcT7G+Od&110Ds?byx>5mpnLhV%)){!oHmI4?w4u}Hhx&__#tjiUs;a9)V8D$+Eh zZ~JwW67<4(A;QYbx2t9uKm1xv33}nY5MgzvX~-Dm*MmyX3+IIhD@Y||9Q12WCFq6o zLWEVS5;E5Mb*&Qg!g(RWN>~XQ&;8n233}nYCu*y0oug#V@auCW=!Nq_gcZHbYF-0S zf?hIT*?A#?YEap9qb0AGxzFniO3(}Eg$T-orXlmI*D{o#7tRY2)DM|Cf72>6y;o8+ z0-zVp3lTIKO+(@Yuk|QFFPs-5C`B!z6g5jM;x9Nv z!7GtbjhYpYg)rUci_4ael%jAQo~G{Oiqft62q2VC>eIk+8cJHv7d2SDZTqDnr3hYW zsLeo7_n`&HX=pKlpzcEpj?>U8jezb$3y#y!@&iHLhZY>Cp?3v>x(_WlPD2k4gy}xM zbZNnH8b*mgnC{c(KmTr}1;=R^i2`A|k57XZ9H(Kl3xw%DkKVri^|atP4I^qGO!x6= z(1PPMjM{-P-KW|#pp_OJr(tFYgy}v$4O(!VhS?_&ru%f?c@ZD`6iN|}(=ZPPBFvn* zPlFa5r(qTigy}vD51Q0U3y#w;QwPFypGUv{eWVn@%VLH=nC|nt!{7CqOraFvn7WVj zTFHI}-N(lw`dcA-@y8bX)YDMiXR&ub^xBe-ij1&hpQ}O-Dk8Fc@fVNv`c+}UvA^;{ z4=SR*{E4x5MM@F8eCZZ?P!U0_V5f@9wj3q7c=`}kHu3yytjFZ7@y($8m94xLR4j(v|R^q^ujq1QnRj(x8!^q^wJ zl24xZRx>R)_9H`~2NkO#O@kI3`_ZS+gNl`x613phk8p(^RIKilpasW%6fN|iVg;!L zEjacgb)g3pt5hXu!LgqW3Oz_88P$EVN3+?q;MmVNg&tI_wyQ_qb44pHIQFwzp$8Q! zdYw6G!Lgq?3q7b%4V0h-$EGucUQ69aX5>OC!m+NH7RpC0IJWw5J|-$^(8q~cr~|d&*y=nG(0#H{&uYQ3wW~mw?&H%4ZAmRSwzeAx z(|x41_YLh;EjYIRVMNep7ndG(yyuEL?bq*ROmG zXSuRtixUH3y3d&At0JXHuG~~3i$w!ry3b{QTCT5@XrUD0*w>)xK5`wV`^c3y(Sl=( zsY4p3`)o7oG=E>s$JA=Uv5%Ha_mMPA_wi}af@517gfvX|3DJ@%LQYz{9s3?t=s|Ve z$EQIHj%|$-(lFg8L`#KIB)!&-{m4-0L3Q27r$GyjZLJp4Fx}_dOV=yOh*Ky(;xrr7W`v{=W zgX+4^-JjhZDMj$|QHCix(%Mb;@oCV4W9mLanC>G_A@!B$rBI4+?4u=n3P}k0>8$o| zmItrI&ob~zpWO9@^y9aV2+u8vxBtuJpL|vKeA+zw%Swo;e0oYZBs>%m;X0IH+NPds zG7<68>d&PM7db%*(#3UX8nloIC9QN!&_ZIhQS;Irewf>U2=$!$E2r0ttDj1bnDSWz zBD5tX=(YR2N7Gdo_SW-pu0nfN3%&06x;HRO z-S)XX9XoSm10wWowa{zQtQ*oz_ny>%2;+xZ=ygf=ndz7V&Tl}3F-k4;>Uraz(pC1k ztN{_mLAB89`N`*`r%t`P0TISpwa_b!+I2#kp>Mk+m>%i4?XstazEVYB$^CKHL}-cX zMLKRJOoL+y>4M1ob*xbtN~FOJ$V5n8ws z^y17A6QPAGK`+ieF%eq067=E>7Zag{D?u;LqA?L#xDxc@OdS)Ug)2cXMguVs+Ncur zV#HAp(&Dq6(F^JSju^Y$`1GrH|ElSc)-X%1 z{qRom%uRn&f?kZsW8%H_uTRe1;8`W;#i&0f9_X=8a`ZLNDM2r+GV0@%mhPgv-Ba1* zXT6uoRSMTQHA1{=F~jAreA(W8yB9PKu5skptHXL;b5#(_eZ69S#R;`E=*3l7O#FEK zIr&%T&DYK)~jbWtCj2x%p@j!sDz*P#S0Bo=($#~pO+BlYXZ#9jWfoE8$&j=fIZfcWc- zE!^cpA5sgws363-dUDsj+}J_)C_yjjk6x#4kj6zH9py%DeXCmNMI|Io~-n}M9(j-bqi-q zRSUgjocB6)17eT=x!Enh<_T({m&_$zr*1%Ox$j(e*8Kg{LNA%GyiVPKc>KmT_x11= zwa`oEM6XlV32h?2mB{?+^=P$_Zb)dmBC%Q1!>;wSwK~ypYbPNQfLF7XARX5^EhM_{ z_k`R0uifg`k@*Yp*Fg&jiBa&(op<&Ao>=etr`?kWzhIF};U#g9*TU=3Ql@|qFE4!7 z%^iBVTIeN_n%BY`5O=Kby!&#=&DBCLSrvILyaDlg{}XuM@tkc#HD?vIYXdw~CnEG}2 zT*+US(?TMQL=A{A!l{K`VYF*Ngi%y2^a>+t10synYN1ycwHpv&Hc$(_!pzWs2s4ga z=oMz421J+NN;)wSVmKv87lfpf<+P9p@niiuYL_7dEhIve z*?l+Z%cSv_4q}|rWcIqWmKd6dm+bsxMWR5CSXR0DGL5s{$rgEoLMPh;$ znU_pSPpOK;1T8ZAm|CAw6^RL2Wd5)_0x4CIn4m@G54-D-QWc2_T4esPdmbrOk(i)G z<`27jk~UN(q)xJ&szGR1&c`Cu2I4em32j#iY6CGrOXwd;P#cH|T0$RGg4#e#&=UH& z64V9?!Z+WXmN1qmL2V!=XbIz$64VA_f|f9HDnV@^CTI!ct`gJ+VuF@1wkttxASP%D z^OX{v*5|(0%3r*84zsfoTp`D4&=Mj5CAdP430gvwp#)dRF+od+WR&0vIVNb~N|-C; zn4pC#VXly4f)=iXxk8Q!TDTJC3OOcd3DK)wIakOrK?_&HT;nQHt8%Gxt{}N;%^F#h3i4C6JvrFt{S;cj0sw}9^^W)Az^p>{F+nOZCoeD1T9<-a-A3xv~WGh zbz)4=!u256i7`P7*MnRq#sn=~4|1g!6I@4eRm9a&Owhtr5m!qwK?_$!TrI@}EnF3G zwG}HA76$!nFa{ z3^73q*9KfO!~`u|8*t4K6SQz`z^FeaLNuvm6=G36<~`_`pjU`@mEe8un4njPsg>Zp z^q8Pmh})Im{rZ@oS6CY;!Dj+uf?i?$p#+~hhzWXyHI5Q|wjn0y71mKo@cD_DpqI=a z{`ni7qxg(QL1+xeJL`OIMP^a|JWF0EkVOPQ3kg0mQ>5X0R06_3hg>{=6X<@DM*J*J zf?V;fE!U9n*AWpi*A~waG3_E(od`S=;7G>=EhIuo`?9KChm}=A3kj@{I}o7;o&PO* zVTIg*z zSRr>H!sw#}y|6;=Kw!P>=!La&2SOr?;#o&}1-(SmF4~p$4-!m|v=ZX&|FR^sMBlev z=qo-hwZ5X~i!?eBp(S>ryCyJ}IMM}?`CQRL0;5m8tdyXI1jexr1jar`FN~EP2#l|e zUKo!%5E#SlsmaurF2?*01m=mz3-d|`0&|h07v`=G1m-(OFU*e}2+XODUYLVB5SX_e zy)e&rAVM3}@}XB~(|SH`yU-0C=}v^STmP3OBoK>4bkPz!5r||Q>4M078nlo=Ow{4Z zX(54Fs{?_E%$~s3@ zj$Vl2I}nKU9lfwl=s;jK;omo~I}P^kLA@nvqw;l*6-(q5^s)v7?y>k>`8OieE9hkn z2&|X5yDTOw9lj&wspTRRD?+akJX?VSj$2Oa5{poIihmi7A3G-x4# z6>A3q>ssI1i}ysaD(*mF?d*G$f15|^K>8!z0F~^7zbwJ}+|diG`wnS9190?`@d|H% zS_-~hL1%FElJU_$SrfMs0kZ^JhNG8^!FU6dX+SUWBX!{=<2>E~B>_#w&jy8;%q4gO zlmzad`x&S3lKBd6fRcbBAakv1m$vp9Uq)acxwkFOkRZR8bl*nof{Y}cV)p%fYr zP@S!;)GL&<>zu1lgKD8ysLcjMXeDZ)S7>hyh|osWLa)%;VS@UD`@cAi(9hM2wANszfDp8hz#WJVbxsS3FcQ^sRZBwB!2J&!uhc7yb`1#JW3e$& zy~2pvfWUnm8+X+!jM@zd+$*xNUA@B0(15`GD4RdjE6hF(2;B3sIZD044A+3beKng0 z)ho=R4Tvy1ck&7|bps+q0BWIEh&~z+xO3J=i{1_bURTfD1Y zlAgT>Tg#Qda{0>=+^M#hS_vsbdk?k)fxF=rw<{s_;h(H&kSpAAx3xhnSJB(DK07{7 zK3BM_Z|e^wq>UBt#K!f3CkJeeqeNICHOLj7POx>9dWE%G10t;MI(dbaUIQYmAk{*z zuzIZ%wF{Rkr@lkFA(8pAqFy3%RBHQ~QWYuYS|wCe!30kNDP#cH|TEgh8X;2%830lI~t^~D#n4l%hS4wbo z9}`?Vb0y3ba!k;|l`vPxF+mGg!dxN81T9<%bA=oev~VTN6>?0_!j&*r$T2|+SHfH& z#{?~033G)U6SRcrRcnwd96$IA|F+mGg5L`3F1T9=a zaLo`Cv~UH%HA6vUhya|AKe>Y7njt1=32}+iTr&o;yay}~+52|hm&6ZDe#quAMo&uAziEnO?o zo=DOA@_cSZW;p+3P10F`q=f{ZnJJfcd}T_q=DWRHzTV;0zP$I3W81SvpR8%hUYasF zIepAqEeG#?bu+wpCqKpcv`*~xZO;-cBzP>u-LFna?s;#^$_g!WoADe#ier18#a}rH zUs_n#c15_R?4-BGCs%jRbk`xQYqlS#8aR08W-dlN;ya9+~*<$wc|eScakS@vevjCHNO ziJ}C~3o&Ecy^@{A_fFal>vlcXwe}{85;!l!2fcPkMsKjT--)dW>sosgMG2f2V!;~& zl3qPFQUdE*dlN+ooEPH3n|_x(-qeyD{Pj=GSn=AMC`#bG5bIs~+hmI$cG5I($KBpU zQ3B_M_;yauWXwPJQ37k{lwLS5gj{g4VD3T5T9fu{#o9Tg7tRZD)V}Xj4jg`j5?DLi z+b)_boEO5K(OxMQLb^9G#>Gsnp z$!jyOY{uF-r5DZ%vB6EH%1zfy)LdchoYD*DJ#pRrEo*-}*|)1!tesPO;k*#LeQ?P( zdwn}4S?_~=`(o{!(hKK>c+?%#{?DtY`0JRBwR1`@oEKvK-iuUs`gW3D2iDFhy>MQL zg-h>JZTtQ-Ei0_5Q+naN5U2ilZgq>BPfj-9^X+Eb+qT^(w9au}h>fPw9p8LTvrg=hfHNKg_q1zF430S#Ws@Cyri+)Rx9PZUc84ASf8i#!g(Q9d$5%ESbaMsus%=eh4Vr@ zFk;hu)b(2^f%SPxFPs*yw)`$-n#hdmY=ca!=`n^Fq9}@96yQpI%i0cac+i z;k*zhOgb)~y72Bw+hJ!lLjy?Zh4VrjHu9wWgEyyZ8qfezdf~hf^A|fU-(s!dm7TNY zOV9vPdf~hf7Yv=0zdW+HrU4Bgr5DZ%vF^|*`Pe5f(XTE*14!wG^FlPq`$RHY`w=^X zI*`%}=Yo2sfX-mORtcOJB8(+UKxeR#K?$4} zB8*o`KxeSgM+ux4B8-VjKxeQKP6?bBB8R0Apo`dQLJ6D~BCK(gfG%Py z7A0_Ah_H_GZMOtn#8yR0;JgrFt>%eV=pwfAQUd3N2-6?_dLWDJ^&IZs$ zYz3(V&I=LNwN+UaHA5G%RjLv=FGN^7YZ}l+Y$dD&&I=LN=Sn~qvDLQDgE%ilPz|bn zRTPv0?`11`C2(Gdpk=g+meCrN2|w$bYM=zp3la2^_FdK*Gdrj%x|c7#sJ0YDOZ%`R zsj!%;qI679nV^<|V=5DAQMwgB*Fuf3vP$Hds7wf9%EVij4Q+)QVfB%Ef{I1aN;C~x zaBT19cv{jhWy0qQnuWD1O#{k=5T;DLe#!=smH{sZWkLv3CVqF^=8={GF9&5p2r3h_ z;Mm^H3D;rDguf1G7S_-8I-pEQ8m3Gvy4LBDmH{umJs<>?38)b^UTGT89E6a}s50Sm zMGKA{lnEhBnK9P>E(H_96M+ZLYOk~*4`r{EdyQ- znu8FgO!zct!LftpAcQFsi!6CoD=j#-Cw@b_qA~$B!q$UYAJ7~m4O1q3u4uurgXSQF zDH9Jay-Z(PaO|Kt2w}>EPlFa5J7^9dpb}i>S=goBBKSzmMe{LitF&vQU=YUD`i5`FlFL*CoF$GG>fj32_a0G@M%D^ z=t`Lo!jy?$-aNY%nnhR2gb+|BGH4cEDHB4NGU0Ot&B9uu^N|dc2_a0GSaRpZ`_h7A z>rtK-!juW01~iKl$JT2D5&C(4V~_JAEra?6lnF@#%0xyBj&1Y_X+W9CpjmXKOh_6~ zCNgLiT`3bnm@?t79GXQ}%7hT6OnfnGp+v~_y^3*cvq88HQzp*5?(J4+7F{V5l7=Z0 zK3C8zx>6>DFlFM*58jHj4C)t9CWJ6$;?Ez z*Usz<&7v!1LULuw#MB-4nGMaND`i3mQzlkP7HfuP(UmgciJ(l#by&2d`K5jVWkLv3 zCb|#4D$+9GWl>+aa#JR5+vCn=XciXrc`u7B17XU9&lNO_6vr052EvqyLw-Ck(lV%D zK$(#1ke^m%Vw;6~Mp_2E9Fz$ms7%m;V~g}du1uNm*8$DKB7MDbC=-%~DHHR*{U*{f z;AJb8kOq|rXco3&(KMh;NE)V0_*~I~V_SKJG)$S;4Y#ln=;{Z1WkS+0WkQ~rxE`8CSIUGCrcB6_9J8TD*s~aVH-m~rQ?}UE%e8O! z+7wlaUjMphdd93{+FOr5$*uB_htfHdTdMvT=hJej3nC?fVZalUIJC4plhu3E2W^4?ZM^g4#^a#i}&$wTyaHy-?HGPN>0_vzt$Ok}i>z;TVp zEe)~c_+5we?0nZmD(Mvjj)jo2O02Bp3UicCj&if}T@$I4XhGmu2&wbL>Rf6nM?E{# zznzbX3`8m|qabiBgtWvKYrE3o9NMcxJGS#(6REWDg21s5*St9>zjl*#l8skdr0ul# z=I6T)e@fdca_D-DcsE}#?e64=BQ8qHr5iVF$#)+AyJXx-SG8R{@u_@^N9L=AUic+R zE|=V>9{EQ{3{6h>>ftt8NHjHFobP?q zkKxLnNPnvCwcH`eHkT!B@N)EeB$<>yF?12_|K-w?lE&AP#+u`X4kW?!NS8}1%5}8K zb?m(OCQ%wF1xH%GKPY9jzm(O0bnrl0NW^6|M(X1WsgEfet{&AO3Dk!xmu{0f-&5-R z+P|$gkoC;pjfpk(**U*+&EM)+!nTCtl)qFi&6JinOIqUbGmeVVAb~WbT|FfAv6Ixt zQop&4rJJG-(ztZh4SB_0W_{iV$}NmlsVmdQrH zUuWRoMm(5|zUK|K&6qAdhd#+0yX=-uJ{d{w|5Qtd5rY_*Ckn|FMTgHAn*WA=fcq z>b$$u`OQmQ(Z+h_@5V&0;e(Uw(`M`E7VofKIsTH)ILS5A5;xj$l_(AA=SDlEA?@lJ zsgI#jA0xKe@Bx&SLmjxdbg!KCRAuZrM<@HWZZ?1x64F1C&}-$&|FPv0m1Cq2{$|;^ z55Oy`^O*Q&ASB$)K*(%R{4S3rjmiHyApd;s;`xQ$2erL3;g@{f1!rqa#W?7>zkicI zebtP-Hu`*Z-l2JAz*p4)e|x6wrWY179pmLX#;i6tN&}_fNS8~eNm<<> zWp&+ihYqBLL|j&zN`2fe^|AaGJ47`|0`(!S{THe8-K5Sp-f_f0)-!)MCeGS#-+cA| z?Vd|ZY+_r&amrsRmrjzF__4Ia=FzuDX^=n~(ysn2^|6@L$91>OVdU_V|rsVrhyQ%&2)z)o;m!lV=S1GGh(s)(U=>MBN z2a;fVq|2o}C5^o#jZdflg#;tyG$yWkcuKy+9h<05O$%~DT5@&zzYa*gl+r!B+tdM4 zib?3_sg$m*qtd|-{+v|Ob3;GhVEX9fgI`{$zIxTF1OB?h5^37|_iCXReo4~UvN}4M zEA8r>WhQMUZ7B`?+>wrn6HXbIoF=V(zm!bIyr! zMdFGZx~CURUN&6E4d0%Y^pIAv_Id9QfLBT{si!pbT4`5JA&s8re)j+gUI*!N$*yC< zYHw{t0@sw1u9wxz|9by^T1cR*Bv-yZ-k17V?C@z1untJa#G=yo>AwH zzf^A}%kQ>Alm-c;A$5MEln^n_Pj!$Vx0~)AB;>ei>BYq7XOF5L zJbb497QN*9s&;)!_{-2VpjkN54G9nBB(D40>(vS4F4y!(7in}NCV#$K{_AlUC_%bw zVwbyi%CBiTRSD8v6PTkMX(i;U{a<_?`@L|Y8~NBAtwGXV6W`u?pxdecT}qJdnxM`^ zy10(a=ZY2*BMu+r4xjaarWX^mkhrx^Klk`*t^q*{iJiV$+CB7_#~To|khrk#8~G2* zKOGZVy0nlO+V|>wR{Q-8h>^+F`5C7^s}_14+-qq5{fZAZAP(!XWB%N8r8zx?Hu z>VL9_8W6LaXI98^8kjT|gSChuv7|JeH7PdZgoA@ydA}yuO&Ah1bFKl&BT1lrHa>OkDPFZtc51N;+Os z*TiS{&vWB?-lhcUu8HO$&$;)PI$R0TT@%;6@w^*z#_L+5q`M{#-Q@-M*{OrHHc2ay z)h<20@~5wR-tG17;@a9t7lcqTvC%INy5knpNtIxHy>X0k{V#K}f z_XqB-7JAJZHQPP*dP@Uh>g3zp=FOwjLNDCs>@Z$!HurjW<^5BXpw~moT;<-Fa6yAK zNH9Ip#g%KFvj$mftf!cuh4sODiV0d+AFQXCpoR6pdWs2JSRbsXn4pFA!E#eV%E|v_ zIoBCK?|ZiUWYRUA>ZWUgYYx&yt~3qK+nkY~fBB4b--Bj1sB>CKNSzmV`-?O(e;qA5 zUX)Io@@LC?;q~}WSETR1d{I3O@%Dc)!Sp(%k$HDdNQtJ_56)ce?)00@hjvOY&J~GE zhCY~1nKMuc(gmTpA|Z92T2Cb%6SR=H^3sRXkNd9C;L2$sA+0iv#u9(!@|Wd1yzoT& z@4qdozeO);`Drv>WeNy!`Qp!{51;Xjj%4(b-jzmUVnKY_e}3Biu#0U>EWD%#r_s3U z3Hdk6Wpqw$1|Z#u5TG;Bci{8sc8ioXJ<@UMG7UUU<4DH@EhLWF{Dt(Caf37_iV0ds zOjzZGw6y&629XRcB*uU6T)O$PgObj%4=p5qnE7lvY{#n_5VVl!zTMO5B3mtJK+r;h z>X%-*)Smy#@^#;MJiT}7QfY{HOs#Xg$5xb8<_SEXD5< z5vP9tK>ALPR0+~u6K7AmE8TqL0ZNeWni#zKO=-^=A3Wb8!v7^3_dAKAKd18wb1Lbbq-F?_{S9uh~thJo&KTsZEB&{v|o2jFW>)~21Nf` z_DJtr(&JurRObnV*{f5+nc6q{QQtw=yl1nE2pn4xFsesU%GFtv2wcWe;!c_ zy`<>VC7!#p0kOyW-zNjUe^M><`sw+HlEEK7Qzyh&8{tSWJ<@S2;cURMonwAX(895u zV}4A~!Wp3JahH0#tlJV<>FH{s>#>A{tN{~Q1L{~yI&QlpaEHc`F0LcY2T#W<+A4o%~e=SL;4%owf&y}H&iNH9Ip zaT>gGUI(u)CTQVxFujUbzO4B1NawJND0zi6MVjebU|o+@H)D$I=$t(on8o| zUH$2lu8HrCf42I@2hS@(x@$rbbvD+LRzk|j|7AHXa-twA-4DsPJ@&c!xSM%@PtYPK z3ZmTS=KT40=QSW`Au;sn_w!E&{jC8(3yF_r_jF?}f2>Z3u{ImfLPBOA7tK)x@%eS@ zxeFIo^|$CHGn|X&!Gie5Lp!*Io8GSky<`@3(Og>)mp?ng{bAZ2O3+JYY8TDt1(Du$ zs;m4|n}z8m(SVC$hJtvx^<4MCxwAA4dP&6LqPV0W`nO%;zTfszCFmtljkCz9Xjhr9 z^Szgu<<{BqJSFIbr=#m5gA&uuxzUaO=rkqhwPEQFcWv*(^n8(qHowF^( z1TCy{){PQcw*ERed)>3oV{Xl!D|D*=t_fEf>4KfX?*`$j!v~)?x++HZ=q`M|$ zZqFsE(b<4>*M!XaxkNQeknWn`Oij8V^vW6CiN>DDJp{WWP^>0nf)OMMQSKADXVGA_ zEoD_a@kuYaJCMlzmOA0zA;0hcv|Sas zBEe@;V}ceE@^nHX&o*d!F@Yy={WA=O7oTn|N;mVlBEj@X7ld91>w~4sa*GN6mOP7* z$deqJ_fENz9QnU2r-cNchmEhC783HbNM*vf%Nvvx;~jd*edmfi4O1sHOFmbOib!`N zGLLwIxndfmi?Yf*!TW$x=ee}2+^a1T>34BQkronC>ctZo5C!KGDq>0;|Q9z}f`@~28s@xBs?wgvaO)mPXlo@+Bta2DqL z+K|vRSniBJ#Tc*X<%Iv!T@ecliKRYVCRyo{S|nSv#LN>noN{`y-jnk+zw#3W-HGrC z$X`rQDG*~p7d4o9f=U5(4XP9|K`&}2R6=5cUesr(w!{Rzr~y&Yi3xg9XQFBp6ZE2% zMP(``s2fu8ZM+V#g;|0wQL#A)yz1c~1+ye_@!=rffr2u*|c zIY@U+@UF~XKH4XJbn@N$yPck_(TnicK?{jj_ZX0#e{-W}qxf78>6o~6*5G8}7k%}a zRQ5Z@S2!uc?_@xz=6vvKHf4Q{uUe(HgzmCaY zTV#h;SW+B2X%sH3qos5$jbU$oJ{w+4Bcki|vETD!)WIeSuHT3EU` z7Q*V|$&04EQFP=?^Y-)mMD*fkk+1~f285P z-BilWG=2YeuAO&v;;mWd_oamdj)jo^k^BC!%8)CYX~D6t8`Jb9S5hCj?;j`k`Ow#g zS$r?DW8d;k(-%VOBlrEoUpXwk7ZqMoAExOGA@z}m{&6iVz84irs)eIHCXliW9%8*`~G1ThvQU!te9)- zX-(ym?~l5$21OBcsNSba$U@Z*)$K~%aZX(6mW zdjIn0R$5rPI2OX{!{>??TsiAQ2rFGrpsZ5)e=AWQ3(@n|VM(`rmrBH=iIF9rfWY~* zPMp5hGuP2V0>?s>9y>G{I^xU9@z=G@rUl22&uElON4FiBy!OuXm3N<5vlW&U#}3bd zAdQPZym~ggQlt^lU8cd`<*}qO_pIZS{zGoBym{;&TA4bI9iL|@mv&wKYrL+NpbA>%uKn|{j}4P_y4$0<)nLCTVY9Y?D$+xxisSPNy*dcvX%E{zt9RxietxT zvC5_0kDZd7H}Tw-%Ft1LVM%f9_s+0A2V9--tppYle(wwrU6mED9LG|+R#u<($)d92 zmE%|lE2|Yxzbh&$UOA41u(G=3zEAto!YjwI5Yj(#^bd*fS^O>)cHY&Azt32w znHCZ_7DD<*?)%3bn;h6o3yyu;wdYwRSJFRn-#_--cVu5!d@m}zct5h9hK!=k@N!5a zqU&j#{P+Dyr1)JP%XLVd=e~dJ^3E2`@bbOLo{jM>-=2Dr>ySFneg7DI;&5N*X7Rnq zj(y9w=UIf1I?sLoxZ;eY85ZA*3NNWyd+J39sq@_TkDqqv+YF2EMTM8txjhXdg!GTx z_m6$nS#vflz84iwSTPX-}!%L@C&)M`8ojnLdcbCeH^*{e19EQ2P`Xxk``j_DHD^qpRLex+KHuV z*v+c4%z|+#ob`X3kf{KCb_!!oKuo@$8YY5DlH^zU+>y=+;QcJ$-D<9Dgmv>_6ke9 zm+kRgBlbJ;xMcd!Yn6af6nWVm-!W>ab))vS{M398Z|p-ffzO?dx45Zargs6nH~DqyKqa8u z*IWqf_fD*RHca6B~i5|%hG2DL;s)zlvMlbf)ci`ca7M-+k=%8?mS8fsI@7* zY+vsh@zk6vDjU3fyb^dS%=T#1G;ELW8qvGk(UmFpoTLPFW7`K(3ES7ZMtm}{Z{?jm zPE`UrwS5Ic3ES7ZMy$H|y)D_56O@30ZC~0@!uIv95l??JeVe_nn5YC4bK5gh3ES7Z zM!fXu0qu(ot`T^W!}jG=!uIv95kEcrOZ#G1pQdTxNe$@kw2l(Edv9MKQo{E2t`S?Tv2*^%f3BMHR9Q}lk&$8Ude?|U7C9|n;-nRnz*}av2euNnuXl~u{(mRr z!(N@PF$3N*vwgOeu-(6F#9P-*^g3VW`yk#jD|Y|(Ube4ylt#NJ@Ge>8WqW+rh;SWM zPvA`?%T?~ZY>)365z0ylyonTf*&g3DBGiWxcoWG=SJSXPzH3CNb0zR5lGUK|Ube?~ zjR@^Z3A~9EdD$M{H6pZKCGaMawM0$B_Vun2p?~DQtniMKwRRs=$lSfT{(PTR89-n_R6KndI9yGDe#LzH3B?6P3Vj3l{Y$Vf%X5h!Be^fjhhwSt?=sde?{$ z?<#?NzZShJVf%X5h!9gNfqTssAuD0~de?{$w=02r+ZKf@VS9Ynh_E(L0&f6Xq_2eS z>s=$l`a=o4acHXvC2WuH8WGkwO5h&7tyq+>eZ6Z$SVt*=yZ5##Qo{E2t`T9arUafA zu$7k*wy$@M2)36 z5!TL1;2jfN2`gdyde?}sK34+onAmDt=Rw=!yG8^JKnc8kVk>$jY>)365tIpy0Pt>K zvHQ38vOT_QM9@o=z`K2smwjcdMy!AB#AM|8A8#%5V1=p*>6pleoSb}i;E0MRsAW*U zpkg8Wa<-n3S60}gipkh%j-E+;}$*o!U#9uir)Gw%5luMf}wo`KGzI~LSh57{*i*hMH zV4Gy+gZnE%3-t>s7Uj~1_imW1bk^od&_ex!ibc6}UjMa|mmV0T1TEAr@H~^~SJj7m zC%^t{x7u|;%blcZUdxS8f)?r*R4mG+KG{>1 zPZ#Q%vqB4%2`U!lQnxd2s4RWd&_ex!ibc7!-+;8z zZHZGf4O*yQP_ZbNj^F-^mMvdX4WL2`^$RK%<dY?lbS9 z%`U1Dv{1jGVo@&b-Tqkny~n9uQlW+V1r-ZvSGTWQZCyk)nF=kDeo=obMcUP$R~uU$ zxTESm6>1sOFQ{0QOWXCmsyc3a)s`x>P`{vJA$v!Us#bqqRQ0P0Ez~clSd>dU-u6y) zvvUvA8l;8#1r>{OX~U;~t@eIrea_QiIub!W~ z@%Bp4Lj8h@MY%MqeZBm?odzgD3-t>s7Uk0QbGFK_8vQ#ZXrX>V#iCr=;_AWq;n)3E z30kOMP_ZbN4!mg3{G_FpSArJm7gQ|Dr3s_=&v(A9NeNo0Ur@1-9<}CSdE4*b)3Kcv z>K9Zj%B3rAIx=5xWv2u!)Gw%5luPgZ=eT^}J2RD_h57{*3;80#awp~eZ#+o}TBu)8 zv5?*IUq2=Pb;k{qpoRJc6^nA|kHaS9CpFFU%0z`0>K9Zj$9PcGAguCzo23vx%&FF{OfKXD?tnO3n~`n(vq8;B5wz6Q}t=kLj8h@ zg~SY{6Z3Nyo~{Hf)Gw%5luLhk@z~t`tyKwHs9#XAkk&qEbiUL}PbfhP^$RK%<=A^5>S@PzhS7Ur@0qmp$LczF9jF8?)Gw%5luNx=f4zF=8Y7jU zh57{*3yJ!!xv%=j@S~NWh57{*i*jk(4KAzBJ>&!>XrX>V#iCpq{mCDy6W2Uh30kOM zP_ZbNR@-T{>f=|Osst_6FQ{0^9@sbC*#6n06O^EZ`UMq>a%qosHhgG>t0yW!3-t>s z7IKI8r|~VzlxqYn)Gw%5$i38=OH@ui>@-b-7U~yNEF>;DcaO?FyN_3b7U~yNEXt)% zZ$H2C-e+T#poRJc6^n9d;$gQ|Ufgwz60}gipkh%jUAO*ol^(|&p#&||FQ{0QOM@4F zUde|YtOPC8FQ{0QO9$P$WOCbTLzSR~`UMq>a_Nk@D<&I0wu=(9P`{vJQ7)bJMRU^g zphO8;s9#XAD3?a=wMlZ$cbh0d3-t>s7INi}Rg%)RB_(K~enG{eTsn8FU6Q%SuA~Gl z)Gw%5$U17)kfeF+QcBQ5{ep^xe68T)gOaZ&f2m_TEz~clSd>d2bw486eZlie&_ex! zibc7!^H0Yl|62KWC1|03LB*n6I^?#o$%5lARDu@j7gQ{yN3A|SY3;MO60}gipkh%j zeZK8!$p%|5qXaF~FQ{0^^H+T)CMWN3rbYm?P`{w&5cQ}k`iDc0a_DKUDT6v#A%Pwh z(M=ipV3Y=Wmm@7-wyxbj*H%Ic3G_$F6?$!z782;2LZH`H(Ni70&^LuZudSk|I(ngR z3V~i*MNf6~Lf;euy|#*;>ga{ODFk|L6+P9_3w=`v^x7(Vs-qYBrV!}0RrFLxFZ4|z z&}*ycsg7Rgn?j)1R?$-(z0fy>K(DQ$r#gC}Zwi54TSZTG^g`bh0=>41p6cj@z9|HH zZ52J$(F=W32=rQe{;DdvVYCMsdaV%96RY-}K~K;NI-?MHV$0I-&v-d{;VCO2@cfls zN8$;3L75Z+nx&PM67+&HDFif2s}CjU1!YnQXqHyzsm~R?piBw@&C=SH67+&HDFif2 zYr9I&3(BMr&@8QgC_yhMlR`kVv_7Z=y`W4A0nO6-xf1k(GART!OB+j+pcj-$A)r~> zc%=lrpjiq5&CF5PzQV3|4Rp^wCUQi~5fM!{RPU+|c zWl{)emR0DKj$TkEg@9&Rg-+?{1!YnQXqHvzl#X6dCWU}zS%psN=mlj`2xyj7=#-9L zP$q?dW?6+!>F5PzQV3|4Rp^wCUQi~5fMzKpwSJ*nTOz%nObP+bvI?Ej(F@9?5YQ~E z&?z0gpiBw@&9Vxe($Ndbq!7?7tI#POy`W4A0nM@sozl?@%A^p`EUVBd9lfAT3IWZs z3Z2r?3(BMr&@8LaDIL9_ObP+bvI?Ej(F@9?5YQ~E&?z0gpiBw@&9Vxe($Ndbq!7?7 ztI#POy`W4A0nM@sozl?@%A~)Jx@K90PU+|cWl{)emPTkKLoXoT znG^z=rCqra^nx-e1T;%4T_xxRWl{)emR5t#=ZaoXCWU}zX{|&FdO?{K0-B|@L?!42 zWl{)eme$&ppcj-$A)r}Wk5YnOP$q?dW@)`v33@@96at#1jSNcA3(BMr&@65AQG#Aj zCWU}zX(OBx^nx-e1T;$$s80!c#d-;zzp7AGfy&uI zVZpOe6>1q&Ca736Wq3BKLJO4%Di%!{o{g%|LS=%AMN@`nqbjsenV@3Pl;PQ^3N2J7 zs8}>*cs8m+3zZ2f7EKwRjjGT>WrB)DQ-)`wDzs3Upkg7hPwjmi)!}HNGC{>c`bX`Z zA0=p^GC{>c)&{lrij<&*$^;dQrVP(URcN6yLB&G)NA3M6O@kIH6I3jkGCUhqp@sSd zv_;=*Ywwb&0!a&%2`Ux^(cfg~~+8t*Qydl~;Tkv{0D{B@zg{ z8CIc%%0wvjK;X?Vs}HqMnFuwT`dFf9C7LT*s7!>`69~K+R-uK;L};Obz?)$eTBuBf zUJwYp8D{-MEmS5#PYVRz46{C{7Ag~=HwOZ5hFL#X3zdm5Vgv$jhS^x67Ag~AR0;&% z472e{Ez~c<$QKB_8D?XmTBuBf(KQfwGt91E?3zZ2f7EKx646D#WWrB)DQ-(LgDzs3UpkmRK z;mxoLEmS6`STtpLGps@jl?f^qO&Q({tI$Gaf{KOINBzyP3N2J7s8}>*cr&a*3zZ2f z7EKx646D#WWrB)DQ-(LgDzs3UpkmRK;mxoLEmS6`STtpLGfYP6x|Ts@f{H~`hBw11 zv{0F#Vj;>z{mrlnEmS6`STtpLGps@jl?f^qO&Q({tI$Gaf{KN#?&@!bRcN6yLB*me z!<%6hTBuA=v1rQhW>|$5Dic&Jnlii@R-uK;1QiQebJpJstI$Gaf{KO2yY)B2Dzs3U zpkmRK;mxoLEmS6`Sjb(O`kP@DTBuA=v5-Dke>1E?3zZ2f7NW4!-VAH@Mf5eK1xuTz>`%%;LR`_;gp~< zfhVhkz?)$h23c6exCuOyUl$B3|781jvvRY2+ z<2|Vlp9U=vQU5ZnT*n6ge7w5$s>dj?@cgEv_t}5ySZk?#7r?%LD@6N=OXWBId6*Kv zblWi5@2j(vpclR?BgEp#y7`S8CQ5wNHY_>)*rS!8m+a+kU#Jn{@p^%TL&HmJ;DQl%N-OmG`+?^AGvo zH~Y5|p{x?02EDM`ybu@6*eyTi-Bog*t56?G&Tz*bn?J_bb5&EDK^pgH>U%nAS`gx1=b0hrtp#;68Kib!IgpgiakzQ-Ls>;Zz1ikPL z9wDUHR;1S|Ay=MDuT_Fx_?m|h(rXjxwMt0o=F)4GpclRiB82qXM0%|fQiHklS|#X( zFE9upy*80vtAwne6X~_q+H>i(+S=)b z?@b6Hy*80vtAzBZTzah%^pgH)Uy2q&dTk=T_My;gb>G*}YYQ*wkM=ccA*9zP(rYWB z*ZMT7q1P5((jV=M*Fs3IO{CWxTIon z3FmEiInw3QaETe(Bxdlj4+%sAj&!+nyIjYIavh$a1=rCbjbAD^RC=s6R-+}RPJ(49 z?+*&Gq!3c)1L2jDj)^0sKCYGe@VNrvP#-QP4!Hg6%6g?kHCMEdU|T4ch6qs-!siNJ zDe0J4^n#wrLDH^#u0Z&2j1=FPh>0azR!>&ywu|P977}dJ<4Vl z<74R`K35>~Yxonk!mJgt1cFw7d%-#4bYkT)`_P9TOKzKR;gjxz7~{ zhkov2;;i5An>@MrvYIPeNN|iPm!=5um=Hc!@JdO?#A0jxA^C@lS3XxD97Z)46DuEo zRMK?wv!3uVT%!@rajYztdI|Bipj#g`Q= zBqZW2<}P`!NQixe@VSClN;)PM|9(ocfy{$GS0Ef_OBWL%SM5Gmw2%nt=^R|-s@>-b zUMcCA_)g~YHkr?Tu0Z&2au(mHiiuEzp0Kjg)JcT83AqY2SoOJrmz9-z#Y8S~$v-77 z@wo!w5SLiH3TcGauDRlGkqGTL@$-Dq+BH}3vUa7v8xzwdzIs&RE1xS64)K-s!H`B6 z8FF7%{4Elp&j%um47o2Wcv&A*ub7x1apFvg6Me2gMBn6$i7<+4u4qAIY2$9lRTxDz zSMaj&O1;8}8i=JN-n~WQU7sru4)Jb>G{TIdx#Dk;2y;nDBg{COD|p%1u3jkk7l;s9YOdgA z@s)bTgy>f-qF-sQKsc-iT}*gwN%Skt6)hbIuM~w`c|z1E%@w>%zp`9`km$8tqF2oo z2p_Q)-y)N=K?LQ_a#dJJNEv$FuU=MOztUX6%TzA)iV2C3s}dn=u0S}6ON(!+#e}r0 zszk_|D_TfMd-J+h$d$CKszk_|D|q=DEb<-`5+PS5Le^Y?@DXzHWx1G;K3J6qS#w1T z3F(_&I}5pzK3J6qS#t$1-`b13$Am=4xkSjCD-h9F_+moFt6U;v%@r*Y$rj)3lX1-J zb0JqUUgZ)YYp&qsM}{KrF(DChE)lZk3WSf4i!T<&gpBREM97*eT1d#4?=`@XD;e8! ziI6o{@baT*k@uL82sxJsS#t%#N65uj7-K@_!CWF_%@r*qWPbEIW5|`vgSkY=nk#tu z8K=m5Oh|;BON6YmGYB6c7hjEx35gkUiI6pBpoN6Q5?;#;QHDgwxkShsGr-Hw&PCp1 zLL%f`B4o`K2p=IAU%!kAiLY{rkTqAdkdTPX>!l%A5?|#KA#1MSeHgMD*4Ameh2sxJsS#!nTmAEu{{NQf-&B>SutzC0P3yIK< z^CCj_tzB~kFKbtttC)}oIhP1oa|Oaj$ccQ7R&x~-VPr^rSIM5@9Y0xe7Cm<_camwyRf6NQ9hAgsiy&;Ui?bYvm*4 z;yzWm6lQ156)hyfyc=>AW@pV6ylfs+ub7YsxhfH|<_d(5kSjZ^cZHT!OoT{Ab43e@ z5Tk@#g-Awo1uu&k)GH?T-}DqPtBG)nZq+#*_bzmT%}P|E7vU$z*? z-z5>3)jX+>esUeh|Gi&SgCtNNu3WlP>ilr2^A|_%Hjwqq-;Ie`2TiGr`FOmlO>9dz zPWema((k1u9xg3$u}5x<(jb8}q+LBN^-+@RShMGjEZr1!kjAAuXoUl-_x3t1|LX?( zwb4Q%y>|7ynk^IReE8N!RmV!Mp8fuU2jJ!CB{|HkuaryMOB!vG#y2ngdjJWhM_Tq( zlQd3{G+sRL7ZNFcH;svY3ooiJ_3}x&FF7qFa4a=AY5MWW(Y==jQ+2EJ3Al8y;l zNFWZbU%8epEhG@ncOYmXfiJ(;2r1cGePG3s(hKXWdKy|EB$yuQ_{#Z>GrY}_GKXCg zcw;0b-8F%?Qc}`g6L|9_`X-VRQWv$d;&tHdn&`Vr1)*g{0&no7q>Eg2BJfSMlypqc zLIUp?)$3f-poIj!?N%o;-v{xXxRi7!LcIN7OyK>fh>pvOY2ZtCDe3siX(53(xa!xT zxuS&xzO~nZ!24q@acsnyC9p{Q^NSt7ieoDG) z0&6NCqZD-41lEQr>8=UR=cJX8`u2ZW!qoXq#ZK3eDIf$bB=8<=hgL!h3G4#afuMy1 zb~fuk&_V)l{dOQ|A%Q1z>x5i=me4|iUotG}LkT<=?7#Ha=zE79(!jIF{3;^9CfR|& z^UaYLzhoHa3eQld^x`)TV*<}<^P7|Wnq-Gu;aTv=i{Chm)4=oQ{3;^9AlV@eJkuU| z;pzAqQM6qWOiyalzEW9FLmGTs=d3~2Y;he*(84cPvSwp~7JjjkH5(JOum)MPF+mIK znKc^|wD60Stl5Il)=mrSnI&BiT2@$LrFd^5s?DwmyqgixT@x~D=eDjP-8F$HlKiTu zpbJ8;oYx`ujfyApNOw)h{jcK5Jknhgav!gH@bHK-}gmfU}er;ust!HW8=_TozcGjT}a*iVX-w{;tNXJ*sG@vb} zqzfYJICFAFCLPxYOP3|eGK>jYSXK?MLvzJ78CP4lLsu_dC1@dW+I#bp-G@Jw_!V+| z<+ul#(rfl{_a;rRzg;Kf_x)d%TzT=8$wvo&r54hih#Js=z@6BXbdjr0X*`llN}d?H zh}UOQ(gl(ET+u=T_oF*pIV~ip`^0HTo!h zBq7tRQoOgFHcUfvMFQ`JM|6>^P6XaRPf2%8;2rmrbk_vlqfbc}MCMDE*MWESQ_@O^ zcWp&a;*w`qPG4DYi?%D$1>vED782M^px&;OpoPS(3pPs6TkJ+nuec5+u$MtfuW7&T zm|njBH4O;tmypuyvULtl&-lj`4G8SXkkaeuO~<8g+<0*V0{cFs^y)SB%(UO#=QJR& zw?s;>ji0zMy`wa-0fGH1QhIGY4MPfpoIk9Uhh!4w2%;;$?f#M z-ec`R;N5wz!xdhl;<>#q|5zi=I9GT-Kc$!GjBeX4?`=R}4}g?jqH?;GKR>-r$W_-` zJN6k!=_RVFJ8qFa4G8RIkkU((VmD`Ui{7))>nPH|ehDePu=7H_UHOb9B$yuQxU5(o zEM1m*Owhv8WvRymEi7G@dQ8y5(q*Z~1T8FGmO?>jS;_d}&X{#fyYJ7~VIwN(f{;4N z5)v|YO+t$5j{G8WybJMzx&@2vc}16Wy-X> zPD9q2xvfk|7ev-ESF)nd<@qbkA?cz9m7s-$tao!;?-qn!IV~haHOO!HW?H?hMaY1m68`lT+Ad7yt6VX)r%aWKVp3#WtB3A;%1a>eJ zqD~h?Rx91Qg#>mp>(I}!YgzQWod`+P|78gY>|mCPv3S0u$dwYbkdPItvsH0HWIhdA zNMQf7dfQb()=th=y!68UXB`MxJ2_kN(hK{a)d{^0Svxsf@zM+XpLHN)?c{95OE2ty z)`5_=#f0qRIKkJYy>~j|VZYLu13HV%*;0(aD<6Mzo3`aU9c<&dx>HZ&gk$In- z1a{V~U%8eQ@5Phun&7$?JCZhDJ8M}do6o&Owht!+jZMzd&Pczjn^OAuDFULfxY`` zbuKNW)}y#mB;AnEG^h?>x3~X8XP{<5qM`bsY4DyPc1im`?ho=#E{RU}gyr}3%JcRa zJqK-ZcMsha_=>lB4jOsqtbTqcKJI#4JT;jKlyi4u(hUipOhk-*V!1)1kDI3HkuK8c zL~w6p(n?5<{9l&SLLxh=$DrX8Uefepf)*0oSve*Kp4ENOkHeQuefiLfdoIVs_?4F) z^xe1(l%N-PR*s2F`Ykc&y!ZB0f?nKNIVMKmwdkOhvyNASUagaVPVZRbTs^OZ7L+e5 z5=@VDL9ldnS4Zxk9coa|cTI%S?L^1d5o%DqLfz;w>4M1obc#C1@cLYS#Ih zEv`ce?qW`_P_qq)|Hs&w$6Gb^f4q6Fdz(xlPwd!+Op%6j&OUw;CBq{rJmy&snIhb} zhD@QzR8ka)LWETJoPCaj%0r$~WGH3GOjL&OTl;%HclX|Py%PwVe%AVaKc92< zUVH7ezF(SEgeINeJT8RGN5Q*vt!)^(N-ZXLZ z7>=jtuQKEq#qTBrLsxunRzxQiWD60j-;h+0Ekr!{(Wqcfr(ZXFWiCZtv3dlp<^+{N z%TP1V6IYHx&QMuBbX1BR&KnoX0M#@VReK=*NBK53yEOH zR-$8ew?a5}!)gVIjukWnTZmvz*(8E3M7VEgq52z|L@=W*t=xCFkodM&I+xsEWyq|# zv~s_dLgE)yX#j^{W?ovk-(w;1tBn!N{!1(On=jOSWpLMzLiII@=o%3g2NBFqOmtE~ zBHZ<{P<;(1I>|0uh+qcgB!VqOxNCbMaW{y$V*X}YxqC?=amR@f%n?m1cfTqm?rJfD zd8ldS?umuOoij!-*EOx&eYa5a-Pzs43)S-kqH9FdioS_NFdH|~Nd<{;^Pqy8=W9SPBRZ|zoU!Ph8EQZ<>pHF6 zytL?^OKLzcvpcQa+_&hSifWi4yIFYAJ)c<%(KRAWK_ZxYp6H~4M7Sr2qI>?d@rX_$ z*g^zz;3pMi3lZ)ax9Hri70)ta1%Z{sBqtOY?U{km#Eu-*i% z^b4*5p(}&6&`Q^s8W6fJSqrUnh1-m9T9owAm9vCsJFQT@%cb`JRtN{!8o|mQ96QMs z$I!Li#vnS0U<(nfJ(5JQg$Uh!Hb)-C;r=Q^Rz9JX?r=3ASY3ryx{KC;(B0WuXr=pn z4G7H*tc6yZWo$-NMnObzX!eqgeuG4Bg>Zna5v*fFbdp_;q4|}KM|2Xw79v<_Cy8JS z5t;$ocu557{Lo6X%o-4^B}6ODWNScZhHSjkO0)AC5SpJGf>xU8Z$>!vqQA;ePY~8Z z^i~Kn-x9&9O+?3BRc?vUGmec%bc`^s*g^#BN+l6&A;QHGJ*#bwJc`5pRfeo;MJvZ! z^gLJtf|avq<+O>OSZhG&DYaU`*vjc2JyX|!U~Mp3x$ju?e7+e`X<@iH-1jwl*0&a- z|2G6{lo1`X>&8ir;eLHADI(kIMTvcv4 zhP&fLt93RW(Mbebh+w6^7-4a+g$Q>?jn)%4M;?Xk{whP(8KjlFpGRw!H6U2akXCN~ z5Ur}#fM8WbTDdvO)@%Ca71!>G-U?9}nMZMOE!@ojqccqBk3c z;EHz=!4@}%i{5M)qQ+Hc^NK6N;>r+Q_f3w$7U^LKuKOktY?0=M;JR-T!4`e<4Z)S$ zB!cUr`qdhOtDi{(TXbb8MtX4dGl^h}u8)SOaRt)YA~{t^vk~ zTG984ExJb;f@^?D1X~;;UJ=}C9WMGNy1&YhYh;>b*ce<1OOC-7&14M0m9Qj&Et)ME zf-7N31Y4Yf@w(Vnt5KB}hKqwMMVjy0w}k6K$uZcXIkh3U9+X6|#eLi3)gi72B@t}V zlZB13)tXEk2iHru`oUF^>IYXvk_fiw3DUgcsz?&S7OsB${mKMa4Y&rtwE-KW zB%o7}EnEZO+CUP)7OnyO{qs4Wo%tlpC*icpA(Z~u!YZqd`?Uv*uv*QJ|`v-Y~l0Z-#@GIIf_q3d|FD5!4^Ih@o6cEU<;p$ z__UNnu!T=WfB(e7rwKkA@R=bV!~NEiPZNAL;4?!K!4^J2@R=crU<;oO{(j!hIW=d< zoH-}QU<+r+oH-{EY~c*~?`N-^S#qAp`D1bnws4-v`C}5n7S0nn156?`3k#x|h30Vf zKlhp>5wy}g(Gc9vl0?wTty9MPZ@6bBMz||!yhA8oT48x7`0}H3r$qm|D{8bmDUAM4 zBG|&6N8G~{Bckta28cjb(HMcy(XOXbemG}sGvo|*x&%bmh=@Q5guAv!JDnom6X@8h ztq|DH5)hq4u!RUQZQ~^oY#{EfC^8x_$(-l1}z{ zQV%@8R%>onTOphl(O+eT2wVpf=$PHD5V(p4M8}BAXbiRxf$Q-Wk+X#eT<5ny;BFAm z3ipyN5V+$6w8FZ^76`1D1hm5H&K3yV?*dw3-KT_bJVk$%8Qd)cqPIen09zn%-%X%n zJ+>MH_w#`07*QE{#TFtkGuR?>wh)0C#})|8OWYkNUf&C_?zaU3>xl^~tbT5Rz^o{s z71l*d2p4tqSDC?_Dj<3*Lj7JkymUX0`tc$B4-N`n3ryW zz`Qn~73RKMATUD?Xoa=+Ef84K4``)zjcjz~OGb|Qd4z~oKg`OF7wvS~jBq@a<|UZj z2SnG1Fg=LCb3y_gd$kq9u^a7lGEaz3BG^I%o@6#hZey^82s|NefxvTAKr1|jZGphE zT0kqU=xk=!c@+IsX7FAu`b94( zCufxxOkbjOMILs_(1%c>!AyxWfMYSD_9S!pe+1_ahDqC01_AIhxUeK*?av>8zu zQ5&)A?%~l+Cu1lCRhqLX?Mfi;cKJey|VF$P9oSs1XiQB;EF9o=$mijCAq>{c=hkYtn}-u0ij>*R#y52 z*MQKK!CGjgYfKFYU6-tdR=UC^5vHK7oFznC+v#Ng|8EGqb*R23ZXP54MR5#W+s%sT zq=IZA0`En(P>?M|=mQ2(}P`H*{Ml$QB|r1GMpy zzd^hotez*Dm1dbWAT)b5erTncYz+v_kPSgA&CY8;;0#8Q2}A$k_6J_WHw*clJ#B9uqgLs! zGUL9l)u)=OpRjGb{|$jX0SR>cZFhVn$8f*LXs45TLUgR4A=p9$b}eiXIa`Qu*OKa! zVOt=y!eY_V%3Zsv&#rBO&?=50XyvYt)u-#WKw!s4Kr5|ASx+%nPLj%uR=KQ&=>H9Y zog>xjSIIGqU5?@IIMGfgvm!dF2V021-j*#QXA2STj#_N-2npf_AUVS=q z3xrlVx3Y5chwAgATOhQOY6x1nIZCwC$v#i&!L@s$YeX2kTnl$Iz-Xsa5Z!UO;vJ7+ z2)4L6T(r~45M1$2BG|%}ZLWAH5nK@#qc#TDeUk{bNHs%n-8YF~i!?U`*L{-+w&+`F z2(H{F5nLD5uhtM;{Y)a*qANo-(u1p?Nd#MTeKZ8uFOvwa4(i%&2(AGp5p2<2#t>Ws zj1hKaV2kcihTs}t62TUSh}ZhKikC!ijZCu)8-puhNd#NC;>DG)B!VrPE!h}c2}>f_ z;uMTmy#9VQiYrB2_u+a_atyX;=560At_LL%Y;oWAc-@EVK}iH#^kiXU{Qa5?*Gsti z!Bvsu7;NF{2UkUs2)5`6(!AoTND{#ou6}H_GU2|r(VxqPxW_w%;fpSfPCF&m0Q9-7 z4J5~43)cX+HjqTHg=+wOx;I3nIpw_KvooKU`GlNAu!Yadd_qnl*up1aJ|QO&Y~hnI zpOBLXK0)fcTZowEb7B&~7CtrdIWdV~3!ex1oR~zgh0lY0PD~>B9K~lRJ}o5?Y~fQ8 zpO%scw(zNlPfJMzTliGO=baegzFUWX_zE2)1yB%$ai%!4}StIrmK>IJ4wzlJmzTf-Rg)a{ib^u!ZwP&HxP& zT}n)I&BE+=r#YPc&%Gu|1g$hrGz9mvBoVZ7>y*(>CtKO%o|!m~$g%1jLU!HdJ|cHT zjdnU^qN_wah9THO1otrc-XqUdWQNSx*rVRq`uQ`<+GGne$}=aeKci5uf1B*QiIb;9 z|JUEQO*Xt@a!2p}a|^x~Tr?ba`c*~uFwbv)qn z3mxK<#(gpmeDYe4MsKzYS6|sW`_P#3Ow>ZFB@J3<8+4k~@vw0hJH+zE?K1OLKG1%g;v?ycPh_BEwp-T`&QX8dpz1Py!29snE3U)^!!_c9{UX+6du2%WwtQ5EEBcR zYEk``*`0rx*s-j8v@7h)srA#7N8Q-{?YAnzhr;sgN8?*$q83_-E6Z%zH8jO`EWae*5HdK8xaSeC7Kz@0W8(Y`l)RK4_Bw;k4F;gTf6 z-3R0RS48{X*w9tz?K-)~iUk!RTZmXTwncVThb1-R4V)uyV+hi_o=%-UokCoF}WOr)YB8c>$)tFSXZ2j^3+2^iW^IMtB z@OdNB?VRS#ziyVjcF6ugq&cld{?s_T-SFe>bKkplpOZ2tKL1jBFZaFbduo&Hybk?> z=zB%0*{d34XIy)weeNpvzIaw<+it7U(RcTddJVHjR$UoH-&b1gR=;lc_w7g8=e{># z=L<8rrmt>=;CMv;J>sPsnq==ksh{;rwC}B-dP(Nl4o}z^Y$0NY0nM|E|Jq-1{A>DI znYX)FTIA%4RwtiQmi_qE7UJss5r=1P+H-GXmwM2u?>*(&h0T}Q@5cA~wAmrk zQjnU{YGK`$*?jsg`!4w2!~4!lXQ!8?j&a`-ey?bi{O*pgDyID|7u)xW2#!az@BJNu z-$bHamE(EWW#)~XoqO@1`uVVX>+Fh)Mu(B+x)O!aH%8Yn``q_thu3BHo;*9((tS&a zXxg@Qc1_RGh9KJaW_@%`=GSgJ?nJ>s(uT4oomUv8cd?R(cZ zyE=3F&L`R!Y$4*PMP=E62bLA0n0!y)l6>_0kj{nZ7ey<5d+hW0H<*upgZkYSqF*ho zUOuvMcJ4L*w9kF7^P;lM9q$azN8gh31~tn5d-vlC(G`GJXZ>C;ds3sz>~r5ce8scr zI(zPukFF(q)T){Gs;DG%L1*i zCgUQ%Wav++>kF6U%JWGC$0OSJo_=m!YUpKsbGxogB5-dn5bb+AF8ek0W#{8^0}B<2 zIEa{jVZ&^n@y95Rj%{bBe{5CTA}3e08h&!q?6Jf56<4~78oShkR{Awd5B<(fL26E` z4n13D@7ZQ~Si0BFdgFpj#hfzxmhgK;tK@fg{2u3JZn*l0tq>fKX!ooA8w9_JL?^%P z{D$x9?t_g7mKCC3FwwqOe#{k_E63etzYn$$q3ff5A4i>dS|(L|$l~BPoL0J*==X8c zY27mmKOb-G@*7U8_Dkw#Yu$ah^yu(G(@b&JZKfc<;k265w08FF+P78zJ~B_GZ$IKt z`dM=s$I5dWX70UloasSEX*KZBUxN{bJLDjM8dWMV)Nt+i#a13oqU;^T>${Ob;?jt69r_ z3vRf4tn`?6Nu5l#>M7HMjMD1E;ok>S&v`<6EZ*bcbh};`njYkYRzK~rCKxf`1?kcL z)y1h@o_ILd;fsopyweI#lTME*OIM^Cwws(AJS&Odctj`JC8L^UnjYjWo{O3uY$0Oi z>N?pA*WWHZP8r-cbN8iRnI2@6R<)XM3Xb1@ob-5fqn~;InvYEnGD@p+>-`vXy>hDb zxbC-K(E3nSEcnMePdHgPhQ6&;0V>lMjm0X6-${n;vW- zqQ&A(!IY`vq(|E?duBS{Qag<1S7ek{w{}_=jO+QN^ceebhs^#9*O?wh%Hd2g{F|Cq24X-I;E9&Ml?~Iib}zBNhb{r@SRS+U`9! zb^EXva|^zz2+2FG@ZQkraaY-Eson?Xa$RR85gd=`B)eqvzE*z(1K$~EdXP8YD?6=U zrsbba!e~y-79!Stxh@#{#*@9bb^Pv7>c^!V`7Ptu!CUT%7jQCjtC{GZ_4eHTlQX2cr5&!%2Jxsbc{n~Lh}7dGFe72XLuJzlm zpx62*O%L+sdoNb@$sG60wx$PLh`4^owZR96zbrjAPVbzVJ!L!7gN)MZ``14R7G5`B zdfc_TRp#_#o0%SDlvZDy@K!MG`gf$qWuGlce=+k@(}RrC>c$OWP&n#C=`r;DtJ8-} ze!%n~C$#GK;fx?y{h9Q5@taAhyRTZ9>-t?qNZx6M^-HJ6oZX*E?KW{~uG6zg1ji#f z$u1eaf8g3+;8ic19^}pa23KV>JH555>A@Bv>Rt9>Frn>h(&M&9du9G}#;&FZ8Ku>( zC%hdjx#_>sV_u6UnGLnunjU17R^RVa40e0|Bk9p&)ckb)1Aa6;$SAFT*!%h5wFkbC z9!;-2Cq4Mv38n`*q1CB3O$zF!eyIL^e0^W4`+_C855KQSWFDp!R-m08+je*~b>BfN zbB8>gL~uN!lkAewhSNU`@<+aAdXP8Yn}17}%$LXQYkIJSi2K*S9prXjB0ahncgY-a z{XV7#8Ku>yJH8T}{_4llWB9CEna91IOb;?jt3UeA46ZBtQhI!H-An1g3pbe_WRzA< z&z>Bl8?2Ka+dgqz`sha?!|iqyH^t;zkq zt|BDww8B0qr^l1~jYzfn=EvONCzA+{M|6^1GCJV%SAx5ztu#Hzo9_)=x{JFzA7*;6 zg@`V*UI=P`_LcN_{?aCyn_kbD9%PhO+l_iW*uCm!>CvI*`|0-{+spJIqqKVZq5Fd4 zI{qO&{`0T<)0dBGWO|TMT2(b45ggaLPO-GI{r2m-r# zyWzxClNY|q4f(ku%J5gc2d+RX?8S3>e3&1UI_j5Sa}%COA~+t=Np{KT{Lfzq{@dYe z(}TSE-U*}HWZqub*YsdZ0#P<47&&yk^!WE5o6;YB*vs@Fqg`N?>vw-Jnp0Wy%nSNL|S1Fq|@Voe;l29_KsTl<&P&3 z9FOQEyJYmMZc_qp&iaxb;LW|ks%n@y`KtaUJjn1*$L#i(^ti3#r|Fdk9%Fit zQCf8wd2?{+t#yl~wZ1b~J)Qo~{as8CGD@orr(G0$P}M+sd{yuK^!n$@O%F0ktEF!p z5e)6zSbF@nWJBtKrgKaWazd-i^IovaZ%w4f;6rvyeRk{mT+fXaA$g}2-da07-g&%J z>h;NW^E*A3L~uN!lkAew;t%%+SDg2k=|SFn&;Rew=_gM-)%0Ks5hwg~bI|O&x<${{ z+fN;`Fg8T@6Ha*BFt?p^jC-@-OM0&irXn4BCTY>38MrpO6(H_D4&zeb( zgFa}VUhwobrUx0N)%p?jf-Cy8kRCq|8kcIbcfs@^C$#$JrDEohO)aFyhhJ3n7&m!S zZuPGfA$g}2c8)kb+Wq5$9wP=c%D?$Y62b9^PO?iz$6WpIpz#k4O%L+sdtZH0l|KId zi%bu;5b@%)K0#N%sq}d5n|ssGRGw~nkWpGa_TC;r*}cuBN51c|=_3amW_plOTCF>! zesI(QWzwVfqw7=QyW5!_WRzA9?LIFvuUWbD=znMb)OLHlVtSAhS`F-RRpzn-%B9Ej z)2{3B#=JjsJO5r0Rd%S}^IxD9_Wn3MHeB>zk0n1e&UcxZL~uN!lkAewqd(~ryw|s> z=|SFn@5;9(rdzEYYOb;?jtIlV?nz>>_x%5a+dMf1)+QIZ7qqO?0)zHkE!&*v@Pu70d zKlr0#3)6$VxqDQH8`5X>yVCSv3lS48Xb`;q&vNPUp8?&{XMJ{_=|M(mwd;xVGxMKp zDLsA~@NsI#u1A_4WRzALr(Bb{Yrj^~yXk4`s`bbo9d_UA zkCGnbgjR!ZZ=S!Vc1!&}+-9O$|7uw)KlqP|C?9h5sht9?v?tl-UGCeSYScYHrfL4b z@ks>7BRa`08U5pq2Ei*=mzy5s&G)X^&@0_)`PHTeTZmZk{rt?Z9a>3`t1qveZglj8 zrUx0NRsD~y&7A#NE9uevfvZwwBYT@3WRzBq?Xx^RcxAO7CwSZSc=zLy9%PhOOCD&E zzp`yB{XY6$GOB9$TO~cn39Y_)Wxw#tvDLqi0rfY{?R&;wxm*4;cB8%E#yhRt@22{k zm-~H;y6w%mZN@jvzdA07;CMtQ*(IYt?D|^f$DozzLEe1t)3r^~uMfJ`^k54S-%h+P z)AGdD(qoo4IyG|nMWzQCrPbmt@1=LXueJ1eJbQSL_B-}5J;*4nIu0+(Usk8JejlHB zpH{szyQBvhrPYb84+z^oUH$ubqs{KQfuHIA0p4kKd2T}Z*wixpKHfg^+NvX`{gJ!p zFT480yweK1O`RU?Z@#$d`JI~P&m5aXPy?cq?2^&*S6`P|UeVh0AaB0c_?dC3Cav9i zrCV=j3lY1nd@p@`!#2|6rT5S6aYf}I(}RrC>WTfz^L<{f*5l&G+vEygmwq2)lvdq4 z9~fRSw)*$c`;(h;y=#^9AfvRp=j(}K*_`V8`MF=-kQ;kwu{7TW@3i{A8$Jz3b*i3U z?K@*`)%-fY=kBgGEV`dppM5OQ3j2kf9zSg}x9YX+n&ewNX!r9NK@EsbvP(t}+V1`I z5uMtY9^}pUmd(1VNAEXEda#9v)Fb8j@q1S5aeLc+avhE+=|M(m^+n6h;i99f_4uIU z)42}6mF^#8lvcIBeiN~YbDQViTe7X`K}Koy>N{-< zA9QIhJqqueO>h4>C%tsn}ZXH)5sJG6g(%sH)04>C%tyDuMDIB0xB>GA4kJLW%qWTxpsPH1&#&#McC zmUX4asM-B;5AFL!Zo7KJqV>eMt{ts(c1?QRv+WtVU*E5l?>WZS6JrF&BRa`08C^K% z%W%(&TiX4Dy!qZ$UC+($dEiy12V01^>*s9?+3sc1V~T%EzSp!fO%F0kt5+I#D?HJ) zne^x|c4Yp&d1=#wjMA$A(vu1YUEN4}EFU#Azxsm~rUx0N)oVLlQ#hz;J?ZiJ^#|k| z-uR5^K~8A(E8=PCva8>Rjrw4hbm3uFO+JJxVUYYAP=C|BI_t<)S zbjr|_;&?A@BvW{>Sw*lS8N>2b*&lkyXG zIo0$aqqJ(U=Hx>Ce>9dJJB^)`pSF89(}RrC>b9BJ7B2dvp7fZ!@y@)ru!-qGMrrlg zH+K}){_>aJM>V>lSAJuDs_8*aXf<@FhYFqAu9qIo=a0xuZTepBf%?Ou_fawLw8AMd zcmME@8I^mxVqNaQyX}2cjNo`gC)p*VOBZ%4bXwHR^dN7(_w%4<^7o#6vFX7UBKEuU zl)|nf8%vLi`sMN$y)wY`AfvQe^VM~Qg(K=qkIbJh=MP@d+4LZzw7Th?I}6*qSxb8C z@yLXH_s$JW4>C%t=MEcRc=U@6(&Lb+C+9n#G|BWJC$t*<>XU^@dwnfEo}YD3uFn6x zojbh2u;_hlTnUp_IOpf|=&fGkm*5AX!YBI zS%vmzu96;yY(Ft~@=Nn`UphU=JFRe1)9I0}Gd;Ip%*xzJqijDzTw9dm5uIe0jGp>q zMd4rN4NMR6=H4iJU*zBarBzSqA)?eLcCPcl8&LPWjc6AIy=-}HWP(=GMF zo4))%(}RrCs`0w%g<GOm1xTITo_}*3BO%F0kt4ZDF7W&-xsr0CSdHt|S$L&oIGD@pi@4sHS zf97)OF?0Tk{Mj8oHa*BFt@iD`q;S!)1=8cpH}B4$Ugt*BgPhRnhdVziRO~lbdQ3g9 zkb7$RW4X~z5Asec*9{=|SGyIj>iD z2#4)?r0KyHB5qzZx3KTwpGl8f&uSMwcKiXR2N|W+w~OB>oS%PBdOUhti}1WT<)#N2 zrPcaJmKHwPX_55kxAu#C?=u&h9%PhO;}2X}DBfEoJs!MqY<`F0<)#NYq18ust}Q%t z!qd{@sO=W!20#2@u3_V0(SGW<#xkwkzV|4yzVmGEggb0Mb&TM6L?_uL zqd#t%TNrV}XQl^v^Sxd29mAte&X^u-A>xEV3ktiQ`@Zye{1-1AKVlElgN)MZwpCg(qr7z zNAkzrce?38PH6Sd8S4sD-kl&l!g@<`mn|8YyUgi9-f88|g+y6hrN_cmU*tBnoRpjG z)|ZIjctj`JC8PZxT~HV}@qN>Sy!qaK+aC~q^loR((106pA-f^mzN$xw{0KxAHT`=x06v?jePa%!ooSvN{{{{|H_XV|GeozMrqY$ z*w2NZ>OLYp9`5`^{)sV1nI7bXR#U(Jz3}h+DCzO$ZXe_(Hm%4lb$XC@S|LA&yPvPU z_{ZGM&yUIN<@6we;}M-?myEtNVp-waZ{9RL$eZsywy;Nd@MFH|!4@LAoVmJCr)MZV zI%m3uby~GHJ;*4n_FMZ+VXu2C%t_KW@~)LuMVdYtu-r}O^XT}%&hLaW=`)hQmkbEWk7ZSd+``i3)ddo~#somY$N zs?!P?R-7LDZu492uHsF(X}8;XwHU$ih)%LgMi)N3x-j6X(DWd0zSsAS!^7I|>|}bd zg@_Rozb!1@@j2;nAfvSUabAPsyywr59z7e*$`9$=%=929v?_kzs5t-6 zwDfrD^6zqAHQyumlGB5{(@NQzbpP0?SH1j+Z}!fuxUC|A;CMtQ*(IY3y8lv`I%JaR zLEhXumKz3yw_aY)^k54SGhV1w9I@&i>Cyb_W5cii^O5O6MrrlS?e&UXZn{Bw8^dO_Ox@SVe;+MOeB|Wwu-7>s-&(ll~GD@q{e{NjtbzvYqe%>%Af7<0==c4oH z|=b0X4lve!?Z&duK z>)Fy{`qQcK%5(2FJ;*4n_F3Abc=4pH^tkc4HerWschiH6((2+zn-%Z8aA)apU*~-O z!HaSwJ-|Dy7SCy3Y`S!PSlZwI!m16qX@|X6wN2AuA$g}2a(TP!RnJ=*=YL$^DEEI( z4aXq&UuYPG9(k zP4jh6d#kF<=|Kd?BRa`08GU6*qvGt2=a?Sk&G+im`gi!=^cPJJwh-~**G-Ez@9}@q zKR_%_b}6gjMD0W8D+(1yZ#!M_P3WGxqbM| z&#QCM`42Kms~68JFRr}nIq6aNu2=H;WogrcoY3l;3(Je^>i3f#{@CAhJKWf<>L{lN zd8ZZf>N!0IywogzLWA3@zPz;}f#7&VC)p*V&z3hUu0HwyOb_zr-negfSvY&}gQf>t zhlNPjack3qjMD12<60KK zdFFZP@$Q@*!XsXL!1N%awCZ2cvUttd6Qswq$LHnW*gvd_?jPiYRyY4#UhI1Fo%z!B zYWB!Yx%{T9=bq^FAn&w7bp)qJ`x~3*C--hrwZ!Q`1ji#f$u1c^#QnDaTDFVnLEc>c zl0HMi6^CDGda#9vY44O5=kNQw<*)I*lkYu0tkr36(}RrCs;Yjg;?E;zN{>e-9vLp2 zKR*|puO*|j`qu@mihupoUwWj+whL#p*v|AIqqMr9QLEy;WA4hAu2;3|zM7AA97cMO z6I$u>bV85rksjooR$@KMlIHXn`g(I4W0BLN288KMbdp^%`uaxq+rIR7%kM+pd~fMJ zL&NE>9AbK~g@~#lt%{#-^Mdp^Z~lehup>XuMd#1SD6NL>+`9PbA16wWON+h3U3WX& z^dO_OI&OWd;wRUP%9pNJL)WwmBX*CO!1~=z-sdwNL}1lkAewUJth__CEXt(}TRZH}2nD8@AnPV=mec#}*>~Il6VR z$>Rg0$4A=?3QwAKuIWKWX|=<&*2Poy9-S|p$JwhxA7eNAeUMRF>GO0+5B)wYD;F81 zm3}wM%BA~93fC*+omRTeOAp=8dqnqh@=hz=wWWvdA3bpYuoh}Sbdp^%y8Eow#pWLm zFg?hd@BPu=?OnO&D$|24M4Y};o8tEmjm~>^9%tAsgN)ti_d!N!rO(qPJ@orXK@a1d zR{Gs2OPcN9K2p%bT8Pl^CR5Tw_Yc#9jM7T?73rb*RT}qm7nQI6rRtmh2s$&|2~XeGOFK7 zCenkv#aB2(u!RWSSEPsLS83eOjdxmU-X%Ts{9$^KQCjJ_Bq-fK^n7l5kWpIcxm|i_ z{VE;ZKgbEKw9X_ww4RuX))UD)t+Z+=J+yw6!unN7kJ5UH^-FY;T{5bBiRnS!;u%01 z_jBW&2+g~shn_!74>C$CJ(mQf>y@6*O%F0kD?PVM53OIB9%PhOTGx^uTHiH2$O)~q z4l6yh-kyrq+sQkvv<@#lw7#3d`mVKbJff5Al2OgIOb_xF&yY%SWR(ek%J@h^*6}^ul@3hie zC+VU0A1S>5uojL-bdp^%s%McPx?YjD_zBYVU<(m?ZkHZfzcM|@D6O=vB|WshYkH7T zT4~)^dg%R!=|M(mrS~GzL+=Mo4{|~)y~mRtdS9E0-q(_MTIsE<^w9gk6y6V73&$fm z$u1eyv%2X)-r^M&(}OKUXkANsXnoi8AfvR>y07%m`w!EDjM7T)MWlz`51Jlilva9g zC_VK4-1HzPw97o4$sc1g~d8d{3IYy)5R(dZYJ@kIi^dO_O(tAVcq4(#e2N|W6-m6Ow?JqGs$O)~q4@7!s zzfUUK??c{crCmMJL;Fio*k58T9FOQEyJS>ry`~3wi&yAP54I4Y_af3m?*~l}GD<7G zH(n|YIq=)ujnI7bXR@x^eJ+vP#743&3@3hiBIq9MO zS1IhjvKEdC$C z?K_bk+J9wwkWpG`UzYUH{zTJ*oX|@92&ISii>9LeqU4=c+D9rqv_CP0{fXAX@rX{c zOGfps(DWd0@f%*#gDphpy}IUW+)a0F3+Gj02w0}2+{kzt}@rX{cOGfoB-Si-D@eT;n zgDpg8---0l{wvdijM7T`vZROhCz>8)lvdieC_S`)*YqHxw9>v_>2XMDf4k{HPH3fl z=+Z;y4N}p01M*HQokNfw+TWhS{&s8Octj`JC8OGFVtSCbc!!Yb!4@L4FH3r8f1>F@ zMroyei_$~;cTEp6N-OQ_l^)vPZhDYWT4~>VwH~GOAEpO6p_R^QNDrOINk!*z$UCic zPDgs^{6`AsKdgo05uIe0jA}2I=|SG&9dxD#TZquUMd_jayQT*jrIq&eN)PRCH$BKG zt+el5dg%N|CR)EDqqNew5b2@wQKknup_R@tNe`V@OGW3^$UCicjxAeS-_`l36wXJP z9vqM8B)eo(dlgL&@)qwfH9gou#LcDs)Y3!y+f5HLN-OPqmmWI*VS12JTIpPf^w9Yz z(}RrCO6R7eht3b09^`~pI_H-yt?%kQXDT|+N#1FN>V@w8pw17baDLE~;&?A@BvwC`Pd==_K2K}Kn%b0N}0=c7yyGD<6*o645f6Lo&j^dO_O(z(KH zX?<7cYfTSwLMxqvl^#0poQlpnlXqI_9JGEPI$xW{`C4n?ctj`JC8OHwZhDZn_=JM# z!4@KPE<}3he3a=yMroyUQ`ypbqRtPR9%PhOI#(z?biUT~AfvR>xm)R>^XH}qIiZ!# ziAxXV14u>r0LVM7lqW!X==^ya=g+N$;}M-?myGHxi0MJz;uAck2V02Hxv8vY?+0~$ z(DWdqw9>gk>7nzrrUx0NmCoHt51l_ZJ;*4nbS_g->7n!I zrUx0NmCmJ059MbtJ;*4nl(#{8D1V9RK~89;JR{OW`D9X2J{j^(E9IGy9?D;mM*b3O z;dn$R*(IYoOK5tKxA+98>A@BvbnaGq=={0qK}Kn%bLrAU`58y)5R?2H4J(SEF=7o3IrUyBpmGT@)59PB=MfohrJFS%G zQhF$VVjB4qt%c(eon)7cDwm1rLEhXO_fmcz(}OKUDDRK-Q2r~^gN)Kjd9kF&#ijgk zrUx0NmGZ_(59LoZJ;*4nlvh!DD8H!bK~89;JfPA;`Cd~|zE|>2D|cUs^1w%DB97(nI-o)5yPTEgX;NB)eo( zxv)$R@)l<>Gd7ji3sVJX5d8d_oZV&!?wxRS;{`NHTw_6LxBRa`08C5Pt(}TRl88A%` zwh*DbqtZk9cTEp6N-O2%l^)7ZZF-PVS}AX}^ickG(}RrCN_pL-hw2-c9^`~pszV?> zRBs{`)teyiv~ufO!IhH=w_Ekr1y)5 zR;mjkJyajZ^dO_OQr#Tsq54s#2RWgY>O2Ld_aCa~m5S2Y7F-d!rHcSqi7<=(3YeINczdZ@ly3iZ{jh2s&O zWS5Mp)`96k-r@=srUzSyP+bt|q53$c2N|W6>gGrf)sHeg$SAE;S4!^(RbS2YAfvQW z-8Jc<`h%tiIiZ#61WFIpgG@#BAjvze+`f~bJmy1)#o%l z$O)}fN3;6(QL2}kit443cUrl9S;5<*-;y4x&zVAfPHW+KL?_uLqpFo-dXTrc!jb90 z79vzvO790%U(NI&qqI`pHR+-HgQf==rIqRuN)OfNG(E^DtyH&DdZ>P_=|N6tr8=|H zL-mAHQ9WVuPAj)>F<7;{C_PlaHii1N*23|KPO?izRZGg=50baI0+{K+79v#1PI{>R zpy@$IX{EY^(nIw*O%F0kE7k3k9;#n!dXQ0CsjjW`PTRc@dfVik zR&HN!F!Rh8q=)J|r%>P7S~wojNp{JoYOR?b9Kf^htutPU1)lc6Iz`+_uJqCe~R=tc*u%W^H)Zv4*ATo z@5Q{+%AE@dT)sZ(F=gqBRKs?YQ-fzE5gd@3eB~rh*ymZ`*DZN{tMUH{&q4- zt8?r97<9dIs`Qw4Nu5l#>M7HMjM8f0p}z(lu6s~=9G-b9eftrInjYkYR^M-1D?9qn zTcpQJSALzky5hoA*H0|_Ud%hK+_}PRYQ$ja(Pyu3QV$kyPA#6BL~uN!lkAdF)p|BP z$Xi^Y+w@=y5vq$WJ&u1oXL^uPTFq%%J9~ER+p6_g@oc)zp8J>{3mCV(}RrCs#fz&!SVZ#lO78%-Y@gWi3>~*GD@p9AJxuI zU3r`I=yVSv% zC$E@kdXQ0CwO>*{TkG!2rAOyQWtltP8EkrxQCgihs8ROcyB{Y#I<}pi{;^eU(}SGQ zs%yU{*?9+ck{%nc{WEpe;_}pj6_$N3=ABk9Z$tLiQ<_PShCTjD9rV}!scEky5gd=` zB)eqvzE*z(1K$~EdXP8Y+vD<6GHdVo-Oj7Ag@~D}>trunf4lVf2cF(-7^b6A8&e)QChuxWaI4IYyK%cPB@@-CUbOO(}RrCYWT@bv&RnK zS9r%_lKu&1YWKOf}30|}6`^T`_>2<4C_qgdj%f1)$PAiw!BzwxWOO#LM z(j~Ri`E;vP!}&=B$0It)E*agee%{Si2Gp@Z- zdfd9tNtqL$f64S9qqG|NQ{(J*!;hC9PrjAO44*f`^dO_O8k1_4tv`N0>2XB!Z88@( z^i2;kN~=}#n`g`SYc4$|j|$Vh|1rh%ASbk1Hnv4}Rfi?YC)2BE-E^aRlY8vD%(Cyr zywl3%{mGtx$(_>U+1u)-@96kxk3p{|5gd!Sc!Uy{A08u=z5}Q$nj|-?z+O?~PLalE=EY z%N%vy*{PG=`HzKlTW0g=yDWbRt&U&PGFup2rhGCVzCSO0((6Hw6*mkD9}3H}AB}He zywhq?{g&CCf0@{^wBFt&J1@QC<7KJmuT3I29?`x>uE@`>KbB=14=gJ&o#5*FW>;rU z-}yvim;4ZM=Zh_~^>fRW{bJS|7i22tlo`9^hgPE}x5|!LHcIUNw^#4Xb#w1cb#*%x*#|ANi`Fl<%oL2t_hx-`P3G5bI~Z4NA);y9*4Z^ZM~ka*w_TL!vF+2T zqufbWMoX*JSGLYRG^Si!P57gC=GHx4@A35q?LzuXt0fIuXB%{y)UkBZV*7r*Gc%sO zH+6Yc62b9^PR2ps!|tuKD=r#sk<&xpn;l-4*?aQrR7-b;mn}qeU)wsn!|UaW{E#yT zWp*3+MUUPMUd?lKT0K|QIy-s8q>iOC4ORDCl$lxo>D19P<|Pmuk7#!`W8QU{c_U}1 zUOcFNo}Qdp)+Sq+QEqW05y3MRnPqK$=`mtc{XAQUsK0NUYSv@Ib0z+ zYo&Rc{jb?Tq4cZOoFNy@8Q4OE?pH$S&Y6oc>FC;Ch`!ad(pB3&cdIx9x64d!UoRh> zK3h4hMRupQEeg@MfmXVXg{5zau5gy&PruqQ;+n`%L`cCfI&VO+KdMP|s1jaAY4 zb0X^XZeHbmR zG+z-yGnuMrCc|iHm7K{;{CZw`{;fgPer^m#NOTf0d{n*kS+^ZlwQz}L9**Xm7Ol$z znmzc1=Jr25^t}n4>!)XIe^}K8Z&ieBA%Y(I-jIjtr*E2l-aqJJG7jExc)g;BMEf4EaQxNML!y0; zzjJ=usXx)acm9aOGdJzIcRtEY!8<2CWPHhcEw9w{kZ9lIwVl^1dPubI{cHMJnYX)F z8oSNEZkD}v$o_@s?yMPkA-eDC*~k9(yCjJ+>)F{N*R!)l z&Y0MfQ?Rs_VR2|J!{$+pi7X@$9E0d2LaR~vXb#6&A6ejdzNb|Ki(IP)7CEEU3W6fn zDvm|2RUC_)(XuDs)2f<9u2nUQoH4N{-_t6m#i3P4o3St^vXDe@45E_=tzTK>TEDW$ z8Ld`c6uH(DEpn|VTI7tDJ-N!HrS)BlTVZdR2NqXmRL$oy9@l z*^}?-J&whp_c#^@eb*ZZ#i93V7Kh%eSse78J^7yAb6OmF&uMYcclP9adhcv;=smE- zLEqVvd;XZ-IWv38b{2=;4_X}bU2nD&hu+tQ(OpgNYb_4?&YpZv@6Rm`y+5}&=sSCI zJ2PkBmu^wJ!s5{W0*iybvnSuvduNM7@0~3U`mQ&oibMMVEDr4husG;Dd-6T)%dj}K zFT>)X@9fF1`^?T4~B=sSCIxmZ`V&D{F?!4`-1$yglpU3+E} zhxRR59NM>JanN`6TD!{7N=rw^I@fW@JGb`}SHXHUMT z{Z|%;_Fq{X^j$lL6o>Z1SsdCAXK~PX_T+oopJ;Jtf1<@f-`SJzX}_q&q5Yc{2YqKx zzNdYC7KirrmEtIy5{w+W-h9`NG{vEPmKKNhSy~+Qojv)U_PvJDN|E-xS{(G9J^7yY zAzK{U7i@9RclP9d=N&&yuRQP=i$nWGi_z?rzH6sr(X&-G?ccRHw12l4ty9r=_T+oo zPi=8%KXox$7oqR$$?fcKnMz;!;xvmx`^}5d>HvLbPrj#p$QFn8AzK{uT{~zMhxUbA z9NHIdanN`66x|0$q!+GfW^rhrzQsY`*^}?-+=RuUa|{*-eP>U;r~T~~hxWHy9Q0i~ zvlWNV8(17VZ(woIclPA=A=f)Uz5cm!i$mu>EDrk4o?Mlfk6WgH{{BUaL+4{G4*JfX zd{5^lEDoKUusGu{h|vPLe1NosY6ObUw=BpzrL-_jF#(;?Q|Di-W$i zC*RZgL5oA@`793l&Ys+Fa6q^8S)ZL}ap;_v#X;Y7LP>Gx+?~atb9WX8eP>U;r*n`N zht5G-9Q2(%MHwB&rP}OWusC#1)Z(D;?8*0Ze$e93`9X_=zU$VZ&bjux9tT`H&*IRzc8i0)vnSuvd1s45 z=bbGM`mU3@ibLnmEe@SOw>aoKdvZ_o-gZ6S{kWaQp?m-q2YqKxzNh>Q7KidBSRC}7 zJ^7x_(OVokM{jY^cbx!N9Lj58aVW2W#X;ZMlVjKWwCbhVr8tyl!s4Ls?8#-oyku0> z@V82OC=Z9lLEqVv`zB6UkXzWP^u1Dk28)BfE3<&&P`(U{L-{f+4*JfX-0%F8n{vHt zmEutT5{rYrvnStEJ{i+P`CTjy`p%wQHQHZx%3pKP1*V7cepnpzT^TDBhw`vk9LmFD zanN`6VZjmi1T^9%3$r^TUseHI6OSEf0|q5O#!hw>*{9Q2(%xi$Tbcjmo?O)L)Ov$W?Z z`p%wwPx(bH4(0o_=P3Hlp4=GE{E&b6kv(!yqxwtNZ;9$ z+Yk51gnakT4J;1jNwqlWJA3jy<*l_iltV8;d@tgw>Xry*5aV= zHVw>aoK zd-6Ty*|s>8XWQbS@5&IZIF$F?;!xgmi-W$iC*M;ZdW%DO=q(QV&YpZvbpb36<>|LL z=sSCIV|>4FxXrdZTO7*YZgJ3eWgb@?%BOE}D4)K?LEqVv^J?uE`QB$Pwm4MZz~Z3q z?8(ja-@H42dYv0B4%L6KIOscja&MP1UBf!9T3Z~d3t(~3cV)C!9IDe`>+P!3U~$lQ z_T+o2n_+RNZidA{-`SJzsg8-op}Ha#2YqKx?wj~=He6ZR(Be?N35$cit5SmEQ2h^! zL-ju_4*JfX+?;ykU-?nvpSL(vkHzAk@9fF#znc0;{VU<#^Rvw?8*03$Hd-8 zsg8-oLElw@Lvg6CjK!h4G8PAYXHU+n-|B_EXHK#>ROiRypzrL-_f&Vu;!qtVi-W$i zC*MYN*n}?IzUvF`!E}6wa-`SIU znz-Qk{KS(xSRAU`W^vGW_T-+=QIB5ryzF~L-&Ki9aj3qU#ld>?^qoDqIo#-$;njPd zW^t(Aoy9@l*^}G-*>F~VNZ)1_hw2Yn9Q2(%xqB_@xU+6JeOHAu#i6==7KiHgnI80= zJ^7yMC|Vq0rg%6Yc`()U=8 zp7qb^JA3jy)#tQ0SdX5*vnStEy;O@s^-FEP7=33?$-3dJQ%&DlVcGXs$DMV<={tLJ zzmFrg51;vYwe6Z@9e4W9o_tSrcr6aq#kDx-JA3jy*4t)%XZo&6pVEW%&slGqzOyIa zV?BD-Kd0~P$@f&>+2T;WWs8HpvnStUood!arthri>-N2(ZaC{y(|7jd)ne~M8o_hzy+QPn9L%nU*cebkBto7{P zT5etc-0Gauch=tay&CG#v;MhNt!L%#SdXph@X~iykd5`&sxC5pXGPywkFDxd(|1-_ zj`grQ?yTcY-&yfG{(V>+tO!islQmgc-W>1dw}>%P)=RxFLLSLtY92J7(BclH!tuPhE$nx^mUDZXA=9IP8n-`P`q|FAe% zFO|Nt(r0}CusC!F2%`73^qoD$_m6b+-kJ4;={tLh?;jQi>n+oF_7vaGEe_q0gXq08 zeP@MC-(wwK)_tY#>?yvVTO6#zOW)a3d_OP6fjY(Xojt|#D~p5mIq5qqOS&wyPp85w z&%N99V7*lO&Yt4=mBqpOwe+1m#q+Cl^!s3aU;56T;`y${!Mc|8ofR3~D(9z%gs)_$ zS{$r1O5fR2Jm0lASof8_v!{5zYjLnHE`4WD@$-kp!FrJNos|sT>c>R~hD)x?TO4|V zu-^xLXHW6-hsD8qsq~#a#m^rW2kXhwclH!N4_X|oqe$Ob0nn}1_Sz@Bw$4(EgLN(G zJ9~p{|Y_7p##TO4}A z4x;@f^qoD$&*v5g>zC4Z_7ty|SRAa|N8ed-&doBmZ6Ed@zsdB_iidr#=sSCg*Gnu8 zt$0`*^qoD$>m?Qk>weOA_7tyQSsbi)N8eeg&G%RjlJy7aJ9~=PuPhGMgQV~5DPF&_ zI9M-}zO$!zJ<;M|ojCf=3TM8@I*P2@N8i~~yq;)ru#O^qXHW5ZqQ${Flk}ZE#p}Bk zhgN9qK1knhPE=%L{Xy2dqwnk~Uf;DiSbvbdv!{4{*WzG(M*7a4;`MfmgLTR1J1c6r zHzsp7=9m7pOD39Mu}&O)XHW5ZyT!q}ee|6@#p~@B2kRQrclH#&|FAe%&x^jZ5|x`R zO1&Yt4;9~KAe0n&H&6u*zMI9LaZzO#ap+l4gq zt^CcaI$0d7OGe+>Q~W;4;$WRP`p%x>_fZxH>*&#U_7uM#v^ZElioUb*k?*m-8tZw{ zclH#&AGA1FUyZ)Ar}+J##liY>^qoD$?`tg%)?K3StQh2btV_l^SoEDe#qVn^4%Q{3 z@9ZglUu$u&ZX11PPx1S6i-Yxw=sPRzxYHbCN9Ny~m$vT}>qpUd_7uNAw>VhOi@vj` z`2D%X!Fp%(ojt|-87vOg`JwOH+mMac9DI*;uvmAAzO$!zKZC`=I#~3bJ;nPOEDqKQ zqwnk~-d|#Ius#lbXJr>xB_?}Fe#r8kriXTjWTWRn`p%x>{UsI$>qpUd_7v|gu{c;? zi@vj`c)yRu!MZZ^ofT1hk9C(==ZC(tr+B}Q#lgBu^qoD$`+Y19)}^BF>?z)VWpS_` z3w>uL5#M9IBG$*D@9Zhwe`Rs7UJ-p~Px1aMi-Yx?=sSCg_rqBntYbpoS%Jg%Sm%dz zW#~J5iuc1=9IW$0-`P{VAI{=n9VGhBp5pz976oo zeP>Vceo>2qb$94Hdy4n(S{$r5LEl*^!S`5?h4nw^J9~=v?^+zJ$3oxPll#?{_V1Q{ zAE=K*-`P{VpW5PJod){O3Ii@TRpVXKx9r}_zE`Z9LEqU^yr0_QU>y_s&Yt4^)D{Qp zywG>{6z^}hI9T6+zB4nwTTkqJZ2HInhglq~H$mUoQ@p?3;$Zy``p%x>{p}V9>!Z+j z_7tBtusB#3fW9-Mz3;JZ2J1A?clH#YH?TNZH-o;jr}(^q#lgBF^qoD$=RYhC=F_L| z%mnZ1DDL$@`k*^{m>#TeK;PL@eE!4YV7&?Y&Yt4)9~KAeanN`66rabjIGBf?zB7Zm zyZWqpI{lyfyI35o3qar5ll$(L&f{1dtkXc>*;9NT$Kqfe3;NEU;`31!2lKbncV-@U zSpC<=i6rYc>I9T6+zO$$Je3Zq(`VaJ-J;mqMEDq*9r|-$Q+$5V;z;BRFP*y!qPaSA zhr6rjqHojFXYOWkFn>FJXHV{~cHK+q!3#IpIs^0R(|7h1pC7b1SZ{#7v#0nxr^UfM z+w`3oqJ58f=$ZGNzO$$JJg3FMJoNOPJ;moaEe_`Cr|;}3K3{8bFh4bYXJ%#hG|{3- zW<%|^rU&zd(|7h1pRctzn7^IAvnO|DD4nmhIGEp_zOyIyJ8!gC=09ibYH={HGks@9 zVwX*Kb*s$j$2PM#m}i^5v#0pHv&F%@=k%RD#pj(Z4(5fY@9Zf)e{OLwA2NMsCSR9H zXU}#SfBU)?2lG?YclH#YKesrTFPy%!r}+H2#ld{)^qoD$`2Z{q<`Jgv%z*2%Cn3)^ z^E%Ua_7vv>usE1!o4&KBI3Iw;!93*jojt|*87vOw-=*)&9P8Gpk)N9Rkm);nitdA( z^Mx}%HGOAKaefAigZaDZJ9~=rW!U>D=B=gg%(&`%%_m~fv`FH6%dy4aySRBlUOyAj4oWI24V7_Sj&Ypaa zS%H~_mYy&pZJbZWyi!gVyF1ep_7rD_F|U+ECWua9(-Za-X9TiuiE{eb+YEZ5965HU zP9m5gmgppc*^QNz$Ks&x%I{IYOS7^vSse6T8Jdg{mtzarbd?z^gWOc60kfgTIkqegWyZ3+uJn*S zxz&$SK1=&vDKnO3&7~)dDT&}1L?;oDm%JNm4Vyo^zE?B`yJ-ywnQics%5|= zdNbnbn=XC~Eddbx->p-h*03UT(x`U%89iTn3|0mFA1HIIjkg&ww0{qeEq{Y>as06F zHJM$19gvUWQ2yOQl#3JS0G~TV`obX@Z{h8RPa&5Rr~HQ(dVa!=W& z4M8h>?hwcBIw*5~)%^Ui1A@ti)N7bMvg%4h&>inv1m5(V$xFKkT z&mH2~fv0BL=l`%cl#|>Lw8G~OQ9Q7J=D+(j3nQ+SRo)P^!sib0Znkfx)gRl1KOZ|| zH`N6&1g-G7Lkzy-|1yts@xmw$Rdz50t?;=+EZ(teX4%sH%q!LAFa)jexkG%hX`jsF z3%VOZ)m02ZD}3${eY$kWOlW$zAygm75VXSQ4sqb}wwX<%k8yF-dR!Hb3_&Y=?hqHO zZIpTX*a2bmEm4gsL(mGJJH*iMHl+V`=;`K_s*Dw*?=G$IxkGH+<%9IKr=DjB)rm6% zt?;=+%)cR@K6Jvr!@JUr9#^G5L(mGJJ4DBQA5G_fzs$uk`Z3jNGz6{ixkJ=H^v3j( zORoyQ>iOVqsFlO!qHoD=s+VdATH$kt7}Bm;`l$yhEOJ%6H3Y5j zxkFq~cYNyZ?C|j2!^iEWn#G2o6+U-}kt>GwIOCV$;U#@`+f`Mk4M8h>?huVm=$;!i zcX)XA#e*lSZnz<6h0h(LW0w`VZ*CuEaj5dUA!voq9b(h3d*76&~W-`$L=_?X&quE*NaTk8ZD@QaIt+#)hC3K6i-2zIro%^tcNxj#GcEDEzCufgxyx z&mH2LUBAqa{`xFKENe5W@bZtf4M8h>?hq$r>V)&oIwf@1-N)ukoltoEncwU;NGp8q z5UU55g>9Pji{jXA#N$sF+K>Ff5VXSQ4)N~xJBC9(?`>ZFxM^--#0{Srf>!w4A=-D^ zBYe1aHhl2NT^{fM=z_w)iSHYNR`}c@GLsGrH=KQN*yy}fyS+4GS>fAn-ZTWQ@VP@A zbx}HeXotN@-;#${7Y1Av8iG~}H-GLBb%q}i_T8s_3g)~2|rI65EQacG6l9impPO4B=J4tc}eTmt3Xq9u86xe(p89_nI;mq70#Arci_sqLNveLVeF9 z8RC+gEAx~onTH7RTW6i;?B3_P_1Afw{jBz9J?neU*?aBvd7jFuh{F38p_<3`-QGiW z_6VZzzD4NoDz;y>JM_2Y5k%pAi_qV$uS$Qf9zhh|w+MYcD(9G{&xA)1h4(E&pTVS( zxjuIuK@{G%2z}0z$~pAe_6VZzzD4M}#LuDc504-U?^}evuPW!5uJ0(1APVnWguWA# z-wqoP=zGv3h{F38q3>N^mA-2|f+)Oi5&CYoRW;dM-{&4d6yCQ8{eC2sD`fp+ z-y-xI<*U-~Qm*osNEF_;2>lLvgns)xf+)Oi5&Er7D%Ya=ef0>U@V-Up_dKz0>OjBY z9zhh|w+LM`B=%doxvmpDf+)Oi5xOp^{*_d(WITc>U87Xqw+LPPc!aKZJc1~^ZxOn_ zN+yBZ$KLb`D*OdLFv| z^a!HxzD4MIH<`MB@9Db6^$4QyzD4Mox>CXE^t>ku?^}ef+b!a~9&}|V3h!Hl?hO+A zRqH|DaH8{YPS#Q zUrQ9;w+P)2`l{%#N)+C=2;Fmf1U*2B!uuAX`&y5nOC?cw-y(GH?B720Q6viQTZHb< zE1%lwbowI-?^}d=0KO`E(Gi9BEkb<;kDyx`QFz}X)XRwPJA7deI;0VW_bo#GlFIL3 z5A{g=dzUD@ZxQOr#FftnJ;R8?`xc?TkN-N;2a71YZxQM(c?8{{h{F38q5f5D-_&=| zMTsc9ZxQOM#akZwR1fvV{Mv^oyl)Ze_4)OcI(HsH6yCQ8^%EQH^D*szINVgC)B1j5 ztpnNm(_WjSJ6P*Fx<5{RM6GkT>9(EfdVQ;;B5IwxecKN0!6SH`q940hOXBXA$h& z@d#e0=*d|GJ9j*S*C~2(7E$ZmRWj!hyiU=Rvxr*f?&B|Ztn2jwm7*tS5w*@;%UrPs zkKlERo}5LnbH^iiouVga5w*@;B@Z6K>l8gXi>P((hVTC2bRNO$6g@eMsCDjkS?`0o zULQ~?dU6&~>)ahMW^i4v52zG9Ig6-u?xsxKp{~~lREnOQMbtWXmCShruT%8oETY!A zYjyVNoAU@>r|8L9M6Gi-?${ru@d#e0=*d|`t#fz7g3i-<1g}%{(le36g=kEKL&)u9y@H$0L z&LV1^yUICu1g}%{P((R^B{hI*;IWik_TB)H-*SRq+U3 zr|8L9M6Gjo%YQb$gGcZ>MNiHmYMr~vId}xGYdx}J^>be9+zp?6R$Z@eHJv*<$N%Wu zd9QCZojZ%rIs7^iJ-u45@4q{DtMZ7Nu;dSk=#P1ohzpHrDjdt1`-MSK9*ZvX}QS01oyT$c&y}s3S z?rc@H&Ru0y=+>3+y7r0EIclA|e{cVf>FCy#@VfS?RYa|GS2+i|btSy6eKRPc*13D< zq;038TUWyC+P9A)YMr~vInb>u;dSjBP7$@v-A8M_R@duWP3O+Is&($3Jz=xDUf*gu zcNS6W+*MYEZe0nlYrh6sRjqUP)t>F9qgz+P>)J1lB5IwxTZ=o@_4-!RxwBQVbBAtS z39oCvoZj8Zerx^S8Qr=PUe|t|6;bQl?Xty+9_ZGU@Va&dpom)MZsv$x>Uw>v>D*Z! zwa(q9o9#Cp-MSK9*REuA4tDO)tt;Vm?P^I8wa#6og6P(j@Va(IrifbSZg{J6H%GUw zgx9sJK1I|zce7?}Uc2h^Bdh7$S?0CQUB3T~)6uOf;dSlmRp+R6?ktTl=+>3+x^{)E zh+5}v`^(1E_4-!RxwBQ(I(H)pnEDuGhDk&YeZnI(G+tyk>xI zT?wyicPz>Sox3sU)|K$Oc2}f`TIa696}ojLysq7O=`&dC-0k&n`#aFBtIbSQP_?@| zMbtWXYyE4Dx?bOEI(L>iI(K8xtt;Vm?Jia4K<91@x^*SIuH6YMqSm>qWR7lK39oB+ z+lr`l?zUe#vW)pYJGb9C;;pj%hM>sn_*=csk=DtVw= zSHkOB_d^l2&Yks3>Uw>v>D<|>YMs0P{M>(Ybn8lZUF+iL9JS8f$?vth1Kqk3Ue`KB zia_UX47znCyspiWDWcZ7t7MLDU9B5cLDi<){0e7P=kD^$`quUOR@1q&%xj%Ho4Kp& z^{u9JXA!l|U1e41>D9cc*}3zcobB80eO~hJwksNzZ8R}LL~8nQxvwTqh;1LsfA#u) zUU7CZcem4{5r0c#Mwk*?uJs)UCzS|BhrurWMkj0EIVbw>b1)A^+m4ZmBa?4l{NB&O zBaAS`wA{z*KH}$dUA3f1&p%ZrWn)uD%Y8rY;mTxYN|Y&$<$gNpXMf-I$dcja++(^Q zi7ATZX7*W8naoUyGKH?(6+sy&HO-zX^cjbv2Rpwh$qDR#l!r4(`V@4JU-}!fzcb6kE)B{`4}Ar_YD6s`mEhn(d_>^hur1; z|7CO-{CTUEaj?_Y(WQ0{9;u6%)F#(2*-&|yl4pFwkbFhKtd1*FWy?^e%9i`=&L1n& zt;VjYY$m3%S($sSs|Qi0V3+&+frq?K=E^>0&t$>;`4y$Ygf%D1)c$fGt~^LJH+9P7 z(8rFgs0haVyCSOoZ`X7=lhJ#A{D%mhkI}AF_`f6Y_sVGdJwM{y z^D)|#DaMXWrk-%H*Mp4Wdp;#^VerLo!;`KnPxE^42qR2UFgN?YO)9hQ#;)lIC&M~i z<@F$=M41v_?)$5ERXt3vFOgnfLPm))1-snRO^#MQOxHOvU1zTc870b;-*Q`aK40}P zed^fssl6WLgecREOHV3{S3O?n@n$ro&8X;=wMHl8ov3}LexF`_)+E(qyLEq#t}0&? z-D~w=1kcB4yDNI;^yH9}$9g@;D1V*FTNvE`>M6;6%_n(1c!UwAjF`J*tKC!&)2B|p z+xu>>2N@;G6a{l{_Zh5unC@UA-NA&65@kw!xp7O*S3OKGJn6jMHC_)gN|Y(srA-%3 zP(4idJic?{Ag>2GAK2CE*X zd!FpFY@XMHj1pzah`F6FxdYBGC%WDe zHM>pqFg^X)^z^+R@8X z>FFoS{`I!kgNzbo3Xi!RPq{|*FdfK5I*p@P4GCjg{)b?{#kGqa5MfWV89!+R9Iw9{wy)gBa^u5Jp)nnx8 zZ%6-rd1iFL6{G4Rcs@pl!4F-INe-X*zSo0{@*ao0g~1i;{WCdb!7{H0k1)a%H**)i zca7>{J`KrHZ!hhSRJQ`ha#;mBl)q}hfb@!lW)0ZZ^ zsCtap`QOofA2vo!uN+ku!SgXX45mE&k7UrgE4?0Mly|A*&346)Ixy+IbF-v!eZ?b; zFy+wnyS=8W9_Ig%nEyv*e{D=gi895_ben5usUD`wnMjv2A)`c@Qe`^p>AdP;ek`&1 zv3NbmC{d>Hm=1aMIn~2_W#VCXj`Mnu6QWEXGX3JoS5%K3-nl3G0`7K8$G{od1UE(P4+DqZgv*qPbQNM(})$w!O$R4oJGa(k7`~?~+mW8OWO{%B{CgvTNIp zUJo8&gejn=3paRB_2`xKNz7Nq>p@0|GUd>8*n-X_bnf(9!H+~M6}DxuS6GKHL5Ox=VNpjtUYH?vSdp@0| zGUd?p`iB>*9_Akvf7gDQ*Mp1_Wr~~Ww(UMpJWollO|j2==I-LWeTY2?Vl`HJoIj&Lj;;e?D5Wy-qgx-T@T=#Cm!=Fb_MKd0A&j1pyvwCPT5 zn&+xLOY<3xKfLW>uLn6H%Jgj0<~OgYdbDraJ6ikPFQNg>MknN*sGo94`uoh5s>e0! z9T}~7y-D0};;6a^o{!O{RXk#yARH%=a}m-&d~( z870b;b<>@0wnIy&mL*DAVOl*PXGJ>M?cP`q9@Pe;W;5V{}5^iMsxr z4bvHiw^ls{teuN)`n*|u)U~7PB6vPV+l=s)t&+**gS;MO6i+Zy@)iakzWICn$e9Ow zJ$Qr>raYaFf2nCj71;iE&A&D_|5~pH870aTo6`jsw@^Jy*Ezm-%U!%4WRxgVI!<>w ztCi|ue!}s@V>)|1$S6^!5S(_rueIu7zR1z`i|2Yh$O%!VFPwJXwyo;1@6w+d9zXHN z=%S{h6Y@^f6}^`yUtHE!^=N zrpvkV!+3|c5BGZT2qR2EJKgAu7OIE&BF96XJlN|&Mu{@z>9obBYpEWlPaR92Iw7M( znPPL=>dH2%hxt^;uN}RP*Mp1_WlG2Cn>)8tJ#h|9Sk{qV>EUWRxgVY)-b0I;bAz;~w3(YuW2TPKYwS=Vba_ z9aN8(_B^Ly&wE!!*Ze*zA@4-(ef0jxxoHR0}j`Uswn(Kh?hybyP5 zdXm?JjB@sayxB9a7w(G>*=(rSgGU%)istDyGuo;i=HnilkGt1{j1px^;A!!N_Ns^J zg~!qhPsk`yrl6gS4LYhG<9AsY@=?j8Rhg2c{3Hknd9TXE+6Lg;1NccGJBfq+d=ghaK(Xf=YJmS^&q1}nWA~} z+TxC?hv}ZjTMroEpARxhlqrEHuTSr!dJKI3qG(`~?p_ZvN|Y&RCmY}2N%h$Kl<^Jc zy*SV7K~9J={q6Ydrkzv|n|x^Uk4{bEVJk-^}s~+zMA2!T>qFN6!N|Y&q$EUB;S@p>6 zQ=Gfa%4$8x2~nmaUijvn+UMhv3BS%g@XOz$y?=FfGv0}^&rNaF_tj@ntGR`VZQ>no zu8-jP7;T$eIPlizq6IyN zcs)UN^*A8t+W4P$s`VhFM46&_;ofg+ zpO5!H{jza~Q>*nLCq$VZdhxU!YW2A9@N*lVo%dU`(J%h(lkrZJ{jL;O{hp^^hmEaT zw22?Mr9Oh^W3(w+7uv*Me|4_cgN$+plDvh%@B6IaNW9&NH zMw<;7>h&O_M43{4yw~HkdYGPmqxAF>GD?&w%om2eTl;(*)ilmua7wivWRxgVW-l(; zy;cv?Z_jt#ruzFqPKf$^cDZ=lueIx|w?1iXylL96(FZI1*E!>zD7)?|uDae`KIDeR zMPIKK?>wbGg6Cs&81%V$a#XlswAX`-a*CC_g~7GI?;IW4^Bk`Sk1)cV3*wu%UR(8; z{ra(uBgRzgK}Lx(#s9)a*VXFLZqk|g4&$ny4>C%WDdiWh+P+qgcFU%0J4f;C{YO_=U9vSFQl&+~eaQO+Tgw=hVLKfSTfiPd`W2qVma zq42kswR$`jOvsO0T>ZWxqePi=L2>X$wcii(H^^_$r~3OrMu{@T|Kf<{wd<>axBrkY z{->+ggNzboO8KP`d)Zu(-=A;Wi47H z-DSKJW%uo+RsE7}hP2POir0)!o?0Kl^D)|VQeWRCKcI899%Pi0@NBL zO#C|f@CWaHWV{n)eXY`}e&Wk_^vpjqty#R`^!fp@0|GAD`B$xAw@9_BYukl#c? zMu{>9hSL0x+NvIx@4b6r|K(l09%Pg#b1o>2?6sEaao9VZ3g3VAsMmv>5M{mxrAI$* zu6nGu{Gfd6M?Qe&uY*}cx<%3=i zazd2(Hz(xxJRhTN zXYu6Y3jdyYme+%faz74vvkuGWV+t3v9`5zv5k{CpNoh*c_NvFzpI=*eV9XI-4>C%W zIeV1e%(qrO%>Sbx|Br->5@n7Ur8gVbR6Wc$qp-j_&z0v`qbP z)JO02dXN*M%!i`%>q9Hj>hq8P48AOX>wveS)4uViOBwG(*;ByMs^_(LZ+~&V^XK10 z!|tw+;Q1JByMC8mU1)r8gx7rqxT_<}zc!Uw=v{LF5woyHfZZWHH z*SN#H9%Pg#b0{fYa&$}8!+cB%@-a!sC{gC@Q99`3HB^s({p0$=@bRs@9%Pg#bHph1 zx#|}^k6Q1}{R;csc8Ax4oDgMx8l`5@*Q&>L%dX4!eQr_o)>r=YHRGKqd#+wuHP5il z858pduKYCG_ul#lo{!NsO*L|6;noGGcsC%WIjxj-y{wt)VSX$H`LQHqlqhp3Debq#NC*`r??l<$ zNom!*&w88Pp1*FVccb3-*GKStj5Z&|qh2WV`27U02N~tAM)GE^h`TH<9G4#L_23ak znDb4k?U&6|kIT3Cu<-7V`+7adC{gAZQ##}D-}HRYd}Rvql}X4bQRcK#dhe?5R1foG zDael{A)`c@LrLlBNuQ`5Bac6;(0ke>uLn6H%KS}A6YhJX_W3w$X8!TRO3`JX`}9u6 zJ5e@eRa!L1G|&j;%xcs@pl!S+j=7Jq;FFs}z0<<4UA76uQT zwPvyBnfrS^c!Uw=qEs3;@(0!9p;KEIFM1~NdXQ0~%)zJh%yyrt9_I5?yd&7qudm1` zQRaM8>haLqs>f*`Eh>ES@P}RxGD?&=#+1I;ZlUVYxADqC%VRF}dXN*M%x|Xj{+ngh zWAb00&QDr;ceL_TpZ?5vC(7n}ORMIouj=r0e&CMzsL#Xo5j-EG!=PE`4#ihT{mtt^ zM!7efyoJG)f9g^^pO=`HRD4Sw0t=exe=FNrqJ~r{Y@1yk*JRhUO zVA4a~i@O~$(Ca})xx1gd*^ZI@H!dD_@vhZ+fKf)6GgRrRVehIQeao8^2b{mH*Mp1_ zWsXXvMHl^B^)TP1qI{PUGD?&=5tZ)0{3+FA;+9_)e)`LEUJo)#lsWj6=FNOm^;o#o zErss=PxN|_6Qa!jr*uL%L-qK}8E@pSm!F?{J;*5a8OWPyw|%&Eaii0Edp&rB5$14J%5S+y^)Mf-qI|Go zGD?&=LzNbsJ74uM|EQw;qY^SolsPJuE_`*i>T&MRD+&kvb&l7Aj1px|M5Viqxl{Gn ze2wXawhtWW^&lrinU7Ja!`~;V9_t^zB)_EJg;Bc1ch_XR6J@)gN~`v(E&pao{)FwW zizYu&AHnl6+O*rY*|GSy&v){AkWngZkT+8>dwHi~pPAcwJ$Qr>=G0ZXb)BbGk00;r zReWMbSO0vFQKHP@s`S9)kEtH!gH`k%9z4Pba~vzZ zxyR$G$KURVihCT|&g(%&i880I(oOyDRz1wmtN8la?|41PC{gBcRk~pKjjG4H$FwY7 zd*Mx94>C%WIYX5PH@&=8k2hu(*4TPmuLn6H%6z5D-IHOe$Ndj}n;&`F-qGgo`tHn( zccN?`bh)+<+MM4ngNzboPF>}@ z-o0G)*zCh4}dZcjmvFmv~$O%#As8!zU=6zLWci*Ui(Fdlhbqsdl#=h^)ufeMMjA-=d^OKv13&a^H(e0 zJ>p@n2N@;GJj%*Vt{$#>^m@KS@rsv+c|FJ|QReMcK55JSR1b3iD}2+rsn>&?5M|C_ z<#{{yR6Tw?=ePXP3p+;7y)h~w??ml#ahvjrzqeIAS~mQi-|6>1NB2HiAHnl6It=z) zct~+n(!%ROMyWJK-fZ{s;6sZW?y|!7tMLdU%*n2N;tyk05A(Y#j`(4r*Mp1_Wu9^6 zfrSyOhdIj?7kqrP*Mp1_WnOFLxo7`X^)N@aVzSTPUJo)#lzEhu|L?r*R1b49D=fI| z6;~-BCq$XUS^0pVZSD7CbkoAO?|sm4(QBg;@=ny46Wf*le$Jw#I^TZkqNasH+&OAF zzdnNJV{{kT&mrN%6dS7kfR(C{gAzS8j3h_NvE#cIy^TZW($#$S6_f z&Q|WYeLK}-+W2B&;HERY9^{0mS8r@zes8lyNwvS*zhARLtLD=hwtIC{Lf(lw?dkUA z<4?I#^_Y2iv%(cyeAqDbnfeHxkI`YU^9jcnA2@H3*Mp2w?Tx&J!TDbuSG;oPC%qm# z!U%H{EYI6)f7N5qL5CNk@?@_E870bG_{!&;@n_Xz^GkOtPR;$@>p@0|GWWXjhU>Ji zeLfE9TAa3VbFT*(CCa?-%8x(tiZnTHZY&qVolo|9kQ1U_`KCj;`3_gA9_Nj3UO4*l z-5VAx8kLZDqVkhEl>hQbJJsXHV)Me?eWo?M@mzfb&&O!nUpw^V;*C$u_Ii*}>h+Pg zFt~N-NyV`f@9=u?2qVl>vApp2KdT=9xbNuVOMS<9J;*3g=0#Y3=c)Fp$MF~MQM_pD zKY2aKC{gC&S6rG6%qNA-+oWxMjO}h1`7|qJ2$Og`5yI zx!AG%_RZ~8k25B>C|vZ!g?;1MTIN`M&%KDDzP)pC61@J*M~VUL17X;OH=W9z{lp`rD#T<fTe&nq1IOxp0q1w#{ZLe%puI+Zv2Y04JW@2jKkYEhUr{=&I08N1}2DE&{xYJ}?1 zhs+B6MB1*q-iqLgQ z9@ixvL6ojh6rn52JgzJ~f+$^ODnj=LdE6U#1W~$AP=xO8^0>S62%>bSrwHAj=W&1T z5k%=;T@mWA9$ik4AW9uiMW|1mN1xgwh*Hm5 z5qi>)$CCz+AWBai6rpEDc|0rf2%_}dND+G4m&emSk044<{uH6-wRt?R^$4Q$?6zF} z+tm~IJf66hD}TF0>FK*7G&51a%!Ee}rTGa(XzHbasTYqRN)s@O(A-i1b4wmUlxCO| zp~U>Af(5TzXviqJlm0`{?Z1X0@4q6qCo zDqts)M-Zi5Ns7>3vI6#!c?40~SEdN<1}tDVphpm;oq>wbe$G7hb9w|(+S{p5ly>Ci zu_M<%QABBXt|GLjI*&co9zm4$S1Urh;`7)Q?-4|4hrA-BYmkSofkzM}jRQqUnIaEm z3XdR4Diw;5wn!e@A|64MbVd{*b(lQVVLXB;Da9y4`aXH+`*;LV()v+^6q@o-Xz~c6 zq}HSeX>8@8vE>m&NpDLLQc250CCwvkTIqh<7Uim>+GT$88CT@24i;W#D!tMui zb|3CnGDLlRV29kv$t*=2JiBdtz?x$lmtN-gA33{I^a!HPKCxr&+ZOvPV&eXPp}=K5T6Wuf|uGxC{s6<44!&s&6D_2mXXc1pzN8wVJQ|RPM-Zi)6d|q}z?DZ3CEgUFdPJy4T3HoQRCqKs_Km-bHa?_v zw9NGSs1~VedUSon;ZL7gyrOi5-%ap-0P624ulh~@s`2#V^bHR1y9pj)ggLaATjUo@ z4bgnui=*ar@Vg1#4-jRp?B$8Cj@RA9zxxj?o;&y2sE?_`@P2@(O-h~1V>j$ryPJ5b zd-1d`H#UsywpYUY0is^)X6M-I_ARQ@(NmVqE6l$vZQS1O?sz{yl>Vn;HDc%7yut=| zbjUw+PImv{f1^a{PDT;Bqt91#Ie9-o6tDWt!M=LWna4e+pM&=wjJBG0Ij7k3-9BDH z)_^MiWZKSg$yvo23%Ys*d4v&d*6C7S(r0b zY*cabjX$|!FKa+&2QnQ7Cmnls@$#jQMeA>##yrA^zMpm}um4O(Rj~I_LyJAeebO*+ z&8K44fT#x>yOgIbpSnd=LE!zh_9{+#|LMk7_8DXih|>R5tVVR(e_(Oe%xm+*8?%}_ z??maZM-l280PI1uu9~xe~FpYVH5iPb`yIdSGZHvG) z2ht%!i%0DEN#pwV8DtHJ(*IPfMl@bCr1)@)`}6zEnpdm2^G=lhdK95=>Ow_VjWr-j z-{7jC`f!Cx1z7{4)SoL=Keg&pdj-iNQR-i-f_jcqsCNR!U+8>RD5MjHA0`-eC1Qi z8W2UM!=Ud?=M{hWVMXJUpT>Dc@O+HUzDx3zJa|OkE54HYbLiKgP7#3!Y=vI@2;~;7P6})XO~A9p{uA;^;4@}xU)-sh*FPS?CM#OvrB%6 z(laEnt7oasE;A%b&sfFo9@SX`=ZY*6#V%eLupW%y`50}Q{ncwxXP5lwy0ldJ6p@9j zv+eBi2qV<-7Q1@#e{84{)W8L_K5GG~`862LzJdr#IB~ooLy!}l%~bRuBIlPU9w0NJL&c}q1GSh=z!KSXJgOYCZ*(b*+GL}}7d>}ulI*=2@AX%blMY9ijbB8x=v2~8NV9*p4m z7@f`g6f4&Z5EogyyouuI3Y+UGhVe<`%`S=68#g>vr-(l;(QH zuIAgFU1ms>=HA7w_J26LWRWO7&9dv=>JEiJMDTo!&ZgU(UGk$zH)oeDWYdPuE{`xm zQ;1?$)40wq`5{VEx?)$;>dr3tAxcy1VpqF4oLy!}ly-TDUF~*quE-)$eDW6ttOp}_ zK1OG=oX#%!(OjpqOBS-(T4$F>7@?V4v8&m0XP5jCrI~cGtGyY{F8Lu!dp5+b_AWWQ z%#bMUX%f5I+vn_(MWXnW)b0nXyU+d*!SgXXn_PBw$&aR(on5k!O_DpiJi-V~n2TNQ zv~YIG4^i5IA$GMB$=M}8L}`bT*ws!wXO|fgr5$`?S36mqE3!xwpD3G#P<5~6A0l`@ zMrU*S&Mx`U%)YZr7P5U4&MuEILi;JiuJ#o@Jx9aq``T4fhU z7@?h^Vplt)on7)nly**+t35I)2spdshbSovh+QdcIJ?Y{C@F71OMZxw28`I17Lv0|eu$DrlGv42 zn6t|aiIRqx*p-%^vr86<;uKmKupW%y`52ukg*dz9N2(#tE?LNwTbx}UVT2T2#IBT$ zoL%xmloXG|u9Ux=UGhVe6v4!o{!O) zE{?NHex#A(?2?5{r^wmm5k^SANbE|-%h@GAL`mOE>`Ld(*(E*(E>HKXZ1; zLZ(6I?D7aBq)jJwrP1i@k{_a^-6(dYVe0IXAEKmfDt4vu>+CW^qNM#RcBO&s?2<*I zI5isvtOp}_K1OE>f6gxXk=mcLOBOQ4MQ4{s7$GG_u`5MVXP5jCC8biaE5%-Cm;4YV zC10^CMQdl584@L>Yq2ZEcW0L@62%E)^LDCglK&xs=VNrHXX)&cA8A`UyJR8L7j<@d zgb~sm6}!^kb#}=QQPSlVyV9q2cF7M>(ybP|(ri4g=PM z5j-EGGxb(ym;6Y{)!8KrnVPP%%Oi}C%C6Xz+O)Gveu$C^wb+#!yR%Dvh>}XX*p*v> zv&#&Ll8b@Zm79mNOBRXZdfc0Pm&&TLYncLYV zKT_#-cF97fl7_c6U;Q1Jxxh^=n+{e^CmkXb>OBRXZ zPMa`bJs83BF*@@Yadyd%{6?HzvXFVcIJ-Q;2zkMXU3nroyX1!`c_oQmd4@T=N&g2kSKZWiQV2+&q-&OEE2_CNp_c7bw&I`1kcCl%u&bLB|mc4adyc<=5XZf z@(3g3d?a?|0OstHAEM+8CU)hJ=j@UnqU4;XXA^Rebat5`QF4~7v0HUmb*{)FQQW~5 z2CN4ocs@pF{!z{@`H`2Dvr85-KQCvOM;IZWFR?4XJ7<^t5G5ZxJ)4jpq_azYh>}mF z*p*+ZKec3rM9D{0?8;Br*(HlaakrbXi+V7E=VNr{mgek|A33M_vk9`0xz{2mYG;@H5GDU=u`3^UXP5jC zC4YCZyME8_Z}2urDLW%Aa-xM>$Z5m>yB`)$RbhPof`(M2P1esMrSU^ z&Mx_p65I{xr?()eu&!s)6dgwuAL=zzaG6s(zo!bvrB%6 zdZYF7bZpDp#qLc%H%|sWJk{A{hD2@r{K~ZH!UbyNmm8o1C-8E6y(YA?o#Ge^0-fbG6w0Xx3Uu=k2a>c9|hjTX$)e+p_cd zVt2p^55-ds+sxS|i$rmUd>F7EjNthg9R_R98I&xU)YaJ~KktU$rTu@n+u0=xVX%0; zeUe?%1~O3U9w=`)T0hedhguK+2s*N%zC6r?&9~Z z5xeb{{a>=|UvE3RY7_y=9X@9wAk%7p;L0! z)`vU0%#f%fzF#ZX|HM@6e!qN9eE9HXzDJQP67^sD45$Yqcs@pl!IY=}kqlaQrBC*g zpB^om<$mcl&e^v-xya*FA%%O3_K{=#rD!yCi}?`QTy-F zD))Au!D9Em`=jLaW3P60$q!N6zS25(^3B6 zUWNFEA^9r1(61nhDit=*z=y_1 zU5$~MKJ%Sj@-zE_*178s-QU?I3t`ZF!HLPwKR@j3@(3f|TGl3a$yU3G z-3M-PLmkXO}F5!TqnElHAvPlC#SrjF>sKeQx%Bn~2?)FFq#eKXI_LOMZy@>d20{ zpHBK&yUCx=_fM{Sr;D>oeu(;czfQT&A9zUY{%6km$$+OPIlIh|r~^lJ%AI}V0b=*w zJLbjD{<+v#*-cIsiK0@B&5NQQjNthgZL`kLoSqzV@>pk={A~VBhum6+bZ~abLKuAU z+wi38%F~=(9%012FL%t%-|iRf!anTUK`X`&i($~fnqnlv3oMBeOG6f84`6utIoM=Ctg*kPDeLw_EbfCr%8ofvPe|D z_73a82%eA8VQ}Wyk;&8(4t93Q&qr@|%02(XV&8>L7Hmd1J~J7%*3Ql@k1(R~jLx}_ z*L_6n9ykBQWb~dN=PSQz+F&rqSn8+ zOYZM~noy`tM{l#)Ud~nJdzbtWrT611yZYOWz^=1Ml>Ww&D!cleNBCxNB_^V%)?_=X zs^2AE5Ase%865_@^c$V5ediq4XCOaEbyz!Bn$^+SB?~qqyyEO+?rx_$yF9{(BQ{(+ z_toSHg}|qyM_)SBxvKo_k{_bUN`8pa-*i%CSKqtNE;A%b-;ZKfzfsOE zStN?eR@wLNA0l`@M%(>I@AHy(w_VX#*=tFDnjg4!Zr+q>TU2Jx$$~xkIrSXps`9tX zBmW~JuClAY-3aVDi;8xX{-%>EyZYXBcF7M>`aTxBx@K^8nITd7Z5O+`zH+X}B2o3q zU#tfscs@pl!4uHTR%4qw93lsLIA~@GuB({3Tld!d)5%Sp-q0Rh=on@fS4= zK7C|G^hKM=jeoHSqNpy%E1WQR$o$q8L6rH`q~=%S5$ssld`XWtqbY4hFINVX(tH_e7tZ zJU4%S%h5?4s@L4qyc0cw&yeg%T(>FFVYBDwm##TFF^9zrW$u@$xnFt&pU{QDLyuh( zt+Crn`8_OxDDy8(&A-$m_{1~}+ReW>x~t7=`AIECCq$V8ZE6m*9>Hhcrc!Xzu;{s# z@8#caUin0=LYaqfY97L_9LkA;Fc|;D{?X*^KFN2r2%^jdIyD#QKWL4HLHnk?qqWcd zB0r$n=!7Wq@lMUh+aow}69!Yqtsi~;@wfS*Ym82aGAH)boY*~r6HsBW@6w+d9zXHN z{6$SiCq!M*dwKH3Woiy%2an*4XBZsZ;@7@=ANhO!(%(iUL=ByPWxUA?)d)_|+HP|D z_m56Z3d2^8N{F)8g<1qBn#16d3BS%g@XO!xd;jVY8OqLAtgVU@=3#K(;pa9!JMXvr zM!)!~GL+?1tYywU0`}DMlg7rIru~}#V1;L%p^Ud;ja}}*2!jne{nEJ8_!aq^ei~I_ zH$z!%DxU7n6?eqgZrQ5ydmhg3j*{DZmEEdmxs-0@O`eB0xufJq?ytGW%yyYp-Lvy> z&vuj?v;8&q{MprO)!#V}e`iO@)7d{!+=Cegav;vbf!I-U9roAU;cA_Usz+`f9=VQ^ zFRs7l9%Z{`sJgi3;o|BjIk)<2?isgpRDDMC@ELWKyhZ&rcjQ}NwCaSJhZClw`D-drnbK6%cPS6w zB}d8g$6r%JEDYofl!r5rqwM;j;s)fesWfMKRK05&;a%e>`KGvrE%gY)K<+Aya944Z zoIU(C6(z$!{vVC-|8SJNC;T;aN5eo46?5TG;V8NzP;1nl-Bmpl`c^y?sFV6XBBWcZ zE3$^l6&aOhb#<2fw}x$Y)z?tD>LW^5fF8knhV06+p>kzOl&&&8f_G%u)ob6%)hki| zLm^nI!19}DtoTh(;dR~^?lfx;JqxPd2UmtKp##=ydM02bw2gs*o|U`MR|C(jJA0O^kmp) zAft@7-`Z;L^$&NcTs!Yr!$AGrxYET@f7kDLiBh*s_s)z^m(!0hx;{dE(YSJdu3n#i z))=iWl|F;&Q+tGZuW9Aesh)LOxr^uj6b5=?5?6XldV-NwdPuxq<_ha0^xPn=bW#{y zAE74=&J|a}Xy#<9T-B!;o`*X0o`;@ncpl6z4D_tX&q0))8~F-(?(8X<_ZjpIGOgV4 zvbVsT>Lc_l&ADQ9eT1I&IlEj5qsfB()>faAdFFcZ?*wa4AL_vO3x!b zb24JnZPh2dzAB>h^wo3XYQsR!&*Mrzktp5wJ8#U%_B2$VrFtHEKInPqxvJ;E{A|a1 z^+~noL6n|admhX$3^WJec@U*%^qvRv%bx0c9z>}d;dwAWyA!THarZp*6xs98(|6B< z`GtYz89Wc7G~3{LFuyR+w20?HlqNYm59XK6es~^4sYl{@FhA>;ROd2056v2Q9-7hc zJeZ&T)>fxpJP)EY0pocvKbxki&J=kbL}}i~^I(42gplV!lsY$_2lKN@+3NI8Qu$8Q zM2hF3NgmIG`PuH}>THzfL6qjCJP+n)Q{L6dGtYx4O@() zFV91BOP+`3y*v-*XTQ$X2|CY%C{5FO9?Z|~SgP}ho(EBy9rQeyUp8&%c@U*8m*>I! z!a$RNo`wBDkd=RuU_w>=N$XWwxD zej)y@{W8ykC{3$-9?UPBZ}&WiQlHZEV1DM-yi3RAwKMyA9-622JT!;yc`!fQ={@Ji z_?6!`@jQsql)vY}{Ol@YgF-x``;VRnQQFhsc`(0h7lh|Ql)9&$2lF$vg-e?!7cJe* z^U&12=b_ySo(J=@>#J!?;(_T_o(ECd3*vb&KkJt~_&|K&Mop8--xX2X`QmvnKg*-K zcggc0NhxTUV0=u%*o|atY%98onzPpECj4yewr{_VGb`0ez z*Nn{1ln`#aHSXJMP0xcU?T_+2m|wP|%JU#foo3I2`PsG4@r&aH*ZtM=&<-BYLpz^5 z59ViTB)>f#|K*Kdo(ECdSLS&zKjZ4hE8}26YtMry?V`(7uCJM2w(rjKAWAzNbCv5- z<`)Lq6X$topO@#M{c)ZL^9uv*IP^S-((XgggZbGN!1$5z2XD6bJc!a>OV5M(WxF#y z52DnS_dJ-Nea^3#8sECfKRpla2J}3%i_-I8ex_1z>d9mj~l=i549?Z|KEO$LH zo_I`W&x0uK$n`v!U$%$W^B_vk3Oo52+M*9#VJkJeXe?NH4?lAWGU9o(J;_1F4aC9z;ng#PeW&nYM`ML6n|B zc^=Hq_6e`EZM4~dp`M4dEIbcsfOsCvFASur;&~7yg%!_(`I#0{@L|L3C%StcL`hG^ z^I(3N0*&WEl%9-v9?Z|~&tE^bam1Kv9#TB;Mw5dD~=9j5ic^*XRDWd1W{K7y=Q~q})^(4oV1CxKoO(|_9J;>OgD5GOc^=F!(>(J$h|;r7&x84y+s(nd z6psGrIL|{GTb_rs$vh9{7Y0&$^E`->@|)+u{Oogn`w#izf4X`eL`mn)^I(3NGM?u_ zl%BYH9?Z|?$gVi8@X?gPo`;m!JP#?@c^=F!45SI@c@QOiK+l8u*_Gv+8yB9te_hXm zD5)WO9?UP(PxL&9l2WDT!TiEN+J>Ho^!hvx=^T0<%+F?6o9YuAWABdo(Jgah$4b$^re)cSN zn@NS8u4wQ)h?3T*=fV8KKrC9@75wJfxZG zc`!fw_IdCA!oRNH+4CSuinN{w^RvI*Q!XwnSkl(>AWHhXo(J>G6ni}nqVy!+^I(2f z^DRCsyu0JRo`)1-{eDo&y4Cyh?=C5|{j!6)9e&ztS^4G%KZ}s;)q_gaKNPpS$V19Pp-tYCoYty&! zJcyFIwdcY7?5eMEMxp%^%{&jHq~+~-FuzRw+w&kwQxBd8^RwBgQ(G4=dM2sn@z^7! zrXPLgc}S((^I(4VE&BWyh5H`v;du}x4Rp_g`Pr}9xw8wy7X0dc2BM_+?s+i3Oe5a& zAWE|so(J=@y=3pLQ@re#zjz+fB=}vi=fV7JI(q#4 zLW>=~@jQr%x}W;AWCy9o(J=@&v~nDivK!tbI(Km2A+p} zAv_P}7Y1_L@H~i;>xSpS{A`-))b|U&9=6!?AW9x1o(J>GTuD3+qBKq8c`!el7P+ri z@rfB-JrB8Hcph>O@jRHH&1G!ey%=_D=6Mh$Zx+vk`GtYpZafd7x9z@AA z&hub?_RINZn_~H~%RLXGzC-bfmxp;CM9D|d^I(3N^P=ZLlqT9d59Vi6 z-Ul6CjLMTe4>|pL9&$+ZJeZ$p>Ajc~&zpC#=RuVGCp{15XZPnjbSWnL?Cp6FCAUq_ zgZX9toSp|!nzQpfm|qykJJa)!AEf6YA5G7L`Ppai(%p(vbAR_dh>}aG=fV7}*Vk^{ z;>j&T&x0s=%X%KnFLR^ynF*pa{pWcwKl6~@>bT+sXAST?jQJP8g=|ARY{Sr98%Ujm-poci~vuE2+ z4=BF-&T`)?Llj-$nV%`duDyP-^@zMrArU3NZO?=GWe(k*2T_`o^gNiKT~k+`l%tB1 zGUxX=naBL>iAmK9JF0kL6U8|@<`)KXGmk26=0tI7j`^7@V%3j6s`$|prTIk9gZbGL z_o|P39zO0qJIGl+dH|aOfB%8SbLU>0?_Cnx|JUT_&TwmYr#X-jn&L3va)#!Q7 z2}=G?*7B~eX1~t9Dx&C2%hhJT&b}(5 z=)=p^X4gKxDtc$qbCj#iu6=w}MA6ZetIe)`d{sozzm}`bt}K03^qizuCs&(YS^BDo zq7y1tn_XG@s)(ZRD_5Icw-+nl4D@QG$0b*rUAOzHh@yiiSDRh8`>KedUn*Cd-4*$& z=y6DINUk=!EAmwlMdwYfHoGhGRS`v>QLZ+-=k!(48<3ugTy1vGS*(0t5k<#Jt~R^p z^i>f>e@?D8yQBA2(Nm9Jgj{WQNAIg5icXJQZFWcRt0IcNmRxPtFY#5;i;fzDYdh@u}PSDSUCd{y*tqxT(Gn{}gnRYcKQkgLtQQNAjo=%dKhX1%`Z zs^ER5Ze6J|!@|{Oy*^(RQFP?vYO`LSuZk%84|26xC)HO)&oFwe(aA3Br249eqLUq0 zn{`r)m0xF~=-bEDW_@a36}`6TQO4C~eQIA7QFMUgYO_AIuZk%8-Ep zMHKzjxZ3OqmamGQNc588YO^O;zAB>V)Wy}>UrF@|mamE^`jTVaK+VT&j)=~MA6TStIeLi`l{%`L+>K4HhcQ&t0GFzPrZU%ZT9rlS49+k zu(;an*|x8W-Zk|6;cByI+rBEI=%~ciX3w^LRYcK0imS~g2YglZe4$qkSDQ@^_^ODa z6A@RNO%C{~h@$TjSDVdc_^RlYLXR1)Hk-@vRS`u8AFkG}+k>u+|9PjouZk%86>+uM z)Qhi*9wYQ-;cBy~7he@obiUzgv#A$f6;bs0;cBy)B3~7~IW!eiuKW&iwb@LOuZk!- z#&EUv*Z%%R(ZD8Eu87i9P`NS#$<<~PTfQoKTF?uGtIa01d{sng=E^^VTx~Y7f>{|~MRUY!2C1 zMHKxexY}&W+gC-6cxvl&wb_)nuZk!-7jU)Nl((;nDEc&Twb=~4uZr60)THNXvl)6{ z6;V|D=W4SVdS4Y$^f%yYvmFY)s!O2kPAzw?*4VA?Q1Dd|MWuYMHrt`#cN0X>7l5nH z_J8=QsO3!!bgnkr|KY15iVE{wZMOfzS49-{^tsw>ca5)#8rakh=W4UvHNGmMv_Ga) zxkBb@v)whmDx#=E&(&somwZ*!j;7`|SDWo!@>LNkeB8vL$Ty3^9%vVLt zWolJ(wb{-v@5vBFC2+1b+ZpDoB8s}_Ty3`R&R0dPVro2dwb{NqUlmbQ(B^8heRsYp zqNo?n)n>aIz1K&LUuq+Bwb`ylUlmc>m*{_2Ty3_i(N{$jb+)ib}^^ZMGxVS49+cow?d< zzq7B3TCCc!>^&K-Hrwy)t0IaD!CY;&-`Q716!nm~+HC*1uZkL`)PCh^v;F73Dx#>Y z%hiSfm7s~z4)Rjv3Yn|5sTZiwQu~vdsa&nyJ454_DDBU8WL`gfrSH;!Z-xZXHiIT#fuZpWRmoccGQUiht5?pNt~Lz*AFuna#Q*>R literal 0 HcmV?d00001 diff --git a/autorally_description/urdf/autoRallyTrack.stl b/autorally_description/urdf/autoRallyTrack.stl new file mode 100644 index 0000000000000000000000000000000000000000..93c5931c69211d321db85fa4463905a9109958d5 GIT binary patch literal 708084 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̌B<&Cvl-fvD&)TURkh2glLH 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 literal 0 HcmV?d00001 diff --git a/autorally_description/urdf/autoRallyTrack.urdf b/autorally_description/urdf/autoRallyTrack.urdf new file mode 100644 index 00000000..836523fd --- /dev/null +++ b/autorally_description/urdf/autoRallyTrack.urdf @@ -0,0 +1,33 @@ + + + + + true + Gazebo/Black + + + + + + + + + + + + + + + + + + + + + + + Gazebo/Grey + 0.6 + 0.6 + + diff --git a/autorally_description/urdf/jump18deg.stl b/autorally_description/urdf/jump18deg.stl new file mode 100644 index 0000000000000000000000000000000000000000..f8cc78051687583fb3376e891e005f7c988ec242 GIT binary patch literal 3084 zcmb7`acI?56vvNgK`db{3L;{!n17fU4|V9Tt^MBH3wf=@(glh|C^{G_Or6W=wzo?t zp|n+d(-qao#BvM^r{ep`d%x$V5V(gHEjANYuB{bGqf9au**(9r-`n?Y`==jcyZfE< zx##}w_ndof<;&%zfpF!Efo02rPY0)dg26zfqP$}5v*~pDZs31C#l(-Y`S+!oYl{ZQ z$4hzq_UT7T{c&gS2Pb44jqrO?Q-qo(#4;DbG^u?nJ6)c4XML@X^?(CeKjPk8fs z@1qfZKNleuB+OOqSX7qe81pBaIYu8*G{XPOSVrFr%0=0+g4jilbwvd zc7a#*#L-7X=#`U6*i1B@D+`f|Z!U5-ymiA`bF#rsoIMm`qWkLB5PIe1=7*VR{kuaG zmrrhVpC5ItdoS*_KieM;Gci{GX$ZYW{%!M!iLL=nga_Vmccojb4Qh|QVsocQ6yE+m zgkIaPed`ftx)*8%ANu96`&{BF>*klc?M%~kj~E`y4I5sD=J6#5+*o>{Qx)7}5E##( zRZi{BRDSUx>;6_>52BfRh_XbiEU6x?VBN*fouRCPLZBX~CaF!!-PD@QVXJR6Hl?`` zq9)NyHAy|FHSc-stYc}-ab6@)O;S6~&vQF&9Wp5J3q+g?q@HQ1cIUmi((0_(YopHSCE5^i zF6d0u3a%^4tYQUGDfE(DAmUt*EaBSZERmBz>fG>x6NA*Y6YcI-PYxvd@0bL}Gia}( z?pbikiR+5O-Nn7aJtWnxE2_Hj6KAciD74^S;U1Fe*A?~K{)5hax}wm6dxd)_6}7sk z+~JBs3+@$ulj!l?ftbU3U`=2J<4mNsXwA1Q?sERpnxhw<61ZB)tDN{HXH4f6df`cg zJ3^{P=kAr}uN}@^^up5)cb(KmT~Ws;t~$NCqRO4M@cBbn*8sR#}Q`@ZC zwwg@xDfm;$E3CB(8T0P-sB{weezb82!~m zs36j_2sIah8H2PD!&ns(n4tzinC&?4EF!xqB(S=WHewj7LIS&;LFnD$yAR%EM9o=5 zc2#o`)3>v!T+rV9sI>fL&E=7`6LH31R%Tb_5okd|6qIgf5@^K+$El7y6L~`Fn0xd}RW4VR@2OtTY A!~g&Q literal 0 HcmV?d00001 diff --git a/autorally_description/urdf/jump18deg.urdf b/autorally_description/urdf/jump18deg.urdf new file mode 100644 index 00000000..cfd34b94 --- /dev/null +++ b/autorally_description/urdf/jump18deg.urdf @@ -0,0 +1,32 @@ + + + + + true + + + + + + + + + + + + + + + + + + + + + + Gazebo/Grey + 1.0 + 1.0 + + + diff --git a/autorally_description/urdf/jump22deg.stl b/autorally_description/urdf/jump22deg.stl new file mode 100644 index 0000000000000000000000000000000000000000..80acabe2108e38ab9ed000b98e097762378d4bf1 GIT binary patch literal 3184 zcmb7`e`u9e7{?#XC4^%jIl&puO0b18Mzap;&USCX#UB}SA~^lWB?b}G-CWpe_h?~% zSbvO>LzFPYxy(rl6OZh^uk*(WlVD=dAC+hX1!HYPB4cXrbI!Z>exJ6GUhW?+e9!0o zKF@icd!DnQVQs3sZo|6rs;bImmGQ5#vOK+h?fUvvVHiFv|6flHxyKM0?O$hKBFdzr z_mc4&KMwHw>Nm@3j?KN3;`diND!!m-H9w9ps37rr__?DGY%bG+po95!PHF2tt&yHW zn8~P+SXgo9B1dv`URf>D!b3!b#7C*0qdYU|Pakio6$EWxQc}lC!~I_I-6=#86%rRt z8As1+8Wyzh5K$qqc&>Hy53}dj34)&K8+FQ4dsB6o?Gz%3YC59gtK})A$$Y)1^EkQ3 zgkB+XwI!~6seQaeoS~19h;!v6! z)lud@?e7VCN3AOD-=!;Nc01*EW3gBzGk>h~aFETOwJ+VvYTQwzC2{LPXE0JUpt5sz z3!=Vblk@v^+s#^}$s8KpA1oR^Z^y=41%dTPn#>bB+Jjkl2Gz^=-qENa@mb5|TF(6D zA6-!=KKb$-?TlHe|yBZZFI$k>&a?O|AT^-eYIjszesxGOb?lz6J#Z~_7 zBI47IOzdIV0}1p)I`Oat4}bRInJ9^-vFC!TBj2f|+4nRmNOY%)2RM(GZFi%yed8x{ zf|U=isLfm7*BCFZ@+UYEpZR2B56d1%pdZqShb?&c34oJ95?6LT$iK00NUfOJu2Dha z_lbQjkDVi}QB+;$hVpAV2bDR|t}$L*aCk{J8A zC;v<74RvZ!PNRZE{gKe+(bw8rLuSorTfS;!Q2q8nF8;2M7gza7O~kXEOzdIV12aTF zq!SNY@W`ZjPw)mHiR9+)Be33}4Q7CiiY2Pc^%UcI)U-_6JSIV}{NeIhEinoRW1=jY$^)z4jw zHn{;f0u`LpSSLxKf&_M`Bv3&D|C^FP1qnQrB!LPNIEf^I3KBR=B!LPNa(?(a_m$NDocEyk2G055cPHQZKIh*v O>Hi|UG9BS>`u_l3%Nia4 literal 0 HcmV?d00001 diff --git a/autorally_description/urdf/jump22deg.urdf b/autorally_description/urdf/jump22deg.urdf new file mode 100644 index 00000000..e53113c6 --- /dev/null +++ b/autorally_description/urdf/jump22deg.urdf @@ -0,0 +1,32 @@ + + + + + true + + + + + + + + + + + + + + + + + + + + + + Gazebo/Grey + 1.0 + 1.0 + + + diff --git a/autorally_description/urdf/jump26deg.stl b/autorally_description/urdf/jump26deg.stl new file mode 100644 index 0000000000000000000000000000000000000000..cf3940923101b85026de56ba70015f86c4d9e067 GIT binary patch literal 3384 zcmb7{e`r=^6vt02H>yQJlVMi8gh)Tgy{+Z$V0qv7y^7K{I;{@0ZwzLd+q2OnSXVfXz% zm`9h!*XE-8uNDvOmwVsi=cJN^Smq*_CRNup6>^McYTI?JY7^t&8w1&hFz+?beUG2d zMTi9ndsU17X&B`g*Nc4|V~oi6_;0zFJ8#~F<3!`R+Q0TJBlZ62L!&F_S2RuD-sjHz zeNJ0^&#ODI47~=2_8a2H2VQbX-Ls=2yrbum)9}-F_m@=O5b8vai(X%zUvG$yYk$?m z(r4?!jSqd}yxG|6cHX(x5a-{y>Y~@5A54DEt9rP7MTS(x%(`&r@*~bjO^;jIaZ+1+ z@6@|38T8s)Q=`9eJh%1xJ(`%P>Wn7t zZXFKyHFrB7J-^xQx_Dh%d~g1SZ!_q%YwwF$CRU%lMdxE_TOqu1yvb>v>U8rHFKdhM z-8EgEMX%OZ4jN+T?ng9n?~<`_VDMVwxgR^+*LM{RQMJAyi(Yl!1w$O^ZqvklJI;pN zt8QDA>3YExi|?_;^0HLY(KZ&IZm(Lj`@0T{z<3s|@^o}`(@oRPC)ZvrWl*bmRt7~2 zM6884=RrB=LSP0l|D^g0mEq*gUpq%nMJf?O@=r87|FKE}Rtdfr3CusKM;F$I)t!f( zngzWsT96R+5V3klU2b?fT-fxMGyKOk7nOltq8=hv52^I;{b9vKm*cJ5;-WIpOVmTe z>LGRb*0;mnnMUWyCpNpN4D=H95V3klRZkVd6@{yf^khjFzA08oz$!s6>_oWQScw5E z5xub6;f};=4_NK!g&h@lJ+7#LD+;}^Yhz~PIuE$c(F-R7Rx?H2Cn$Fx-{bCs)5q>5 zKfl*J`rD^B9NYStJ)>~K;k=5c+OhIflTL>3wTV)UCXRvA68oS{Ja}f_KCTbl*NV|Z zHk01WU9m*dSxx{+!uMtq_)UDuD4#UYf_r7hkhtbFqtJo`=ElU}F#4;BFoQ@Z2sIah zib2|nVXX=YRH#J|svX~(AmUXafz^ey6~kH;5?IX^LDKtVI^%m2M7$~_bT;(~5YKZZ zEog7Pk{O(fh|Z#hC>k)KJ|fl_>Nx%mL!d>zLkP*aUWu+vn?MT^ICpIVEl5cIqv@PpDd literal 0 HcmV?d00001 diff --git a/autorally_description/urdf/jump26deg.urdf b/autorally_description/urdf/jump26deg.urdf new file mode 100644 index 00000000..cebeabcd --- /dev/null +++ b/autorally_description/urdf/jump26deg.urdf @@ -0,0 +1,32 @@ + + + + + true + + + + + + + + + + + + + + + + + + + + + + Gazebo/Grey + 1.0 + 1.0 + + + diff --git a/autorally_description/urdf/jump30deg.stl b/autorally_description/urdf/jump30deg.stl new file mode 100644 index 0000000000000000000000000000000000000000..6a60a9d3556d06ed451c7a43f5df427fe5a1013f GIT binary patch literal 3684 zcmb7{e`u9e7{?!r+>$ja3n3ydF`*wKx0Q8YQ_sD7tzO1r%#Coi#V|DyRzpcwt2|qg zKXAq%k_u*)!G!J~GL`#Q_r0@Axfn~ybof`gtsk07xwH^!z0W!KJ@`JV52Zhb>dRV-EibgZ&6zA#?+iN|AZZB6ZprMX;gGWNeNkNA>;fAQV#51y>z zzjH=5RYmtD*UJv*d(Y+PoH>=yk(mgl)z~>6cci~LoU2UD(cZT&6%lG&_1ts$`Ame4 zAYrfS`=j+)o};O6E6?#2k>~RN`d;5182jre(O}i0ZyJ`7e151udp!TObM1z$qG``) z81dXMV#k+ZR^#RYMO^Nz6C`C%Y4GjsS!d^w*Tv43v?A)_-2$_!>vkxj_q88GVsPTo z;GW+OI@`{5h}$l-1Se|tJLlheMYN2UDB|obE0dU& z?_WK@pX2d$Jt0xHWJfUi*t^cveVfIKEB}UX+H-fiy-CdayP`VD#6#u7A<=qhZ}7}# zozCLLo5b*VcNp>96MN4jF{@+w-6(cx#ML79*NYw8c3jSFAfKxiYK^&XAT@g?9E=plm`r*ThSbt-4NF*+t4L&culqkQx zR$QFxE8@uyT2h!bEB=cj=1jaD5|#H~3)Vj;6YsRQh?+akE8_I!Z7D0u($&wg(O{so zH8YZ4YY{k~MawtOoyu1HbI|$t{Wl6VCz@JwtsWv)k5P$VREZ|6np?Vh;mdi!(5-z= z*Mdk_n$U_NnyMJ1E1z|R<065IA=$ZPdGKBOLuX~GLtq36tv4dp8_5f++Jg8GyPSDv z+68I}v$WobSZ^dx(eB`%+mEIV!e?ps3gHEK{a5O z)*BJ)O)HT-hLxxtPWzRW1aRb+ZS3-h-HhCj(a2>~o*@IcDMM zgX$q!a37!D2ea^mLyw`z6aAtmdM=#dG z?XNhlO%&#Ecn&=E(VcDLu4m<^ylaVMF6t~)$D;ZN9f`UO-N{TRJa;OApGkExG8{i# z5nsi=1mBfChtAYJ7DkZ3+Ne1~NY8;4M0y$_XChEBNLzDAj39vuwFpABBR!2Ut3m>I z7t+=o)~b-e-E0wr&Vb`iBh0Fhz>WiHYYuBwNQ7Dl`(WsIO$DQ|ie0$T*mNT7_V{95 z=}Xf@tV&eAS(PF%f`nFy?mlb+BS>KXU=tWYLMtZfGW4pYS`|i+&?=A F?msR0zh3|V literal 0 HcmV?d00001 diff --git a/autorally_description/urdf/jump30deg.urdf b/autorally_description/urdf/jump30deg.urdf new file mode 100644 index 00000000..23370c9c --- /dev/null +++ b/autorally_description/urdf/jump30deg.urdf @@ -0,0 +1,32 @@ + + + + + true + + + + + + + + + + + + + + + + + + + + + + Gazebo/Grey + 1.0 + 1.0 + + + diff --git a/autorally_gazebo/CMakeLists.txt b/autorally_gazebo/CMakeLists.txt new file mode 100644 index 00000000..1fdd89ff --- /dev/null +++ b/autorally_gazebo/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.8.3) +project(autorally_gazebo) +find_package(catkin REQUIRED) +catkin_python_setup() + +catkin_package() + +install(PROGRAMS + nodes/autorally_controller.py + nodes/wheelSpeedsGazebo.py + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}) + +install(DIRECTORY launch/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch + FILES_MATCHING PATTERN "*.launch" PATTERN "*.machine" PATTERN "*.yaml" PATTERN "*.urdf" +) + +install(DIRECTORY config/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/config + FILES_MATCHING PATTERN "*.yaml" +) diff --git a/autorally_gazebo/LICENSE.md b/autorally_gazebo/LICENSE.md new file mode 100644 index 00000000..37ec93a1 --- /dev/null +++ b/autorally_gazebo/LICENSE.md @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/autorally_gazebo/config/autoRallyPlatformCtrlrParams.yaml b/autorally_gazebo/config/autoRallyPlatformCtrlrParams.yaml new file mode 100644 index 00000000..ef4c4298 --- /dev/null +++ b/autorally_gazebo/config/autoRallyPlatformCtrlrParams.yaml @@ -0,0 +1,52 @@ +# autoRallyPlatformCtrlrParams.yaml +# +# This file defines auto_rally_controller parameter values used for simulating an +# AutoRally autonomous platform. +# +# Copyright (c) 2013 Wunderkammer Laboratory +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +left_front_wheel: + steering_link_name: left_front_wheel + steering_controller_name: left_steering_ctrlr + axle_controller_name: left_front_axle_ctrlr + diameter: 0.19 + +right_front_wheel: + steering_link_name: right_front_wheel + steering_controller_name: right_steering_ctrlr + axle_controller_name: right_front_axle_ctrlr + diameter: 0.19 + +left_rear_wheel: + link_name: left_rear_wheel + axle_controller_name: left_rear_axle_ctrlr + diameter: 0.19 + +right_rear_wheel: + link_name: right_rear_wheel + axle_controller_name: right_rear_axle_ctrlr + diameter: 0.19 + +# The equilibrium position of each shock absorber was measured from a stationary vehicle. + +shock_absorbers: + - controller_name: left_front_shock_ctrlr + equilibrium_position: 0.08 + - controller_name: right_front_shock_ctrlr + equilibrium_position: 0.08 + - controller_name: left_rear_shock_ctrlr + equilibrium_position: 0.09 + - controller_name: right_rear_shock_ctrlr + equilibrium_position: 0.09 diff --git a/autorally_gazebo/config/autoRallyPlatformJointCtrlrParams.yaml b/autorally_gazebo/config/autoRallyPlatformJointCtrlrParams.yaml new file mode 100644 index 00000000..74148fb0 --- /dev/null +++ b/autorally_gazebo/config/autoRallyPlatformJointCtrlrParams.yaml @@ -0,0 +1,87 @@ +# autoRallyPlatformJointCtrlrParams.yaml +# +# This file defines joint controller parameter values used for simulating an +# AutoRally autonomous platform. +# +# Copyright (c) 2013-2014 Wunderkammer Laboratory +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Publish the joint states to joint_states. +joint_state_ctrlr: + type: joint_state_controller/JointStateController + publish_rate: 50 + +left_steering_ctrlr: + joint: left_steering_joint + type: effort_controllers/JointPositionController + pid: {p: 5.0, i: 0.0, d: 0.3} +right_steering_ctrlr: + joint: right_steering_joint + type: effort_controllers/JointPositionController + pid: {p: 5.0, i: 0.0, d: 0.3} + +left_front_axle_ctrlr: + joint: left_front_axle + type: effort_controllers/JointEffortController + pid: {p: 1.5, i: 0.2, d: 0.0, i_clamp: 10.0} +right_front_axle_ctrlr: + joint: right_front_axle + type: effort_controllers/JointEffortController + pid: {p: 1.5, i: 0.2, d: 0.0, i_clamp: 10.0} +left_rear_axle_ctrlr: + joint: left_rear_axle + type: effort_controllers/JointEffortController + pid: {p: 1.5, i: 0.5, d: 0.0, i_clamp: 10.0} +right_rear_axle_ctrlr: + joint: right_rear_axle + type: effort_controllers/JointEffortController + pid: {p: 1.5, i: 0.5, d: 0.0, i_clamp: 10.0} + +# The proportional gain of each shock absorber controller is: +# front shock constant is 15 lb/in = 2626.902525 N/m +# rear shock constant is 19 lb/in = 3327.409865 N/m +# front: 2 * (0.06 * 2626.902525 / 0.1) = 3152.28303 +# rear: 2 * (0.07 * 3327.409865 / 0.11) = 4234.88528273 +# +# 2 * (shock_stroke * shock_spring_constant / wheel_travel). shock_stroke is +# 0.07 m. shock_spring_constant, an approximation of the AutoRally platform Shock +# shock absorber spring's constant +# +# looks like for 17 lb/in +# 2 * (0.07 * 2977.156195 / 0.1) = 4168.018673 +# sqrt(3 * 2977.156195)) = 94.5064473197 +# +# The derivative gain of each shock absorber controller is 2 * shock_damping. +# shock_damping, an approximation of the viscous damping coefficient of an +# Ultra Shock shock absorber, is 36.2416 Ns/m +# (i.e. sqrt(3 * shock_spring_constant)). +# sqrt(3 * needs to be computed)) = +# sqrt(3 * needs to eb computed)) = + +left_front_shock_ctrlr: + joint: left_front_shock + type: effort_controllers/JointPositionController + pid: {p: 3152.28303, i: 0.0, d: 20} +right_front_shock_ctrlr: + joint: right_front_shock + type: effort_controllers/JointPositionController + pid: {p: 3152.28303, i: 0.0, d: 20} +left_rear_shock_ctrlr: + joint: left_rear_shock + type: effort_controllers/JointPositionController + pid: {p: 4234.88528273, i: 0.0, d: 25} +right_rear_shock_ctrlr: + joint: right_rear_shock + type: effort_controllers/JointPositionController + pid: {p: 4234.88528273, i: 0.0, d: 25} diff --git a/autorally_gazebo/launch/autoRallyJumpGazeboSim.launch b/autorally_gazebo/launch/autoRallyJumpGazeboSim.launch new file mode 100644 index 00000000..683ada15 --- /dev/null +++ b/autorally_gazebo/launch/autoRallyJumpGazeboSim.launch @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_gazebo/launch/autoRallyJumpWorld.launch b/autorally_gazebo/launch/autoRallyJumpWorld.launch new file mode 100644 index 00000000..367316b6 --- /dev/null +++ b/autorally_gazebo/launch/autoRallyJumpWorld.launch @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_gazebo/launch/autoRallyTrackGazeboSim.launch b/autorally_gazebo/launch/autoRallyTrackGazeboSim.launch new file mode 100644 index 00000000..0cc756bb --- /dev/null +++ b/autorally_gazebo/launch/autoRallyTrackGazeboSim.launch @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_gazebo/launch/autoRallyTrackWorld.launch b/autorally_gazebo/launch/autoRallyTrackWorld.launch new file mode 100644 index 00000000..8b9f52ac --- /dev/null +++ b/autorally_gazebo/launch/autoRallyTrackWorld.launch @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autorally_gazebo/nodes/autorally_controller.py b/autorally_gazebo/nodes/autorally_controller.py new file mode 100755 index 00000000..2642eee2 --- /dev/null +++ b/autorally_gazebo/nodes/autorally_controller.py @@ -0,0 +1,600 @@ +#!/usr/bin/env python + +"""autorally_controller.py + +Control the wheels of a vehicle with Ackermann steering. + +Subscribed Topics: + servoCommand (autorally_msgs/servoMSG) + Servo command for the position fo each of the servos [-1, 1] + servoCommand (autorally_msgs/safeSpeed) + Whether the vehicle can move or not + +Published Topics: + /command (std_msgs/Float64) + Command for the left steering controller. + /command (std_msgs/Float64) + Command for the right steering controller. + /command (std_msgs/Float64) + Command for the left front axle controller. + /command (std_msgs/Float64) + Command for the right front axle controller. + /command (std_msgs/Float64) + Command for the left rear axle controller. + /command (std_msgs/Float64) + Command for the right rear axle controller. + /command (std_msgs/Float64) + One of these topics exists for each shock absorber. They are latched + topics. + +Services Called: + controller_manager/list_controllers (controller_manager_msgs/ + ListControllers) + List the states of the controllers. + +Parameters: + ~left_front_wheel/steering_link_name (string, default: left_steering_link) + ~right_front_wheel/steering_link_name (string, + default: right_steering_link) + Names of links that have origins coincident with the origins of the + left and right steering joints, respectively. The steering links are + used to compute the distance between the steering joints, as well as + the vehicle's wheelbase. + + ~left_front_wheel/steering_controller_name (string, default: + left_steering_controller) + ~right_front_wheel/steering_controller_name (string, default: + right_steering_controller) + Steering controller names. + + ~left_rear_wheel/link_name (string, default: left_wheel) + ~right_rear_wheel/link_name (string, default: right_wheel) + Names of links that have origins coincident with the centers of the + left and right wheels, respectively. The rear wheel links are used to + compute the vehicle's wheelbase. + + ~left_front_wheel/axle_controller_name (string) + ~right_front_wheel/axle_controller_name + ~left_rear_wheel/axle_controller_name + ~right_rear_wheel/axle_controller_name + Axle controller names. If no controller name is specified for an axle, + that axle will not have a controller. This allows the control of + front-wheel, rear-wheel, and four-wheel drive vehicles. + + ~left_front_wheel/diameter (float, default: 1.0) + ~right_front_wheel/diameter + ~left_rear_wheel/diameter + ~right_rear_wheel/diameter + Wheel diameters. Each diameter must be greater than zero. Unit: meter. + + ~shock_absorbers (sequence of mappings, default: empty) + Zero or more shock absorbers. + + Key-Value Pairs: + + controller_name (string) + Controller name. + equilibrium_position (float, default: 0.0) + Equilibrium position. Unit: meter. + + ~cmd_timeout (float, default: 0.5) + If ~cmd_timeout is greater than zero and this node does not receive a + command for more than ~cmd_timeout seconds, vehicle motion is paused + until a command is received. If ~cmd_timeout is less than or equal to + zero, the command timeout is disabled. + ~publishing_frequency (float, default: 30.0) + Joint command publishing frequency. It must be greater than zero. + Unit: hertz. + +Required tf Transforms: + <~left_front_wheel/steering_link_name> to <~right_rear_wheel/link_name> + Specifies the position of the left front wheel's steering link in the + right rear wheel's frame. + <~right_front_wheel/steering_link_name> to <~right_rear_wheel/link_name> + Specifies the position of the right front wheel's steering link in the + right rear wheel's frame. + <~left_rear_wheel/link_name> to <~right_rear_wheel/link_name> + Specifies the position of the left rear wheel in the right rear + wheel's frame. + +Copyright (c) 2013-2014 Wunderkammer Laboratory + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +import math +import numpy +import threading +import operator + +from math import pi + +import rospy +import tf + +from autorally_msgs.msg import servoMSG +from autorally_msgs.msg import safeSpeed +from std_msgs.msg import Float64 +from controller_manager_msgs.srv import ListControllers + + +class AutoRallyCtrlr(object): + """AutoRally controller + + An object of class AutoRallyCtrlr is a node that controls the wheels of a + vehicle with Ackermann steering (AutoRally platform). + """ + + def __init__(self, namespace='controller_manager'): + """Initialize this _AutoRallyCtrlr.""" + + rospy.init_node("autorally_controller") + + # Parameters + + # Wheels + (left_steer_link_name, left_steer_ctrlr_name, + left_front_axle_ctrlr_name, self._left_front_inv_circ) = \ + self._get_front_wheel_params("left") + (right_steer_link_name, right_steer_ctrlr_name, + right_front_axle_ctrlr_name, self._right_front_inv_circ) = \ + self._get_front_wheel_params("right") + (left_rear_link_name, left_rear_axle_ctrlr_name, + self._left_rear_inv_circ) = \ + self._get_rear_wheel_params("left") + (self._right_rear_link_name, right_rear_axle_ctrlr_name, + self._right_rear_inv_circ) = \ + self._get_rear_wheel_params("right") + + list_ctrlrs = rospy.ServiceProxy(namespace + '/list_controllers', + ListControllers) + list_ctrlrs.wait_for_service() + + # Shock absorbers + shock_param_list = rospy.get_param("~shock_absorbers", []) + self._shock_pubs = [] + try: + for shock_params in shock_param_list: + try: + ctrlr_name = shock_params["controller_name"] + try: + eq_pos = shock_params["equilibrium_position"] + except: + eq_pos = self._DEF_EQ_POS + eq_pos = float(eq_pos) + except: + rospy.logwarn("An invalid parameter was specified for a " + "shock absorber. The shock absorber will " + "not be used.") + continue + + pub = rospy.Publisher(ctrlr_name + "/command", Float64, + latch=True, queue_size=1) + _wait_for_ctrlr(list_ctrlrs, ctrlr_name) + pub.publish(eq_pos) + self._shock_pubs.append(pub) + except: + rospy.logwarn("The specified list of shock absorbers is invalid. " + "No shock absorbers will be used.") + + # Command timeout + try: + self._cmd_timeout = float(rospy.get_param("~cmd_timeout", + self._DEF_CMD_TIMEOUT)) + except: + rospy.logwarn("The specified command timeout value is invalid. " + "The default timeout value will be used instead.") + self._cmd_timeout = self._DEF_CMD_TIMEOUT + + # Publishing frequency + try: + pub_freq = float(rospy.get_param("~publishing_frequency", + self._DEF_PUB_FREQ)) + if pub_freq <= 0.0: + raise ValueError() + except: + rospy.logwarn("The specified publishing frequency is invalid. " + "The default frequency will be used instead.") + pub_freq = self._DEF_PUB_FREQ + self._sleep_timer = rospy.Rate(pub_freq) + + # _last_cmd_time is the time at which the most recent Ackermann + # driving command was received. + self._last_cmd_time = rospy.get_time() + + # _ackermann_cmd_lock is used to control access to _steer_ang, + # _steer_ang_vel, _speed, and _accel. +# self._ackermann_cmd_lock = threading.Lock() +# self._steer_ang = 0.0 # Steering angle +# self._steer_ang_vel = 0.0 # Steering angle velocity +# self._speed = 0.0 +# self._accel = 0.0 # Acceleration + + + self._last_steer_ang = 0.0 # Last steering angle + self._theta_left = 0.0 # Left steering joint angle + self._theta_right = 0.0 # Right steering joint angle + + self._last_speed = 0.0 + self._last_accel_limit = 0.0 # Last acceleration limit + # Axle angular velocities + self._left_front_ang_vel = 0.0 + self._right_front_ang_vel = 0.0 + self._left_rear_ang_vel = 0.0 + self._right_rear_ang_vel = 0.0 + + # _joint_dist_div_2 is the distance between the steering joints, + # divided by two. + tfl = tf.TransformListener() + ls_pos = self._get_link_pos(tfl, left_steer_link_name) + rs_pos = self._get_link_pos(tfl, right_steer_link_name) + self._joint_dist_div_2 = numpy.linalg.norm(ls_pos - rs_pos) / 2 + lrw_pos = self._get_link_pos(tfl, left_rear_link_name) + rrw_pos = numpy.array([0.0] * 3) + front_cent_pos = (ls_pos + rs_pos) / 2 # Front center position + rear_cent_pos = (lrw_pos + rrw_pos) / 2 # Rear center position + self._wheelbase = numpy.linalg.norm(front_cent_pos - rear_cent_pos) + self._inv_wheelbase = 1 / self._wheelbase # Inverse of _wheelbase + self._wheelbase_sqr = self._wheelbase ** 2 + + #self.lastCmdTime = rospy.get_time() + self.servoCmds = dict() + self.servoCmdLock = threading.Lock() + + #load servo commander priorities + self.commandPriorities = rospy.get_param("~servoCommandProirities", []) + self.commandPriorities = sorted(self.commandPriorities.items(), key=operator.itemgetter(1)) + rospy.loginfo("AutoRallyGazeboController: Loaded %d servo commanders", len(self.commandPriorities)) + + #safeSpeed information + self.safeSpeeds = dict() + self.safeSpeedLock = threading.Lock() + + self.front_axle_max_effort = 2.5 + self.rear_axle_max_effort = 8 + self.rear_axle_brake_effort = 4 + + #self.rear_axle_reverse_percent = 0.25 # percent of max_effort applied when reversing + #self.rear_axle_reverse_effort = self.rear_axle_max_effort*self.rear_axle_reverse_percent + + # Publishers and subscribers + self._left_steer_cmd_pub = \ + _create_cmd_pub(list_ctrlrs, left_steer_ctrlr_name) + self._right_steer_cmd_pub = \ + _create_cmd_pub(list_ctrlrs, right_steer_ctrlr_name) + + self._left_front_axle_cmd_pub = \ + _create_axle_cmd_pub(list_ctrlrs, left_front_axle_ctrlr_name) + self._right_front_axle_cmd_pub = \ + _create_axle_cmd_pub(list_ctrlrs, right_front_axle_ctrlr_name) + self._left_rear_axle_cmd_pub = \ + _create_axle_cmd_pub(list_ctrlrs, left_rear_axle_ctrlr_name) + self._right_rear_axle_cmd_pub = \ + _create_axle_cmd_pub(list_ctrlrs, right_rear_axle_ctrlr_name) + + self.servoCmdSub = dict() + for cmd, priority in self.commandPriorities: + self.servoCmdSub[cmd] = \ + rospy.Subscriber(cmd+"/servoCommand", servoMSG, + self.servoCmdCb, queue_size=1) + + self.safeSpeedSub = rospy.Subscriber("/safeSpeed", safeSpeed, + self.safeSpeedCb, queue_size=1) + + self.servoStatusPub = rospy.Publisher("/servoStatus", servoMSG, queue_size=1) + + def spin(self): + """Control the vehicle.""" + + last_time = rospy.get_time() + + while not rospy.is_shutdown(): + t = rospy.get_time() + delta_t = t - last_time + last_time = t + + frontBrake = 0.0; + speed = 0.0; + servoStatus = servoMSG() + servoStatus.safeSpeed = self.getSafeSpeed(); + if (self._cmd_timeout > 0.0 and + t - self._last_cmd_time > self._cmd_timeout): + # Too much time has elapsed since the last command. Stop the + # vehicle. + steer_ang_changed, center_y = \ + self._ctrl_steering(self._last_steer_ang, 0.0, 0.001) + self._ctrl_axles(0.0, 0.0, 0.0, steer_ang_changed, center_y) + elif delta_t > 0.0: + #with self._ackermann_cmd_lock: + # steer_ang = self._steer_ang + # steer_ang_vel = self._steer_ang_vel + # speed = self._speed + # accel = self._accel + with self.servoCmdLock: + foundSteering = False + foundThrottle = False + foundFrontBrake = False + steer_ang = 0.0 + steer_ang_vel = 0.0 + foundSteering = False + accel = 0.0 + + if servoStatus.safeSpeed < 0.0001: + servoStatus.throttle = 0.0; + foundThrottle = True + + for cmd,priority in self.commandPriorities: + #rospy.logwarn("looking for servo commander %s with priority %d", cmd, priority) + if cmd in self.servoCmds: + if abs(self.servoCmds[cmd].steering) <= 1.0 and \ + (rospy.Time.now()-self.servoCmds[cmd].header.stamp) < \ + rospy.Duration.from_sec(0.2) and\ + not foundSteering: + #rospy.loginfo("%s in control of steering", cmd); + steer_ang = -math.radians(25)*self.servoCmds[cmd].steering + steer_ang_vel = 0.0 + servoStatus.steering = self.servoCmds[cmd].steering + foundSteering = True + + if abs(self.servoCmds[cmd].throttle) <= 1.0 and \ + (rospy.Time.now()-self.servoCmds[cmd].header.stamp) < \ + rospy.Duration.from_sec(0.2) and\ + not foundThrottle: + + #rospy.loginfo("%s in control of throttle", cmd); + if self.servoCmds[cmd].throttle >= 0.0: + speed = self.rear_axle_max_effort*self.servoCmds[cmd].throttle + else: + speed = self.rear_axle_brake_effort*self.servoCmds[cmd].throttle + + accel = 0.0 + servoStatus.throttle = self.servoCmds[cmd].throttle + foundThrottle = True + + if self.servoCmds[cmd].frontBrake > 0.0 and \ + self.servoCmds[cmd].frontBrake < 1.0 and \ + (rospy.Time.now()-self.servoCmds[cmd].header.stamp) < \ + rospy.Duration.from_sec(0.2) and\ + not foundFrontBrake: + + #rospy.loginfo("%s in control of front brake", cmd); + frontBrake = -self.front_axle_brake_effort*self.servoCmds[cmd].frontBrake + servoStatus.frontBrake = self.servoCmds[cmd].frontBrake + foundFrontBrake = True + + else: + frontBrake = 0 + + steer_ang_changed, center_y = \ + self._ctrl_steering(steer_ang, steer_ang_vel, delta_t) + self._ctrl_axles(speed, accel, delta_t, steer_ang_changed, + center_y) + + # Publish the steering and axle joint commands. + '''self._left_steer_cmd_pub.publish(self._theta_left) + self._right_steer_cmd_pub.publish(self._theta_right) + if self._left_front_axle_cmd_pub: + self._left_front_axle_cmd_pub.publish(self._left_front_ang_vel) + if self._right_front_axle_cmd_pub: + self._right_front_axle_cmd_pub.\ + publish(self._right_front_ang_vel) + if self._left_rear_axle_cmd_pub: + self._left_rear_axle_cmd_pub.publish(self._left_rear_ang_vel) + if self._right_rear_axle_cmd_pub: + self._right_rear_axle_cmd_pub.publish(self._right_rear_ang_vel) + ''' + servoStatus.header.stamp = rospy.Time.now() + self.servoStatusPub.publish(servoStatus) + + self._left_steer_cmd_pub.publish(self._theta_left) + self._right_steer_cmd_pub.publish(self._theta_right) + if self._left_front_axle_cmd_pub: + self._left_front_axle_cmd_pub.publish(frontBrake) + if self._right_front_axle_cmd_pub: + self._right_front_axle_cmd_pub.publish(frontBrake) + if self._left_rear_axle_cmd_pub: + self._left_rear_axle_cmd_pub.publish(speed) + if self._right_rear_axle_cmd_pub: + self._right_rear_axle_cmd_pub.publish(speed) + + try: + self._sleep_timer.sleep() + except rospy.exceptions.ROSTimeMovedBackwardsException: + continue #rospy.loginfo() + + def servoCmdCb(self, servoCommand): + """Servo command callback + + :Parameters: + servoCommand : autorally_msgs.msg.servoMSG + Position to set the control servos + """ + with self.servoCmdLock: + #self.lastCmdTime = rospy.get_time() + self.servoCmds[servoCommand.header.frame_id] = servoCommand + self._last_cmd_time = rospy.get_time() + + def safeSpeedCb(self, safeSpeed): + with self.safeSpeedLock: + self.safeSpeeds[safeSpeed.sender] = safeSpeed + + def getSafeSpeed(self): + with self.safeSpeedLock: + ss = 25; + for safeSpeed in self.safeSpeeds: + if self.safeSpeeds[safeSpeed].speed < ss: + ss = self.safeSpeeds[safeSpeed].speed + return ss + + def _get_front_wheel_params(self, side): + # Get front wheel parameters. Return a tuple containing the steering + # link name, steering controller name, axle controller name (or None), + # and inverse of the circumference. + + prefix = "~" + side + "_front_wheel/" + steer_link_name = rospy.get_param(prefix + "steering_link_name", + side + "_steering_link") + steer_ctrlr_name = rospy.get_param(prefix + "steering_controller_name", + side + "_steering_controller") + axle_ctrlr_name, inv_circ = self._get_common_wheel_params(prefix) + return steer_link_name, steer_ctrlr_name, axle_ctrlr_name, inv_circ + + def _get_rear_wheel_params(self, side): + # Get rear wheel parameters. Return a tuple containing the link name, + # axle controller name, and inverse of the circumference. + + prefix = "~" + side + "_rear_wheel/" + link_name = rospy.get_param(prefix + "link_name", side + "_wheel") + axle_ctrlr_name, inv_circ = self._get_common_wheel_params(prefix) + return link_name, axle_ctrlr_name, inv_circ + + def _get_common_wheel_params(self, prefix): + # Get parameters used by the front and rear wheels. Return a tuple + # containing the axle controller name (or None) and the inverse of the + # circumference. + + axle_ctrlr_name = rospy.get_param(prefix + "axle_controller_name", + None) + + try: + dia = float(rospy.get_param(prefix + "diameter", + self._DEF_WHEEL_DIA)) + if dia <= 0.0: + raise ValueError() + except: + rospy.logwarn("The specified wheel diameter is invalid. " + "The default diameter will be used instead.") + dia = self._DEF_WHEEL_DIA + + return axle_ctrlr_name, 1 / (pi * dia) + + def _get_link_pos(self, tfl, link): + # Return the position of the specified link, relative to the right + # rear wheel link. + + while True: + try: + trans, not_used = \ + tfl.lookupTransform(self._right_rear_link_name, link, + rospy.Time(0)) + return numpy.array(trans) + except: + pass + + def _ctrl_steering(self, steer_ang, steer_ang_vel_limit, delta_t): + # Control the steering joints. + + # Compute theta, the virtual front wheel's desired steering angle. + if steer_ang_vel_limit > 0.0: + # Limit the steering velocity. + ang_vel = (steer_ang - self._last_steer_ang) / delta_t + ang_vel = max(-steer_ang_vel_limit, + min(ang_vel, steer_ang_vel_limit)) + theta = self._last_steer_ang + ang_vel * delta_t + else: + theta = steer_ang + + # Compute the desired steering angles for the left and right front + # wheels. + center_y = self._wheelbase * math.tan((pi / 2) - theta) + steer_ang_changed = theta != self._last_steer_ang + if steer_ang_changed: + self._last_steer_ang = theta + self._theta_left = \ + _get_steer_ang(math.atan(self._inv_wheelbase * + (center_y - self._joint_dist_div_2))) + self._theta_right = \ + _get_steer_ang(math.atan(self._inv_wheelbase * + (center_y + self._joint_dist_div_2))) + + return steer_ang_changed, center_y + + def _ctrl_axles(self, speed, accel_limit, delta_t, steer_ang_changed, + center_y): + # Control the axle joints. + + # Compute veh_speed, the vehicle's desired speed. + if accel_limit > 0.0: + # Limit the vehicle's acceleration. + self._last_accel_limit = accel_limit + accel = (speed - self._last_speed) / delta_t + accel = max(-accel_limit, min(accel, accel_limit)) + veh_speed = self._last_speed + accel * delta_t + else: + self._last_accel_limit = accel_limit + veh_speed = speed + + # Compute the desired angular velocities of the wheels. + if veh_speed != self._last_speed or steer_ang_changed: + self._last_speed = veh_speed + left_dist = center_y - self._joint_dist_div_2 + right_dist = center_y + self._joint_dist_div_2 + + # Front + gain = (2 * pi) * veh_speed / abs(center_y) + r = math.sqrt(left_dist ** 2 + self._wheelbase_sqr) + self._left_front_ang_vel = gain * r * self._left_front_inv_circ + r = math.sqrt(right_dist ** 2 + self._wheelbase_sqr) + self._right_front_ang_vel = gain * r * self._right_front_inv_circ + # Rear + gain = (2 * pi) * veh_speed / center_y + self._left_rear_ang_vel = \ + gain * left_dist * self._left_rear_inv_circ + self._right_rear_ang_vel = \ + gain * right_dist * self._right_rear_inv_circ + + _DEF_WHEEL_DIA = 0.19 # Default wheel diameter. Unit: meter. + _DEF_EQ_POS = 0.0 # Default equilibrium position. Unit: meter. + _DEF_CMD_TIMEOUT = 0.5 # Default command timeout. Unit: second. + _DEF_PUB_FREQ = 50.0 # Default publishing frequency. Unit: hertz. +# end _AckermannCtrlr + + +def _wait_for_ctrlr(list_ctrlrs, ctrlr_name): + # Wait for the specified controller to be in the "running" state. + # Commands can be lost if they are published before their controller is + # running, even if a latched publisher is used. + + while True: + response = list_ctrlrs() + for ctrlr in response.controller: + if ctrlr.name == ctrlr_name: + if ctrlr.state == "running": + return + rospy.sleep(0.1) + break + + +def _create_axle_cmd_pub(list_ctrlrs, axle_ctrlr_name): + # Create an axle command publisher. + if not axle_ctrlr_name: + return None + return _create_cmd_pub(list_ctrlrs, axle_ctrlr_name) + + +def _create_cmd_pub(list_ctrlrs, ctrlr_name): + # Create a command publisher. + _wait_for_ctrlr(list_ctrlrs, ctrlr_name) + return rospy.Publisher(ctrlr_name + "/command", Float64, queue_size=1) + + +def _get_steer_ang(phi): + # Return the desired steering angle for a front wheel. + if phi >= 0.0: + return (pi / 2) - phi + return (-pi / 2) - phi + +# main +if __name__ == "__main__": + ctrlr = AutoRallyCtrlr() + ctrlr.spin() diff --git a/autorally_gazebo/nodes/wheelSpeedsGazebo.py b/autorally_gazebo/nodes/wheelSpeedsGazebo.py new file mode 100755 index 00000000..54e574c8 --- /dev/null +++ b/autorally_gazebo/nodes/wheelSpeedsGazebo.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# license removed for brevity +import rospy +import math +from autorally_msgs.msg import wheelSpeeds +from gazebo_msgs.msg import ModelStates +from sensor_msgs.msg import JointState + +from autorally_msgs.msg import servoMSG + + +class WheelSpeedsGazebo(object): + + def getWheelSpeed(self, data, name, dia): + try: + idx = data.name.index(name) + #return data.twist[idx].angular.y * (dia)/2.0 #if data is from linkState message + return abs(data.velocity[idx]*(dia/2.0)) + except IndexError: + rospy.logerror('modelStates does not contain ' + name) + return 0.0 + + + def callback(self, data): + ws = wheelSpeeds() + ws.header.stamp = rospy.Time.now() + ws.header.frame_id = 'gazeboSim' + + #print data + ws.lfSpeed = self.getWheelSpeed(data, self.left_front_name, self.left_front_dia) + ws.rfSpeed = self.getWheelSpeed(data, self.right_front_name, self.right_front_dia) + ws.lbSpeed = self.getWheelSpeed(data, self.left_rear_name, self.left_rear_dia) + ws.rbSpeed = self.getWheelSpeed(data, self.right_rear_name, self.right_rear_dia) + + if self.pub: + self.pub.publish(ws) + + + def getJointStateWheelParams(self, lr_prefix, fr_prefix): + dia = rospy.get_param('/autorally_platform/autorally_controller/' + lr_prefix + '_' + fr_prefix + '_wheel/diameter') + name = lr_prefix + '_' + fr_prefix + '_axle' + return name, dia + + def getLinkStateFrontWheelParams(self, lr_prefix): + dia = rospy.get_param('/autorally_platform/autorally_controller/' + lr_prefix + '_front_wheel/diameter') + name = 'autorally_platform::' + rospy.get_param('/autorally_platform/autorally_controller/' + lr_prefix + '_front_wheel/steering_link_name') + return name, dia + + def getLinkStateRearWheelParams(self, lr_prefix): + dia = rospy.get_param('/autorally_platform/autorally_controller/' + lr_prefix + '_rear_wheel/diameter') + name = 'autorally_platform::' + rospy.get_param('/autorally_platform/autorally_controller/' + lr_prefix + '_rear_wheel/link_name') + return name, dia + + def __init__(self): + + rospy.init_node('wheelSpeedsGazebo') + + self.left_front_name, self.left_front_dia = self.getJointStateWheelParams('left', 'front') + self.right_front_name, self.right_front_dia = self.getJointStateWheelParams('right', 'front') + self.left_rear_name, self.left_rear_dia = self.getJointStateWheelParams('left', 'rear') + self.right_rear_name, self.right_rear_dia = self.getJointStateWheelParams('right', 'rear') + + #don't set up callback until params are initialized + self.pub = rospy.Publisher('/wheelSpeeds', wheelSpeeds, queue_size=1) + #self.sub = rospy.Subscriber('/autorally_platform/gazebo/link_states', ModelStates, self.callback) + self.sub = rospy.Subscriber('/autorally_platform/joint_states', JointState, self.callback) + +if __name__ == "__main__": + speed = WheelSpeedsGazebo() + rospy.spin() diff --git a/autorally_gazebo/package.xml b/autorally_gazebo/package.xml new file mode 100644 index 00000000..16b359ac --- /dev/null +++ b/autorally_gazebo/package.xml @@ -0,0 +1,47 @@ + + + + autorally_gazebo + 0.1.0 + + autorally_gazebo is used with Gazebo to simulate the AutoRally + platform. This package was adapted from ackermann_vehicle_gazebo. + + + Brian Goldfain + BSD + + Brian Goldfain + + http://autorally.github.io + + catkin + + controller_manager + gazebo_ros + gazebo_ros_control + rospy + std_msgs + tf + xacro + hector_gazebo_plugins + hector_gazebo_worlds + joy + effort_controllers + joint_state_controller + + diff --git a/autorally_gazebo/setup.py b/autorally_gazebo/setup.py new file mode 100644 index 00000000..6a3ff9d8 --- /dev/null +++ b/autorally_gazebo/setup.py @@ -0,0 +1,32 @@ +# Software License Agreement (BSD License) +# Copyright (c) 2013, Georgia Institute of Technology +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +from distutils.core import setup +from catkin_pkg.python_setup import generate_distutils_setup + +d = generate_distutils_setup( + scripts=['nodes/autorally_controller.py', 'nodes/wheelSpeedsGazebo.py'], + requires=['std_msgs', 'rospy', 'autorally_msgs'] +) + +setup(**d) diff --git a/autorally_msgs/CMakeLists.txt b/autorally_msgs/CMakeLists.txt new file mode 100644 index 00000000..0a29616a --- /dev/null +++ b/autorally_msgs/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 2.8.3) +project(autorally_msgs) + +find_package(catkin REQUIRED COMPONENTS + genmsg + std_msgs + sensor_msgs + geometry_msgs + diagnostic_msgs +) + +find_package(Boost REQUIRED thread) + +add_message_files( + DIRECTORY msg + FILES + safeSpeed.msg + wheelSpeeds.msg + imageMask.msg + servoMSG.msg + line2D.msg + point2D.msg +) + +generate_messages(DEPENDENCIES + std_msgs + sensor_msgs + geometry_msgs + diagnostic_msgs +) + +catkin_package() diff --git a/autorally_msgs/msg/imageMask.msg b/autorally_msgs/msg/imageMask.msg new file mode 100644 index 00000000..c5548cef --- /dev/null +++ b/autorally_msgs/msg/imageMask.msg @@ -0,0 +1,6 @@ +Header header + +string sender +point2D[] points +line2D[] lines +sensor_msgs/RegionOfInterest[] rois diff --git a/autorally_msgs/msg/line2D.msg b/autorally_msgs/msg/line2D.msg new file mode 100644 index 00000000..f9d7ba44 --- /dev/null +++ b/autorally_msgs/msg/line2D.msg @@ -0,0 +1,2 @@ +point2D start +point2D end diff --git a/autorally_msgs/msg/point2D.msg b/autorally_msgs/msg/point2D.msg new file mode 100644 index 00000000..7f0ef5c4 --- /dev/null +++ b/autorally_msgs/msg/point2D.msg @@ -0,0 +1,2 @@ +uint16 x +uint16 y diff --git a/autorally_msgs/msg/safeSpeed.msg b/autorally_msgs/msg/safeSpeed.msg new file mode 100644 index 00000000..9c0b7adc --- /dev/null +++ b/autorally_msgs/msg/safeSpeed.msg @@ -0,0 +1,4 @@ +Header header + +string sender +float64 speed diff --git a/autorally_msgs/msg/servoMSG.msg b/autorally_msgs/msg/servoMSG.msg new file mode 100644 index 00000000..1bc233dc --- /dev/null +++ b/autorally_msgs/msg/servoMSG.msg @@ -0,0 +1,6 @@ +Header header +float64 throttle +float64 steering +float64 frontBrake +float64 backBrake +float64 safeSpeed diff --git a/autorally_msgs/msg/wheelSpeeds.msg b/autorally_msgs/msg/wheelSpeeds.msg new file mode 100644 index 00000000..b537dbae --- /dev/null +++ b/autorally_msgs/msg/wheelSpeeds.msg @@ -0,0 +1,5 @@ +Header header +float64 lfSpeed +float64 rfSpeed +float64 lbSpeed +float64 rbSpeed diff --git a/autorally_msgs/package.xml b/autorally_msgs/package.xml new file mode 100644 index 00000000..48028b56 --- /dev/null +++ b/autorally_msgs/package.xml @@ -0,0 +1,45 @@ + + + + autorally_msgs + 0.1.0 + Custom messages used by autorally + + Brian Goldfain + + Brian Goldfain + + http://autorally.github.io + + BSD + + Brian Goldfain + + catkin + genmsg + + geometry_msgs + sensor_msgs + std_msgs + + geometry_msgs + sensor_msgs + std_msgs + + + + diff --git a/autorally_util/99-autoRally.rules b/autorally_util/99-autoRally.rules new file mode 100644 index 00000000..ea1441f6 --- /dev/null +++ b/autorally_util/99-autoRally.rules @@ -0,0 +1,41 @@ +# GPS Base +# Replace "PORT_*_SERIAL" with the serial number for the USB-to-serial adapter for each port +SUBSYSTEM=="tty", ATTRS{serial}=="PORT_A_SERIAL", MODE="0666", SYMLINK+="arGPSBasePortA" +SUBSYSTEM=="tty", ATTRS{serial}=="PORT_B_SERIAL", MODE="0666", SYMLINK+="arGPSBasePortB" + +# GPS Rovers +# Replace "PORT_*_SERIAL" with the serial number for the USB-to-serial adapter for each port +SUBSYSTEM=="tty", ATTRS{serial}=="PORT_A_SERIAL", MODE="0666", SYMLINK+="arGPSRoverPortA" +SUBSYSTEM=="tty", ATTRS{serial}=="PORT_B_SERIAL", MODE="0666", SYMLINK+="arGPSRoverPortB" +SUBSYSTEM=="tty", ATTRS{serial}=="PORT_D_SERIAL", MODE="0666", SYMLINK+="arGPSRoverPortD" + +# Xbee Nodes +# Replace "XBEE_ADAPTER_SERIAL" with the serial number of the USB-to-serial adapter for the compute box XBee +SUBSYSTEM=="tty", ATTRS{serial}=="XBEE_ADAPTER_SERIAL", MODE="0666", SYMLINK+="arXbeeNode" + +# Coordinator +# Replace "XBEE_ADAPTER_SERIAL" with the serial number of the USB-to-serial adapter for the base station XBee +SUBSYSTEM=="tty", ATTRS{serial}=="XBEE_ADAPTER_SERIAL", MODE="0666", SYMLINK+="arXbeeCoordinator" + +# Cameras +# For each camera, replace "CAMERAGUID" with the camera's GUID shown in FlyCap +# For each camera, replace "CAMERA_SERIAL" with the camera's serial number shown in FlyCap +SUBSYSTEM=="usb", ATTRS{idVendor}=="1e10", ATTRS{serial}=="CAMERA_SERIAL", MODE="0666", SYMLINK+="arCamera_CAMERAGUID", GROUP="plugdev" +SUBSYSTEM=="usb", ATTRS{idVendor}=="1e10", ATTRS{serial}=="CAMERA_SERIAL", MODE="0666", SYMLINK+="arCamera_CAMERAGUID", GROUP="plugdev" + +# +# The following rules do not need to be customized +# + +# Arduino UNO +SUBSYSTEM=="tty", ATTRS{manufacturer}=="Arduino (www.arduino.cc)", ATTRS{idProduct}=="0043", SYMLINK+="arRunStop" +SUBSYSTEMS=="usb", ATTRS{manufacturer}=="Arduino (www.arduino.cc)", ATTRS{product}=="Arduino Uno", MODE="0666", SYMLINK+="arRunStop" + +# Arduino Micro +SUBSYSTEM=="tty", ATTRS{manufacturer}=="Arduino Srl", ATTRS{idProduct}=="8037", ATTRS{product}=="Arduino Micro", SYMLINK+="arComputeBoxArduino" + +# Arduino Due +SUBSYSTEM=="tty", ATTRS{manufacturer}=="Arduino (www.arduino.org)", ATTRS{idProduct}=="003d", ATTRS{product}=="Arduino Due Prog. Port", MODE="0666", SYMLINK+="arChassis" + +# IMU +DRIVERS=="usb", ATTRS{manufacturer}=="Lord Microstrain", ATTRS{product}=="Lord Inertial Sensor", MODE="0666", SYMLINK+="arLordIMU" diff --git a/autorally_util/CMakeLists.txt b/autorally_util/CMakeLists.txt new file mode 100644 index 00000000..519c710d --- /dev/null +++ b/autorally_util/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 2.8.3) +project(autorally_util) + +find_package(catkin REQUIRED COMPONENTS +) + +catkin_package() + +install(DIRECTORY config/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/config + FILES_MATCHING PATTERN "*" +) diff --git a/autorally_util/chrony.keys b/autorally_util/chrony.keys new file mode 100644 index 00000000..4023c8be --- /dev/null +++ b/autorally_util/chrony.keys @@ -0,0 +1,25 @@ +####################################################################### +# +# This is an example chrony keys file. You should copy it to /etc/chrony.keys +# after editing it to set up the key(s) you want to use. In most situations, +# you will require a single key (the 'commandkey') so that you can supply a +# password to chronyc to enable you to modify chronyd's operation whilst it is +# running. +# +# Copyright 2002 Richard P. Curnow +# +####################################################################### +# A valid key line looks like this + +1 PASSWORD + +# It must consist of an integer, followed by whitespace, followed by a block of +# text with no spaces in it. (You cannot put a space in a key). If you wanted +# to use the above line as your commandkey (i.e. chronyc password), you would +# put the following line into chrony.conf (remove the # from the start): + +# commandkey 1 + +# You might want to define more keys if you use the MD5 authentication facility +# in the network time protocol to authenticate request/response packets between +# trusted clients and servers. diff --git a/autorally_util/chronyClient.conf b/autorally_util/chronyClient.conf new file mode 100644 index 00000000..dcac100a --- /dev/null +++ b/autorally_util/chronyClient.conf @@ -0,0 +1,323 @@ +####################################################################### +# +# This is an example chrony configuration file. You should copy it to +# /etc/chrony.conf after uncommenting and editing the options that you +# want to enable. The more obscure options are not included. Refer +# to the documentation for these. +# +# Copyright 2002 Richard P. Curnow +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# +####################################################################### +### COMMENTS +# Any of the following lines are comments (you have a choice of +# comment start character): +# a comment +% a comment +! a comment +; a comment +# +# Below, the '!' form is used for lines that you might want to +# uncomment and edit to make your own chrony.conf file. +# +####################################################################### +####################################################################### +### SPECIFY YOUR NTP SERVERS +# Most computers using chrony will send measurement requests to one or +# more 'NTP servers'. You will probably find that your Internet Service +# Provider or company have one or more NTP servers that you can specify. +# Failing that, there are a lot of public NTP servers. There is a list +# you can access at +# http://www.eecis.udel.edu/~mills/ntp/servers.htm. + +server AUTORALLY_COMPUTE_BOX_HOSTNAME + +# However, for dial-up use you probably want these instead. The word +# 'offline' means that the server is not visible at boot time. Use +# chronyc's 'online' command to tell chronyd that these servers have +# become visible after you go on-line. + +server 0.pool.ntp.org +server 1.pool.ntp.org +server 2.pool.ntp.org + +# You may want to specify NTP 'peers' instead. If you run a network +# with a lot of computers and want several computers running chrony to +# have the 'front-line' interface to the public NTP servers, you can +# 'peer' these machines together to increase robustness. + +! peer ntp0.my-company.com + +# There are other options to the 'server' and 'peer' directives that you +# might want to use. For example, you can ignore measurements whose +# round-trip-time is too large (indicating that the measurement is +# probably useless, because you don't know which way the measurement +# message got held up.) Consult the full documentation for details. + +####################################################################### +### AVOIDING POTENTIALLY BOGUS CHANGES TO YOUR CLOCK +# +# To avoid changes being made to your computer's gain/loss compensation +# when the measurement history is too erratic, you might want to enable +# one of the following lines. The first seems good for dial-up (or +# other high-latency connections like slow leased lines), the second +# seems OK for a LAN environment. + +maxupdateskew 100 +! maxupdateskew 5 + + +####################################################################### +### +# This directive forces chronyd to step system clock if the adjustment +# is larger than a threshold value, but only if there were no more clock +# updates since chronyd was started than a specified limit (a negative +# value can be used to disable the limit). +# makestep 1000 10 +# Would step system clock if the adjustment is larger than 1000 seconds, +# but only in the first ten clock updates. + +makestep 5 -1 + +####################################################################### +### FILENAMES ETC +# Chrony likes to keep information about your computer's clock in files. +# The 'driftfile' stores the computer's clock gain/loss rate in parts +# per million. When chronyd starts, the system clock can be tuned +# immediately so that it doesn't gain or lose any more time. You +# generally want this, so it is uncommented. + +driftfile /etc/chrony.drift + +# If you want to use the program called chronyc to configure aspects of +# chronyd's operation once it is running (e.g. tell it the Internet link +# has gone up or down), you need a password. This is stored in the +# following keys file. (You also need keys to support authenticated NTP +# exchanges between cooperating machines.) Again, this option is +# assumed by default. + +keyfile /ABSOLUTE_PATH/chrony.keys + +# Tell chronyd which numbered key in the file is used as the password +# for chronyc. (You can pick any integer up to 2**32-1. '1' is just a +# default. Using another value will _NOT_ increase security.) + +commandkey 1 + +# chronyd can save the measurement history for the servers to files when +# it it exits. This is useful in 2 situations: +# +# 1. On Linux, if you stop chronyd and restart it with '-r' (e.g. after +# an upgrade), the old measurements will still be relevant when chronyd +# is restarted. This will reduce the time needed to get accurate +# gain/loss measurements, especially with a dial-up link. +# +# 2. Again on Linux, if you use the RTC support and start chronyd with +# '-r -s' on bootup, measurements from the last boot will still be +# useful (the real time clock is used to 'flywheel' chronyd between +# boots). +# +# Enable these two options to use this. + +dumponexit +dumpdir /var/log/chrony + +# chronyd writes its process ID to a file. If you try to start a second +# copy of chronyd, it will detect that the process named in the file is +# still running and bail out. If you want to change the path to the PID +# file, uncomment this line and edit it. The default path is shown. + +! pidfile /var/run/chronyd.pid + +####################################################################### +### INITIAL CLOCK CORRECTION +# This option is only useful if your NTP servers are visible at boot +# time. This probably means you are on a LAN. If so, the following +# option will choose the best-looking of the servers and correct the +# system time to that. The value '10' means that if the error is less +# than 10 seconds, it will be gradually removed by speeding up or +# slowing down your computer's clock until it is correct. If the error +# is above 10 seconds, an immediate time jump will be applied to correct +# it. Some software can get upset if the system clock jumps (especially +# backwards), so be careful! + +initstepslew 10 AUTORALLY_COMPUTE_BOX_HOSTNAME + +####################################################################### +### LOGGING +# If you want to log information about the time measurements chronyd has +# gathered, you might want to enable the following lines. You probably +# only need this if you really enjoy looking at the logs, you want to +# produce some graphs of your system's timekeeping performance, or you +# need help in debugging a problem. + +! logdir /var/log/chrony +! log measurements statistics tracking + +# If you have real time clock support enabled (see below), you might want +# this line instead: + +! log measurements statistics tracking rtc + +####################################################################### +### ACTING AS AN NTP SERVER +# You might want the computer to be an NTP server for other computers. +# e.g. you might be running chronyd on a dial-up machine that has a LAN +# sitting behind it with several 'satellite' computers on it. +# +# By default, chronyd does not allow any clients to access it. You need +# to explicitly enable access using 'allow' and 'deny' directives. +# +# e.g. to enable client access from the 192.168.*.* class B subnet, + +! allow 192.168/16 + +# .. but disallow the 192.168.100.* subnet of that, + +! deny 192.168.100/24 + +# You can have as many allow and deny directives as you need. The order +# is unimportant. + +# If you want chronyd to act as an NTP broadcast server, enable and edit +# (and maybe copy) the following line. This means that a broadcast +# packet is sent to the address 192.168.1.255 every 60 seconds. The +# address MUST correspond to the broadcast address of one of the network +# interfaces on your machine. If you have multiple network interfaces, +# add a broadcast line for each. + +! broadcast 60 192.168.1.255 + +# If you want to present your computer's time for others to synchronise +# with, even if you don't seem to be synchronised to any NTP servers +# yourself, enable the following line. The value 10 may be varied +# between 1 and 15. You should avoid small values because you will look +# like a real NTP server. The value 10 means that you appear to be 10 +# NTP 'hops' away from an authoritative source (atomic clock, GPS +# receiver, radio clock etc). + +! local stratum 10 + +# Normally, chronyd will keep track of how many times each client +# machine accesses it. The information can be accessed by the 'clients' +# command of chronyc. You can disable this facility by uncommenting the +# following line. This will save a bit of memory if you have many +# clients. + +! noclientlog + +# The clientlog size is limited to 512KB by default. If you have many +# clients, especially in many different subnets, you might want to +# increase the limit. + +! clientloglimit 4194304 + +####################################################################### +### REPORTING BIG CLOCK CHANGES +# Perhaps you want to know if chronyd suddenly detects any large error +# in your computer's clock. This might indicate a fault or a problem +# with the server(s) you are using, for example. +# +# The next option causes a message to be written to syslog when chronyd +# has to correct an error above 0.5 seconds (you can use any amount you +# like). + +! logchange 0.5 + +# The next option will send email to the named person when chronyd has +# to correct an error above 0.5 seconds. (If you need to send mail to +# several people, you need to set up a mailing list or sendmail alias +# for them and use the address of that.) + +! mailonchange wibble@foobar.org 0.5 + +####################################################################### +### COMMAND ACCESS +# The program chronyc is used to show the current operation of chronyd +# and to change parts of its configuration whilst it is running. + +# Normally, chronyd will only allow connections from chronyc on the same +# machine as itself. This is for security. If you have a subnet +# 192.168.*.* and you want to be able to use chronyc from any machine on +# it, you could uncomment the following line. (Edit this to your own +# situation.) + +cmdallow 192.168/16 + +# You can add as many 'cmdallow' and 'cmddeny' lines as you like. The +# syntax and meaning is the same as for 'allow' and 'deny', except that +# 'cmdallow' and 'cmddeny' control access to the chronyd's command port. + +# NOTE, even if the host where you run chronyc is granted access, you +# still need a command key set up and you have to know the password to +# put into chronyc to allow you to modify chronyd's parameters. By +# default all you can do is view information about chronyd's operation. + +# Some people have reported that the need the following line to allow +# chronyc to work even on the same machine. This should not be +# necessary, and the problem is being investigated. You can leave this +# line enabled, as it's benign otherwise. + +cmdallow 127.0.0.1 + +####################################################################### +### REAL TIME CLOCK +# chronyd can characterise the system's real-time clock. This is the +# clock that keeps running when the power is turned off, so that the +# machine knows the approximate time when it boots again. The error at +# a particular epoch and gain/loss rate can be written to a file and +# used later by chronyd when it is started with the '-s' option. +# +# You need to have 'enhanced RTC support' compiled into your Linux +# kernel. (Note, these options apply only to Linux.) + +! rtcfile /etc/chrony.rtc + +# Your RTC can be set to keep Universal Coordinated Time (UTC) or local +# time. (Local time means UTC +/- the effect of your timezone.) If you +# use UTC, chronyd will function correctly even if the computer is off +# at the epoch when you enter or leave summer time (aka daylight saving +# time). However, if you dual boot your system with Microsoft Windows, +# that will work better if your RTC maintains local time. You take your +# pick! + +! rtconutc + +# By default chronyd assumes that the enhanced RTC device is accessed as +# /dev/rtc. If it's accessed somewhere else on your system (e.g. you're +# using devfs), uncomment and edit the following line. + +! rtcdevice /dev/misc/rtc + +####################################################################### +### REAL TIME SCHEDULER +# This directive tells chronyd to use the real-time FIFO scheduler with the +# specified priority (which must be between 0 and 100). This should result +# in reduced latency. You don't need it unless you really have a requirement +# for extreme clock stability. Works only on Linux. Note that the "-P" +# command-line switch will override this. + +! sched_priority 1 + +####################################################################### +### LOCKING CHRONYD INTO RAM +# This directive tells chronyd to use the mlockall() syscall to lock itself +# into RAM so that it will never be paged out. This should result in reduced +# latency. You don't need it unless you really have a requirement +# for extreme clock stability. Works only on Linux. Note that the "-m" +# command-line switch will also enable this feature. + +! lock_all diff --git a/autorally_util/chronyServer.conf b/autorally_util/chronyServer.conf new file mode 100644 index 00000000..a91f0f43 --- /dev/null +++ b/autorally_util/chronyServer.conf @@ -0,0 +1,319 @@ +####################################################################### +# +# This is an example chrony configuration file. You should copy it to +# /etc/chrony.conf after uncommenting and editing the options that you +# want to enable. The more obscure options are not included. Refer +# to the documentation for these. +# +# Copyright 2002 Richard P. Curnow +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# +####################################################################### +### COMMENTS +# Any of the following lines are comments (you have a choice of +# comment start character): +# a comment +% a comment +! a comment +; a comment +# +# Below, the '!' form is used for lines that you might want to +# uncomment and edit to make your own chrony.conf file. +# +####################################################################### +####################################################################### +### SPECIFY YOUR NTP SERVERS +# Most computers using chrony will send measurement requests to one or +# more 'NTP servers'. You will probably find that your Internet Service +# Provider or company have one or more NTP servers that you can specify. +# Failing that, there are a lot of public NTP servers. There is a list +# you can access at +# http://www.eecis.udel.edu/~mills/ntp/servers.htm. + +! server ntp0.your-isp.com +! server ntp1.your-isp.com +! server ntp.public-server.org + +# However, for dial-up use you probably want these instead. The word +# 'offline' means that the server is not visible at boot time. Use +# chronyc's 'online' command to tell chronyd that these servers have +# become visible after you go on-line. + +server 0.pool.ntp.org +server 1.pool.ntp.org +server 2.pool.ntp.org + +# set larger delay to allow the NMEA source to overlap with +# the other sources and avoid the falseticker status +refclock SHM 0 offset 0.0 delay 0.1 refid GPS +refclock SHM 1 offset 0.0 delay 0.05 refid PPSshm +refclock SOCK /var/run/chrony.arGPSroverPortB.sock refid PPSsock + +# You may want to specify NTP 'peers' instead. If you run a network +# with a lot of computers and want several computers running chrony to +# have the 'front-line' interface to the public NTP servers, you can +# 'peer' these machines together to increase robustness. + +! peer ntp0.my-company.com +peer OTHER_COMPUTE_BOX_HOSTNAME + +# There are other options to the 'server' and 'peer' directives that you +# might want to use. For example, you can ignore measurements whose +# round-trip-time is too large (indicating that the measurement is +# probably useless, because you don't know which way the measurement +# message got held up.) Consult the full documentation for details. + +####################################################################### +### AVOIDING POTENTIALLY BOGUS CHANGES TO YOUR CLOCK +# +# To avoid changes being made to your computer's gain/loss compensation +# when the measurement history is too erratic, you might want to enable +# one of the following lines. The first seems good for dial-up (or +# other high-latency connections like slow leased lines), the second +# seems OK for a LAN environment. + +maxupdateskew 100 +! maxupdateskew 5 + +####################################################################### +### FILENAMES ETC +# Chrony likes to keep information about your computer's clock in files. +# The 'driftfile' stores the computer's clock gain/loss rate in parts +# per million. When chronyd starts, the system clock can be tuned +# immediately so that it doesn't gain or lose any more time. You +# generally want this, so it is uncommented. + +driftfile /etc/chrony.drift + +# If you want to use the program called chronyc to configure aspects of +# chronyd's operation once it is running (e.g. tell it the Internet link +# has gone up or down), you need a password. This is stored in the +# following keys file. (You also need keys to support authenticated NTP +# exchanges between cooperating machines.) Again, this option is +# assumed by default. + +keyfile /ABSOLUTE_PATH_TO/chrony.keys + +# Tell chronyd which numbered key in the file is used as the password +# for chronyc. (You can pick any integer up to 2**32-1. '1' is just a +# default. Using another value will _NOT_ increase security.) + +commandkey 1 + +# chronyd can save the measurement history for the servers to files when +# it it exits. This is useful in 2 situations: +# +# 1. On Linux, if you stop chronyd and restart it with '-r' (e.g. after +# an upgrade), the old measurements will still be relevant when chronyd +# is restarted. This will reduce the time needed to get accurate +# gain/loss measurements, especially with a dial-up link. +# +# 2. Again on Linux, if you use the RTC support and start chronyd with +# '-r -s' on bootup, measurements from the last boot will still be +# useful (the real time clock is used to 'flywheel' chronyd between +# boots). +# +# Enable these two options to use this. + +dumponexit +dumpdir /var/log/chrony + +# chronyd writes its process ID to a file. If you try to start a second +# copy of chronyd, it will detect that the process named in the file is +# still running and bail out. If you want to change the path to the PID +# file, uncomment this line and edit it. The default path is shown. + +! pidfile /var/run/chronyd.pid + +####################################################################### +### INITIAL CLOCK CORRECTION +# This option is only useful if your NTP servers are visible at boot +# time. This probably means you are on a LAN. If so, the following +# option will choose the best-looking of the servers and correct the +# system time to that. The value '10' means that if the error is less +# than 10 seconds, it will be gradually removed by speeding up or +# slowing down your computer's clock until it is correct. If the error +# is above 10 seconds, an immediate time jump will be applied to correct +# it. Some software can get upset if the system clock jumps (especially +# backwards), so be careful! + +! initstepslew 10 ntp0.your-company.com ntp1.your-company.com ntp2.your-company.com + +####################################################################### +### LOGGING +# If you want to log information about the time measurements chronyd has +# gathered, you might want to enable the following lines. You probably +# only need this if you really enjoy looking at the logs, you want to +# produce some graphs of your system's timekeeping performance, or you +# need help in debugging a problem. + +! logdir /var/log/chrony +! log measurements statistics tracking + +# If you have real time clock support enabled (see below), you might want +# this line instead: + +! log measurements statistics tracking rtc + +####################################################################### +### ACTING AS AN NTP SERVER +# You might want the computer to be an NTP server for other computers. +# e.g. you might be running chronyd on a dial-up machine that has a LAN +# sitting behind it with several 'satellite' computers on it. +# +# By default, chronyd does not allow any clients to access it. You need +# to explicitly enable access using 'allow' and 'deny' directives. +# +# e.g. to enable client access from the 192.168.*.* class B subnet, + +allow 192.168/16 + +# .. but disallow the 192.168.100.* subnet of that, + +! deny 192.168.100/24 + +# You can have as many allow and deny directives as you need. The order +# is unimportant. + +# If you want chronyd to act as an NTP broadcast server, enable and edit +# (and maybe copy) the following line. This means that a broadcast +# packet is sent to the address 192.168.1.255 every 60 seconds. The +# address MUST correspond to the broadcast address of one of the network +# interfaces on your machine. If you have multiple network interfaces, +# add a broadcast line for each. + +! broadcast 60 192.168.1.255 + +# If you want to present your computer's time for others to synchronise +# with, even if you don't seem to be synchronised to any NTP servers +# yourself, enable the following line. The value 10 may be varied +# between 1 and 15. You should avoid small values because you will look +# like a real NTP server. The value 10 means that you appear to be 10 +# NTP 'hops' away from an authoritative source (atomic clock, GPS +# receiver, radio clock etc). + +local stratum 1 + +# Normally, chronyd will keep track of how many times each client +# machine accesses it. The information can be accessed by the 'clients' +# command of chronyc. You can disable this facility by uncommenting the +# following line. This will save a bit of memory if you have many +# clients. + +! noclientlog + +# The clientlog size is limited to 512KB by default. If you have many +# clients, especially in many different subnets, you might want to +# increase the limit. + +! clientloglimit 4194304 + +####################################################################### +### REPORTING BIG CLOCK CHANGES +# Perhaps you want to know if chronyd suddenly detects any large error +# in your computer's clock. This might indicate a fault or a problem +# with the server(s) you are using, for example. +# +# The next option causes a message to be written to syslog when chronyd +# has to correct an error above 0.5 seconds (you can use any amount you +# like). + +! logchange 0.5 + +# The next option will send email to the named person when chronyd has +# to correct an error above 0.5 seconds. (If you need to send mail to +# several people, you need to set up a mailing list or sendmail alias +# for them and use the address of that.) + +! mailonchange wibble@foobar.org 0.5 + +####################################################################### +### COMMAND ACCESS +# The program chronyc is used to show the current operation of chronyd +# and to change parts of its configuration whilst it is running. + +# Normally, chronyd will only allow connections from chronyc on the same +# machine as itself. This is for security. If you have a subnet +# 192.168.*.* and you want to be able to use chronyc from any machine on +# it, you could uncomment the following line. (Edit this to your own +# situation.) + +cmdallow 192.168/16 + +# You can add as many 'cmdallow' and 'cmddeny' lines as you like. The +# syntax and meaning is the same as for 'allow' and 'deny', except that +# 'cmdallow' and 'cmddeny' control access to the chronyd's command port. + +# NOTE, even if the host where you run chronyc is granted access, you +# still need a command key set up and you have to know the password to +# put into chronyc to allow you to modify chronyd's parameters. By +# default all you can do is view information about chronyd's operation. + +# Some people have reported that the need the following line to allow +# chronyc to work even on the same machine. This should not be +# necessary, and the problem is being investigated. You can leave this +# line enabled, as it's benign otherwise. + +cmdallow 127.0.0.1 + +####################################################################### +### REAL TIME CLOCK +# chronyd can characterise the system's real-time clock. This is the +# clock that keeps running when the power is turned off, so that the +# machine knows the approximate time when it boots again. The error at +# a particular epoch and gain/loss rate can be written to a file and +# used later by chronyd when it is started with the '-s' option. +# +# You need to have 'enhanced RTC support' compiled into your Linux +# kernel. (Note, these options apply only to Linux.) + +! rtcfile /etc/chrony.rtc + +# Your RTC can be set to keep Universal Coordinated Time (UTC) or local +# time. (Local time means UTC +/- the effect of your timezone.) If you +# use UTC, chronyd will function correctly even if the computer is off +# at the epoch when you enter or leave summer time (aka daylight saving +# time). However, if you dual boot your system with Microsoft Windows, +# that will work better if your RTC maintains local time. You take your +# pick! + +! rtconutc + +# By default chronyd assumes that the enhanced RTC device is accessed as +# /dev/rtc. If it's accessed somewhere else on your system (e.g. you're +# using devfs), uncomment and edit the following line. + +! rtcdevice /dev/misc/rtc + +####################################################################### +### REAL TIME SCHEDULER +# This directive tells chronyd to use the real-time FIFO scheduler with the +# specified priority (which must be between 0 and 100). This should result +# in reduced latency. You don't need it unless you really have a requirement +# for extreme clock stability. Works only on Linux. Note that the "-P" +# command-line switch will override this. + +! sched_priority 1 + +####################################################################### +### LOCKING CHRONYD INTO RAM +# This directive tells chronyd to use the mlockall() syscall to lock itself +# into RAM so that it will never be paged out. This should result in reduced +# latency. You don't need it unless you really have a requirement +# for extreme clock stability. Works only on Linux. Note that the "-m" +# command-line switch will also enable this feature. + +! lock_all diff --git a/autorally_util/config/arChassisConfig_CHASSIS_NAME.yaml b/autorally_util/config/arChassisConfig_CHASSIS_NAME.yaml new file mode 100644 index 00000000..d8d1536e --- /dev/null +++ b/autorally_util/config/arChassisConfig_CHASSIS_NAME.yaml @@ -0,0 +1,4 @@ +'0': {name: 'steering', center: 1562, min: 1020, max: 2020, reverse: false} +'1': {name: 'throttle', center: 1541, min: 1088, max: 2000, reverse: false} +'2': {name: 'backBrake', center: 1535, min: 1535, max: 1952, reverse: false} +'3': {name: 'frontBrake', center: 1535, min: 1535, max: 1952, reverse: false} diff --git a/autorally_util/config/camera_calibration_GUID.yaml b/autorally_util/config/camera_calibration_GUID.yaml new file mode 100644 index 00000000..5fef1989 --- /dev/null +++ b/autorally_util/config/camera_calibration_GUID.yaml @@ -0,0 +1,20 @@ +image_width: 1280 +image_height: 1024 +camera_name: 00b09d0100c6fd73 +camera_matrix: + rows: 3 + cols: 3 + data: [817.5407824512795, 0.0, 621.2921026865581, 0.0, 821.052045507326, 532.5863503315023, 0.0, 0.0, 1.0] +distortion_model: plumb_bob +distortion_coefficients: + rows: 1 + cols: 5 + data: [-0.21164792680999517, 0.07450723755795918, 6.170763931583324e-06, 0.0001256454560449464, 0.0] +rectification_matrix: + rows: 3 + cols: 3 + data: [0.9902892812162726, -0.03715804338771576, 0.1339642464232711, 0.03760219237732265, 0.9992924783792697, -0.0007859917528086568, -0.13384025790686854, 0.005815708573621687, 0.9909858540348645] +projection_matrix: + rows: 3 + cols: 4 + data: [831.5144044576164, 0.0, 468.27288818359375, 0.0, 0.0, 831.5144044576164, 525.1802101135254, 0.0, 0.0, 0.0, 1.0, 0.0] diff --git a/autorally_util/config/servoCommandPriorities.yaml b/autorally_util/config/servoCommandPriorities.yaml new file mode 100644 index 00000000..3ff03298 --- /dev/null +++ b/autorally_util/config/servoCommandPriorities.yaml @@ -0,0 +1,4 @@ +'constantSpeedController': 2 +'joystick': 3 +'OCS': 4 +'RC': 7 diff --git a/autorally_util/config/throttlePositionCalibration.yaml b/autorally_util/config/throttlePositionCalibration.yaml new file mode 100644 index 00000000..e1de5a58 --- /dev/null +++ b/autorally_util/config/throttlePositionCalibration.yaml @@ -0,0 +1,7 @@ +'0.00': 0.00 +'0.11': 0.25 +'0.13': 1.00 +'0.14': 2.80 +'0.15': 4.00 +'0.16': 4.80 +'0.17': 5.00 diff --git a/autorally_util/package.xml b/autorally_util/package.xml new file mode 100644 index 00000000..53a81de3 --- /dev/null +++ b/autorally_util/package.xml @@ -0,0 +1,51 @@ + + + + autorally_util + 0.1.0 + Utility files for configuration and setup of autorally software. + Brian Goldfain + + Brian Goldfain + + http://autorally.github.io + + BSD + + Brian Goldfain + + catkin + + roscpp + rospy + std_msgs + sensor_msgs + geometry_msgs + nav_msgs + autorally_msgs + cv_bridge + + roscpp + rospy + std_msgs + sensor_msgs + geometry_msgs + nav_msgs + cv_bridge + autorally_msgs + + diff --git a/autorally_util/roscoreAutostart.sh b/autorally_util/roscoreAutostart.sh new file mode 100755 index 00000000..375bfd7f --- /dev/null +++ b/autorally_util/roscoreAutostart.sh @@ -0,0 +1,7 @@ +#! /bin/bash +source /opt/ros/indigo/setup.bash +source /PATH_TO_CATKIN_WS/install/setup.sh + +export ROS_PACKAGE_PATH=/PATH_TO_REPOSITORY:$ROS_PACKAGE_PATH +export PATH=$PATH:$ROS_ROOT/bin +roscore diff --git a/autorally_util/setCameraPermissions.sh b/autorally_util/setCameraPermissions.sh new file mode 100755 index 00000000..9ef54be9 --- /dev/null +++ b/autorally_util/setCameraPermissions.sh @@ -0,0 +1,5 @@ +#! /bin/bash + +sudo chmod -R 777 /dev/bus/usb/ + +exit 0 diff --git a/autorally_util/setupEnvLocal.sh b/autorally_util/setupEnvLocal.sh new file mode 100755 index 00000000..fcddba1f --- /dev/null +++ b/autorally_util/setupEnvLocal.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# source this when you launch everything on a local machine +export ROS_MASTER_URI=http://localhost:11311 +export MASTER_HOSTNAME=localhost +export HOSTNAME=localhost +export ROSLAUNCH_SSH_UNKNOWN=0 +# Find directory of script file to avoid hard-coded paths +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source $DIR/setupEnvVariables.sh diff --git a/autorally_util/setupEnvRemote.sh b/autorally_util/setupEnvRemote.sh new file mode 100644 index 00000000..42f41f0d --- /dev/null +++ b/autorally_util/setupEnvRemote.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# source this before you perform a distributed launch with a remote AutoRally chassis +export ROS_MASTER_URI=http://COMPUTE_BOX_HOSTNAME:11311 +export MASTER_HOSTNAME=COMPUTE_BOX_HOSTNAME +export HOSTNAME=$(hostname) +export ROSLAUNCH_SSH_UNKNOWN=1 +# Find directory of script file to avoid hard-coded paths +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source setupEnvVariables.sh diff --git a/autorally_util/setupEnvVariables.sh b/autorally_util/setupEnvVariables.sh new file mode 100644 index 00000000..ddb4446e --- /dev/null +++ b/autorally_util/setupEnvVariables.sh @@ -0,0 +1,72 @@ +DEBUG=false +while [[ $# > 0 ]] +do +key="$1" + +case $key in + -d|--debug) + DEBUG=true + shift + ;; +esac +done + +if [[ $MASTER_HOSTNAME == "localhost" ]] + then + devList=$(ls /dev/) +else + devList=$(ssh $MASTER_HOSTNAME ls /dev/) +fi + +# Locate config folder +export AR_CONFIG_PATH=`rospack find autorally_util`/config + +# Setup servo controller and determine chassis +if [[ $devList == *"arChassis"* ]] # If Arduino Due is connected... + then + AR_CHASSIS_SERIAL=`udevadm info --query=property --name=/dev/arChassis | grep 'ID_SERIAL_SHORT'` + AR_CHASSIS_SERIAL=${AR_CHASSIS_SERIAL#*=} + if [ $AR_CHASSIS_SERIAL == '75439313737351F052A0' ] + then + export AR_CHASSIS="gamma" + fi +fi +if [[ $devList == *"arServoController"* ]] # If Pololu Servo Controller is connected... + then + AR_CHASSIS_SERIAL=`udevadm info --query=property --name=/dev/arServoController | grep 'ID_SERIAL_SHORT'` + AR_CHASSIS_SERIAL=${AR_CHASSIS_SERIAL#*=} + if [ $AR_CHASSIS_SERIAL == '00082495' ] + then + export AR_CHASSIS="beta" + elif [ $AR_CHASSIS_SERIAL == '00026587' ] + then + export AR_CHASSIS="alpha" + fi +fi +if [[ $DEBUG == true ]]; then + echo "AR_CHASSIS set to ${AR_CHASSIS}" +fi + +# Setup cameras +if [[ $devList == *"arCamera_b09d0100d70a0a"* ]] + then + export AR_RIGHTCAM="b09d0100d70a0a" +elif [[ $devList == *"arCamera_b09d0100d70a17"* ]] + then + export AR_RIGHTCAM="b09d0100d70a17" +fi +if [[ $DEBUG == true ]]; then + echo "AR_RIGHTCAM set to ${AR_RIGHTCAM}" +fi + +if [[ $devList == *"arCamera_b09d0100d70a1c"* ]] + then + export AR_LEFTCAM="b09d0100d70a1c" +elif [[ $devList == *"arCamera_b09d0100c6fd73"* ]] + then + export AR_LEFTCAM="b09d0100c6fd73" +fi +if [[ $DEBUG == true ]]; then + echo "AR_LEFTCAM set to ${AR_LEFTCAM}" +fi + diff --git a/doc/autorally.png b/doc/autorally.png new file mode 100644 index 0000000000000000000000000000000000000000..a862b8e1efad07ce98c569095b3026755db97884 GIT binary patch literal 97938 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 z zDd+aQghcp$8$i>GnLUL5c0XiU?qgy|E~T}F8N;Wm;@gG!`NRIbq^mOju-h@n)pB{c z%$GSGb`NFr+kw7Z6^`VtZ5q|K>3>nzFP5|Y5I;R%J+}QX?{@n>62!NhZj#^a`z$LS zV@}QvLpo@>-|l?hSz?R$Vzu7)-Z@^(=f=9d_YMxXW?BX&cQU)*hdNWG=> zRKMW~(@u2AujGV8s4%%^L=aF^(#JUY2%)3u29st!6=hRcPEZQZt4F5eF#v!#ivB!u zLdR2JIw8giO`nJ3>5fkKbrSoISa;G$PCQ2J4KItVG$2WznxXe;+l4v^C}-BZU01Ky zi!P?#$3q{Qn4HOS=g4NnRsr8_>v_fiN^Ak?$D3j++(zCauja*lGbGWBao=`^G0$A?>>){6%$H?;Ub?jvPT|lG zNaO`F!Ys1|a-R}O6io|f9O5^-;o&gsdLLAqkb>`D&9b*=)vPM6pALPD-#xa6fK_Hi zL&03-=62UMesD}GV2v#;r=hKMpwR#R7iZD;yF>*B&1|!^B=$cWI3CEfB$%;9siR*`U3<+CNoN5M==nAj+6`F#2MnK9^%K63!c+0 z$H<&ydn8g&Ilg~H!czu&B0ok>5fG12hKM@4;l{XSLT1*FoBk9$%uL56>XEI)lXN-N zna@!EgxgaQNT^8skwJxLOP#2ik9L_;Dtq(!mlrRa<{*;B zXeA^@j7bq_q>b2+WeO>(LQ3i-877pN6uKci9U4}N!4D}lK@(tZ*^-c?rt485B#3~W zT1C!_ydIKI>AWneJnN%A1< zLL(`OULX1oPlq-Fvth&MrCaCxSa*+uG|@x=2YTDY%$d*6s~?_~cTLO2Jhonwh{DAz z?~^=rvOgT^wtF06j4~wI_k-lcYPAZ2n1)3`$q%ne+lTnj_CBRo=L@#Q?y$SPyU8%^ z>vrGt!S@Dahyu2-62g9WXgff>$PB4iCPSRti~)zX&U`zw?$8Zv@b!9my=#`Us!!5H zxPI7bicDY-w?TR#cKHCb>(kB$eSGYP(5ba~&bF|{%oOGM*%>h3>~=r@=9kxX%YXXE zf2gCzfFvqM!X1bSdGfCu4PHmq5>cK>8XtEyBI;B_o^b61fX_{E(|`Fn5lScX+Emw# zN5DvOFrTbq$7?>%gk>T=5Yyyq)gue5#i6qe!6M_QL=wAhz{;GWvm*tAc5(e+Lb+

jd`;w7r8-A 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

5?(UfCp4I$*Lsv2@8q;^aN;%zfDWAKCy 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 literal 0 HcmV?d00001 diff --git a/doc/autorally_repo.jpg b/doc/autorally_repo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ab5ca004da17d9eba39da4624e8caaa844df899a GIT binary patch literal 192563 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 Tv*-Rk{-gQ-0D(WL{5k*G@u4)B literal 0 HcmV?d00001 diff --git a/mainpage.dox b/mainpage.dox new file mode 100644 index 00000000..500f1e34 --- /dev/null +++ b/mainpage.dox @@ -0,0 +1,21 @@ +/** +\mainpage +The autorally repository is developed in the Computational Perception Lab in +the College of Computing at Georgia Tech as the software for an autonomous +ground vehicle capable of agressive rally-style driving + +Project Website: +https://research.cc.gatech.edu/muri/ + +GitHub Repository: +https://github.com/AutoRally/autorally + +Copyright (c) 2010-2016, Georgia Institute of Technology. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +\li Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +\li Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/