Added Tilt Control:
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <microhttpd.h>
#include "libfreenect.h"
#define PORT 8000
pthread_mutex_t kinect_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t camera_mutex = PTHREAD_MUTEX_INITIALIZER;
volatile int die = 0;
freenect_context *f_ctx;
freenect_device *f_dev;
freenect_video_format current_format = FREENECT_VIDEO_RGB;
int tilt_angle = 0;
uint8_t *rgb_back, *rgb_mid, *rgb_front;
int pipe_fd[2];
void set_kinect_tilt(int angle) {
pthread_mutex_lock(&kinect_mutex);
if (freenect_set_tilt_degs(f_dev, angle) < 0) {
printf("Failed to set Kinect tilt angle\n");
}
pthread_mutex_unlock(&kinect_mutex);
}
void rgb_cb(freenect_device *dev, void *rgb, uint32_t timestamp) {
pthread_mutex_lock(&camera_mutex);
// Swap buffers
assert(rgb_back == rgb);
rgb_back = rgb_mid;
freenect_set_video_buffer(dev, rgb_back);
rgb_mid = (uint8_t *)rgb;
// Write RGB data to the pipe for ffmpeg
if (pipe_fd[1] != -1) {
write(pipe_fd[1], rgb_mid, 640 * 480 * 3); // RGB24 format
}
pthread_mutex_unlock(&camera_mutex);
}
void *camera_thread(void *arg) {
freenect_set_video_callback(f_dev, rgb_cb);
freenect_set_video_mode(f_dev, freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, current_format));
freenect_set_video_buffer(f_dev, rgb_back);
freenect_start_video(f_dev);
while (!die && freenect_process_events(f_ctx) >= 0);
freenect_stop_video(f_dev);
freenect_close_device(f_dev);
freenect_shutdown(f_ctx);
return NULL;
}
int request_handler(void *cls, struct MHD_Connection *connection,
const char *url, const char *method,
const char *version, const char *upload_data,
size_t *upload_data_size, void **ptr) {
static int dummy;
if (&dummy != *ptr) {
*ptr = &dummy;
return MHD_YES;
}
*ptr = NULL;
if (strcmp(method, "GET") == 0 && strcmp(url, "/tilt") == 0) {
const char *angle_str = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "angle");
if (angle_str) {
int angle = atoi(angle_str);
if (angle >= -30 && angle <= 30) {
set_kinect_tilt(angle);
char response[128];
snprintf(response, sizeof(response), "Tilt set to %d\n", angle);
struct MHD_Response *res = MHD_create_response_from_buffer(strlen(response),
(void *)response,
MHD_RESPMEM_MUST_COPY);
int ret = MHD_queue_response(connection, MHD_HTTP_OK, res);
MHD_destroy_response(res);
return ret;
} else {
const char *error = "Invalid tilt angle. Range: -30 to 30.\n";
struct MHD_Response *res = MHD_create_response_from_buffer(strlen(error),
(void *)error,
MHD_RESPMEM_MUST_COPY);
int ret = MHD_queue_response(connection, MHD_HTTP_BAD_REQUEST, res);
MHD_destroy_response(res);
return ret;
}
} else {
const char *error = "Missing angle parameter.\n";
struct MHD_Response *res = MHD_create_response_from_buffer(strlen(error),
(void *)error,
MHD_RESPMEM_MUST_COPY);
int ret = MHD_queue_response(connection, MHD_HTTP_BAD_REQUEST, res);
MHD_destroy_response(res);
return ret;
}
}
const char *not_found = "Not Found\n";
struct MHD_Response *res = MHD_create_response_from_buffer(strlen(not_found),
(void *)not_found,
MHD_RESPMEM_MUST_COPY);
int ret = MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, res);
MHD_destroy_response(res);
return ret;
}
int main() {
int res;
rgb_back = (uint8_t *)malloc(640 * 480 * 3);
rgb_mid = (uint8_t *)malloc(640 * 480 * 3);
if (freenect_init(&f_ctx, NULL) < 0) {
fprintf(stderr, "freenect_init() failed\n");
return 1;
}
freenect_set_log_level(f_ctx, FREENECT_LOG_DEBUG);
freenect_select_subdevices(f_ctx, FREENECT_DEVICE_CAMERA | FREENECT_DEVICE_MOTOR);
if (freenect_open_device(f_ctx, &f_dev, 0) < 0) {
fprintf(stderr, "Could not open device\n");
freenect_shutdown(f_ctx);
return 1;
}
// Create a pipe for inter-process communication
if (pipe(pipe_fd) == -1) {
perror("pipe");
return 1;
}
// Fork a process to run ffmpeg
pid_t pid = fork();
if (pid == 0) {
// Child process: Run ffmpeg
close(pipe_fd[1]); // Close write end
dup2(pipe_fd[0], STDIN_FILENO); // Redirect stdin to read end of pipe
execlp("ffmpeg", "ffmpeg",
"-f", "rawvideo",
"-pixel_format", "rgb24",
"-video_size", "640x480",
"-framerate", "30",
"-i", "-",
"-f", "v4l2",
"-pix_fmt", "yuv420p",
"/dev/video0",
NULL);
perror("execlp");
exit(1);
}
close(pipe_fd[0]); // Close read end in the parent process
// Start camera thread
pthread_t cam_thread;
res = pthread_create(&cam_thread, NULL, camera_thread, NULL);
if (res) {
fprintf(stderr, "pthread_create failed\n");
freenect_shutdown(f_ctx);
return 1;
}
// Start HTTP server for tilt control
struct MHD_Daemon *server = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL,
&request_handler, NULL,
MHD_OPTION_END);
if (server == NULL) {
fprintf(stderr, "Failed to start HTTP server\n");
die = 1;
}
printf("HTTP server running on port %d\n", PORT);
getchar(); // Wait for user input to exit
// Cleanup
MHD_stop_daemon(server);
die = 1;
pthread_join(cam_thread, NULL);
free(rgb_back);
free(rgb_mid);
close(pipe_fd[1]); // Close write end
return 0;
}
configuration.yaml for sending HTTP with curl using host shell
input_number:
kinect_tilt_angle:
name: Kinect Tilt Angle
min: -30
max: 30
step: 15
shell_command:
set_kinect_tilt: 'curl -X GET "http://kinect motion host:8000/tilt?angle={{ angle }}"'
Automation to update shell_command with input number
alias: tilt
description: Send tilt angle to Kinect when slider changes
triggers:
- entity_id:
- input_number.kinect_tilt_angle
trigger: state
conditions: []
actions:
- data:
angle: "{{ states('input_number.kinect_tilt_angle') | int }}"
action: shell_command.set_kinect_tilt
mode: single
Also use mjpeg integration for the stream with motion.