20 #include <prbt_hardware_support/ModbusMsgInStamped.h> 29 const std::string& modbus_read_topic_name,
30 const std::string& modbus_write_service_name,
double read_frequency_hz)
31 : registers_to_read_(registers_to_read)
32 , RESPONSE_TIMEOUT_MS(response_timeout_ms)
33 , READ_FREQUENCY_HZ(read_frequency_hz)
34 , modbus_client_(
std::move(modbus_client))
36 , modbus_write_service_(
44 while (
ros::ok() && (retries == -1 || static_cast<int>(retry_n) < retries))
58 <<
" failed. Make sure that your cables are connected properly and that " 59 "you have set the correct ip address and port.");
61 << ip <<
":" << port <<
" failed. Try(" << retry_n <<
"/" << retries
62 <<
"). Make sure that your cables are connected properly and that " 63 "you have set the correct ip address and port.");
72 State expected_state{ State::not_initialized };
73 if (!
state_.compare_exchange_strong(expected_state, State::initializing))
76 state_ = State::not_initialized;
83 state_ = State::not_initialized;
89 state_ = State::initialized;
96 ModbusMsgInStamped
msg;
97 msg.disconnect.data =
true;
105 State expected_state{ State::initialized };
106 if (!
state_.compare_exchange_strong(expected_state, State::running))
121 boost::optional<ModbusRegisterBlock> write_reg_bock{ boost::none };
137 holding_register =
RegCont(static_cast<unsigned long>(num_registers), 0);
139 ROS_DEBUG(
"blocks.size() %zu", blocks.size());
142 for (
auto& block : blocks)
144 ROS_DEBUG(
"block.size() %zu", block.size());
145 unsigned short index_of_first_register_block = *(block.begin());
146 unsigned long num_registers_block = block.size();
147 RegCont block_holding_register;
150 block_holding_register =
modbus_client_->writeReadHoldingRegister(
151 static_cast<int>(write_reg_bock->start_idx), write_reg_bock->values,
152 static_cast<int>(index_of_first_register_block), static_cast<int>(num_registers_block));
154 write_reg_bock = boost::none;
158 block_holding_register =
modbus_client_->readHoldingRegister(static_cast<int>(index_of_first_register_block),
159 static_cast<int>(num_registers_block));
161 for (uint i = 0; i < num_registers_block; i++)
162 holding_register[i + index_of_first_register_block - index_of_first_register] = block_holding_register[i];
176 if (holding_register != last_holding_register)
180 last_update =
msg->header.stamp;
181 last_holding_register = holding_register;
185 msg->header.stamp = last_update;
194 state_ = State::not_initialized;
199 std::vector<std::vector<unsigned short>> out;
200 std::sort(in.begin(), in.end());
201 unsigned short prev{ 0 };
202 std::vector<unsigned short> current_block;
209 else if (reg == prev + 1)
211 current_block.push_back(reg);
215 std::vector<unsigned short> to_out(current_block);
218 out.push_back(to_out);
220 current_block.clear();
221 current_block.push_back(reg);
225 std::vector<unsigned short> to_out(current_block);
228 out.push_back(to_out);
std::vector< unsigned short > registers_to_read_
Registers which have to be read.
void run()
Publishes the register values as messages.
std::vector< uint16_t > RegCont
Convenience data type defining the data type for a collection of registers.
Expection thrown by prbt_hardware_support::PilzModbusClient.
bool init(const char *ip, unsigned int port)
Tries to connect to a modbus server.
State
States of the Modbus-client.
ServiceServer advertiseService(ros::NodeHandle n, std::string name, boost::function< bool(const typename ActionSpec::_action_goal_type::_goal_type &, typename ActionSpec::_action_result_type::_result_type &result)> service_cb)
static std::vector< std::vector< unsigned short > > splitIntoBlocks(std::vector< unsigned short > &in)
Splits a vector of integers into a vector of vectors with consecutive groups.
const unsigned int RESPONSE_TIMEOUT_MS
Defines how long we wait for a response from the Modbus-server.
ros::Publisher modbus_read_pub_
void publish(const boost::shared_ptr< M > &message) const
std::atomic_bool stop_run_
PilzModbusClient(ros::NodeHandle &nh, const std::vector< unsigned short > ®isters_to_read, ModbusClientUniquePtr modbus_client, unsigned int response_timeout_ms, const std::string &modbus_read_topic_name, const std::string &modbus_write_service_name, double read_frequency_hz=DEFAULT_MODBUS_READ_FREQUENCY_HZ)
Sets up publisher. To open the modbus connection call PilzModbusClient::init.
static ModbusMsgInStampedPtr createDefaultModbusMsgIn(const std_msgs::MultiArrayLayout::_data_offset_type &offset, const RegCont &holding_register)
Creates a standard ModbusMsgIn which contains default values for all essential elements of the messag...
std::atomic< State > state_
Connects to a modbus server and publishes the received data into ROS.
#define ROS_WARN_STREAM_COND(cond, args)
static constexpr int DEFAULT_QUEUE_SIZE_MODBUS
#define ROS_DEBUG_STREAM(args)
std::mutex write_reg_blocks_mutex_
ModbusClientUniquePtr modbus_client_
std::unique_ptr< ModbusClient > ModbusClientUniquePtr
std::queue< ModbusRegisterBlock > write_reg_blocks_
#define ROS_ERROR_STREAM(args)
ROSCPP_DECL void spinOnce()
Expection thrown by prbt_hardware_support::LibModbusClient::readHoldingRegister if a disconnect from ...
const double READ_FREQUENCY_HZ
Defines how often the Modbus registers are read in.