PdsNode.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2017-2018, Dataspeed Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Dataspeed Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 #include "PdsNode.h"
37 
38 namespace dataspeed_pds_can
39 {
40 
46 {
47  // Setup message synchronizers
51  sync_ros_slave1_->registerCallback(boost::bind(&PdsNode::recvSyncSlave1, this, _1, _2));
52  sync_ros_slave2_->registerCallback(boost::bind(&PdsNode::recvSyncSlave2, this, _1, _2, _3));
53  sync_ros_slave3_->registerCallback(boost::bind(&PdsNode::recvSyncSlave3, this, _1, _2, _3, _4));
54 
55  // Reduce synchronization delay
56  const ros::Duration SYNC_50_MS(0.016); // 30% of 50ms period
61  sync_ros_slave1_->setInterMessageLowerBound(SYNC_50_MS);
62  sync_ros_slave2_->setInterMessageLowerBound(SYNC_50_MS);
63  sync_ros_slave3_->setInterMessageLowerBound(SYNC_50_MS);
64 
65  // Setup Publishers
66  pub_status_ = node.advertise<dataspeed_pds_msgs::Status>("status", 10);
67  pub_can_ = node.advertise<can_msgs::Frame>("can_tx", 10);
68 
69  // Setup Subscribers
70  sub_relay_ = node.subscribe("relay", 10, &PdsNode::recvRelay, this, ros::TransportHints().tcpNoDelay(true));
71  sub_mode_ = node.subscribe("mode", 10, &PdsNode::recvMode, this, ros::TransportHints().tcpNoDelay(true));
72  sub_script_ = node.subscribe("script", 10, &PdsNode::recvScript, this, ros::TransportHints().tcpNoDelay(true));
73  sub_can_ = node.subscribe("can_rx", 80, &PdsNode::recvCAN, this, ros::TransportHints().tcpNoDelay(true));
74 }
76 {
77  if (sync_ros_slave1_) {
78  delete sync_ros_slave1_;
79  sync_ros_slave1_ = NULL;
80  }
81  if (sync_ros_slave2_) {
82  delete sync_ros_slave2_;
83  sync_ros_slave2_ = NULL;
84  }
85  if (sync_ros_slave3_) {
86  delete sync_ros_slave3_;
87  sync_ros_slave3_ = NULL;
88  }
89 }
90 
91 void PdsNode::recvCAN(const can_msgs::Frame::ConstPtr& msg)
92 {
93  if (!msg->is_rtr && !msg->is_error && !msg->is_extended) {
98  switch (msg->id) {
99  case ID_REQUEST: // These command messages aren't handled.
100  case ID_MODE:
101  case ID_SCRIPT:
102  break;
103  case ID_RESERVED1: // Reserved for the Touchscreen Display
104  case ID_RESERVED2:
105  case ID_RESERVED3:
106  case ID_RESERVED4:
107  break;
108  case ID_STATUS1_MASTER:
109  case ID_STATUS2_MASTER:
110  case ID_CURRENT1_MASTER:
111  case ID_CURRENT2_MASTER:
112  case ID_CURRENT3_MASTER:
113  break;
114  case ID_STATUS1_SLAVE1:
115  case ID_STATUS2_SLAVE1:
116  case ID_CURRENT1_SLAVE1:
117  case ID_CURRENT2_SLAVE1:
118  case ID_CURRENT3_SLAVE1:
119  break;
120  case ID_STATUS1_SLAVE2:
121  case ID_STATUS2_SLAVE2:
122  case ID_CURRENT1_SLAVE2:
123  case ID_CURRENT2_SLAVE2:
124  case ID_CURRENT3_SLAVE2:
125  break;
126  case ID_STATUS1_SLAVE3:
127  case ID_STATUS2_SLAVE3:
128  case ID_CURRENT1_SLAVE3:
129  case ID_CURRENT2_SLAVE3:
130  case ID_CURRENT3_SLAVE3:
131  break;
132  default:
133 #if 0
134  ROS_WARN("Unknown message ID: %1$d (0x%1$01x)", msg->id);
135 #endif
136  break;
137  }
138  }
139 }
140 
141 void PdsNode::recvRelay(const dataspeed_pds_msgs::Relay::ConstPtr &msg)
142 {
143  can_msgs::Frame out;
144  ((MsgRelay*)out.data.elems)->channel = msg->channel;
145  ((MsgRelay*)out.data.elems)->request = msg->request;
146  out.id = ID_REQUEST;
147  out.dlc = sizeof(MsgRelay);
148  out.is_extended = false;
149  pub_can_.publish(out);
150 }
151 
152 void PdsNode::recvMode(const dataspeed_pds_msgs::Mode::ConstPtr &msg)
153 {
154  can_msgs::Frame out;
155  ((MsgMode*)out.data.elems)->mode = msg->mode;
156  out.id = ID_MODE;
157  out.dlc = sizeof(MsgMode);
158  out.is_extended = false;
159  pub_can_.publish(out);
160 }
161 
162 void PdsNode::recvScript(const dataspeed_pds_msgs::Script::ConstPtr &msg)
163 {
164  can_msgs::Frame out;
165  MsgScript *ptr = (MsgScript*)out.data.elems;
166  ((MsgScript*)out.data.elems)->script = msg->script;
167  out.id = ID_SCRIPT;
168  out.dlc = sizeof(MsgScript);
169  out.is_extended = false;
170  pub_can_.publish(out);
171 }
172 
173 void PdsNode::recvSync(const std::vector<can_msgs::Frame::ConstPtr> &msgs, UnitId id)
174 {
175  ROS_ASSERT((MASTER <= id) && (id <= SLAVE3));
176  ROS_ASSERT(msgs.size() == 5);
177  ROS_ASSERT(msgs[0]->id == ID_STATUS1_MASTER + id);
178  ROS_ASSERT(msgs[1]->id == ID_STATUS2_MASTER + id);
179  ROS_ASSERT(msgs[2]->id == ID_CURRENT1_MASTER + id);
180  ROS_ASSERT(msgs[3]->id == ID_CURRENT2_MASTER + id);
181  ROS_ASSERT(msgs[4]->id == ID_CURRENT3_MASTER + id);
182  if ((msgs[0]->dlc >= sizeof(MsgStatus1))
183  && (msgs[1]->dlc >= sizeof(MsgStatus2))
184  && (msgs[2]->dlc >= sizeof(MsgCurrent))
185  && (msgs[3]->dlc >= sizeof(MsgCurrent))
186  && (msgs[4]->dlc >= sizeof(MsgCurrent))) {
187  const MsgStatus1 *ptrS1 = (const MsgStatus1*)msgs[0]->data.elems;
188  const MsgStatus2 *ptrS2 = (const MsgStatus2*)msgs[1]->data.elems;
189  const MsgCurrent *ptrC1 = (const MsgCurrent*)msgs[2]->data.elems;
190  const MsgCurrent *ptrC2 = (const MsgCurrent*)msgs[3]->data.elems;
191  const MsgCurrent *ptrC3 = (const MsgCurrent*)msgs[4]->data.elems;
192 
193  // Merge CAN messages into a single ROS message
194  dataspeed_pds_msgs::Status msg;
195  msg.header.stamp = msgs[0]->header.stamp;
196  msg.mode.mode = ptrS1->mode;
197  msg.script.script = ptrS1->script;
198  msg.chan.resize(12);
199  msg.chan[ 0].status = ptrS1->status_01;
200  msg.chan[ 1].status = ptrS1->status_02;
201  msg.chan[ 2].status = ptrS1->status_03;
202  msg.chan[ 3].status = ptrS1->status_04;
203  msg.chan[ 4].status = ptrS1->status_05;
204  msg.chan[ 5].status = ptrS1->status_06;
205  msg.chan[ 6].status = ptrS1->status_07;
206  msg.chan[ 7].status = ptrS1->status_08;
207  msg.chan[ 8].status = ptrS1->status_09;
208  msg.chan[ 9].status = ptrS1->status_10;
209  msg.chan[10].status = ptrS1->status_11;
210  msg.chan[11].status = ptrS1->status_12;
211  msg.chan[ 0].current = bytesToAmperes(ptrC1->current_01);
212  msg.chan[ 1].current = bytesToAmperes(ptrC1->current_02);
213  msg.chan[ 2].current = bytesToAmperes(ptrC1->current_03);
214  msg.chan[ 3].current = bytesToAmperes(ptrC1->current_04);
215  msg.chan[ 4].current = bytesToAmperes(ptrC2->current_05);
216  msg.chan[ 5].current = bytesToAmperes(ptrC2->current_06);
217  msg.chan[ 6].current = bytesToAmperes(ptrC2->current_07);
218  msg.chan[ 7].current = bytesToAmperes(ptrC2->current_08);
219  msg.chan[ 8].current = bytesToAmperes(ptrC3->current_09);
220  msg.chan[ 9].current = bytesToAmperes(ptrC3->current_10);
221  msg.chan[10].current = bytesToAmperes(ptrC3->current_11);
222  msg.chan[11].current = bytesToAmperes(ptrC3->current_12);
223  msg.master.inverter.request = ptrS1->inverter_request;
224  msg.master.inverter.status = ptrS1->inverter_status;
225  msg.master.inverter.overload = ptrS1->inverter_overload;
226  msg.master.inverter.overtemp = ptrS1->inverter_overtemp;
227  msg.master.temp.internal = bytesToCelsius(ptrS2->board_temp);
228  msg.master.temp.external = bytesToCelsius(ptrS2->thermocouple_temp);
229  msg.master.voltage = bytesToVoltage(ptrS2->voltage);
230 
231  // Publish for single unit, or forward to multi-unit synchronization
232  const dataspeed_pds_msgs::Status::ConstPtr ptr(new dataspeed_pds_msgs::Status(msg));
233  const ros::Time now = ros::Time::now();
234  switch (id) {
235  case MASTER:
236  sync_msg_master_.add(ptr);
237  if ((now - stamp_slave1_) > TIMEOUT) {
238  pub_status_.publish(msg);
239  }
240  break;
241  case SLAVE1:
242  stamp_slave1_ = now;
243  sync_msg_slave1_.add(ptr);
244  break;
245  case SLAVE2:
246  stamp_slave2_ = now;
247  sync_msg_slave2_.add(ptr);
248  break;
249  case SLAVE3:
250  stamp_slave3_ = now;
251  sync_msg_slave3_.add(ptr);
252  break;
253  }
254  }
255 }
256 
257 void PdsNode::recvSyncSlave1(const SyncPtr& master, const SyncPtr& slave1)
258 {
259  if ((ros::Time::now() - stamp_slave2_) > TIMEOUT) {
260  dataspeed_pds_msgs::Status msg = *master;
261  msg.chan.insert(msg.chan.end(), slave1->chan.begin(), slave1->chan.end());
262  msg.slave.push_back(slave1->master);
263  pub_status_.publish(msg);
264  }
265 }
266 void PdsNode::recvSyncSlave2(const SyncPtr& master, const SyncPtr& slave1, const SyncPtr& slave2)
267 {
268  if ((ros::Time::now() - stamp_slave3_) > TIMEOUT) {
269  dataspeed_pds_msgs::Status msg = *master;
270  msg.chan.insert(msg.chan.end(), slave1->chan.begin(), slave1->chan.end());
271  msg.chan.insert(msg.chan.end(), slave2->chan.begin(), slave2->chan.end());
272  msg.slave.push_back(slave1->master);
273  msg.slave.push_back(slave2->master);
274  pub_status_.publish(msg);
275  }
276 }
277 void PdsNode::recvSyncSlave3(const SyncPtr& master, const SyncPtr& slave1, const SyncPtr& slave2, const SyncPtr& slave3)
278 {
279  if (1) { // There is no slave4
280  dataspeed_pds_msgs::Status msg = *master;
281  msg.chan.insert(msg.chan.end(), slave1->chan.begin(), slave1->chan.end());
282  msg.chan.insert(msg.chan.end(), slave2->chan.begin(), slave2->chan.end());
283  msg.chan.insert(msg.chan.end(), slave3->chan.begin(), slave3->chan.end());
284  msg.slave.push_back(slave1->master);
285  msg.slave.push_back(slave2->master);
286  msg.slave.push_back(slave3->master);
287  pub_status_.publish(msg);
288  }
289 }
290 
291 } // namespace dataspeed_pds_can
292 
void recvSync(const std::vector< can_msgs::Frame::ConstPtr > &msgs, UnitId id)
Definition: PdsNode.cpp:173
message_filters::Synchronizer< SyncPolicy3 > * sync_ros_slave3_
Definition: PdsNode.h:115
void publish(const boost::shared_ptr< M > &message) const
void recvMode(const dataspeed_pds_msgs::Mode::ConstPtr &msg)
Definition: PdsNode.cpp:152
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
message_filters::Synchronizer< SyncPolicy2 > * sync_ros_slave2_
Definition: PdsNode.h:114
float bytesToVoltage(uint16_t input)
Definition: PdsNode.h:82
dataspeed_pds_msgs::Status::ConstPtr SyncPtr
Definition: PdsNode.h:109
message_filters::PassThrough< SyncMsg > sync_msg_master_
Definition: PdsNode.h:116
message_filters::PassThrough< SyncMsg > sync_msg_slave1_
Definition: PdsNode.h:117
#define ROS_WARN(...)
message_filters::PassThrough< SyncMsg > sync_msg_slave3_
Definition: PdsNode.h:119
message_filters::PassThrough< SyncMsg > sync_msg_slave2_
Definition: PdsNode.h:118
dataspeed_can_msg_filters::ApproximateTime sync_can_slave1_
Definition: PdsNode.h:103
ros::Publisher pub_can_
Definition: PdsNode.h:94
void recvSyncSlave3(const SyncPtr &master, const SyncPtr &slave1, const SyncPtr &slave2, const SyncPtr &slave3)
Definition: PdsNode.cpp:277
ros::Subscriber sub_can_
Definition: PdsNode.h:90
message_filters::sync_policies::ApproximateTime< SyncMsg, SyncMsg > SyncPolicy1
Definition: PdsNode.h:110
ros::Subscriber sub_relay_
Definition: PdsNode.h:87
Connection registerCallback(C &callback)
dataspeed_can_msg_filters::ApproximateTime sync_can_slave2_
Definition: PdsNode.h:104
void recvRelay(const dataspeed_pds_msgs::Relay::ConstPtr &msg)
Definition: PdsNode.cpp:141
void recvCAN(const can_msgs::Frame::ConstPtr &msg)
Definition: PdsNode.cpp:91
void recvScript(const dataspeed_pds_msgs::Script::ConstPtr &msg)
Definition: PdsNode.cpp:162
dataspeed_can_msg_filters::ApproximateTime sync_can_master_
Definition: PdsNode.h:102
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
const ros::Duration TIMEOUT(0.5)
PdsNode(ros::NodeHandle &node, ros::NodeHandle &priv_nh)
Definition: PdsNode.cpp:41
float bytesToAmperes(int16_t input)
Definition: PdsNode.h:83
float bytesToCelsius(int8_t input)
Definition: PdsNode.h:84
ros::Subscriber sub_script_
Definition: PdsNode.h:89
dataspeed_can_msg_filters::ApproximateTime sync_can_slave3_
Definition: PdsNode.h:105
ros::Publisher pub_status_
Definition: PdsNode.h:93
void setInterMessageLowerBound(ros::Duration lower_bound)
void add(const MConstPtr &msg)
static Time now()
message_filters::sync_policies::ApproximateTime< SyncMsg, SyncMsg, SyncMsg, SyncMsg > SyncPolicy3
Definition: PdsNode.h:112
#define ROS_ASSERT(cond)
message_filters::Synchronizer< SyncPolicy1 > * sync_ros_slave1_
Definition: PdsNode.h:113
message_filters::sync_policies::ApproximateTime< SyncMsg, SyncMsg, SyncMsg > SyncPolicy2
Definition: PdsNode.h:111
void recvSyncSlave2(const SyncPtr &master, const SyncPtr &slave1, const SyncPtr &slave2)
Definition: PdsNode.cpp:266
void recvSyncSlave1(const SyncPtr &master, const SyncPtr &slave1)
Definition: PdsNode.cpp:257
ros::Subscriber sub_mode_
Definition: PdsNode.h:88


dataspeed_pds_can
Author(s): Kevin Hallenbeck , Eric Myllyoja
autogenerated on Sat Jul 11 2020 03:09:52