WEBVTT

00:00.000 --> 00:11.760
Okay, so everyone, first thing first, as we say on social network, I'm thrilled to announce

00:11.760 --> 00:15.280
that that's the very first time we talk about this, okay?

00:15.280 --> 00:20.760
So, feel free to give us a lot of feedback after the meeting after the presentation, okay?

00:20.760 --> 00:27.360
So, today we will talk about the technical stack, so I will present bottlenecks really quickly

00:27.360 --> 00:33.080
the product as well, which is XE, and then we will dive directly into the technical things.

00:33.080 --> 00:39.120
First thing first, let me present the team, so I'm Antoine, I'm the CTO and co-founder of

00:39.120 --> 00:43.720
Botronics, so that's why I started with some gray air.

00:43.720 --> 00:51.680
Then you have Enzo, which joined Botronics early in 2024, is one of our monster in navigation

00:51.680 --> 00:58.440
and Rostou, and then we have David, who joined us in September, 2020, to divide straight

00:58.440 --> 01:03.640
from the ULB, so, from this university.

01:03.640 --> 01:12.080
Okay, so let me present Botronics, as you can see, with a slight template, we are a startup.

01:12.080 --> 01:19.560
We found Botronics in 2022, we are, of course, in Belgium, or it quarter is in Nivel, in Dutch

01:19.560 --> 01:25.880
which we say in Nivel, right, that's 40 minutes from Ian Vicar, and yeah, we just closed,

01:25.880 --> 01:32.600
so that you know, or situation, we just closed the seed round of 1.6 million rubles in September,

01:32.600 --> 01:39.560
2020, 25, we are only 10 people right now, out of them are engineers, and yeah, we basically

01:39.560 --> 01:43.320
love open source, we contribute to it in different ways.

01:43.320 --> 01:49.600
One of the ways is that we are a friend of NAF2, it means like, that's a pay-sponsorship

01:49.600 --> 01:56.160
of NAF2, that's a way to pay for, I mean, we pay for smart and people that I am to contribute

01:56.160 --> 02:03.360
to open source, then yeah, some of us are always a super thing individual, so it means

02:03.360 --> 02:12.080
you pay annually to sponsor the organization behind Rost, and then you contribute to open source

02:12.080 --> 02:20.080
as well, so we do code, so we participate to all the tutorial and tests, parties, we build

02:20.080 --> 02:24.760
some Rost packages, you saw Christoph and Nicolas before talking about some packages we

02:24.760 --> 02:30.720
built, and then yeah, in October last year, if you have from Belgium, you may be know

02:30.720 --> 02:39.760
that we create the very first Rost-Metop in Belgium, okay, then so it was Botronics and Botronics

02:39.760 --> 02:45.280
built XE, so this is the product, this is the first ever autonomous gold trolley, so you

02:45.280 --> 02:50.640
have to know that goldfills have to carry their bag when I play gold, that's 20 kilometers,

02:50.640 --> 02:55.880
that's five hours, so that's quite painful, and that's why when you are more than 50, that

02:55.880 --> 03:02.320
becomes quite difficult, so they play with a gold cart, that's not really a gold cart,

03:02.320 --> 03:08.600
that's a trolley, really a trolley, okay, we sold 300 units in codefunding last year, and

03:08.600 --> 03:16.680
so now we are in the industrialization phase, so bringing the prototype to product, okay,

03:16.680 --> 03:21.800
and the final price we are really on a premium product, so that's something like 5,000

03:21.800 --> 03:29.680
euros in the end, let's talk about now the product constraints as a robotics engineer,

03:29.680 --> 03:37.420
right, so you see, let's talk about the features of XE first, so that's a very first

03:37.420 --> 03:43.340
gold trolley with a large core of touch screen, okay, so that's really something important

03:43.340 --> 03:49.580
for this touch screen, and then you have some mechanical constraints as well that we want to

03:49.580 --> 03:55.100
push forward, like the stability on the golf course, there is a lot of steep slope on golf

03:55.100 --> 04:00.620
courses, so you have to deal with them, and then of course we have a camera, which is AI power,

04:01.100 --> 04:08.700
let's say so it means we can do a lot of stuff based on this camera, we have three main kind

04:08.700 --> 04:14.220
of features I would say, the first are the autonomous things, so it's able to go to some point

04:14.220 --> 04:18.860
of interest on the golf course, so they are able to go to the next E to the green and that kind

04:18.860 --> 04:24.460
of things, then you have a lot of seamless interaction things, so for example, if you want the golf

04:24.540 --> 04:30.620
trolley to follow you, you can put your end in your back, the trolley, recognize your end and try

04:30.620 --> 04:35.660
and start to follow you, okay, and then you have advanced features like filming your swing,

04:35.660 --> 04:41.900
giving you some advice and so on, and this is a B2C product, so it's really a constraint,

04:41.900 --> 04:49.180
it brings some constraint at least, so for example, the price, so the final price is 5,000 euros,

04:50.060 --> 04:57.260
the 18 included, right, so if you remove the VAT, you add something like 4,000, and if you consider

04:57.260 --> 05:02.860
after sales, if you consider stock and so on, while the bill of materials become something really

05:02.860 --> 05:11.020
important, right, so we can't afford expensive sensors or solution, we have to avoid initial setup,

05:11.020 --> 05:16.460
so let's imagine this is a B2B product, we saw it in the golf courses, we can go to the golf

05:16.460 --> 05:24.060
courses and say, okay, we need to push an airtica, an airtica, docking station, and then we can do

05:24.060 --> 05:31.020
a slam manually or that kind of thing, we can't do this because like, or trolley,

05:31.020 --> 05:36.620
they will bring the it to different golf courses, and then of course the user experience must be

05:37.820 --> 05:44.140
really, that's a premium product, so from day one, you have to provide something really reliable,

05:45.100 --> 05:51.260
that's also a node of robotics, so you have some constraints linked to this as well, okay, so

05:51.260 --> 05:58.780
now we talked about the product, it's dive into the technical stack, and so we solved, that's basically

05:58.780 --> 06:04.780
a technical stack, that's not a architectural diagram, right, that's a slide, but that's basically

06:04.780 --> 06:11.100
what we'll talk about today, we'll talk about the user interfaces, there is two kind of user

06:11.100 --> 06:15.500
interfaces, there is a mobile application of course, but there is also this embedded screen,

06:16.300 --> 06:20.300
and then of course we will talk about the co-application, the embedded application,

06:21.420 --> 06:27.260
we will talk about one important capability, we provide which is the remote update capability,

06:27.260 --> 06:31.420
and then some additional things like testing and observability,

06:32.380 --> 06:41.260
so we're going to start with the co-application, without too much surprise, it's based on Rostu,

06:41.260 --> 06:47.100
and so why the choice of Rostu, so first of all, it's open source, I think it will not be too

06:47.100 --> 06:52.940
difficult to convince you that it's a huge asset for a solution, for us it's mainly on the fact that

06:52.940 --> 06:57.740
we have control on the solution, we know what's inside, but other capabilities and the limit,

06:57.740 --> 07:03.980
and so we have a more possibility to master it, also Rostu has a really large and active

07:03.980 --> 07:09.180
community, and for us it's a huge asset, there is a lot of features, a lot of package available,

07:09.180 --> 07:15.340
and also it's really easy, I would say, easier to recruit and expand the team,

07:15.340 --> 07:19.500
that we have a fully custom solution, and you know, everyone needs to retrain and to be

07:19.500 --> 07:25.740
re-informed about it, and it's more durable, it's designed, and it really allows us to

07:25.740 --> 07:32.540
expand the stack and I think to skate it properly with a different update, as said in the previous

07:32.540 --> 07:40.060
talks, Rostu has some limits, but for example, in our use case, we don't have a real

07:40.060 --> 07:44.700
real-time constraints, I don't know if you have already seen a golf play, but it's not the

07:44.700 --> 07:50.620
constant sports to life, so I would say the odd real-time is not something really to blocking

07:50.620 --> 08:01.340
for us, the non-distarmistic behavior is not also a big default to the same reason, so yeah,

08:01.340 --> 08:07.740
so about the version of Rostu, so we are using Rostu jersey, and so we have done a release

08:07.740 --> 08:13.740
some migration, we start on Rost1, we have Rost Noetic, we migrate to Embell, and more recently

08:13.820 --> 08:19.180
we have done the migration to jersey, so the migration subject is something really important,

08:19.180 --> 08:23.900
because it can take some times, it's challenging every time, or you manage your dependencies,

08:23.900 --> 08:28.780
or you are able to, you know, make scale, you stuff, and so we have made the choice to make

08:28.780 --> 08:33.980
a frequent migration, to have access to the Rostu features, and also from the package,

08:33.980 --> 08:39.820
we have done some contribution in a different project by the past, but we are a bit limited,

08:39.820 --> 08:45.020
because, you know, for example on NAF2, if you want the last feature, you need to target the latest

08:45.020 --> 08:50.780
release, otherwise you need to backport a lot of things, and so in the end, the gain of time

08:50.780 --> 08:56.940
to stay on the same release, it's not always evident, so for the moment we only target the LTS,

08:57.180 --> 09:03.340
but because we have some, you know, we are working with CUDA, that gives us a lot of capabilities

09:03.420 --> 09:10.620
for AI models, but in the end it bind us a bit with Ubuntu, Jetpack version, that depend on Ubuntu

09:10.620 --> 09:17.020
version, and so we have explored your CID before, that with Pixi, we think that we could simplify

09:17.020 --> 09:21.980
your migration process for the next release, so that's why we are trying to do, and the next

09:21.980 --> 09:31.020
release to be able to target the LERIC cloud list for the next release LTS. So Rostu, as I said before,

09:31.020 --> 09:37.420
it provides a lot of out-of-the-box features, such as all the wrapper for Python, C++,

09:37.420 --> 09:42.060
also the Rostu controls suite, that's a really help us a lot to gain a lot of time to

09:42.060 --> 09:46.700
know, start experimenting with the robots, integrate the hardware, interface, and

09:46.700 --> 09:54.140
also the community project that you will see after in the presentation as some core of our stack,

09:54.140 --> 09:59.580
such as NAF2, a robot localization, and in the end the Rostu framework, it really gives us

10:01.020 --> 10:07.980
a kind of guide line and a standard way to integrate our custom business logic for the sense

10:07.980 --> 10:14.220
of driver, and also for all the business related to how we put our navigation

10:14.220 --> 10:24.460
behavior at the top of the stack. So yeah, there is a new monster in tone, right? Let's talk a

10:24.460 --> 10:31.660
little bit about RMW and our choice and in fact, our journey. But first, that's only based on

10:31.660 --> 10:39.500
our experience, okay? So we have an experience with the localhost only model, meaning that

10:39.500 --> 10:47.740
all our nodes are running on the same device, okay? When we start, so we migrate from Rostu

10:47.740 --> 10:55.660
from Rostu, to Rostum, and we start with the default DDS implementation, which is

10:55.660 --> 11:03.820
fast DDS. We try to use it, but in the end we run into a bug with the integration with Rostu

11:03.820 --> 11:10.780
control at some point it stopped, and so we try to figure out what's missing, and at some point

11:10.780 --> 11:14.940
we are like, okay, we open some issue and get up, but didn't find the solution, and at some point

11:14.940 --> 11:21.660
we say, okay, maybe we can just try cyclone DDS, that's what we did, and in fact, we cyclone

11:21.660 --> 11:26.860
DDS, we were really happy with it, we had some configuration issue at the very beginning,

11:26.860 --> 11:32.460
but then at some point it was working really cool, so we worked with this during like two years,

11:33.100 --> 11:42.140
but then we wanted to explore shared memory, okay? And at this point we found some issue to put

11:42.220 --> 11:49.100
shared memory in practice, and that's why in fact we decided, okay, maybe we should try with Zeno

11:49.100 --> 11:56.380
to see if it's easier with Zeno to use the shared memory, and yeah, it's quite easy, so that's

11:56.380 --> 12:02.300
four months ago we moved to Zeno and now we are using Zeno and we are really happy with it and we

12:02.300 --> 12:10.300
won't move anymore, I guess, right now, until the next solution. There is three important things,

12:10.380 --> 12:16.460
the first thing is that yeah, that's really easy to integrate the shared memory even for dynamic

12:16.460 --> 12:28.140
size messages with Zeno, then we win 10% CPU usage just by moving to Zeno with shared memory,

12:28.780 --> 12:36.380
and final thing is the initial setup is really easy, I mean you just have to change some

12:36.460 --> 12:41.420
environment variable, and then you have something working, of course we can still optimize it

12:41.420 --> 12:48.860
a little bit, I mean for no, for example the shared memory size is not optimized, but it definitely works,

12:48.860 --> 12:56.540
and so we can move on, and now that we talk about the value on top of this, you have everything

12:56.540 --> 13:02.860
regarding sensors, so let's share some guidance and experience we have, some people call it

13:02.940 --> 13:09.580
pain, but that's experience, we have with sensors, for some sensors you will have

13:10.380 --> 13:16.540
host two drivers provided, and that's great, that doesn't do everything, but that's great, okay,

13:17.260 --> 13:24.220
for other sensors we have some cheap sensors because of the final price, and in this case you don't have

13:24.220 --> 13:31.580
any host driver provided, in this case we recommend really a reader, a RIP, which are good guidance

13:31.580 --> 13:36.620
provided by the host community, to implement your host to driver, okay, so that's really

13:37.420 --> 13:44.780
something that's not easy, don't underestimate this, but do this with RIP, in mind it will be easier

13:44.780 --> 13:53.660
than to implement and to integrate the host to driver with your whole host tag, that's definitely

13:53.660 --> 14:01.020
not always plug-in play, even if you have the host to driver implemented, I mean at some point we had

14:01.500 --> 14:09.260
to configure the kernel to integrate a new sensor or to install some driver, so that's not

14:10.540 --> 14:18.460
a low level driver, the host to driver is a high level driver, yeah, we also had to

14:18.460 --> 14:25.980
patch the kernel, it was to integrate 12 Bluetooth working with multiple devices at once, so that's

14:26.060 --> 14:32.460
something you will have to do in the end, so really when you estimate the task of introducing your sensor,

14:32.460 --> 14:38.700
don't underestimate it, in any case, well what I suggest is before diving into the, okay,

14:38.700 --> 14:43.580
there is a host to driver, let's use it and it works, no, hit the datasheet, understand it,

14:43.580 --> 14:48.860
try some basic tests without choosing a host at all, and then go step by step,

14:49.500 --> 14:59.500
okay, thank you, Antoine, so I guess now everyone has a clear idea of the quote Hardware is hard

15:00.220 --> 15:08.060
and now let's talk about the fact that even though you have achieved that point where you can interact

15:08.060 --> 15:17.580
with your hardware, you're still not finished yet, so basically what we advise you to do after

15:18.540 --> 15:26.780
to check your data, for instance, we were working with GPS and we simply weren't understanding

15:26.780 --> 15:33.660
why our robot wasn't getting this data coming from our GPS, by looking back on the message that

15:33.660 --> 15:40.700
we were getting from the GPS, we were seeing that in the header message, actually the data was

15:40.700 --> 15:46.700
correct and the time was correct, at this time it was long time ago, we didn't have any RTC on

15:46.700 --> 15:53.500
our trolley and hence from our robot perspective, this message is coming from the future and it's

15:53.500 --> 16:01.500
simply this regard, this message, second tip, visualized your data, in our case we use plot

16:01.500 --> 16:09.180
juggler, shout out to David Fagonti, botronics love you, so if you don't know plot juggler,

16:09.180 --> 16:16.060
allows you to visualize your topic dynamically and even analyze them, it's really, really good,

16:16.220 --> 16:23.340
a really good plugin, and the last recommendation is don't be to bind it with your hardware,

16:23.340 --> 16:30.060
and when I mean what I mean here are two things, the first one is from the sensor perspective,

16:30.060 --> 16:34.300
don't get a sensor that is a jack of all trade, you will have a lot of trade-offs with this,

16:34.300 --> 16:38.780
for instance, at botronics, we were using a GPS that was also a magnetometer,

16:39.900 --> 16:44.780
having this GPS, so obviously the GPS has to be in the upper part of the trolley,

16:44.940 --> 16:51.740
but unfortunately we have clubs with iron, which implies that we will have magnetic disturbances

16:51.740 --> 17:00.300
or magnetometer listen to, to the magnetic field obviously, the second one is to avoid the

17:00.300 --> 17:07.100
all-in-one SDK, obviously take for instance cameras that come with a pre-made SDK that does

17:07.100 --> 17:12.700
object detection and tracking, we don't want to bind our software, we really want to have a

17:12.700 --> 17:19.740
hardware-agnostic software and isolate our piece of software every time and having a

17:19.740 --> 17:24.060
piece of software that depends on our hardware is not the best idea.

17:26.380 --> 17:31.260
Okay, now that our sensors are working well, we can think about the localization,

17:31.740 --> 17:36.780
and for this we rely on the robot localization package, so we will not dive into too much

17:36.860 --> 17:43.660
detents here, the big overview of the framework is that we have some relative

17:44.940 --> 17:49.660
measurements coming from certain sensor, let's think about the IMU, for example, or the

17:49.660 --> 17:57.740
odometry of what else. We will fuse those sensors into an extended

17:57.740 --> 18:02.380
Kalman filter to have a note put related to the displacement of our robot.

18:02.940 --> 18:10.860
Afterwards, we will have our GPS data that is being given in a lower frequency.

18:10.860 --> 18:15.980
We want to fuse all of these and make the use of the NAVSA transform in order to transform

18:15.980 --> 18:24.940
this position into UTM frame in order to have them in Cartesian frame, and as a product we have

18:25.100 --> 18:28.540
basically the position of our robot.

18:31.980 --> 18:37.980
And so more specifically, particularly on what we've been using and some advises with the sensor

18:37.980 --> 18:45.820
that we've been using. In our case, we use a stereo vision camera which implies that we can use

18:45.820 --> 18:52.300
visual odometry. In our case, didn't work quite well because of the fact that there are many

18:52.380 --> 18:57.900
features in golf fields. Obviously, we have some trees and nothing else.

19:00.300 --> 19:08.540
Yeah, we don't rely anymore really much on this visual odometry. Another fact is an important

19:08.540 --> 19:17.500
in our case is that we ship our trollies in many places on the world. Obviously, the magnetic field

19:17.500 --> 19:23.260
is not everywhere the same and we have to think about this magnetic declination, obviously.

19:23.260 --> 19:31.420
And so what we had to do at Botronics for XC is to dynamize a dynamic magnetic declination that

19:31.420 --> 19:37.740
is computed based on your position on the earth. And obviously, the magnetic field of the earth

19:37.740 --> 19:47.340
changed with time and obviously we have to recompute it each year. And the last part is related

19:47.580 --> 19:54.220
to the fact that we have a B2C product. As Anton mentioned, we cannot pre-install devices

19:54.220 --> 20:00.220
on the golf field. And so a challenge is to compute the initial pose of our trollies. So when

20:01.660 --> 20:07.100
consumer uses our trollie, if he wants, he doesn't want to calibrate anything, he just wants to play.

20:07.100 --> 20:15.180
And that's a big challenge. And so the big lesson, let's not say related to the localization,

20:15.260 --> 20:23.500
is make sure that your localization is reliable before diving directly onto navigation. Since navigation

20:23.500 --> 20:30.620
rely assumes that your localization is perfect. If you have issues with your navigation, it will

20:30.620 --> 20:43.100
probably be due to the fact that your localization is not good also. So for the navigation, we are using

20:43.100 --> 20:48.940
Neptune. It's a really complete framework. It provides a lot of advanced features out of the box,

20:48.940 --> 20:53.820
which is basically me when we switch to Ross 2. And so when I look at the Neptune instead of move

20:53.820 --> 21:00.620
base. And so it provides a lot of out of the box features such as planar controllers and collision

21:00.620 --> 21:08.060
monitors that provide safety software. So it's highly modular and it relies on Baviotry and it

21:08.060 --> 21:13.820
helps us a lot to manage the concurrency between the different Bavios and also provide the capabilities

21:13.820 --> 21:19.020
to use custom plugin. It's really important for us because in the end, at some point you have

21:19.020 --> 21:25.420
the choice to make all your custom logic, implements you know, every new Bavior from your part.

21:25.420 --> 21:31.180
And we make the choice to rely on the plugin, the plugin configuration of Neptune. And it gives us a lot

21:31.180 --> 21:36.380
of flexibility to manage our stack. And it's as it's a complete framework, it provides a lot of good

21:36.380 --> 21:42.220
practices. And to propel to that and to behave your trees in January, make something robust and

21:42.220 --> 21:48.460
really reliable. Also, it's a really well maintained project framework. It's quite popular. There

21:48.460 --> 21:54.380
is a lot of new features, update, backfix. So for us, it was definitely a good choice from our

21:54.380 --> 22:03.260
point of view to rely on Neptune. So how we use Ross to a Neptune in the XC case? So it's quite special

22:03.340 --> 22:10.060
because it's other robotics. We rely on GPS. I said David before. And we don't do slam. There are

22:10.060 --> 22:15.580
not some that much features on the golf course. And we have the chance to have a full data set

22:15.580 --> 22:21.660
of the different golf course around the world. So based on the loud static map, we process them,

22:21.660 --> 22:27.820
make them available for the robot. And as we know, basically, the GPS position of every of the

22:27.900 --> 22:32.860
circles on the golf course, such as the burn curves, the ponds. But also kind of a semantic

22:32.860 --> 22:38.940
of circles, such as the greens. And the starting areas is particularly not obstacle, but more restricted

22:38.940 --> 22:45.500
area. So based on that, we are able to manage our navigation only from that and from that too,

22:45.500 --> 22:54.140
to positions at Mesf map, based on the initial location of the robot. We also use obstacle avoidance

22:54.140 --> 22:59.900
based on vision. And as Antoine said, we cannot afford a 3D LiDAR of this kind of thing for the

22:59.900 --> 23:05.660
application. So we had to be smart about the computation and also reduce it. So we have only a

23:05.660 --> 23:12.060
front camera. So we have only a small field of view to detect the obstacles. And to save

23:12.060 --> 23:16.860
computation, we use depth to let us cancel. We compute the depth image from the camera to let us

23:16.860 --> 23:22.940
cancel to have it to the understanding of the environment. And we use a special temporal

23:23.260 --> 23:29.100
layer to make sense of it and take the most that we cannot this relatively limited field of view

23:29.100 --> 23:35.980
to understand the obstacles. And the custom plugin, we used it a lot during our development.

23:35.980 --> 23:41.500
I think the best example that we have is the follow feature. It's basically, you see, we have the golfer

23:41.500 --> 23:47.420
here, is a follow by the caddy because you don't want to take care of it all the time. And so

23:47.420 --> 23:53.980
based on vision, we perform this following. So we integrate it as a custom plugin. So we have a

23:53.980 --> 23:59.420
custom behavior tree and an navigator to be able to have no balance between going to goals.

23:59.420 --> 24:05.420
Following and don't have concurrency between this behaviors. And we take a lot of benefits

24:05.420 --> 24:10.460
from this choice because relying on that to it gives us a lot of feature integrated on it,

24:10.460 --> 24:15.660
such as the access to the cost map, to the localization and a lot of features that

24:15.660 --> 24:20.620
in the end really help us to integrate new features. For example, the collision monitor for specific

24:20.620 --> 24:26.620
behaviors, the fact to detect some features such as the bankers to be sure that even if you are

24:26.620 --> 24:31.420
supposed to be followed in the restricted area, it's going to stop. So in the end, you really

24:31.500 --> 24:34.620
expand what we can do on this custom plugins.

24:44.700 --> 24:52.460
Okay. So as Antoine said, for the follow, we're basing ourselves on a computer vision stack.

24:53.180 --> 24:59.500
So the idea here again is to have a hardware agnostic software. We know that specific is the case

25:00.380 --> 25:06.620
from specific cameras provide an object detection algorithm and a tracking algorithm.

25:06.620 --> 25:13.900
But in our case, we wanted to do it by ourselves. And for instance, for the object detection,

25:14.700 --> 25:20.460
we used the yellow model that we've tuned to by applying transfer learning. So we just

25:20.460 --> 25:26.380
trained the last layer of the model in order to fit our data, which is golf specific data.

25:26.380 --> 25:32.380
So we have, obviously, we have human. But we also have the backhand that triggers a follow.

25:32.380 --> 25:37.820
And we also have the better, which is some kind of golf club.

25:40.460 --> 25:46.300
Concerning the object tracking, obviously, your object detection model doesn't make any difference

25:46.300 --> 25:53.020
between Antoine, which is at the left and a quick stuff, which is at the right. We need to use

25:53.020 --> 25:58.700
an object tracking algorithm. In order to assign an ID to this person and also to estimate the

25:58.700 --> 26:05.020
next position at the next frame of this person. To do this, we rely on the open source,

26:05.020 --> 26:15.020
bots are tracking algorithm. So now, let's talk a little bit about remote update, which is called

26:15.100 --> 26:23.660
OTA update for Overture update, right. Let's talk about Ojourney again. So we rely on an

26:23.660 --> 26:32.060
envidiate JSON. So basically, envidiate JSON provide the jetpack, which you can see in a custom

26:32.860 --> 26:40.860
Ubuntu-like distribution provided and maintained by Nvidia. It provides some Overture capability.

26:41.020 --> 26:44.620
We start with it, but at some point, we are like, okay, we don't want to depend on

26:45.340 --> 26:51.820
Nvidia lifecycle for the jetpack. And we don't want to depend on the hardware, in fact, for the

26:51.820 --> 26:59.660
Overture capability. So we were looking for something else. We found the OCTO as a lot of people

27:00.380 --> 27:07.740
in this room. We start with the OCTO. It was nice, a full-time job, to maintain it. So at some point,

27:07.820 --> 27:12.460
we were like, okay, we capability with Mender, which allows us to do the Overture update. But at

27:12.460 --> 27:17.900
some point, we were like, okay, we started with, don't want to have a full-time job to work on this

27:17.900 --> 27:22.860
image. Of course, that's really optimized. That's really something interesting. You only

27:22.860 --> 27:28.540
ship when what you want to, to have a turn-time. That's really great. We had some issues with it,

27:28.540 --> 27:33.900
but that's okay. But we were like, okay, that's really, it takes too much time. And then,

27:33.980 --> 27:41.820
okay, we say that maybe we should create a simple YCTO image and install the Docker engine in it.

27:41.820 --> 27:48.140
So that we can render Docker in this YCTO simple image. That's, and at some point, we were looking

27:48.140 --> 27:54.620
on the internet. We find Ballena, which definitely, that's the purpose of Ballena. So that's why

27:54.620 --> 28:00.780
we, we know use Ballena. So Ballena is quite simple. That's a basic YCTO image. That's, this image is

28:00.780 --> 28:06.220
open, so you can modify it if you need. But at a finger cross, we don't have to right now.

28:07.660 --> 28:14.460
We don't want to return into this YCTO hell. And yeah, that definitely docker on top of it.

28:14.460 --> 28:18.860
So that's definitely what it provides. So that's really what we use now. And it provides also

28:18.860 --> 28:23.900
Ballena Cloud, which is not a free solution, that's because that's a Cloud solution. But it's

28:23.900 --> 28:31.740
relies on an open-end giant, which is open-source. So yeah, that's definitely all go to solution

28:31.740 --> 28:38.860
right now for this God-for-e. And the one important thing is that because of the Bitosy product,

28:38.860 --> 28:45.420
we have some requirement like the, we need the user to confirm when he wants to make the

28:45.420 --> 28:49.980
update. So that's really something we had to customize Ballena for this a little bit.

28:49.980 --> 28:58.220
So that's definitely a development flow today. So it's quite simple to understand. We rely a lot

28:58.220 --> 29:09.820
of on VS Code Defcontner for laptop or laptop as on Ubuntu, at least for the developers. And with NVIDIA GPU,

29:09.820 --> 29:15.020
so that we can test the model. We have ONN and X models, so other independent model, but in the

29:15.100 --> 29:20.300
N, we have to convert it to TensorFlow T, so that we are other dependent, but really optimized

29:20.300 --> 29:29.340
model. Then we deploy them to the Def-for-e, which is still based on the Defcontner in VS Code.

29:30.700 --> 29:37.820
But this fully is based on the Jetpack. And yeah, we have a clean SSH configuration we share together.

29:37.820 --> 29:42.940
And then only at this time we deploy to Ballena to make our test at this point, the only difference

29:43.020 --> 29:50.300
might be some small differences in the kernel itself, because yeah, of course, Docker relies on the kernel

29:51.180 --> 30:04.460
installed. So let's move on our testing pipeline. So this slide comes from the Roscon 2025.

30:04.460 --> 30:11.260
I'd love to have the best testing Pyramid pipeline with the cheap test is first.

30:11.820 --> 30:18.940
And at the end, we have the test on the real robot. Today at Botronics, unfortunately,

30:18.940 --> 30:26.300
we are following the right one, which is do a lot of things, not on the robot,

30:26.300 --> 30:32.860
after word test on the robot, and do a lot of tests on the robot. We obviously want to change this.

30:33.740 --> 30:38.620
We want to follow this Pyramid. The team is growing, it makes sense.

30:39.580 --> 30:45.260
Nowadays, to change it, and we're working on to change this testing pipeline.

30:46.300 --> 30:53.660
So obviously, to have a more robust testing pipeline, we need to have a robust simulation environment.

30:54.460 --> 31:01.420
As of today, we have localization and navigation that is implemented in to navigation.

31:01.420 --> 31:07.580
Unfortunately, the vision stack, so the computer vision stack isn't yet implemented in our

31:07.580 --> 31:16.140
simulation, so we cannot simulate for a loss. For example, as you can see on this gazebo screenshot,

31:16.140 --> 31:23.260
the dynamic of our robot is an really well explained on simulation, but we're working on it,

31:23.260 --> 31:31.740
obviously, and we want to upgrade all these specific points. So the test on the field,

31:31.820 --> 31:38.940
what do they look like? So today, we have two kinds of debugging. The first one are the

31:38.940 --> 31:47.340
live debugging, so we can use graphical user interfaces such as RVs and plug-jigler that it's

31:47.340 --> 31:57.500
forgotten. And the RQT over VNC, so that on laptops, we can directly visualize what the robot sees.

31:58.380 --> 32:05.260
Afterwards, what we also have since our CEO plays golf, he goes on the field and tells the

32:05.260 --> 32:13.900
trolley, what we've implemented is a button on our UI, on our mobile application. And by simply

32:13.900 --> 32:20.380
pushing this button, he can report a bug, and we've implemented custom bugs with rolling windows,

32:20.380 --> 32:25.580
so that we have a bug that takes what was happening sometimes before, and what was

32:25.660 --> 32:31.900
happening sometimes after the bug. Afterward, he only has to plug the trolley to

32:32.460 --> 32:39.020
internet, and we can directly download the bugs through an essential channel.

32:45.180 --> 32:52.780
So no observability. Well, basically, we implement the X-Tack, which is famous for telegraph,

32:52.780 --> 32:58.220
in FixDB, and Grafana. It is what happens in our trolley, so you have two different things,

32:58.220 --> 33:03.100
you have the embedded with what is returns on the trolley directly, and then you have cloud,

33:03.100 --> 33:10.300
which is what runs over the internet, right? So the main piece is on the embedded devices telegraph,

33:10.300 --> 33:17.580
telegraph, super, two kind of input for trolley, to big kind of input, which are telegraph input

33:17.660 --> 33:25.100
that are plug-in, that you set to collect data by default, like CPU, disk, and that kind of thing,

33:25.100 --> 33:31.340
and then we use ROS diagnostics, which is the famous package to collect other

33:31.340 --> 33:39.660
diagnostics, and we send it directly to the telegraph, and telegraph provide two kind of outputs,

33:39.660 --> 33:46.700
which are file, and then on the other end, directly to In FixDB, which is a time series that

33:47.260 --> 33:54.220
is, and then you have Grafana plugged on In FixDB for dashboard. There is several interesting

33:54.220 --> 34:02.140
thing here. About ROS diagnostics, it provides several things. First, a user interface, we can access

34:02.140 --> 34:09.820
directly offline over VNC on the trolley, so that we can see what's happened. Then we have two kind of

34:09.820 --> 34:18.140
diagnostics, with ROS diagnostics. One is common diagnostics provided directly by the package,

34:18.140 --> 34:25.260
that's some note that collects like the shared memory usage or the kind of thing, and then we

34:25.260 --> 34:31.980
implement custom diagnostics so that like covariance for GPS or status for a mandatory

34:31.980 --> 34:39.500
and that kind of metrics, and then we rely on a new ROS diagnostic package, which is the

34:39.500 --> 34:45.660
diagnostic remote logging that allows us to collect metrics and send them directly to telegraph.

34:46.620 --> 34:54.460
On the output, the In FixDB is quite normal, but we have also a file output, because at some point

34:54.460 --> 35:01.500
we have some trolleys without any internet connection on the field, so it allows us to have

35:02.140 --> 35:09.260
everything in a file when it's needed. In fact, that's quite an unusual way to use it,

35:09.260 --> 35:15.820
is that we give this file to an LLM, and it gives us what's wrong with it. It quite work well.

35:16.620 --> 35:24.060
That's really something like Artisanal, I don't know. But in fact, it helped us

35:24.060 --> 35:29.660
exploring tool by tool at the very beginning. I think at the end this file will disappear,

35:29.660 --> 35:35.900
but right now it allows us to set telegraph and then consider the internet connection,

35:35.900 --> 35:41.820
stuff issues, and so on. So that's really why we choose this. There is one important thing on

35:41.820 --> 35:46.940
why we choose the tick stack is also because of the pricing model, which is a pricing model

35:48.060 --> 35:56.140
oriented on dollar per megabytes or by queries or something and not by device, because of the

35:56.140 --> 36:00.940
B2C product, most of the time, a pricing by device is quite expensive for us.

36:07.580 --> 36:12.300
So we are building a B2C project, so there are the question of user interfaces,

36:12.780 --> 36:18.860
and we have two user interfaces, we have a mobile application and one running locally on the screen.

36:19.500 --> 36:24.540
So basically, the general takes that we have is a key crossover away from your UI.

36:25.180 --> 36:29.900
Because in the end, we are developing this application, we want to keep them as standard as possible,

36:29.900 --> 36:35.980
and we don't want to require robotics developer to maintain a web app. You see the logic behind.

36:36.540 --> 36:41.580
It's quite clear, it's easier to maintain, it keeps something as the architecture of the application

36:41.580 --> 36:47.820
standard, and in the end, we are able to separate the concern. We can change our solution

36:47.820 --> 36:53.260
and keep the different stacks separated, and just to rely on bridge to communicate between them.

36:53.820 --> 37:00.220
So for the mobile app, it's the first step that we have developed, and we have tried a lot of things.

37:00.220 --> 37:06.620
We start with the classic Rost Bridge Server plus Wi-Fi, and in the end, we have observed

37:06.620 --> 37:12.940
that it's not suited for B2C, because people don't point on the normal operation to connect

37:12.940 --> 37:17.980
on the not spot, don't have the 4G access on the iOS, it can be a bit complicated.

37:17.980 --> 37:25.420
So the not spot Wi-Fi solution in the end for our configuration was not optimal, so we tried Bluetooth,

37:25.420 --> 37:30.620
and so we went to Bluetooth Classic at first, and we have again iOS, there is a bit of issue,

37:30.700 --> 37:37.660
with a certificate, and it's not as well maintained as BLE, so we moved to the BLE, the Bluetooth

37:37.660 --> 37:43.100
low energy, and it provided really good performance of what we are doing, and for the moment

37:43.100 --> 37:50.540
we're using BLE, which is a Python library, but we're exploring a Rost option blue R, and maybe

37:50.540 --> 37:55.180
it could be the first use case for a R-cell address in our stack. So that's why we are deployed on

37:56.140 --> 38:01.900
and so we have basically by the end with this choice, something relatively classic, a

38:01.900 --> 38:08.300
rack native application running for the UI on the phone, and a kind of Bluetooth API to communicate

38:08.300 --> 38:13.580
with our stack, and so a Bluetooth API on the Rost site to communicate and just give the query.

38:14.380 --> 38:19.260
So we have also observed interestingly that there is no Rost from what we know, no Rost to package

38:19.260 --> 38:26.060
using Bluetooth, so we had to make something about something like that, and for the tactile application,

38:26.060 --> 38:31.740
we have well connected directly on the device, so we have just a web socket, it's wired communication,

38:31.740 --> 38:38.540
so we have a web socket, we have a stack with RGS and electron, so in the end is a desktop application

38:38.540 --> 38:45.020
running on the device. With this stack, we achieve to make something reliable, easy to deploy,

38:45.100 --> 38:51.260
we are running it into a Docker, so it's just another container on our Balena configuration,

38:51.260 --> 38:58.300
and based on the APMage, in the end, it's quite easy to deploy and push new images, so in the

38:58.300 --> 39:02.940
end we are quite happy with this stack. We have designed a custom web socket instead of relying on

39:02.940 --> 39:10.220
the Rost GGS for the reasons that I have seated before. So basically this is the end of the tour for

39:10.220 --> 39:15.580
stack, so we are up into question, as Antoine said, it's kind of the first time that we present it

39:15.580 --> 39:20.620
like that, so we are up into feedback and question to the top, so thank you in advance.

39:21.660 --> 39:30.220
Thank you, thank you, Enzo. Thank you, everyone. One last thing, thank you for being here,

39:30.220 --> 39:44.860
as a robotics enthusiast, we love seeing that much people engaged in a robotic, and we also

39:46.060 --> 39:59.020
want to contribute to this robotics ecosystem, especially in Belgium, and I can say that

39:59.980 --> 40:05.100
I have the honor to announce you that we are for the first time in Belgium,

40:06.780 --> 40:11.820
opening the Rost GGS.

40:19.820 --> 40:28.700
So save the date, it will be on 25 and 26 November, this year obviously, so we're Rost GGS,

40:29.180 --> 40:36.220
it will be held at Nivell, so as Antoine said, it's 40 minutes away from here, Brussels,

40:37.020 --> 40:44.060
and it's something really important, it will be held in English, because in Belgium we don't know

40:44.060 --> 40:51.580
which language to speak, we have. We've made a common agreement that English was nice,

40:52.460 --> 41:00.780
and we're obviously looking for speakers, feel free to contact Antoine, and we're obviously

41:00.780 --> 41:09.820
also looking for sponsors, again feel free to contact Antoine, and that's not finished yet,

41:10.780 --> 41:18.540
second announcement, we are hiring, so as a senior robotics engineer, you've seen another

41:18.540 --> 41:25.420
view of our stack, if you think that it might be interesting to join our team, feel free to apply

41:25.420 --> 41:31.980
on LinkedIn, and yeah, that's it, you can have a look at the job desk on LinkedIn,

41:32.860 --> 41:41.820
and obviously you can question every single member of the team concerning the job application.

41:42.780 --> 41:47.820
So yes, thank you everyone, we are open to any question.

41:58.380 --> 42:02.780
Hello, thanks for the presentation, thank you, just wondering what kind of

42:03.340 --> 42:06.140
certification was this required as a product?

42:08.220 --> 42:15.180
Well, I think that the basic CE certification, right, so there is not a lot of direct machine

42:15.180 --> 42:19.500
because we don't fall in the category, we fall in, of course, in the category of the machine

42:19.500 --> 42:25.820
directive, but we don't have a lot of big constraints, I don't remember the kind of category,

42:25.820 --> 42:33.180
because I'm not the safety expert, right, but that's not that big, yeah, we don't have to,

42:33.180 --> 42:36.140
we don't have real-time big constraints.

42:42.460 --> 42:49.180
Also, as a golf course, it's a private environment, and we don't fall in the configuration of a vehicle,

42:49.180 --> 42:53.340
for example, so we don't have, you know, I would say the difficulties that could have

42:53.420 --> 42:57.660
autonomous car, for example, on thermostatification, so it's way easier for us.

42:59.260 --> 43:01.500
I hope it understands the answer to the question.

43:02.780 --> 43:09.900
Okay, I had a question, did you ever have a problem with the trolley that's bricked?

43:12.540 --> 43:20.860
It can't, like, note a failed and it overwrote some boot sequence or something like that,

43:20.940 --> 43:28.940
and you had to go and fix it, do you have special, something special to prevent that sort of thing?

43:31.500 --> 43:40.140
In fact, we rely a lot of life cycle on life cycle node, so life cycle node, that's for the boot.

43:40.540 --> 43:52.300
Okay, yeah, we rely on life cycle node, we have a lot of diagnostic as well, so that we can understand

43:52.300 --> 43:59.260
what's going wrong, that's why we have some magnetometer status, for example, because magnetometer

43:59.260 --> 44:05.820
is one of the things that can fail quite easy, so we have to monitor those things, and so that we can

44:05.820 --> 44:11.340
and the same for the covariance of the GPS, the GPS covariance will allow us to say, okay,

44:11.340 --> 44:17.020
there is an issue with the GPS and so based on that, we have a node that is able to

44:17.020 --> 44:22.140
deal with it and to say, okay, I can't do autonomous navigation right now, that's an advantage,

44:22.140 --> 44:28.860
we have is that in fact, we are, the goal trolley is always with its golfer, it can be at

44:28.860 --> 44:33.260
100 meters from its golfer, but it's never something like, okay, it doesn't work and it

44:33.260 --> 44:38.300
is always an hours in place, no, because the golfer will say, okay, I can take it remotely,

44:38.300 --> 44:46.300
if needed. And also we have, it was described quite quickly, but we have also this all V and

44:46.300 --> 44:52.300
C debugging sort of stack that allows together data from the field, and so we can do basically

44:52.300 --> 44:57.820
remote debugging as a support, so it's really, you know, it's wasn't spared a bit by the

44:57.900 --> 45:03.660
all this like experience, we know if the remote support. Hi, just that a quick question,

45:04.860 --> 45:10.060
I mentioned using Belena for the OTA updates, but I was curious, do you have anything set up for,

45:10.060 --> 45:14.540
do you have a standardized kind of build environment for building releases or do you currently kind of

45:14.540 --> 45:20.380
do all the release management manually and how does that see I and release them inside work?

45:21.340 --> 45:28.220
Well, that's really linked to the testing Pyramid. Right now we are doing it on a server,

45:28.220 --> 45:36.860
we have, but yeah, in the end we will have to build it in a CI and GitHub, we'll use GitHub,

45:36.860 --> 45:41.820
but yeah, right now we are doing it on a separate server that's already something, but

45:41.820 --> 45:47.660
definitely we need to go one step further now, you know, that's start-up life after all.

45:47.660 --> 45:54.460
And yeah, we're a team of really few robotics developers, so next release.

