Skip to content

Commit 3b387b5

Browse files
committed
Use replacement dictionary for replacing variables
1 parent 4e96383 commit 3b387b5

File tree

4 files changed

+107
-95
lines changed

4 files changed

+107
-95
lines changed

include/ur_client_library/control/script_reader.h

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,18 @@ class ScriptReader
5050
RobotType robot_type;
5151
};
5252

53-
ScriptReader() = delete;
53+
using DataDict = std::unordered_map<std::string, std::variant<std::string, double, int>>;
5454

55-
/*!
56-
* \brief Creates a ScriptReader object with the robot info
57-
*/
58-
explicit ScriptReader(const RobotInfo& robot_info) : robot_info_(robot_info)
59-
{
60-
}
55+
ScriptReader() = default;
6156

62-
std::string readScriptFile(const std::string& filename);
57+
std::string readScriptFile(const std::string& filename, const DataDict& data = DataDict());
6358

6459
private:
6560
std::filesystem::path script_path_;
66-
RobotInfo robot_info_;
67-
std::unordered_map<std::string, std::variant<std::string, float, int>> replacement_data_;
6861

69-
void replaceIncludes(std::string& script_code);
7062
std::string readFileContent(const std::string& filename);
63+
void replaceIncludes(std::string& script_code);
64+
void replaceVariables(std::string& script_code, const DataDict& data);
7165
};
7266
} // namespace control
7367
} // namespace urcl

src/control/script_reader.cpp

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,19 @@
3333

3434
#include <fstream>
3535
#include <regex>
36+
#include "ur_client_library/log.h"
3637

3738
namespace urcl
3839
{
3940
namespace control
4041
{
41-
std::string ScriptReader::readScriptFile(const std::string& filename)
42+
std::string ScriptReader::readScriptFile(const std::string& filename, const DataDict& data)
4243
{
4344
script_path_ = filename;
4445
std::string script_code = readFileContent(filename);
4546

4647
replaceIncludes(script_code);
48+
replaceVariables(script_code, data);
4749

4850
return script_code;
4951
}
@@ -71,28 +73,57 @@ std::string ScriptReader::readFileContent(const std::string& filename)
7173

7274
void ScriptReader::replaceIncludes(std::string& script)
7375
{
74-
std::string line;
7576
std::regex include_pattern(R"(\{\%\s*include\s*['|"]([^'"]+)['|"]\s*\%\})");
7677

77-
std::stringstream input_stream(script);
78-
std::stringstream output_stream;
78+
std::smatch match;
7979

80-
while (std::getline(input_stream, line))
80+
// Replace all include patterns in the line
81+
while (std::regex_search(script, match, include_pattern))
8182
{
82-
std::smatch match;
83-
std::string processed_line = line;
83+
std::filesystem::path file_path(match[1]);
84+
std::string file_content = readFileContent(script_path_.parent_path() / file_path.string());
85+
script.replace(match.position(0), match.length(0), file_content);
86+
}
87+
}
8488

85-
// Replace all include patterns in the line
86-
while (std::regex_search(processed_line, match, include_pattern))
89+
void ScriptReader::replaceVariables(std::string& script_code, const DataDict& data)
90+
{
91+
std::regex pattern(R"(\{\{\s*([\w-]+)\s*\}\})");
92+
std::smatch match;
93+
while (std::regex_search(script_code, match, pattern))
94+
{
95+
std::string key = match[1];
96+
URCL_LOG_INFO("Found replacement pattern %s", match[0].str().c_str());
97+
if (data.find(key) == data.end())
8798
{
88-
std::filesystem::path file_path(match[1]);
89-
std::string file_content = readFileContent(script_path_.parent_path() / file_path.string());
90-
processed_line.replace(match.position(0), match.length(0), file_content);
99+
std::stringstream ss;
100+
ss << "Variable '" << key << "' not found in data.";
101+
URCL_LOG_ERROR(ss.str().c_str());
102+
throw UrException(ss.str().c_str());
91103
}
104+
std::string replaced_value;
92105

93-
output_stream << processed_line << '\n';
106+
if (std::holds_alternative<std::string>(data.at(key)))
107+
{
108+
replaced_value = std::get<std::string>(data.at(key));
109+
}
110+
else if (std::holds_alternative<double>(data.at(key)))
111+
{
112+
replaced_value = std::to_string(std::get<double>(data.at(key)));
113+
}
114+
else if (std::holds_alternative<int>(data.at(key)))
115+
{
116+
replaced_value = std::to_string(std::get<int>(data.at(key)));
117+
}
118+
else
119+
{
120+
std::stringstream ss;
121+
ss << "Unsupported type for variable '" << key << "'.";
122+
URCL_LOG_ERROR(ss.str().c_str());
123+
throw UrException(ss.str().c_str());
124+
}
125+
script_code.replace(match.position(0), match.length(0), replaced_value);
94126
}
95-
script = output_stream.str();
96127
}
97128

98129
} // namespace control

src/ur/ur_driver.cpp

Lines changed: 25 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
//----------------------------------------------------------------------
3333

3434
#include "ur_client_library/ur/ur_driver.h"
35+
#include "ur_client_library/control/script_reader.h"
3536
#include "ur_client_library/exceptions.h"
3637
#include "ur_client_library/helpers.h"
3738
#include "ur_client_library/primary/primary_parser.h"
@@ -42,16 +43,16 @@
4243

4344
namespace urcl
4445
{
45-
static const std::string BEGIN_REPLACE("{{BEGIN_REPLACE}}");
46-
static const std::string JOINT_STATE_REPLACE("{{JOINT_STATE_REPLACE}}");
47-
static const std::string TIME_REPLACE("{{TIME_REPLACE}}");
48-
static const std::string SERVO_J_REPLACE("{{SERVO_J_REPLACE}}");
49-
static const std::string SERVER_IP_REPLACE("{{SERVER_IP_REPLACE}}");
50-
static const std::string SERVER_PORT_REPLACE("{{SERVER_PORT_REPLACE}}");
51-
static const std::string TRAJECTORY_PORT_REPLACE("{{TRAJECTORY_SERVER_PORT_REPLACE}}");
52-
static const std::string SCRIPT_COMMAND_PORT_REPLACE("{{SCRIPT_COMMAND_SERVER_PORT_REPLACE}}");
53-
static const std::string FORCE_MODE_SET_DAMPING_REPLACE("{{FORCE_MODE_SET_DAMPING_REPLACE}}");
54-
static const std::string FORCE_MODE_SET_GAIN_SCALING_REPLACE("{{FORCE_MODE_SET_GAIN_SCALING_REPLACE}}");
46+
static const std::string BEGIN_REPLACE("BEGIN_REPLACE");
47+
static const std::string JOINT_STATE_REPLACE("JOINT_STATE_REPLACE");
48+
static const std::string TIME_REPLACE("TIME_REPLACE");
49+
static const std::string SERVO_J_REPLACE("SERVO_J_REPLACE");
50+
static const std::string SERVER_IP_REPLACE("SERVER_IP_REPLACE");
51+
static const std::string SERVER_PORT_REPLACE("SERVER_PORT_REPLACE");
52+
static const std::string TRAJECTORY_PORT_REPLACE("TRAJECTORY_SERVER_PORT_REPLACE");
53+
static const std::string SCRIPT_COMMAND_PORT_REPLACE("SCRIPT_COMMAND_SERVER_PORT_REPLACE");
54+
static const std::string FORCE_MODE_SET_DAMPING_REPLACE("FORCE_MODE_SET_DAMPING_REPLACE");
55+
static const std::string FORCE_MODE_SET_GAIN_SCALING_REPLACE("FORCE_MODE_SET_GAIN_SCALING_REPLACE");
5556

5657
UrDriver::~UrDriver()
5758
{
@@ -87,52 +88,21 @@ void UrDriver::init(const UrDriverConfiguration& config)
8788
// Figure out the ip automatically if the user didn't provide it
8889
std::string local_ip = config.reverse_ip.empty() ? rtde_client_->getIP() : config.reverse_ip;
8990

90-
startPrimaryClientCommunication();
91-
waitFor([this]() { return primary_client_->getConfigurationData() != nullptr; }, std::chrono::milliseconds(500));
92-
control::ScriptReader::RobotInfo robot_info;
93-
robot_info.robot_type = primary_client_->getRobotType();
94-
script_reader_.reset(new control::ScriptReader(robot_info));
91+
trajectory_interface_.reset(new control::TrajectoryPointInterface(config.trajectory_port));
92+
script_command_interface_.reset(new control::ScriptCommandInterface(config.script_command_port));
9593

96-
std::string prog = readScriptFile(config.script_file);
97-
while (prog.find(JOINT_STATE_REPLACE) != std::string::npos)
98-
{
99-
prog.replace(prog.find(JOINT_STATE_REPLACE), JOINT_STATE_REPLACE.length(),
100-
std::to_string(control::ReverseInterface::MULT_JOINTSTATE));
101-
}
102-
while (prog.find(TIME_REPLACE) != std::string::npos)
103-
{
104-
prog.replace(prog.find(TIME_REPLACE), TIME_REPLACE.length(),
105-
std::to_string(control::TrajectoryPointInterface::MULT_TIME));
106-
}
94+
startPrimaryClientCommunication();
10795

96+
control::ScriptReader::DataDict data;
97+
data[JOINT_STATE_REPLACE] = std::to_string(control::ReverseInterface::MULT_JOINTSTATE);
98+
data[TIME_REPLACE] = std::to_string(control::TrajectoryPointInterface::MULT_TIME);
10899
std::ostringstream out;
109100
out << "lookahead_time=" << servoj_lookahead_time_ << ", gain=" << servoj_gain_;
110-
while (prog.find(SERVO_J_REPLACE) != std::string::npos)
111-
{
112-
prog.replace(prog.find(SERVO_J_REPLACE), SERVO_J_REPLACE.length(), out.str());
113-
}
114-
115-
while (prog.find(SERVER_IP_REPLACE) != std::string::npos)
116-
{
117-
prog.replace(prog.find(SERVER_IP_REPLACE), SERVER_IP_REPLACE.length(), local_ip);
118-
}
119-
120-
while (prog.find(SERVER_PORT_REPLACE) != std::string::npos)
121-
{
122-
prog.replace(prog.find(SERVER_PORT_REPLACE), SERVER_PORT_REPLACE.length(), std::to_string(config.reverse_port));
123-
}
124-
125-
while (prog.find(TRAJECTORY_PORT_REPLACE) != std::string::npos)
126-
{
127-
prog.replace(prog.find(TRAJECTORY_PORT_REPLACE), TRAJECTORY_PORT_REPLACE.length(),
128-
std::to_string(config.trajectory_port));
129-
}
130-
131-
while (prog.find(SCRIPT_COMMAND_PORT_REPLACE) != std::string::npos)
132-
{
133-
prog.replace(prog.find(SCRIPT_COMMAND_PORT_REPLACE), SCRIPT_COMMAND_PORT_REPLACE.length(),
134-
std::to_string(config.script_command_port));
135-
}
101+
data[SERVO_J_REPLACE] = out.str();
102+
data[SERVER_IP_REPLACE] = local_ip;
103+
data[SERVER_PORT_REPLACE] = std::to_string(config.reverse_port);
104+
data[TRAJECTORY_PORT_REPLACE] = std::to_string(config.trajectory_port);
105+
data[SCRIPT_COMMAND_PORT_REPLACE] = std::to_string(config.script_command_port);
136106

137107
robot_version_ = rtde_client_->getVersion();
138108

@@ -153,10 +123,9 @@ void UrDriver::init(const UrDriverConfiguration& config)
153123
<< config.tool_comm_setup->getStopBits() << ", " << config.tool_comm_setup->getRxIdleChars() << ", "
154124
<< config.tool_comm_setup->getTxIdleChars() << ")";
155125
}
156-
prog.replace(prog.find(BEGIN_REPLACE), BEGIN_REPLACE.length(), begin_replace.str());
157-
158-
trajectory_interface_.reset(new control::TrajectoryPointInterface(config.trajectory_port));
159-
script_command_interface_.reset(new control::ScriptCommandInterface(config.script_command_port));
126+
data[BEGIN_REPLACE] = begin_replace.str();
127+
script_reader_.reset(new control::ScriptReader());
128+
std::string prog = script_reader_->readScriptFile(config.script_file, data);
160129

161130
if (in_headless_mode_)
162131
{

tests/test_script_reader.cpp

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ class ScriptReaderTest : public ::testing::Test
4848

4949
std::stringstream simple_script_;
5050

51-
ScriptReader::RobotInfo robot_info_;
52-
5351
void SetUp() override
5452
{
5553
invalid_script_path_ = "test_resources/non_existent_script.urscript";
@@ -66,49 +64,43 @@ class ScriptReaderTest : public ::testing::Test
6664

6765
valid_script_path_ = existing_script_file;
6866

69-
simple_script_ << "movej([0,0,0,0,0,0])\n";
67+
simple_script_ << "movej([0,0,0,0,0,0])";
7068

7169
// Create test resources
7270
std::ofstream valid_script(valid_script_path_);
7371
valid_script << simple_script_.str();
7472
valid_script.close();
75-
76-
std::ofstream empty_script(empty_script_path_);
77-
empty_script.close();
78-
79-
robot_info_.robot_type = urcl::RobotType::UR3;
8073
}
8174

8275
void TearDown() override
8376
{
8477
std::remove(valid_script_path_.c_str());
85-
std::remove(empty_script_path_.c_str());
8678
}
8779
};
8880

8981
TEST_F(ScriptReaderTest, ReadValidScript)
9082
{
91-
ScriptReader reader(robot_info_);
83+
ScriptReader reader;
9284
std::string content = reader.readScriptFile(valid_script_path_);
9385
EXPECT_EQ(content, simple_script_.str());
9486
}
9587

9688
TEST_F(ScriptReaderTest, ReadEmptyScript)
9789
{
98-
ScriptReader reader(robot_info_);
90+
ScriptReader reader;
9991
std::string content = reader.readScriptFile(empty_script_path_);
10092
EXPECT_EQ(content, "");
10193
}
10294

10395
TEST_F(ScriptReaderTest, ReadNonExistentScript)
10496
{
105-
ScriptReader reader(robot_info_);
97+
ScriptReader reader;
10698
EXPECT_THROW(reader.readScriptFile(invalid_script_path_), std::runtime_error);
10799
}
108100

109101
TEST_F(ScriptReaderTest, ReplaceIncludes)
110102
{
111-
ScriptReader reader(robot_info_);
103+
ScriptReader reader;
112104

113105
char existing_script_file[] = "main_script.XXXXXX";
114106
std::ignore = mkstemp(existing_script_file);
@@ -135,8 +127,34 @@ TEST_F(ScriptReaderTest, ReplaceIncludes)
135127
ofs_included.close();
136128

137129
std::string processed_script = reader.readScriptFile(existing_script_file);
138-
EXPECT_EQ(processed_script, "movej([1,2,3,4,5,6])\n");
130+
EXPECT_EQ(processed_script, "movej([1,2,3,4,5,6])");
139131

140132
std::remove(existing_script_file);
141133
std::remove(existing_include_file);
142134
}
135+
136+
TEST_F(ScriptReaderTest, ReplaceVariables)
137+
{
138+
ScriptReader reader;
139+
ScriptReader::DataDict data;
140+
data["VAR1"] = "value1";
141+
data["VAR2"] = 42;
142+
data["VAR3"] = 6.28;
143+
144+
char existing_script_file[] = "main_script.XXXXXX";
145+
std::ignore = mkstemp(existing_script_file);
146+
std::ofstream ofs(existing_script_file);
147+
if (ofs.bad())
148+
{
149+
std::cout << "Failed to create temporary files" << std::endl;
150+
GTEST_FAIL();
151+
}
152+
ofs << "movej([{{VAR1}}, {{VAR2}}, {{VAR3}}, 0, 0, 0])" << std::endl;
153+
ofs << "This is just a line without any replacement" << std::endl;
154+
ofs.close();
155+
156+
std::string script = reader.readScriptFile(existing_script_file, data);
157+
158+
// By default std::to_string will convert double to 6 decimal places
159+
EXPECT_EQ(script, "movej([value1, 42, 6.280000, 0, 0, 0])\nThis is just a line without any replacement\n");
160+
}

0 commit comments

Comments
 (0)