This is the second step for this activity.
In this step, we are going to improve this LED panel node with a service server.
And this service server will allow us to modify the state of an LED from the outside of the node.
So basically by using a service client from another node.
And now if we think about what kind of data we need to send, well we will need to send the number of
the LED and then the state.
The question is do we have an existing interface that does that.
If yes, we might use it, but if not we will need to create it.
And here we're going to create a new interface.
So a new service interface for that new service server.
All right.
So let's go here and let's go to our source folder my robot interfaces.
And let's go to the service folder.
We already have one service I'm going to create another one.
Let's just name it set led.sv.
RV, just like for the example we used in the real life analogy.
Okay.
And let's edit that file which is in the my robot interfaces.
So in SV set LED.
So I have the three dashes for the separation between the request and the response.
First I want to give an LED number.
LED number is going to be an integer.
So int 64.
Let's call it LED number which can be one, two, three etc..
And then after we have provided the LED number, we also want to provide the state, which I have decided
that the state is going to be an integer number also.
So it's going to be 0 or 1.
Let's call it state.
Okay.
So led number and state.
That's what we send from the client to the server.
And then the server is going to execute this.
And it could be nice to know if it worked or not.
So I'm going to add a bool success here there's going to be a flag that we can return to the client.
You could also add, for example, a string message if you want to.
I'm just going to keep it like this.
So I save the file.
I go to Cmakelists.txt.
And then you see we already have three interfaces.
I'm going to add another one.
Here's RV set LED dot s RV and save.
And that's it.
Super quick.
Okay.
So make sure you have created the service in the right folder here that you have saved all the files
and that you have this line in the Cmakelists.txt.
Now we can go back here and build the package.
Package is select with my robot interfaces.
Okay.
So because I have built a new interface that I'm going to use directly in my code.
Let's close this code.
Let's close everything like here.
And let's reopen terminals.
Okay, it might seem that it takes some time, but you're going to actually save more time doing this
than trying to debug stuff when you have weird errors in the future and you see it's actually very quick.
Great.
So now I'm going to go to I don't need all of that.
I'm going to go back to my LED panel, Dot Pi, and here I will.
So let's wait that it's initialized okay.
We have the auto completion and all that stuff.
Now how do we add simply my new interface my robot interfaces, dot CSV import set LED.
And because we have used the My Robot interfaces package before here, we don't need to add anything
else in the package dot XML.
You see it's already there.
All right.
And now let's create a service server.
Before I create the service server I'm just going to create the callback here.
That's going to be callback.
So the service name is going to be set LED.
Okay.
We get self and then we get request which is set LED dot request.
Okay I provide the type.
This is optional but it's a best practice to do so.
Response which is a set LED dot response.
Okay so what do we do.
We will need to take from that request.
Okay.
We have two things in the request.
We have so I can see it here.
We have the LED number and the state.
So we need to modify the elements of the list that corresponds to the LED number and apply the state.
But before we do this It could be nice to actually validate the data, because what if you send an LED
number that is negative or that is outside of the list?
Well, you're going to try then to modify an element outside of the list and you're going to get an
exception in your code.
Or what if you get a state that is not 0 or 1?
Well, we have decided that the state is only 0 or 1, so that's specific to the application.
Now what if I give you three?
Are you going to put three inside the array.
No you will not.
So for that you need to validate the data.
Okay.
First what I'm going to do is just create some variables here.
And the number is equal to request dot led number.
So we don't have to write the whole thing every time.
And state request dot state.
And then first let's validate the LED number.
And so actually because in programming we start to count from zero.
So we're going to have index zero one and two.
Well let's use that in our code.
You could decide to just say that the LED number is one two and three.
And then you could do minus one in your code to get access to the corresponding array.
But because this service is going to be used by a client from another node, and basically that person
writing the other node is a developer.
So they know we start to count from zero.
Okay.
You could put it explicitly in the service here.
You could add a comment for example here LED number or just maybe a comment here okay LED number starting
at zero something like that.
So if LED number is greater or equal than the length of a self led state.
All right.
So if we provide three so One, two, three.
We are outside of the array or if LED number is strictly lower than zero.
Basically, if we are going before I mean there is nothing before zero in the list.
So in this case we know that we have a wrong LED number.
And so we are going to do response dot success is equal to false.
So we fill the response with what we have here.
And then we return the response okay.
So if we don't pass this test we're just going to return right away.
We don't do anything else.
Then I'm going to do another test.
If state let's say state not in zero one okay.
So state must be 0 or 1.
If not same thing we do.
Response dot success false and return The response.
If you had added a message, for example, a string, you could add a different string message here
to explain what was the issue.
And now if I reach this line of code, I know that we have a correct LED number that corresponds to
an index of that list and the state is correct.
So I can just do self led state and reach the LED number index.
And I can just say that that becomes the state, because now I know all the data is correct.
And if I do this I can also do response dot success is equal to true and return.
Let's not forget to return the response okay?
It's a very common mistake.
Great.
And that's going to be the end for this callback right.
So we first get the different elements of the request.
If needed, we might want to validate the data, and then we do the action and we return a response.
So let's actually create a service because this callback is not going to be called if we don't create
a service.
So here for example after the timer we can do self set LED service is equal to self dot create service.
We need to provide the service type which is set LED.
We need to provide a name which we decide here.
So I gave you set LED before and then the callback self dot callback set LED.
All right.
And that's it.
So you see in this node we have one publisher one timer and one service.
So in the end we have two callbacks.
You see we have one callback for the timer.
There's going to be triggered every five seconds, and then we have one callback for the service that's
going to be triggered whenever we get an incoming request from a client.
So let's save that.
Let's go back to the terminal.
And I have used Simulink install, so I should be able to run it without building again.
Let's just do a source bashrc still just in case.
And just to run my Python package with LED panel.
Okay, so you can see we have reached the end of the constructor.
Now if I do rust to service list, you see I have my set LED and so I can already test it.
And because this is quite easy.
So the request actually is quite easy.
It's just two integers.
We can easily test it from the terminal.
Okay, so I can do ros2 service call and then set LED.
Then I need to provide the interface so my I can just press tab here.
It's going to find it.
My robot interface is set LED.
And then I can build the request.
So if you don't remember Ros2 interface show my robot interfaces solve set LED okay.
So we need to provide LED number.
Let's say zero.
That's the first one.
And state let's say one.
We want to turn on the LED and to verify that so we can run it and see if it's working.
But to double check we can also see what's going to happen on the topic.
So Series two.
Topic.
Eco led panel.
State.
Let's see for the first message to arrive.
Okay.
And then let's run that.
You see it's working.
We have response success.
And the next time that we have the topic the first LED here is turned on.
Okay.
Now I can turn it off with zero.
Okay.
But what you can see is when I do this, it's working.
But then we receive the topic because we publish every five seconds.
So we might wait as long as five seconds to receive the new data on the topic.
And how can we kind of solve that?
Well, there are two ways.
First, you could increase the frequency a lot and say that, for example, you publish every 0.1 second
or something like that, but then you're going to publish a lot of messages and still you will not get
exactly immediately the new data on the topic.
So what we can do is that directly after we set the new state here, and before we return the response,
we could publish here.
From there we could do self-publish led state.
All right.
I told you that you could publish on a topic from anywhere so you can publish from a timer callback.
You can publish from a subscriber callback.
We have done that previously.
You can also publish from a service callback.
Okay.
There is no problem with that.
And so here what we do is we publish every five seconds.
But then whenever we change the state, we publish immediately the new state.
So let's save that and let's go back.
Let's run everything again okay.
And let's do this.
Okay.
Now I'm going to wait for the next one.
Okay.
And I'm going to run the service.
And you see, as soon as we have gotten a response here, we also see the new state here.
Okay.
We don't have to wait five seconds.
So here you see, as soon as we have that we get the new state.
So there is a new message on the topic.
Great.
So that's currently working.
And let's just test the cases where we're going to get an error.
So when the success is going to be false.
So for example LED number if I put four you see I should get success false.
And then let's put zero.
So that's the correct number.
But then let's put two for the state.
And you see we have success false.
So we can validate that our data validation is also working great.
And that's the end of the second step for this activity.