OpticalFlow_Onboard.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /*
  2. This program is free software: you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation, either version 3 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program. If not, see <http://www.gnu.org/licenses/>.
  12. */
  13. #include <AP_HAL/AP_HAL.h>
  14. #if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_BEBOP
  15. #include "OpticalFlow_Onboard.h"
  16. #include <fcntl.h>
  17. #include <linux/v4l2-mediabus.h>
  18. #include <pthread.h>
  19. #include <stdio.h>
  20. #include <sys/stat.h>
  21. #include <sys/types.h>
  22. #include <time.h>
  23. #include <unistd.h>
  24. #include <vector>
  25. #include "CameraSensor_Mt9v117.h"
  26. #include "GPIO.h"
  27. #include "PWM_Sysfs.h"
  28. #include "AP_HAL/utility/RingBuffer.h"
  29. #define OPTICAL_FLOW_ONBOARD_RTPRIO 11
  30. static const unsigned int OPTICAL_FLOW_GYRO_BUFFER_LEN = 400;
  31. extern const AP_HAL::HAL& hal;
  32. using namespace Linux;
  33. void OpticalFlow_Onboard::init()
  34. {
  35. uint32_t top, left;
  36. uint32_t crop_width, crop_height;
  37. uint32_t memtype = V4L2_MEMORY_MMAP;
  38. unsigned int nbufs = 0;
  39. int ret;
  40. pthread_attr_t attr;
  41. struct sched_param param = {
  42. .sched_priority = OPTICAL_FLOW_ONBOARD_RTPRIO
  43. };
  44. if (_initialized) {
  45. return;
  46. }
  47. _videoin = new VideoIn;
  48. const char* device_path = HAL_OPTFLOW_ONBOARD_VDEV_PATH;
  49. memtype = V4L2_MEMORY_MMAP;
  50. nbufs = HAL_OPTFLOW_ONBOARD_NBUFS;
  51. _width = HAL_OPTFLOW_ONBOARD_OUTPUT_WIDTH;
  52. _height = HAL_OPTFLOW_ONBOARD_OUTPUT_HEIGHT;
  53. crop_width = HAL_OPTFLOW_ONBOARD_CROP_WIDTH;
  54. crop_height = HAL_OPTFLOW_ONBOARD_CROP_HEIGHT;
  55. top = 0;
  56. /* make the image square by cropping to YxY, removing the lateral edges */
  57. left = (HAL_OPTFLOW_ONBOARD_SENSOR_WIDTH -
  58. HAL_OPTFLOW_ONBOARD_SENSOR_HEIGHT) / 2;
  59. if (device_path == nullptr ||
  60. !_videoin->open_device(device_path, memtype)) {
  61. AP_HAL::panic("OpticalFlow_Onboard: couldn't open "
  62. "video device");
  63. }
  64. #if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_BEBOP
  65. _pwm = new PWM_Sysfs_Bebop(BEBOP_CAMV_PWM);
  66. _pwm->init();
  67. _pwm->set_freq(BEBOP_CAMV_PWM_FREQ);
  68. _pwm->enable(true);
  69. _camerasensor = new CameraSensor_Mt9v117(HAL_OPTFLOW_ONBOARD_SUBDEV_PATH,
  70. hal.i2c_mgr->get_device(0, 0x5D),
  71. MT9V117_QVGA,
  72. BEBOP_GPIO_CAMV_NRST,
  73. BEBOP_CAMV_PWM_FREQ);
  74. if (!_camerasensor->set_format(HAL_OPTFLOW_ONBOARD_SENSOR_WIDTH,
  75. HAL_OPTFLOW_ONBOARD_SENSOR_HEIGHT,
  76. V4L2_MBUS_FMT_UYVY8_2X8)) {
  77. AP_HAL::panic("OpticalFlow_Onboard: couldn't set subdev fmt\n");
  78. }
  79. _format = V4L2_PIX_FMT_NV12;
  80. #endif
  81. if (!_videoin->set_format(&_width, &_height, &_format, &_bytesperline,
  82. &_sizeimage)) {
  83. AP_HAL::panic("OpticalFlow_Onboard: couldn't set video format");
  84. }
  85. if (_format != V4L2_PIX_FMT_NV12 && _format != V4L2_PIX_FMT_GREY &&
  86. _format != V4L2_PIX_FMT_YUYV) {
  87. AP_HAL::panic("OpticalFlow_Onboard: format not supported\n");
  88. }
  89. if (_width == HAL_OPTFLOW_ONBOARD_OUTPUT_WIDTH &&
  90. _height == HAL_OPTFLOW_ONBOARD_OUTPUT_HEIGHT) {
  91. _shrink_by_software = false;
  92. } else {
  93. /* here we store the actual camera output width and height to use
  94. * them later on to software shrink each frame. */
  95. _shrink_by_software = true;
  96. _camera_output_width = _width;
  97. _camera_output_height = _height;
  98. /* we set these values here in order to the calculations be correct
  99. * (such as PX4 init) even though we shrink each frame later on. */
  100. _width = HAL_OPTFLOW_ONBOARD_OUTPUT_WIDTH;
  101. _height = HAL_OPTFLOW_ONBOARD_OUTPUT_HEIGHT;
  102. _bytesperline = HAL_OPTFLOW_ONBOARD_OUTPUT_WIDTH;
  103. }
  104. if (_videoin->set_crop(left, top, crop_width, crop_height)) {
  105. _crop_by_software = false;
  106. } else {
  107. _crop_by_software = true;
  108. if (!_shrink_by_software) {
  109. /* here we store the actual camera output width and height to use
  110. * them later on to software crop each frame. */
  111. _camera_output_width = _width;
  112. _camera_output_height = _height;
  113. /* we set these values here in order to the calculations be correct
  114. * (such as PX4 init) even though we crop each frame later on. */
  115. _width = HAL_OPTFLOW_ONBOARD_OUTPUT_WIDTH;
  116. _height = HAL_OPTFLOW_ONBOARD_OUTPUT_HEIGHT;
  117. _bytesperline = HAL_OPTFLOW_ONBOARD_OUTPUT_WIDTH;
  118. }
  119. }
  120. if (!_videoin->allocate_buffers(nbufs)) {
  121. AP_HAL::panic("OpticalFlow_Onboard: couldn't allocate video buffers");
  122. }
  123. _videoin->prepare_capture();
  124. /* Use px4 algorithm for optical flow */
  125. _flow = new Flow_PX4(_width, _bytesperline,
  126. HAL_FLOW_PX4_MAX_FLOW_PIXEL,
  127. HAL_FLOW_PX4_BOTTOM_FLOW_FEATURE_THRESHOLD,
  128. HAL_FLOW_PX4_BOTTOM_FLOW_VALUE_THRESHOLD);
  129. /* Create the thread that will be waiting for frames
  130. * Initialize thread and mutex */
  131. ret = pthread_mutex_init(&_mutex, nullptr);
  132. if (ret != 0) {
  133. AP_HAL::panic("OpticalFlow_Onboard: failed to init mutex");
  134. }
  135. ret = pthread_attr_init(&attr);
  136. if (ret != 0) {
  137. AP_HAL::panic("OpticalFlow_Onboard: failed to init attr");
  138. }
  139. pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
  140. pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
  141. pthread_attr_setschedparam(&attr, &param);
  142. ret = pthread_create(&_thread, &attr, _read_thread, this);
  143. if (ret != 0) {
  144. AP_HAL::panic("OpticalFlow_Onboard: failed to create thread");
  145. }
  146. _gyro_ring_buffer = new ObjectBuffer<GyroSample>(OPTICAL_FLOW_GYRO_BUFFER_LEN);
  147. _initialized = true;
  148. }
  149. bool OpticalFlow_Onboard::read(AP_HAL::OpticalFlow::Data_Frame& frame)
  150. {
  151. bool ret;
  152. pthread_mutex_lock(&_mutex);
  153. if (!_data_available) {
  154. ret = false;
  155. goto end;
  156. }
  157. frame.pixel_flow_x_integral = _pixel_flow_x_integral;
  158. frame.pixel_flow_y_integral = _pixel_flow_y_integral;
  159. frame.gyro_x_integral = _gyro_x_integral;
  160. frame.gyro_y_integral = _gyro_y_integral;
  161. frame.delta_time = _integration_timespan;
  162. frame.quality = _surface_quality;
  163. _integration_timespan = 0;
  164. _pixel_flow_x_integral = 0;
  165. _pixel_flow_y_integral = 0;
  166. _gyro_x_integral = 0;
  167. _gyro_y_integral = 0;
  168. _data_available = false;
  169. ret = true;
  170. end:
  171. pthread_mutex_unlock(&_mutex);
  172. return ret;
  173. }
  174. void OpticalFlow_Onboard::push_gyro(float gyro_x, float gyro_y, float dt)
  175. {
  176. GyroSample sample;
  177. struct timespec ts;
  178. if (!_gyro_ring_buffer) {
  179. return;
  180. }
  181. clock_gettime(CLOCK_MONOTONIC, &ts);
  182. _integrated_gyro.x += (gyro_x - _gyro_bias.x) * dt;
  183. _integrated_gyro.y += (gyro_y - _gyro_bias.y) * dt;
  184. sample.gyro = _integrated_gyro;
  185. sample.time_us = 1.0e6 * (ts.tv_sec + (ts.tv_nsec*1.0e-9));
  186. _gyro_ring_buffer->push(sample);
  187. }
  188. void OpticalFlow_Onboard::_get_integrated_gyros(uint64_t timestamp, GyroSample &gyro)
  189. {
  190. GyroSample integrated_gyro_at_time = {};
  191. unsigned int retries = 0;
  192. // pop all samples prior to frame time
  193. while (_gyro_ring_buffer->pop(integrated_gyro_at_time) &&
  194. integrated_gyro_at_time.time_us < timestamp &&
  195. retries++ < OPTICAL_FLOW_GYRO_BUFFER_LEN);
  196. gyro = integrated_gyro_at_time;
  197. }
  198. void OpticalFlow_Onboard::push_gyro_bias(float gyro_bias_x, float gyro_bias_y)
  199. {
  200. _gyro_bias.x = gyro_bias_x;
  201. _gyro_bias.y = gyro_bias_y;
  202. }
  203. void *OpticalFlow_Onboard::_read_thread(void *arg)
  204. {
  205. OpticalFlow_Onboard *optflow_onboard = (OpticalFlow_Onboard *) arg;
  206. optflow_onboard->_run_optflow();
  207. return nullptr;
  208. }
  209. void OpticalFlow_Onboard::_run_optflow()
  210. {
  211. GyroSample gyro_sample;
  212. Vector2f flow_rate;
  213. VideoIn::Frame video_frame;
  214. uint32_t convert_buffer_size = 0, output_buffer_size = 0;
  215. uint32_t crop_left = 0, crop_top = 0;
  216. uint32_t shrink_scale = 0, shrink_width = 0, shrink_height = 0;
  217. uint32_t shrink_width_offset = 0, shrink_height_offset = 0;
  218. uint8_t *convert_buffer = nullptr, *output_buffer = nullptr;
  219. uint8_t qual;
  220. if (_format == V4L2_PIX_FMT_YUYV) {
  221. if (_shrink_by_software || _crop_by_software) {
  222. convert_buffer_size = _camera_output_width * _camera_output_height;
  223. } else {
  224. convert_buffer_size = _width * _height;
  225. }
  226. convert_buffer = (uint8_t *)calloc(1, convert_buffer_size);
  227. if (!convert_buffer) {
  228. AP_HAL::panic("OpticalFlow_Onboard: couldn't allocate conversion buffer\n");
  229. }
  230. }
  231. if (_shrink_by_software || _crop_by_software) {
  232. output_buffer_size = HAL_OPTFLOW_ONBOARD_OUTPUT_WIDTH *
  233. HAL_OPTFLOW_ONBOARD_OUTPUT_HEIGHT;
  234. output_buffer = (uint8_t *)calloc(1, output_buffer_size);
  235. if (!output_buffer) {
  236. if (convert_buffer) {
  237. free(convert_buffer);
  238. }
  239. AP_HAL::panic("OpticalFlow_Onboard: couldn't allocate crop buffer\n");
  240. }
  241. }
  242. if (_shrink_by_software) {
  243. if (_camera_output_width > _camera_output_height) {
  244. shrink_scale = (uint32_t) _camera_output_height /
  245. HAL_OPTFLOW_ONBOARD_OUTPUT_HEIGHT;
  246. } else {
  247. shrink_scale = (uint32_t) _camera_output_width /
  248. HAL_OPTFLOW_ONBOARD_OUTPUT_WIDTH;
  249. }
  250. shrink_width = HAL_OPTFLOW_ONBOARD_OUTPUT_WIDTH * shrink_scale;
  251. shrink_height = HAL_OPTFLOW_ONBOARD_OUTPUT_HEIGHT * shrink_scale;
  252. shrink_width_offset = (_camera_output_width - shrink_width) / 2;
  253. shrink_height_offset = (_camera_output_height - shrink_height) / 2;
  254. } else if (_crop_by_software) {
  255. crop_left = _camera_output_width / 2 -
  256. HAL_OPTFLOW_ONBOARD_OUTPUT_WIDTH / 2;
  257. crop_top = _camera_output_height / 2 -
  258. HAL_OPTFLOW_ONBOARD_OUTPUT_HEIGHT / 2;
  259. }
  260. while(true) {
  261. /* wait for next frame to come */
  262. if (!_videoin->get_frame(video_frame)) {
  263. if (convert_buffer) {
  264. free(convert_buffer);
  265. }
  266. if (output_buffer) {
  267. free(output_buffer);
  268. }
  269. AP_HAL::panic("OpticalFlow_Onboard: couldn't get frame\n");
  270. }
  271. if (_format == V4L2_PIX_FMT_YUYV) {
  272. VideoIn::yuyv_to_grey((uint8_t *)video_frame.data,
  273. convert_buffer_size * 2, convert_buffer);
  274. memset(video_frame.data, 0, convert_buffer_size * 2);
  275. memcpy(video_frame.data, convert_buffer, convert_buffer_size);
  276. }
  277. if (_shrink_by_software) {
  278. /* shrink_8bpp() will shrink a selected area using the offsets,
  279. * therefore, we don't need the crop. */
  280. VideoIn::shrink_8bpp((uint8_t *)video_frame.data, output_buffer,
  281. _camera_output_width, _camera_output_height,
  282. shrink_width_offset, shrink_width,
  283. shrink_height_offset, shrink_height,
  284. shrink_scale, shrink_scale);
  285. memset(video_frame.data, 0, _camera_output_width * _camera_output_height);
  286. memcpy(video_frame.data, output_buffer, output_buffer_size);
  287. } else if (_crop_by_software) {
  288. VideoIn::crop_8bpp((uint8_t *)video_frame.data, output_buffer,
  289. _camera_output_width,
  290. crop_left, HAL_OPTFLOW_ONBOARD_OUTPUT_WIDTH,
  291. crop_top, HAL_OPTFLOW_ONBOARD_OUTPUT_HEIGHT);
  292. memset(video_frame.data, 0, _camera_output_width * _camera_output_height);
  293. memcpy(video_frame.data, output_buffer, output_buffer_size);
  294. }
  295. /* if it is at least the second frame we receive
  296. * since we have to compare 2 frames */
  297. if (_last_video_frame.data == nullptr) {
  298. _last_video_frame = video_frame;
  299. continue;
  300. }
  301. /* read the integrated gyro data */
  302. _get_integrated_gyros(video_frame.timestamp, gyro_sample);
  303. #ifdef OPTICALFLOW_ONBOARD_RECORD_VIDEO
  304. int fd = open(OPTICALFLOW_ONBOARD_VIDEO_FILE, O_CLOEXEC | O_CREAT | O_WRONLY
  305. | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP |
  306. S_IWGRP | S_IROTH | S_IWOTH);
  307. if (fd != -1) {
  308. write(fd, video_frame.data, _sizeimage);
  309. #ifdef OPTICALFLOW_ONBOARD_RECORD_METADATAS
  310. struct PACKED {
  311. uint32_t timestamp;
  312. float x;
  313. float y;
  314. float z;
  315. } metas = { video_frame.timestamp, rate_x, rate_y, rate_z};
  316. write(fd, &metas, sizeof(metas));
  317. #endif
  318. close(fd);
  319. }
  320. #endif
  321. /* compute gyro data and video frames
  322. * get flow rate to send it to the opticalflow driver
  323. */
  324. qual = _flow->compute_flow((uint8_t*)_last_video_frame.data,
  325. (uint8_t *)video_frame.data,
  326. video_frame.timestamp -
  327. _last_video_frame.timestamp,
  328. &flow_rate.x, &flow_rate.y);
  329. /* fill data frame for upper layers */
  330. pthread_mutex_lock(&_mutex);
  331. _pixel_flow_x_integral += flow_rate.x /
  332. HAL_FLOW_PX4_FOCAL_LENGTH_MILLIPX;
  333. _pixel_flow_y_integral += flow_rate.y /
  334. HAL_FLOW_PX4_FOCAL_LENGTH_MILLIPX;
  335. _integration_timespan += video_frame.timestamp -
  336. _last_video_frame.timestamp;
  337. _gyro_x_integral += (gyro_sample.gyro.x - _last_gyro_rate.x) *
  338. (video_frame.timestamp - _last_video_frame.timestamp) /
  339. (gyro_sample.time_us - _last_integration_time);
  340. _gyro_y_integral += (gyro_sample.gyro.y - _last_gyro_rate.y) /
  341. (gyro_sample.time_us - _last_integration_time) *
  342. (video_frame.timestamp - _last_video_frame.timestamp);
  343. _surface_quality = qual;
  344. _data_available = true;
  345. pthread_mutex_unlock(&_mutex);
  346. /* give the last frame back to the video input driver */
  347. _videoin->put_frame(_last_video_frame);
  348. _last_integration_time = gyro_sample.time_us;
  349. _last_video_frame = video_frame;
  350. _last_gyro_rate = gyro_sample.gyro;
  351. }
  352. if (convert_buffer) {
  353. free(convert_buffer);
  354. }
  355. if (output_buffer) {
  356. free(output_buffer);
  357. }
  358. }
  359. #endif