-
Notifications
You must be signed in to change notification settings - Fork 1
3 Simulation Driver
The previous pages of this tutorial explained the responsibilities of a driver and parts of the Skinware API related to drivers. This page will build upon that knowledge to create a complete driver which provides emulated data.
First, let's create a skeleton for the program. This skeleton would be the same for drivers, user applications and services, so please take a look at this page describing this common skeleton.
Once you are comfortable with the skeleton program, let's go ahead and add a driver.
#include <skin.h>
URT_MODULE_LICENSE("GPL");
URT_MODULE_AUTHOR("Shahbaz Youssefi");
URT_MODULE_DESCRIPTION("Sample emulation driver\n");
/* provide a simple regular skin */
static unsigned int sensor_per_module_count = 5;
static unsigned int module_per_patch_count = 4;
static unsigned int patch_count = 5;
URT_MODULE_PARAM_START()
URT_MODULE_PARAM(sensor_per_module_count, uint, "Number of sensors per module (default: 5)")
URT_MODULE_PARAM(module_per_patch_count, uint, "Number of modules per patch (default: 4)")
URT_MODULE_PARAM(patch_count, uint, "Number of patches (default: 5)")
URT_MODULE_PARAM_END()
struct data
{
struct skin *skin;
};
static int start(struct data *d);
static void body(struct data *d);
static void stop(struct data *d);
URT_GLUE(start, body, stop, struct data, interrupted, done)
static void cleanup(struct data *d)
{
/* clean up Skinware if initialized */
skin_free(d->skin);
/* clean up URT */
urt_exit();
}
static int driver_details(struct skin_driver *driver, bool revived, struct skin_driver_details *details, void *d)
{
skin_sensor_id s;
skin_module_id m;
skin_patch_id p;
/* let's forget about revival for now */
if (revived)
return -1;
/* say how many modules there are in each patch */
for (p = 0; p < details->overall.patch_count; ++p)
details->patches[p].module_count = module_per_patch_count;
/* say how many sensors there are in each module */
for (m = 0; m < details->overall.module_count; ++m)
details->modules[m].sensor_count = sensor_per_module_count;
/* say what is the unique id and type and of each sensor */
for (s = 0; s < details->overall.sensor_count; ++s)
{
details->sensors[s].uid = s;
details->sensors[s].type = 0; /* give some meaningless type */
}
return 0;
}
static int driver_acquire(struct skin_driver *driver, skin_sensor_response *responses, skin_sensor_size sensor_count, void *d)
{
skin_sensor_id s;
/* create an oscillation effect */
urt_time t = urt_get_time() >> 15;
skin_sensor_response r = t % SKIN_SENSOR_RESPONSE_MAX;
bool turn_off = (t / SKIN_SENSOR_RESPONSE_MAX) & 1;
if (turn_off)
r = SKIN_SENSOR_RESPONSE_MAX - r;
for (s = 0; s < sensor_count; ++s)
{
unsigned int cur = r + s * 300;
if (cur > SKIN_SENSOR_RESPONSE_MAX)
cur = SKIN_SENSOR_RESPONSE_MAX;
/* fill in the sensor responses */
responses[s] = cur;
}
return 0;
}
static int start(struct data *d)
{
*d = (struct data){0};
/* start up URT */
if (urt_init())
return EXIT_FAILURE;
/* start up Skinware */
d->skin = skin_init();
if (d->skin == NULL)
goto exit_fail;
return 0;
exit_fail:
cleanup(d);
return EXIT_FAILURE;
}
static void body(struct data *d)
{
skin_driver_add(d->skin, &(struct skin_driver_attr){
.sensor_count = sensor_per_module_count * module_per_patch_count * patch_count,
.module_count = module_per_patch_count * patch_count,
.patch_count = patch_count,
},
&(struct skin_writer_attr){ .name = "TST" },
&(urt_task_attr){ .period = 50000000 },
&(struct skin_driver_callbacks){
.details = driver_details,
.acquire = driver_acquire,
.user_data = d,
});
skin_resume(d->skin);
done = 1;
}
static void stop(struct data *d)
{
/* wait until a signal arrives */
while (!interrupted)
urt_sleep(10000000);
cleanup(d);
}
This driver takes the number of patches, the number of modules in each patch and the number of sensors in each module
as arguments, but let's just use the defaults. In a real driver, this information would be obtained automatically by
scanning the attached piece of robot skin. The driver registers itself with Skinware with the name "TST"
, and asks
for an acquisition period of 50ms.
In driver_details()
, the driver simply tells Skinware the structure of the skin. In driver_acquire()
, it creates
an oscillation effect for the values of sensors and fills the responses in.
Let's build and execute this driver:
$ gcc -std=gnu11 -c $(urt-config --user-cflags) main.c
$ gcc -std=gnu11 -o test_driver main.o -lskin -lurt $(urt-config --user-ldflags)
$ ./test_driver
Now the driver is running, but we can't see what's happening yet. You can use the following to see some information about the driver:
$ skin_info
Let's actually see what the driver is doing though. There is a visualizer bundled with Skinware that you could use for this purpose. The controls are pretty much like a video game.
The visualizer itself requires to know the position and orientation of each sensor, which is an information we don't yet have. The calibrator bundled with Skinware can fake these data for us, arranging sensors in modules in a grid, and arranging modules themselves in a grid:
$ skin_calibrate fake_fill &
The &
in the end of the command puts this process in the background. This calibrator provides a Skinware service
and is left running in the background. Now, let's execute the visualizer:
$ skin_view show_nontaxel
The show_nontaxel
parameter of the visualizer is required because our driver provides data from sensor of unknown
type. In the code of the driver, the sensor types where given a value of 0
, which doesn't correspond to any of the
types known to Skinware. The visualizer, by default, shows only tactile sensors (taxels) and the show_nontaxel
parameter overrides that.
In the visualizer, you should now be able to see the sensors your driver is providing and also see their values changing. Once you are satisfied with your accomplishment, hit escape to close the visualizer.
To close the calibrator, either use the kill
command (such as kill %1
) or bring it to the foreground (the fg
command) and hit CTRL+C.
To close the driver, you can also hit CTRL+C.
Next: See other tutorials.