20 #include <prbt_hardware_support/ModbusMsgInStamped.h> 29 const std::vector<unsigned short>& registers_to_read,
31 unsigned int response_timeout_ms,
32 const std::string& modbus_read_topic_name,
33 const std::string& modbus_write_service_name,
34 double read_frequency_hz)
35 : registers_to_read(registers_to_read)
36 , RESPONSE_TIMEOUT_MS(response_timeout_ms)
37 , READ_FREQUENCY_HZ(read_frequency_hz)
38 , modbus_client_(
std::move(modbus_client))
50 for(
size_t retry_n = 0; retry_n < retries; ++retry_n)
57 ROS_ERROR_STREAM(
"Connection to " << ip <<
":" << port <<
" failed. Try(" << retry_n+1 <<
"/" << retries <<
")");
72 State expectedState {State::not_initialized};
73 if (!
state_.compare_exchange_strong(expectedState, 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 expectedState {State::initialized};
106 if (!
state_.compare_exchange_strong(expectedState, State::running))
121 boost::optional<ModbusRegisterBlock> write_reg_bock {boost::none};
136 holding_register =
RegCont(num_registers, 0);
138 ROS_DEBUG(
"blocks.size() %d", blocks.size());
141 for(
auto &block : blocks){
142 ROS_DEBUG(
"block.size() %d", block.size());
143 unsigned short index_of_first_register_block = *(block.begin());
144 unsigned long num_registers_block = block.size();
145 RegCont block_holding_register;
148 block_holding_register =
modbus_client_->writeReadHoldingRegister(static_cast<int>(write_reg_bock->start_idx),
149 write_reg_bock->values,
150 static_cast<int>(index_of_first_register_block),
151 static_cast<int>(num_registers_block));
153 write_reg_bock = boost::none;
157 block_holding_register =
modbus_client_->readHoldingRegister(static_cast<int>(index_of_first_register_block), static_cast<int>(num_registers_block));
159 for(uint i = 0; i < num_registers_block; i++)
160 holding_register[i+index_of_first_register_block-index_of_first_register] = block_holding_register[i];
170 ModbusMsgInStampedPtr
msg {
175 if(holding_register != last_holding_register)
179 last_update =
msg->header.stamp;
180 last_holding_register = holding_register;
184 msg->header.stamp = last_update;
193 state_ = State::not_initialized;
197 std::vector<std::vector<unsigned short>> out;
198 std::sort(in.begin(), in.end());
199 unsigned short prev{0};
200 std::vector<unsigned short> current_block;
201 for (
auto & reg : in){
205 else if(reg == prev + 1) {
206 current_block.push_back(reg);
209 std::vector<unsigned short> to_out(current_block);
210 if(to_out.size() > 0) {
211 out.push_back(to_out);
213 current_block.clear();
214 current_block.push_back(reg);
218 std::vector<unsigned short> to_out(current_block);
219 if(to_out.size() > 0) {
220 out.push_back(to_out);
void run()
Publishes the register values as messages.
void publish(const boost::shared_ptr< M > &message) const
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)
const unsigned int RESPONSE_TIMEOUT_MS
Defines how long we wait for a response from the Modbus-server.
ros::Publisher modbus_read_pub_
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.
static constexpr int DEFAULT_QUEUE_SIZE_MODBUS
#define ROS_DEBUG_STREAM(args)
std::mutex write_reg_blocks_mutex_
ModbusClientUniquePtr modbus_client_
std::vector< unsigned short > registers_to_read
Registers which have to be read.
static std::vector< std::vector< unsigned short > > split_into_blocks(std::vector< unsigned short > &in)
Splits a vector of integers into a vector of vectors with consecutive groups.
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.