blob: 493c29e36d8525f8c999ed28b7d80624ddc48d60 [file] [log] [blame]
Brian Silvermanf7f267a2017-02-04 16:16:08 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "vision/VisionRunner.h"
9
10#include "DriverStation.h"
11#include "RobotBase.h"
12#include "opencv2/core/mat.hpp"
13
14using namespace frc;
15
16/**
17 * Creates a new vision runner. It will take images from the {@code
18 * videoSource}, and call the virtual DoProcess() method.
19 *
20 * @param videoSource the video source to use to supply images for the pipeline
21 */
22VisionRunnerBase::VisionRunnerBase(cs::VideoSource videoSource)
23 : m_image(std::make_unique<cv::Mat>()), m_cvSink("VisionRunner CvSink") {
24 m_cvSink.SetSource(videoSource);
25}
26
27// Located here and not in header due to cv::Mat forward declaration.
28VisionRunnerBase::~VisionRunnerBase() {}
29
30/**
31 * Runs the pipeline one time, giving it the next image from the video source
32 * specified in the constructor. This will block until the source either has an
33 * image or throws an error. If the source successfully supplied a frame, the
34 * pipeline's image input will be set, the pipeline will run, and the listener
35 * specified in the constructor will be called to notify it that the pipeline
36 * ran. This must be run in a dedicated thread, and cannot be used in the main
37 * robot thread because it will freeze the robot program.
38 *
39 * <p>This method is exposed to allow teams to add additional functionality or
40 * have their own ways to run the pipeline. Most teams, however, should just
41 * use {@link #runForever} in its own thread using a std::thread.</p>
42 */
43void VisionRunnerBase::RunOnce() {
44 if (std::this_thread::get_id() == RobotBase::GetThreadId()) {
45 wpi_setErrnoErrorWithContext(
46 "VisionRunner::RunOnce() cannot be called from the main robot thread");
47 return;
48 }
49 auto frameTime = m_cvSink.GrabFrame(*m_image);
50 if (frameTime == 0) {
51 auto error = m_cvSink.GetError();
52 DriverStation::ReportError(error);
53 } else {
54 DoProcess(*m_image);
55 }
56}
57
58/**
59 * A convenience method that calls {@link #runOnce()} in an infinite loop. This
60 * must be run in a dedicated thread, and cannot be used in the main robot
61 * thread because it will freeze the robot program.
62 *
63 * <p><strong>Do not call this method directly from the main
64 * thread.</strong></p>
65 */
66void VisionRunnerBase::RunForever() {
67 if (std::this_thread::get_id() == RobotBase::GetThreadId()) {
68 wpi_setErrnoErrorWithContext(
69 "VisionRunner::RunForever() cannot be called from the main robot "
70 "thread");
71 return;
72 }
73 while (true) {
74 RunOnce();
75 }
76}