00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035
00036
00037
00038
00039 #include <float.h>
00040 #include <tf/tf.h>
00041 #include <ecl/streams/string_stream.hpp>
00042 #include <kobuki_msgs/VersionInfo.h>
00043 #include "kobuki_node/kobuki_ros.hpp"
00044
00045
00046
00047
00048
00049 namespace kobuki
00050 {
00051
00052
00053
00054
00055
00061 KobukiRos::KobukiRos(std::string& node_name) :
00062 name(node_name), cmd_vel_timed_out_(false), serial_timed_out_(false),
00063 slot_version_info(&KobukiRos::publishVersionInfo, *this),
00064 slot_controller_info(&KobukiRos::publishControllerInfo, *this),
00065 slot_stream_data(&KobukiRos::processStreamData, *this),
00066 slot_button_event(&KobukiRos::publishButtonEvent, *this),
00067 slot_bumper_event(&KobukiRos::publishBumperEvent, *this),
00068 slot_cliff_event(&KobukiRos::publishCliffEvent, *this),
00069 slot_wheel_event(&KobukiRos::publishWheelEvent, *this),
00070 slot_power_event(&KobukiRos::publishPowerEvent, *this),
00071 slot_input_event(&KobukiRos::publishInputEvent, *this),
00072 slot_robot_event(&KobukiRos::publishRobotEvent, *this),
00073 slot_debug(&KobukiRos::rosDebug, *this),
00074 slot_info(&KobukiRos::rosInfo, *this),
00075 slot_warn(&KobukiRos::rosWarn, *this),
00076 slot_error(&KobukiRos::rosError, *this),
00077 slot_named(&KobukiRos::rosNamed, *this),
00078 slot_raw_data_command(&KobukiRos::publishRawDataCommand, *this),
00079 slot_raw_data_stream(&KobukiRos::publishRawDataStream, *this),
00080 slot_raw_control_command(&KobukiRos::publishRawControlCommand, *this)
00081 {
00082 updater.setHardwareID("Kobuki");
00083 updater.add(battery_diagnostics);
00084 updater.add(watchdog_diagnostics);
00085 updater.add(bumper_diagnostics);
00086 updater.add(cliff_diagnostics);
00087 updater.add(wheel_diagnostics);
00088 updater.add(motor_diagnostics);
00089 updater.add(state_diagnostics);
00090 updater.add(gyro_diagnostics);
00091 updater.add(dinput_diagnostics);
00092 updater.add(ainput_diagnostics);
00093 }
00094
00099 KobukiRos::~KobukiRos()
00100 {
00101 ROS_INFO_STREAM("Kobuki : waiting for kobuki thread to finish [" << name << "].");
00102 }
00103
00104 bool KobukiRos::init(ros::NodeHandle& nh, ros::NodeHandle& nh_pub)
00105 {
00106
00107
00108
00109 advertiseTopics(nh);
00110 subscribeTopics(nh);
00111
00112
00113
00114
00115 slot_stream_data.connect(name + std::string("/stream_data"));
00116 slot_version_info.connect(name + std::string("/version_info"));
00117 slot_controller_info.connect(name + std::string("/controller_info"));
00118 slot_button_event.connect(name + std::string("/button_event"));
00119 slot_bumper_event.connect(name + std::string("/bumper_event"));
00120 slot_cliff_event.connect(name + std::string("/cliff_event"));
00121 slot_wheel_event.connect(name + std::string("/wheel_event"));
00122 slot_power_event.connect(name + std::string("/power_event"));
00123 slot_input_event.connect(name + std::string("/input_event"));
00124 slot_robot_event.connect(name + std::string("/robot_event"));
00125 slot_debug.connect(name + std::string("/ros_debug"));
00126 slot_info.connect(name + std::string("/ros_info"));
00127 slot_warn.connect(name + std::string("/ros_warn"));
00128 slot_error.connect(name + std::string("/ros_error"));
00129 slot_named.connect(name + std::string("/ros_named"));
00130 slot_raw_data_command.connect(name + std::string("/raw_data_command"));
00131 slot_raw_data_stream.connect(name + std::string("/raw_data_stream"));
00132 slot_raw_control_command.connect(name + std::string("/raw_control_command"));
00133
00134
00135
00136
00137 Parameters parameters;
00138
00139 nh.param("acceleration_limiter", parameters.enable_acceleration_limiter, false);
00140 nh.param("battery_capacity", parameters.battery_capacity, Battery::capacity);
00141 nh.param("battery_low", parameters.battery_low, Battery::low);
00142 nh.param("battery_dangerous", parameters.battery_dangerous, Battery::dangerous);
00143
00144 parameters.sigslots_namespace = name;
00145 if (!nh.getParam("device_port", parameters.device_port))
00146 {
00147 ROS_ERROR_STREAM("Kobuki : no device port given on the parameter server (e.g. /dev/ttyUSB0)[" << name << "].");
00148 return false;
00149 }
00150
00151
00152
00153
00154 std::string robot_description, wheel_left_joint_name, wheel_right_joint_name;
00155
00156 nh.param("wheel_left_joint_name", wheel_left_joint_name, std::string("wheel_left_joint"));
00157 nh.param("wheel_right_joint_name", wheel_right_joint_name, std::string("wheel_right_joint"));
00158
00159
00160 if (!nh_pub.getParam("robot_description", robot_description))
00161 {
00162 ROS_WARN("Kobuki : no robot description given on the parameter server");
00163 }
00164 else
00165 {
00166 if (robot_description.find(wheel_left_joint_name) == std::string::npos) {
00167 ROS_WARN("Kobuki : joint name %s not found on robot description", wheel_left_joint_name.c_str());
00168 }
00169
00170 if (robot_description.find(wheel_right_joint_name) == std::string::npos) {
00171 ROS_WARN("Kobuki : joint name %s not found on robot description", wheel_right_joint_name.c_str());
00172 }
00173 }
00174 joint_states.name.push_back(wheel_left_joint_name);
00175 joint_states.name.push_back(wheel_right_joint_name);
00176 joint_states.position.resize(2,0.0);
00177 joint_states.velocity.resize(2,0.0);
00178 joint_states.effort.resize(2,0.0);
00179
00180
00181
00182
00183 if (!parameters.validate())
00184 {
00185 ROS_ERROR_STREAM("Kobuki : parameter configuration failed [" << name << "].");
00186 ROS_ERROR_STREAM("Kobuki : " << parameters.error_msg << "[" << name << "]");
00187 return false;
00188 }
00189 else
00190 {
00191 if (parameters.simulation)
00192 {
00193 ROS_INFO("Kobuki : driver going into loopback (simulation) mode.");
00194 }
00195 else
00196 {
00197 ROS_INFO_STREAM("Kobuki : configured for connection on device_port "
00198 << parameters.device_port << " [" << name << "].");
00199 ROS_INFO_STREAM("Kobuki : driver running in normal (non-simulation) mode" << " [" << name << "].");
00200 }
00201 }
00202
00203 odometry.init(nh, name);
00204
00205
00206
00207
00208 try
00209 {
00210 kobuki.init(parameters);
00211 ros::Duration(0.25).sleep();
00212 if ( !kobuki.isAlive() ) {
00213 ROS_WARN_STREAM("Kobuki : no data stream, is kobuki turned on?");
00214
00215 }
00216 kobuki.enable();
00217 }
00218 catch (const ecl::StandardException &e)
00219 {
00220 switch (e.flag())
00221 {
00222 case (ecl::OpenError):
00223 {
00224 ROS_ERROR_STREAM("Kobuki : could not open connection [" << parameters.device_port << "][" << name << "].");
00225 break;
00226 }
00227 default:
00228 {
00229 ROS_ERROR_STREAM("Kobuki : initialisation failed [" << name << "].");
00230 ROS_DEBUG_STREAM(e.what());
00231 break;
00232 }
00233 }
00234 return false;
00235 }
00236
00237 return true;
00238 }
00248 bool KobukiRos::update()
00249 {
00250 if ( kobuki.isShutdown() )
00251 {
00252 ROS_ERROR_STREAM("Kobuki : Driver has been shutdown. Stopping update loop. [" << name << "].");
00253 return false;
00254 }
00255
00256 if ( (kobuki.isEnabled() == true) && odometry.commandTimeout())
00257 {
00258 if ( !cmd_vel_timed_out_ )
00259 {
00260 kobuki.setBaseControl(0, 0);
00261 cmd_vel_timed_out_ = true;
00262 ROS_WARN("Kobuki : Incoming velocity commands not received for more than %.2f seconds -> zero'ing velocity commands", odometry.timeout().toSec());
00263 }
00264 }
00265 else
00266 {
00267 cmd_vel_timed_out_ = false;
00268 }
00269
00270 bool is_alive = kobuki.isAlive();
00271 if ( watchdog_diagnostics.isAlive() && !is_alive )
00272 {
00273 if ( !serial_timed_out_ )
00274 {
00275 ROS_ERROR_STREAM("Kobuki : Timed out while waiting for serial data stream [" << name << "].");
00276 serial_timed_out_ = true;
00277 }
00278 else
00279 {
00280 serial_timed_out_ = false;
00281 }
00282 }
00283
00284 watchdog_diagnostics.update(is_alive);
00285 battery_diagnostics.update(kobuki.batteryStatus());
00286 cliff_diagnostics.update(kobuki.getCoreSensorData().cliff, kobuki.getCliffData());
00287 bumper_diagnostics.update(kobuki.getCoreSensorData().bumper);
00288 wheel_diagnostics.update(kobuki.getCoreSensorData().wheel_drop);
00289 motor_diagnostics.update(kobuki.getCurrentData().current);
00290 state_diagnostics.update(kobuki.isEnabled());
00291 gyro_diagnostics.update(kobuki.getInertiaData().angle);
00292 dinput_diagnostics.update(kobuki.getGpInputData().digital_input);
00293 ainput_diagnostics.update(kobuki.getGpInputData().analog_input);
00294 updater.update();
00295
00296 return true;
00297 }
00298
00303 void KobukiRos::advertiseTopics(ros::NodeHandle& nh)
00304 {
00305
00306
00307
00308 joint_state_publisher = nh.advertise <sensor_msgs::JointState>("joint_states",100);
00309
00310
00311
00312
00313 version_info_publisher = nh.advertise < kobuki_msgs::VersionInfo > ("version_info", 100, true);
00314 controller_info_publisher = nh.advertise < kobuki_msgs::ControllerInfo > ("controller_info", 100, true);
00315 button_event_publisher = nh.advertise < kobuki_msgs::ButtonEvent > ("events/button", 100);
00316 bumper_event_publisher = nh.advertise < kobuki_msgs::BumperEvent > ("events/bumper", 100);
00317 cliff_event_publisher = nh.advertise < kobuki_msgs::CliffEvent > ("events/cliff", 100);
00318 wheel_event_publisher = nh.advertise < kobuki_msgs::WheelDropEvent > ("events/wheel_drop", 100);
00319 power_event_publisher = nh.advertise < kobuki_msgs::PowerSystemEvent > ("events/power_system", 100);
00320 input_event_publisher = nh.advertise < kobuki_msgs::DigitalInputEvent > ("events/digital_input", 100);
00321 robot_event_publisher = nh.advertise < kobuki_msgs::RobotStateEvent > ("events/robot_state", 100, true);
00322 sensor_state_publisher = nh.advertise < kobuki_msgs::SensorState > ("sensors/core", 100);
00323 dock_ir_publisher = nh.advertise < kobuki_msgs::DockInfraRed > ("sensors/dock_ir", 100);
00324 imu_data_publisher = nh.advertise < sensor_msgs::Imu > ("sensors/imu_data", 100);
00325 raw_imu_data_publisher = nh.advertise < sensor_msgs::Imu > ("sensors/imu_data_raw", 100);
00326 raw_data_command_publisher = nh.advertise< std_msgs::String > ("debug/raw_data_command", 100);
00327 raw_data_stream_publisher = nh.advertise< std_msgs::String > ("debug/raw_data_stream", 100);
00328 raw_control_command_publisher = nh.advertise< std_msgs::Int16MultiArray > ("debug/raw_control_command", 100);
00329 }
00330
00335 void KobukiRos::subscribeTopics(ros::NodeHandle& nh)
00336 {
00337 velocity_command_subscriber = nh.subscribe(std::string("commands/velocity"), 10, &KobukiRos::subscribeVelocityCommand, this);
00338 led1_command_subscriber = nh.subscribe(std::string("commands/led1"), 10, &KobukiRos::subscribeLed1Command, this);
00339 led2_command_subscriber = nh.subscribe(std::string("commands/led2"), 10, &KobukiRos::subscribeLed2Command, this);
00340 digital_output_command_subscriber = nh.subscribe(std::string("commands/digital_output"), 10, &KobukiRos::subscribeDigitalOutputCommand, this);
00341 external_power_command_subscriber = nh.subscribe(std::string("commands/external_power"), 10, &KobukiRos::subscribeExternalPowerCommand, this);
00342 sound_command_subscriber = nh.subscribe(std::string("commands/sound"), 10, &KobukiRos::subscribeSoundCommand, this);
00343 reset_odometry_subscriber = nh.subscribe("commands/reset_odometry", 10, &KobukiRos::subscribeResetOdometry, this);
00344 motor_power_subscriber = nh.subscribe("commands/motor_power", 10, &KobukiRos::subscribeMotorPower, this);
00345 controller_info_command_subscriber = nh.subscribe(std::string("commands/controller_info"), 10, &KobukiRos::subscribeControllerInfoCommand, this);
00346 }
00347
00348
00349 }
00350