00001
00026 #include "ridgeback_base/ridgeback_lighting.h"
00027 #include <boost/assign/list_of.hpp>
00028
00029 namespace ridgeback_base
00030 {
00031
00032 namespace States
00033 {
00034 enum State
00035 {
00036 Idle = 0,
00037 Driving,
00038 Charged,
00039 Charging,
00040 LowBattery,
00041 NeedsReset,
00042 Fault,
00043 Stopped,
00044 NumberOfStates
00045 };
00046 }
00047 typedef States::State State;
00048
00049 namespace Colours
00050 {
00051 enum Colour
00052 {
00053 Off = 0x000000,
00054 Red_H = 0xFF0000,
00055 Red_M = 0xAA00000,
00056 Red_L = 0x550000,
00057 Green_H = 0x00FF00,
00058 Green_M = 0x00AA00,
00059 Green_L = 0x005500,
00060 Blue_H = 0x0000FF,
00061 Blue_M = 0x0000AA,
00062 Blue_L = 0x000055,
00063 Yellow_H = 0xFFFF00,
00064 Yellow_M = 0xAAAA00,
00065 Yellow_L = 0x555500,
00066 Orange_H = 0xFFAE00,
00067 Orange_M = 0xF0A80E,
00068 Orange_L = 0xD69F27,
00069 White_H = 0xFFFFFF,
00070 White_M = 0xAAAAAA,
00071 White_L = 0x555555
00072 };
00073 }
00074 typedef Colours::Colour Colour;
00075
00076
00077 RidgebackLighting::RidgebackLighting(ros::NodeHandle* nh) :
00078 nh_(nh),
00079 allow_user_(false),
00080 user_publishing_(false),
00081 state_(States::Idle),
00082 current_pattern_count_(0)
00083 {
00084 lights_pub_ = nh_->advertise<ridgeback_msgs::Lights>("mcu/cmd_lights", 1);
00085
00086 user_cmds_sub_ = nh_->subscribe("cmd_lights", 1, &RidgebackLighting::userCmdCallback, this);
00087 mcu_status_sub_ = nh_->subscribe("mcu/status", 1, &RidgebackLighting::mcuStatusCallback, this);
00088 puma_status_sub_ = nh_->subscribe("status", 1, &RidgebackLighting::pumaStatusCallback, this);
00089 cmd_vel_sub_ = nh_->subscribe("cmd_vel", 1, &RidgebackLighting::cmdVelCallback, this);
00090
00091 pub_timer_ = nh_->createTimer(ros::Duration(1.0/5), &RidgebackLighting::timerCb, this);
00092 user_timeout_ = nh_->createTimer(ros::Duration(1.0/1), &RidgebackLighting::userTimeoutCb, this);
00093
00094 using namespace Colours;
00095 patterns_.stopped.push_back(boost::assign::list_of(Red_H)(Red_H)(Red_H)(Red_H)(Red_H)(Red_H)(Red_H)(Red_H));
00096 patterns_.stopped.push_back(boost::assign::list_of(Off)(Off)(Off)(Off)(Off)(Off)(Off)(Off));
00097
00098 patterns_.fault.push_back(
00099 boost::assign::list_of(Orange_H)(Orange_H)(Orange_H)(Orange_H)(Orange_H)(Orange_H)(Orange_H)(Orange_H));
00100 patterns_.fault.push_back(boost::assign::list_of(Off)(Off)(Off)(Off)(Off)(Off)(Off)(Off));
00101
00102 patterns_.reset.push_back(boost::assign::list_of(Off)(Red_H)(Off)(Red_H)(Yellow_H)(Yellow_H)(Red_H)(Off));
00103 patterns_.reset.push_back(boost::assign::list_of(Red_H)(Off)(Red_H)(Off)(Red_H)(Red_H)(Off)(Red_H));
00104
00105 patterns_.low_battery.push_back(
00106 boost::assign::list_of(Orange_L)(Orange_L)(Orange_L)(Orange_L)(Orange_L)(Orange_L)(Orange_L)(Orange_L));
00107 patterns_.low_battery.push_back(
00108 boost::assign::list_of(Orange_M)(Orange_M)(Orange_M)(Orange_M)(Orange_M)(Orange_M)(Orange_M)(Orange_M));
00109 patterns_.low_battery.push_back(
00110 boost::assign::list_of(Orange_H)(Orange_H)(Orange_H)(Orange_H)(Orange_H)(Orange_H)(Orange_H)(Orange_H));
00111 patterns_.low_battery.push_back(
00112 boost::assign::list_of(Orange_M)(Orange_M)(Orange_M)(Orange_M)(Orange_M)(Orange_M)(Orange_M)(Orange_M));
00113 patterns_.low_battery.push_back(
00114 boost::assign::list_of(Orange_L)(Orange_L)(Orange_L)(Orange_L)(Orange_L)(Orange_L)(Orange_L)(Orange_L));
00115
00116 patterns_.charged.push_back(
00117 boost::assign::list_of(Green_H)(Green_H)(Green_H)(Green_H)(Green_H)(Green_H)(Green_H)(Green_H));
00118
00119 patterns_.charging.push_back(
00120 boost::assign::list_of(Green_L)(Green_L)(Green_L)(Green_L)(Green_L)(Green_L)(Green_L)(Green_L));
00121 patterns_.charging.push_back(
00122 boost::assign::list_of(Green_M)(Green_M)(Green_M)(Green_M)(Green_M)(Green_M)(Green_M)(Green_M));
00123 patterns_.charging.push_back(
00124 boost::assign::list_of(Green_H)(Green_H)(Green_H)(Green_H)(Green_H)(Green_H)(Green_H)(Green_H));
00125 patterns_.charging.push_back(
00126 boost::assign::list_of(Green_M)(Green_M)(Green_M)(Green_M)(Green_M)(Green_M)(Green_M)(Green_M));
00127 patterns_.charging.push_back(
00128 boost::assign::list_of(Green_L)(Green_L)(Green_L)(Green_L)(Green_L)(Green_L)(Green_L)(Green_L));
00129
00130 patterns_.driving.push_back(
00131 boost::assign::list_of(White_M)(White_M)(White_M)(White_M)(Red_M)(Red_M)(Red_M)(Red_M));
00132
00133 patterns_.idle.push_back(
00134 boost::assign::list_of(White_L)(White_L)(White_L)(White_L)(Red_L)(Red_L)(Red_L)(Red_L));
00135 }
00136
00137
00138 void RidgebackLighting::setRGB(ridgeback_msgs::RGB* rgb, uint32_t colour)
00139 {
00140 rgb->red = ((colour & 0xFF0000) >> 16) / 255.0;
00141 rgb->green = ((colour & 0x00FF00) >> 8) / 255.0;
00142 rgb->blue = ((colour & 0x0000FF)) / 255.0;
00143 }
00144
00145 void RidgebackLighting::setLights(ridgeback_msgs::Lights* lights, uint32_t pattern[8])
00146 {
00147 for (int i = 0; i < 8; i++)
00148 {
00149 setRGB(&lights->lights[i], pattern[i]);
00150 }
00151 }
00152
00153 void RidgebackLighting::userCmdCallback(const ridgeback_msgs::Lights::ConstPtr& lights_msg)
00154 {
00155 if (allow_user_)
00156 {
00157 lights_pub_.publish(lights_msg);
00158 }
00159 user_publishing_ = true;
00160 }
00161
00162 void RidgebackLighting::mcuStatusCallback(const ridgeback_msgs::Status::ConstPtr& status_msg)
00163 {
00164 mcu_status_msg_ = *status_msg;
00165 }
00166
00167 void RidgebackLighting::pumaStatusCallback(const puma_motor_msgs::MultiStatus::ConstPtr& status_msg)
00168 {
00169 pumas_status_msg_ = *status_msg;
00170 }
00171
00172 void RidgebackLighting::cmdVelCallback(const geometry_msgs::Twist::ConstPtr& msg)
00173 {
00174 cmd_vel_msg_ = *msg;
00175 }
00176
00177 void RidgebackLighting::timerCb(const ros::TimerEvent&)
00178 {
00179 updateState();
00180
00181 if (state_ >= States::Charged)
00182 {
00183 allow_user_ = false;
00184 }
00185 else
00186 {
00187 allow_user_ = true;
00188 }
00189
00190 if (!user_publishing_ || !allow_user_)
00191 {
00192 ridgeback_msgs::Lights lights_msg;
00193 updatePattern();
00194 setLights(&lights_msg, ¤t_pattern_[0]);
00195 lights_pub_.publish(lights_msg);
00196 }
00197 }
00198
00199 void RidgebackLighting::userTimeoutCb(const ros::TimerEvent&)
00200 {
00201 user_publishing_ = false;
00202 }
00203
00204 void RidgebackLighting::updateState()
00205 {
00206 if (mcu_status_msg_.stop_engaged == true)
00207 {
00208 state_ = States::Stopped;
00209 }
00210 else if (mcu_status_msg_.drivers_active == false)
00211 {
00212 state_ = States::NeedsReset;
00213 }
00214 else if (pumas_status_msg_.drivers.size() == 4 &&
00215 (pumas_status_msg_.drivers[0].fault != 0 ||
00216 pumas_status_msg_.drivers[1].fault != 0 ||
00217 pumas_status_msg_.drivers[2].fault != 0 ||
00218 pumas_status_msg_.drivers[3].fault != 0))
00219 {
00220 state_ = States::Fault;
00221 }
00222 else if (mcu_status_msg_.measured_battery <= 24.0)
00223 {
00224 state_ = States::LowBattery;
00225 }
00226 else if (mcu_status_msg_.charging_complete == true)
00227 {
00228 state_ = States::Charged;
00229 }
00230 else if (mcu_status_msg_.charger_connected == true)
00231 {
00232 state_ = States::Charging;
00233 }
00234 else if (cmd_vel_msg_.linear.x != 0.0 ||
00235 cmd_vel_msg_.linear.y != 0.0 ||
00236 cmd_vel_msg_.angular.z != 0.0)
00237 {
00238 state_ = States::Driving;
00239 }
00240 else
00241 {
00242 state_ = States::Idle;
00243 }
00244 }
00245
00246 void RidgebackLighting::updatePattern()
00247 {
00248 if (old_state_ != state_)
00249 {
00250 current_pattern_count_ = 0;
00251 }
00252
00253 switch (state_)
00254 {
00255 case States::Stopped:
00256 if (current_pattern_count_ >= patterns_.stopped.size())
00257 {
00258 current_pattern_count_ = 0;
00259 }
00260 memcpy(¤t_pattern_, &patterns_.stopped[current_pattern_count_], sizeof(current_pattern_));
00261 break;
00262 case States::Fault:
00263 if (current_pattern_count_ >= patterns_.fault.size())
00264 {
00265 current_pattern_count_ = 0;
00266 }
00267 memcpy(¤t_pattern_, &patterns_.fault[current_pattern_count_], sizeof(current_pattern_));
00268 break;
00269 case States::NeedsReset:
00270 if (current_pattern_count_ >= patterns_.reset.size())
00271 {
00272 current_pattern_count_ = 0;
00273 }
00274 memcpy(¤t_pattern_, &patterns_.reset[current_pattern_count_], sizeof(current_pattern_));
00275 break;
00276 case States::LowBattery:
00277 if (current_pattern_count_ >= patterns_.low_battery.size())
00278 {
00279 current_pattern_count_ = 0;
00280 }
00281 memcpy(¤t_pattern_, &patterns_.low_battery[current_pattern_count_], sizeof(current_pattern_));
00282 break;
00283 case States::Charged:
00284 if (current_pattern_count_ >= patterns_.charged.size())
00285 {
00286 current_pattern_count_ = 0;
00287 }
00288 memcpy(¤t_pattern_, &patterns_.charged[current_pattern_count_], sizeof(current_pattern_));
00289 break;
00290 case States::Charging:
00291 if (current_pattern_count_ >= patterns_.charging.size())
00292 {
00293 current_pattern_count_ = 0;
00294 }
00295 memcpy(¤t_pattern_, &patterns_.charging[current_pattern_count_], sizeof(current_pattern_));
00296 break;
00297 case States::Driving:
00298 if (current_pattern_count_ >= patterns_.driving.size())
00299 {
00300 current_pattern_count_ = 0;
00301 }
00302 memcpy(¤t_pattern_, &patterns_.driving[current_pattern_count_], sizeof(current_pattern_));
00303 break;
00304 case States::Idle:
00305 if (current_pattern_count_ >= patterns_.idle.size())
00306 {
00307 current_pattern_count_ = 0;
00308 }
00309 memcpy(¤t_pattern_, &patterns_.idle[current_pattern_count_], sizeof(current_pattern_));
00310 break;
00311 }
00312 old_state_ = state_;
00313 current_pattern_count_++;
00314 }
00315
00316 }