Skip to content

Commit cb1e1a6

Browse files
committed
Add ROS1 dynamic reconfigure section
1 parent 1557fa6 commit cb1e1a6

File tree

15 files changed

+592
-30
lines changed

15 files changed

+592
-30
lines changed

ROS/02 ROS - ROS Nodes and Parameters.md

Lines changed: 274 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ and ETHz http://www.rsl.ethz.ch/education-students/lectures/ros.html
3838
2.13 [roscpp: Basic Subscriber](#2.13)
3939
2.14 [roscpp: Parameters](#2.14)
4040
2.15 [Making and building the roscpp package](#2.15)
41+
3. [Dynamic Reconfigure](#3)
42+
3.1 [Introduction](#3.1)
43+
3.2 [Command Line](#3.2)
44+
3.3 [rqt_reconfigure](#3.3)
45+
3.4 [cfg Files](#3.4)
46+
3.5 [Setting Up Catkin for Dynamic Reconfigure](#3.5)
47+
3.6 [rospy: Dynamic Reconfigure](#3.6)
48+
3.7 [rospy: Dynamic Reconfigure Client](#3.7)
49+
3.8 [roscpp: Dynamic Reconfigure](#3.8)
50+
3.9 [roscpp: Dynamic Reconfigure Client](#3.9)
4151

4252

4353

@@ -1321,7 +1331,31 @@ Most of the following sections will be adapted from [the dynamic_reconfigure tut
13211331

13221332

13231333

1324-
### 3.2 rqt_reconfigure <a name="3.2"></a>
1334+
### 3.2 Command Line <a name="3.1"></a>
1335+
1336+
[go to top](#top)
1337+
1338+
You're able to dynamically reconfigure nodes by calling the ROS service that is exposed by the dynamic reconfigure server each dynamically reconfigurable node is running.
1339+
1340+
Use tab completion to automatically generate the configurable parameter names!
1341+
1342+
```shell
1343+
$ rosservice call /NODE_NAME/set_parameters
1344+
```
1345+
1346+
You can also keep track of the descriptions of the dynamically reconfigurable parameters or any updates that the server receives by calling
1347+
1348+
```shell
1349+
# For descriptions
1350+
$ rostopic echo /NODE_NAME/parameter_descriptions
1351+
1352+
# For updates
1353+
$ rostopic echo /NODE_NAME/parameter_updates
1354+
```
1355+
1356+
1357+
1358+
### 3.3 rqt_reconfigure <a name="3.3"></a>
13251359

13261360
[go to top](#top)
13271361

@@ -1332,13 +1366,13 @@ One of the best ways to interact with dynamically reconfigurable nodes and param
13321366
**Installation**
13331367

13341368
```shell
1335-
sudo apt install ros-$ROS_DISTRO-rqt_reconfigure
1369+
$ sudo apt install ros-$ROS_DISTRO-rqt_reconfigure
13361370
```
13371371

13381372
**Usage**
13391373

13401374
```shell
1341-
rosrun rqt_reconfigure rqt_reconfigure
1375+
$ rosrun rqt_reconfigure rqt_reconfigure
13421376
```
13431377

13441378
**Gotchas**
@@ -1350,18 +1384,20 @@ rosrun rqt_reconfigure rqt_reconfigure
13501384

13511385

13521386

1353-
### 3.3 cfg Files <a name="3.3"></a>
1387+
### 3.4 cfg Files <a name="3.4"></a>
13541388

13551389
[go to top](#top)
13561390

13571391
Every parameter that is meant to be used with dynamic_reconfigure requires a cfg file to **define names, types, level, descriptions, defaults, min, and maxes.**
13581392

13591393
It's pretty simple to make one too! It's just Python.
13601394

1361-
[Source](<http://wiki.ros.org/dynamic_reconfigure/Tutorials/HowToWriteYourFirstCfgFile>)
1395+
> Remember to enable execution!
13621396
13631397
![Screenshot-Reconfigure.png](assets/Screenshot-Reconfigure.png)
13641398

1399+
[Source](<http://wiki.ros.org/dynamic_reconfigure/Tutorials/HowToWriteYourFirstCfgFile>)
1400+
13651401
```python
13661402
#!/usr/bin/env python
13671403
PACKAGE = "PACKAGE_NAME"
@@ -1377,11 +1413,11 @@ gen.add("str_param", str_t, 0, "A string parameter", "Hello World")
13771413
gen.add("bool_param", bool_t, 0, "A Boolean parameter", True)
13781414

13791415
# Create an enum mapping (Small is 0, Medium is 1, ...)
1380-
size_enum = gen.enum([ gen.const("Small", int_t, 0, "A small constant"),
1381-
gen.const("Medium", int_t, 1, "A medium constant"),
1382-
gen.const("Large", int_t, 2, "A large constant"),
1383-
gen.const("ExtraLarge", int_t, 3, "An extra large constant")],
1384-
"An enum to set size")
1416+
size_enum = gen.enum([gen.const("Small", int_t, 0, "A small constant"),
1417+
gen.const("Medium", int_t, 1, "A medium constant"),
1418+
gen.const("Large", int_t, 2, "A large constant"),
1419+
gen.const("ExtraLarge", int_t, 3, "An extra large constant")],
1420+
"An enum to set size")
13851421

13861422
# Add enum parameter
13871423
gen.add("size", int_t, 0, "A size parameter which is edited via an enum", 1, 0, 3, edit_method=size_enum)
@@ -1415,15 +1451,15 @@ The generate call will then result in the generation of the relevant files. The
14151451

14161452

14171453

1418-
### 3.4 Setting Up Catkin for Dynamic Reconfigure <a name="3.4"></a>
1454+
### 3.5 Setting Up Catkin for Dynamic Reconfigure <a name="3.5"></a>
14191455

14201456
[go to top](#top)
14211457

14221458
Add these to your `package.xml`
14231459

14241460
```xml
14251461
<build_depend>dynamic_reconfigure</build_depend>
1426-
<run_depend>dynamic_reconfigure</run_depend>
1462+
<exec_depend>dynamic_reconfigure</exec_depend>
14271463
```
14281464

14291465
And these to your `CMakeLists.txt`
@@ -1441,6 +1477,232 @@ Easy! Or you can just adapt and use the starter code.
14411477

14421478

14431479

1480+
### 3.6 rospy: Dynamic Reconfigure <a name="3.6"></a>
1481+
1482+
[go to top](#top)
1483+
1484+
[Source](<http://wiki.ros.org/dynamic_reconfigure/Tutorials/SettingUpDynamicReconfigureForANode(python)>)
1485+
1486+
If you want to use dynamic reconfigure to modify variables storing parameter values, you'd do it in the callback. In here we're just printing it to show what's going on
1487+
1488+
```Python
1489+
#!/usr/bin/env python
1490+
1491+
import rospy
1492+
1493+
from dynamic_reconfigure.server import Server
1494+
from dynamic_reconfigure_example.cfg import ExampleConfig
1495+
1496+
# Create reconfigure callback
1497+
def callback(config, level):
1498+
rospy.loginfo("""Reconfigure Request: {int_param}, {double_param},\
1499+
{str_param}, {bool_param}, {size}""".format(**config))
1500+
1501+
# Config is returned by the server
1502+
return config
1503+
1504+
if __name__ == "__main__":
1505+
rospy.init_node("dynamic_reconfigure_example", anonymous = False)
1506+
1507+
# Bind callback
1508+
srv = Server(ExampleConfig, callback)
1509+
rospy.spin()
1510+
```
1511+
1512+
**Run The Example!**
1513+
1514+
```shell
1515+
# Terminal 1
1516+
$ roscore
1517+
1518+
# Terminal 2
1519+
$ rosrun dynamic_reconfigure_example dynamic_reconfigure_example
1520+
1521+
# Terminal 3
1522+
$ rosrun rqt_reconfigure rqt_reconfigure
1523+
```
1524+
1525+
1526+
1527+
### 3.7 rospy: Dynamic Reconfigure Client <a name="3.7"></a>
1528+
1529+
[go to top](#top)
1530+
1531+
[Source](<http://wiki.ros.org/dynamic_reconfigure/Tutorials/UsingTheDynamicReconfigurePythonClient>)
1532+
1533+
If you want to use dynamic reconfigure to modify variables storing parameter values, you'd do it in the callback. In here we're just printing it to show what's going on
1534+
1535+
```Python
1536+
#!/usr/bin/env python
1537+
1538+
import rospy
1539+
import dynamic_reconfigure.client
1540+
1541+
# Optional callback for the config returned by the server
1542+
def callback(config):
1543+
rospy.loginfo("Config set to {int_param}, {double_param}, {str_param}, {bool_param}, {size}".format(**config))
1544+
1545+
if __name__ == "__main__":
1546+
rospy.init_node("dynamic_reconfigure_client")
1547+
1548+
# We target the server with the first argument
1549+
client = dynamic_reconfigure.client.Client("dynamic_reconfigure_example", timeout=30, config_callback=callback)
1550+
1551+
r = rospy.Rate(0.5)
1552+
x = 0
1553+
b = False
1554+
while not rospy.is_shutdown():
1555+
x = x + 1
1556+
if x > 10:
1557+
x = 0
1558+
b = not b
1559+
client.update_configuration({"int_param": x,
1560+
"double_param": (1 / (x + 1)),
1561+
"str_param": str(rospy.get_rostime()),
1562+
"bool_param": b,
1563+
"size": 1})
1564+
r.sleep()
1565+
```
1566+
1567+
**Run The Example!**
1568+
1569+
```shell
1570+
# Terminal 1
1571+
$ roscore
1572+
1573+
# Terminal 2
1574+
$ rosrun dynamic_reconfigure_example dynamic_reconfigure_example
1575+
1576+
# Terminal 3
1577+
$ rosrun dynamic_reconfigure_example dynamic_reconfigure_client
1578+
```
1579+
1580+
1581+
1582+
### 3.8 roscpp: Dynamic Reconfigure <a name="3.8"></a>
1583+
1584+
[go to top](#top)
1585+
1586+
[Source](<http://wiki.ros.org/dynamic_reconfigure/Tutorials/SettingUpDynamicReconfigureForANode(cpp)>)
1587+
1588+
If you want to use dynamic reconfigure to modify variables storing parameter values, you'd do it in the callback. In here we're just printing it to show what's going on
1589+
1590+
```Python
1591+
#include <ros/ros.h>
1592+
1593+
#include <dynamic_reconfigure/server.h>
1594+
#include <dynamic_reconfigure_example/ExampleConfig.h>
1595+
1596+
void callback(dynamic_reconfigure_example::ExampleConfig &config, uint32_t level)
1597+
{
1598+
ROS_INFO("Reconfigure Request: %d %f %s %s %d",
1599+
config.int_param,
1600+
config.double_param,
1601+
config.str_param.c_str(),
1602+
config.bool_param ? "True" : "False",
1603+
config.size);
1604+
}
1605+
1606+
int main(int argc, char **argv)
1607+
{
1608+
ros::init(argc, argv, "dynamic_reconfigure_example");
1609+
1610+
dynamic_reconfigure::Server<dynamic_reconfigure_example::ExampleConfig> server;
1611+
dynamic_reconfigure::Server<dynamic_reconfigure_example::ExampleConfig>::CallbackType f;
1612+
1613+
f = boost::bind(&callback, _1, _2);
1614+
server.setCallback(f);
1615+
1616+
ROS_INFO("Spinning node");
1617+
ros::spin();
1618+
return 0;
1619+
}
1620+
```
1621+
1622+
**Run The Example!**
1623+
1624+
```shell
1625+
# Terminal 1
1626+
$ roscore
1627+
1628+
# Terminal 2
1629+
$ rosrun dynamic_reconfigure_example dynamic_reconfigure_example
1630+
1631+
# Terminal 3
1632+
$ rosrun rqt_reconfigure rqt_reconfigure
1633+
```
1634+
1635+
1636+
1637+
### 3.9 roscpp: Dynamic Reconfigure Client <a name="3.9"></a>
1638+
1639+
[go to top](#top)
1640+
1641+
Unfortunately there doesn't seem to be a ready-made client for roscpp. But you can just use the raw service interface instead!
1642+
1643+
```c++
1644+
#include <ros/ros.h>
1645+
1646+
#include <dynamic_reconfigure/Reconfigure.h>
1647+
#include <dynamic_reconfigure_example/ExampleConfig.h>
1648+
1649+
int main(int argc, char **argv)
1650+
{
1651+
ros::init(argc, argv, "dynamic_reconfigure_client");
1652+
1653+
ros::NodeHandle nh;
1654+
1655+
// Remember to input the name of the server that the
1656+
// dynamically reconfigurable node is hosting!
1657+
ros::ServiceClient client = nh.serviceClient<dynamic_reconfigure::Reconfigure>("/dynamic_reconfigure_example/set_parameters");
1658+
1659+
// Create service message
1660+
dynamic_reconfigure::Reconfigure service;
1661+
1662+
// Create dependent messages
1663+
dynamic_reconfigure::IntParameter int_param;
1664+
int_param.name = "int_param";
1665+
int_param.value = 0;
1666+
1667+
dynamic_reconfigure::DoubleParameter double_param;
1668+
double_param.name = "double_param";
1669+
double_param.value = 1.0;
1670+
1671+
dynamic_reconfigure::StrParameter str_param;
1672+
str_param.name = "str_param";
1673+
str_param.value = "Rawr";
1674+
1675+
dynamic_reconfigure::BoolParameter bool_param;
1676+
bool_param.name = "bool_param";
1677+
bool_param.value = true;
1678+
1679+
dynamic_reconfigure::IntParameter size;
1680+
size.name = "size";
1681+
size.value = 0;
1682+
1683+
// Populate request
1684+
service.request.config.ints.push_back(int_param);
1685+
service.request.config.doubles.push_back(double_param);
1686+
service.request.config.strs.push_back(str_param);
1687+
service.request.config.bools.push_back(bool_param);
1688+
service.request.config.ints.push_back(size);
1689+
1690+
// Service callback function
1691+
// client.call(service) calls the client!
1692+
if (client.call(service))
1693+
{
1694+
ROS_INFO("Reconfigure call succeeded!");
1695+
}
1696+
else
1697+
{
1698+
ROS_INFO("Reconfigure call failed!");
1699+
return 1;
1700+
}
1701+
1702+
return 0;
1703+
}
1704+
```
1705+
14441706
14451707
14461708
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
cmake_minimum_required(VERSION 2.8.3)
2+
project(dynamic_reconfigure_example)
3+
4+
find_package(catkin REQUIRED COMPONENTS
5+
roscpp
6+
std_msgs
7+
dynamic_reconfigure
8+
)
9+
10+
generate_dynamic_reconfigure_options(
11+
cfg/Example.cfg
12+
)
13+
14+
catkin_package(
15+
INCLUDE_DIRS src
16+
CATKIN_DEPENDS roscpp std_msgs
17+
DEPENDS
18+
)
19+
20+
include_directories(
21+
${catkin_INCLUDE_DIRS}
22+
)
23+
24+
add_executable(dynamic_reconfigure_example src/dynamic_reconfigure_example.cpp)
25+
target_link_libraries(dynamic_reconfigure_example ${catkin_LIBRARIES})
26+
add_dependencies(dynamic_reconfigure_example ${PROJECT_NAME}_gencfg)
27+
28+
add_executable(dynamic_reconfigure_client src/dynamic_reconfigure_client.cpp)
29+
target_link_libraries(dynamic_reconfigure_client ${catkin_LIBRARIES})
30+
add_dependencies(dynamic_reconfigure_client ${PROJECT_NAME}_gencfg)

0 commit comments

Comments
 (0)