Skip to content

Commit e9d8095

Browse files
authored
RSDK-9719: Simple module sensor (#359)
1 parent e14af53 commit e9d8095

File tree

2 files changed

+79
-67
lines changed

2 files changed

+79
-67
lines changed

src/viam/examples/modules/simple/client.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
#include <string>
44

55
#include <viam/sdk/common/proto_value.hpp>
6+
#include <viam/sdk/components/sensor.hpp>
67
#include <viam/sdk/robot/client.hpp>
78
#include <viam/sdk/rpc/dial.hpp>
8-
#include <viam/sdk/services/generic.hpp>
99

1010
using namespace viam::sdk;
1111

@@ -33,20 +33,36 @@ int main() {
3333
std::cout << "\t" << resource << "\n";
3434
}
3535

36-
// Exercise printer methods
37-
auto printer = robot->resource_by_name<GenericService>("printer1");
38-
if (!printer) {
39-
std::cerr << "could not get 'printer1' resource from robot\n";
36+
// Exercise sensor methods
37+
auto sensor = robot->resource_by_name<Sensor>("mysensor");
38+
if (!sensor) {
39+
std::cerr << "could not get 'mysensor' resource from robot\n";
4040
return EXIT_FAILURE;
4141
}
4242

4343
ProtoStruct command{{"hello", "world"}};
44-
ProtoStruct resp = printer->do_command(command);
44+
ProtoStruct resp = sensor->do_command(command);
4545

4646
if (command != resp) {
4747
std::cerr << "Got unexpected result from 'printer1'\n";
4848
return EXIT_FAILURE;
4949
}
5050

51+
ProtoStruct readings = sensor->get_readings();
52+
53+
auto itr = readings.find("signal");
54+
if (itr == readings.end()) {
55+
std::cerr << "Expected signal not found in sensor readings\n";
56+
return EXIT_FAILURE;
57+
}
58+
59+
const double* signal = itr->second.get<double>();
60+
if (signal) {
61+
std::cout << "\t" << itr->first << ": " << *signal << "\n";
62+
} else {
63+
std::cerr << "Unexpected value type for sensor reading\n";
64+
return EXIT_FAILURE;
65+
}
66+
5167
return EXIT_SUCCESS;
5268
}

src/viam/examples/modules/simple/main.cpp

Lines changed: 57 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,90 +2,86 @@
22
#include <memory>
33
#include <sstream>
44

5-
#include <boost/log/trivial.hpp>
6-
75
#include <viam/sdk/common/exception.hpp>
86
#include <viam/sdk/common/proto_value.hpp>
7+
#include <viam/sdk/components/sensor.hpp>
98
#include <viam/sdk/config/resource.hpp>
10-
#include <viam/sdk/module/module.hpp>
119
#include <viam/sdk/module/service.hpp>
1210
#include <viam/sdk/registry/registry.hpp>
1311
#include <viam/sdk/resource/reconfigurable.hpp>
14-
#include <viam/sdk/resource/resource.hpp>
15-
#include <viam/sdk/rpc/dial.hpp>
16-
#include <viam/sdk/rpc/server.hpp>
17-
#include <viam/sdk/services/generic.hpp>
18-
#include <viam/sdk/services/service.hpp>
1912

2013
using namespace viam::sdk;
2114

22-
// Printer is a modular resource that can print a to_print value to STDOUT when
23-
// a DoCommand request is received or when reconfiguring. The to_print value
24-
// must be provided as an attribute in the config.
25-
class Printer : public GenericService, public Reconfigurable {
15+
// Implements a trivial sensor component, constructed with a ResourceConfig that specifies a
16+
// "multiplier" value which is then returned as the only sensor reading.
17+
class MySensor : public Sensor, public Reconfigurable {
2618
public:
27-
void reconfigure(const Dependencies& deps, const ResourceConfig& cfg) {
28-
std::cout << "Printer " << Resource::name() << " is reconfiguring" << std::endl;
29-
for (auto& dep : deps) {
30-
std::cout << "dependency: " << dep.first.to_string() << std::endl;
31-
}
32-
to_print_ = find_to_print(cfg);
33-
std::cout << "Printer " << Resource::name() << " will now print " << to_print_ << std::endl;
19+
MySensor(const ResourceConfig& cfg) : Sensor(cfg.name()) {
20+
this->reconfigure({}, cfg);
3421
}
3522

36-
Printer(Dependencies deps, ResourceConfig cfg) : GenericService(cfg.name()) {
37-
std::cout << "Creating Printer " + Resource::name() << std::endl;
38-
to_print_ = find_to_print(cfg);
39-
std::cout << "Printer " << Resource::name() << " will print " << to_print_ << std::endl;
40-
}
23+
static std::vector<std::string> validate(const ResourceConfig&);
4124

42-
ProtoStruct do_command(const ProtoStruct& command) {
43-
std::cout << "Received DoCommand request for Printer " << Resource::name() << std::endl;
44-
std::cout << "Printer " << Resource::name() << " has printed " << to_print_ << std::endl;
45-
return command;
25+
void reconfigure(const Dependencies&, const ResourceConfig&) override;
26+
27+
ProtoStruct do_command(const ProtoStruct&) override;
28+
29+
std::vector<GeometryConfig> get_geometries(const ProtoStruct&) override {
30+
throw Exception("method not supported");
4631
}
4732

48-
static std::string find_to_print(ResourceConfig cfg) {
49-
auto& printer_name = cfg.name();
50-
auto to_print = cfg.attributes().find("to_print");
51-
if (to_print == cfg.attributes().end()) {
52-
std::ostringstream buffer;
53-
buffer << printer_name << ": Required parameter `to_print` not found in configuration";
54-
throw std::invalid_argument(buffer.str());
33+
ProtoStruct get_readings(const ProtoStruct&) override;
34+
35+
private:
36+
double multiplier_{1.0};
37+
};
38+
39+
std::vector<std::string> MySensor::validate(const ResourceConfig& cfg) {
40+
auto itr = cfg.attributes().find("multiplier");
41+
if (itr != cfg.attributes().end()) {
42+
const double* multiplier = itr->second.get<double>();
43+
if (!multiplier) {
44+
throw Exception("multiplier must be a number value");
5545
}
56-
const auto* const to_print_string = to_print->second.get<std::string>();
57-
if (!to_print_string || to_print_string->empty()) {
58-
std::ostringstream buffer;
59-
buffer << printer_name
60-
<< ": Required non-empty string parameter `to_print` is either not a string "
61-
"or is an empty string";
62-
throw std::invalid_argument(buffer.str());
46+
47+
if (*multiplier == 0.0) {
48+
throw Exception("multiplier cannot be zero");
6349
}
64-
return *to_print_string;
6550
}
6651

67-
private:
68-
std::string to_print_;
69-
};
52+
return {};
53+
}
54+
55+
void MySensor::reconfigure(const Dependencies&, const ResourceConfig& cfg) {
56+
auto itr = cfg.attributes().find("multiplier");
57+
if (itr != cfg.attributes().end()) {
58+
const double* multiplier = itr->second.get<double>();
59+
if (multiplier) {
60+
multiplier_ = *multiplier;
61+
}
62+
}
63+
}
64+
65+
ProtoStruct MySensor::do_command(const ProtoStruct& command) {
66+
for (const auto& entry : command) {
67+
std::cout << "Command entry " << entry.first;
68+
}
69+
70+
return command;
71+
}
72+
73+
ProtoStruct MySensor::get_readings(const ProtoStruct&) {
74+
return {{"signal", multiplier_}};
75+
}
7076

7177
int main(int argc, char** argv) try {
72-
API generic = API::get<GenericService>();
73-
Model m("viam", "generic", "printer");
78+
Model mysensor_model("viam", "sensor", "mysensor");
7479

7580
std::shared_ptr<ModelRegistration> mr = std::make_shared<ModelRegistration>(
76-
generic,
77-
m,
78-
[](Dependencies deps, ResourceConfig cfg) { return std::make_unique<Printer>(deps, cfg); },
79-
// Custom validation can be done by specifying a validate function like
80-
// this one. Validate functions can `throw` exceptions that will be
81-
// returned to the parent through gRPC. Validate functions can also return
82-
// a vector of strings representing the implicit dependencies of the resource.
83-
[](ResourceConfig cfg) -> std::vector<std::string> {
84-
// find_to_print will throw an error if the `to_print` attribute
85-
// is missing, is not a string or is an empty string.
86-
Printer::find_to_print(cfg);
87-
return {};
88-
});
81+
API::get<Sensor>(),
82+
mysensor_model,
83+
[](Dependencies, ResourceConfig cfg) { return std::make_unique<MySensor>(cfg); },
84+
&MySensor::validate);
8985

9086
std::vector<std::shared_ptr<ModelRegistration>> mrs = {mr};
9187
auto my_mod = std::make_shared<ModuleService>(argc, argv, mrs);

0 commit comments

Comments
 (0)