From 588503226ff61c2a440f19e050691af93cef0f5f Mon Sep 17 00:00:00 2001 From: cbdev Date: Fri, 9 Oct 2020 23:17:41 +0200 Subject: Implement VISCA relative movement --- backends/visca.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- backends/visca.h | 20 ++++++++++---- backends/visca.md | 6 +++-- 3 files changed, 96 insertions(+), 9 deletions(-) (limited to 'backends') diff --git a/backends/visca.c b/backends/visca.c index 8465c14..2e82515 100644 --- a/backends/visca.c +++ b/backends/visca.c @@ -2,6 +2,7 @@ #define DEBUG #include +#include #include "visca.h" #include "libmmbackend.h" @@ -87,6 +88,10 @@ static int ptz_configure_instance(instance* inst, char* option, char* value){ return 0; #endif } + else if(!strcmp(option, "deadzone")){ + data->deadzone = strtod(value, NULL); + return 0; + } LOGPF("Unknown instance configuration parameter %s for instance %s", option, inst->name); return 1; @@ -104,6 +109,8 @@ static int ptz_instance(instance* inst){ //start with maximum speeds data->panspeed = ptz_channels[panspeed].max; data->tiltspeed = ptz_channels[tiltspeed].max; + //start with a bit of slack/deadzone in relative movement axes + data->deadzone = 0.1; inst->impl = data; return 0; @@ -135,6 +142,32 @@ static channel* ptz_channel(instance* inst, char* spec, uint8_t flags){ command |= (strtoul(spec + strlen(ptz_channels[command].name), NULL, 10) << 8); } + //store relative move direction + else if(command == relmove){ + if(!strcmp(spec + strlen(ptz_channels[relmove].name), ".up") + || !strcmp(spec + strlen(ptz_channels[relmove].name), ".y")){ + command |= (rel_up << 8); + } + else if(!strcmp(spec + strlen(ptz_channels[relmove].name), ".left") + || !strcmp(spec + strlen(ptz_channels[relmove].name), ".x")){ + command |= (rel_left << 8); + } + + if(!strcmp(spec + strlen(ptz_channels[relmove].name), ".down") + || !strcmp(spec + strlen(ptz_channels[relmove].name), ".y")){ + command |= (rel_down << 8); + } + else if(!strcmp(spec + strlen(ptz_channels[relmove].name), ".right") + || !strcmp(spec + strlen(ptz_channels[relmove].name), ".x")){ + command |= (rel_right << 8); + } + + if(command >> 8 == 0){ + LOGPF("Could not parse relative movement command %s", spec); + return NULL; + } + } + return mm_channel(inst, command, 1); } @@ -177,11 +210,53 @@ static size_t ptz_set_ptspeed(instance* inst, channel* c, channel_value* v, uint return 0; } -static size_t ptz_set_stop(instance* inst, channel* c, channel_value* v, uint8_t* msg){ +static size_t ptz_set_relmove(instance* inst, channel* c, channel_value* v, uint8_t* msg){ ptz_instance_data* data = (ptz_instance_data*) inst->impl; + + uint8_t direction = c->ident >> 8; + double speed_factor = v->normalised; + + if(direction == rel_x + || direction == rel_y){ + //select only one move event + direction &= (speed_factor > 0.5) ? (rel_up | rel_left) : (rel_down | rel_right); + + //scale event value to full axis + speed_factor = fabs((speed_factor - 0.5) * 2); + + //clamp to deadzone + speed_factor = (speed_factor < 2 * data->deadzone) ? 0 : speed_factor; + } + + //clear modified axis + if(direction & rel_x){ + data->relative_movement &= ~rel_x; + } + else{ + data->relative_movement &= ~rel_y; + } + + if(speed_factor){ + data->relative_movement |= direction; + } + + //set stored axis speed msg[4] = data->panspeed; msg[5] = data->tiltspeed; - return ptz_channels[stop].bytes; + + //update motor control from movement data + msg[6] |= (data->relative_movement & (rel_left | rel_right)) >> 2; + msg[7] |= data->relative_movement & (rel_up | rel_down); + + //stop motors if unset + msg[6] = msg[6] ? msg[6] : 3; + msg[7] = msg[7] ? msg[7] : 3; + + DBGPF("Moving axis %d with factor %f, total movement now %02X, commanding %d / %d, %d / %d", + direction, speed_factor, data->relative_movement, + msg[6], msg[4], msg[7], msg[5]); + + return ptz_channels[relmove].bytes; } static size_t ptz_set_zoom(instance* inst, channel* c, channel_value* v, uint8_t* msg){ diff --git a/backends/visca.h b/backends/visca.h index 160398d..47ada19 100644 --- a/backends/visca.h +++ b/backends/visca.h @@ -12,6 +12,15 @@ static int ptz_shutdown(size_t n, instance** inst); #define VISCA_BUFFER_LENGTH 50 +enum /*_ptz_relmove_channel */ { + rel_up = 1, + rel_down = 2, + rel_left = 4, + rel_right = 8, + rel_x = 3, + rel_y = 12 +}; + typedef struct /*_ptz_instance_data*/ { int fd; uint8_t cam_address; @@ -19,6 +28,8 @@ typedef struct /*_ptz_instance_data*/ { uint16_t y; uint8_t panspeed; uint8_t tiltspeed; + uint8_t relative_movement; + double deadzone; } ptz_instance_data; enum /*ptz_channels*/ { @@ -38,6 +49,7 @@ enum /*ptz_channels*/ { store, home, stop, + relmove, sentinel }; @@ -51,9 +63,7 @@ static size_t ptz_set_wb_mode(instance* inst, channel* c, channel_value* v, uint static size_t ptz_set_wb(instance* inst, channel* c, channel_value* v, uint8_t* msg); static size_t ptz_set_memory(instance* inst, channel* c, channel_value* v, uint8_t* msg); static size_t ptz_set_memory_store(instance* inst, channel* c, channel_value* v, uint8_t* msg); - -//relative move test -static size_t ptz_set_stop(instance* inst, channel* c, channel_value* v, uint8_t* msg); +static size_t ptz_set_relmove(instance* inst, channel* c, channel_value* v, uint8_t* msg); static struct { char* name; @@ -77,6 +87,6 @@ static struct { [call] = {"memory", 7, {0x80, 0x01, 0x04, 0x3F, 0x02, 0, 0xFF}, 0, 254, 0, ptz_set_memory}, [store] = {"store", 7, {0x80, 0x01, 0x04, 0x3F, 0x01, 0, 0xFF}, 0, 254, 0, ptz_set_memory_store}, [home] = {"home", 5, {0x80, 0x01, 0x06, 0x04, 0xFF}, 0, 0, 0, NULL}, - //relative move test - [stop] = {"stop", 9, {0x80, 0x01, 0x06, 0x01, 0, 0, 0x03, 0x03, 0xFF}, 0, 0, 0, ptz_set_stop} + [relmove] = {"move", 9, {0x80, 0x01, 0x06, 0x01, 0, 0, 0, 0, 0xFF}, 0, 1, 0, ptz_set_relmove}, + [stop] = {"stop", 9, {0x80, 0x01, 0x06, 0x01, 0, 0, 0x03, 0x03, 0xFF}, 0, 0, 0, ptz_set_relmove} }; diff --git a/backends/visca.md b/backends/visca.md index 1dd516e..cf5906d 100644 --- a/backends/visca.md +++ b/backends/visca.md @@ -19,13 +19,14 @@ The `visca` backend does not take any global configuration. | `id` | `5` | `1` | VISCA Camera address (normally 1 for network communication | | `connect` | `10.10.10.1 5678` | none | Camera network address and port. Default connection is TCP, when optionally suffixed with the `udp` keyword, connection will be UDP | | `device` | `/dev/ttyUSB0` | none | (Linux only) Device node for a serial port adapter connecting to the camera | +| `deadzone` | `0.1` | `0.1` | Amount of event value variation to be ignored for relative movement commands | #### Channel specification Each instance exposes the following channels -* `pan`: Pan axis -* `tilt`: Tilt axis +* `pan`: Pan axis (absolute) +* `tilt`: Tilt axis (absolute) * `panspeed`: Pan speed * `tiltspeed`: Tilt speed * `zoom`: Zoom position @@ -36,6 +37,7 @@ Each instance exposes the following channels * `home`: Return to home position * `memory`: Call memory (if incoming event value is greater than 0.9) * `store`: Store current pan/tilt/zoom setup to memory (if incoming event value is greater than 0.9) +* `move.left`, `move.right`, `move.up`, `move.down`: Relative movement with the currently set `panspeed` and `tiltspeed` Example mappings: -- cgit v1.2.3