Compare commits

...

142 Commits

Author SHA1 Message Date
Brad Miller
964475c724 Bump the version number to 1.1 for the network table changes
Change-Id: Id3ed20c88de5744acfe95ed0916c3c7f3fc0e386
2015-02-10 17:21:02 -05:00
Fredric Silberberg
bfa4bbaf78 Final move of Dustins network tables patches
Change-Id: I7d351d87e63c8174b62f4ec09f805f685c80019c
2015-02-09 14:22:44 -05:00
Mitchell Wills
39158754d7 Partial merge of patch from James Killian
Narrows scope of locks in write manager
added delay to incomming stream monitor loop

Change-Id: I6ced23c11cd3c2102041a73cb94fd1f1d351c7a4
2015-02-07 19:56:12 -05:00
Mitchell Wills
048b02e6cd Applied patch from Dustin Spicuzza to fix robot hang
Change-Id: I273feafcad5c95de04a11bab64c2d5596f248662
2015-02-07 19:56:11 -05:00
Fred Silberberg (WPI)
130319b771 Merge "Fixes artf3989: Java SerialPort no longer ignores return value of serialRead" 2015-01-21 14:58:09 -08:00
Thomas Clark (WPI)
0b414b1bde Merge "Disable Encoder console spam introduced in e13720b." 2015-01-21 14:05:01 -08:00
Thomas Clark (WPI)
8a244cc9dc Merge "Make index encoder constructors work." 2015-01-21 14:03:17 -08:00
Brad Miller (WPI)
397162390b Merge "Correct energy to be in Joules rather then millijoules. Fixes artf3940" 2015-01-21 12:15:23 -08:00
Joe Ross
bbc216f998 Disable Encoder console spam introduced in e13720b.
Change-Id: I10501f9bb9e8f8e0607291209f9a44a8dc3fa6b8
2015-01-18 18:57:34 -08:00
Joe Ross
72a56e6a8a Make index encoder constructors work.
Change-Id: I50e1262128197e7d65ed773c998d820efde152fe
2015-01-17 22:28:02 -08:00
Colby Skeggs
102c992e50 Fixes artf3989: Java SerialPort no longer ignores return value of serialRead
Change-Id: I5d522111189372a3c95b90804abf05ae1d0b553e
2015-01-18 01:30:19 +00:00
Joe Ross
9f057fddfd Correct energy to be in Joules rather then millijoules. Fixes artf3940
Note: power and thus energy will still be wrong until PDP firmware 1.39
or later is used. See artf3939.
Change-Id: Ic68b8a28c78f1b5d524fa5fb45e3bc0d9cd4a76a
2015-01-17 09:59:25 -08:00
Brad Miller
e614217d41 New netconsole-host that overwrites the old one on every deploy
Change-Id: I9f9e94a67810b1b40b354a2bfc511f44a05b858a
2015-01-16 21:03:52 -05:00
Kevin O'Connor
9b7042a51a Fix errors in Vision examples.
Change-Id: I752a99ff7b8872a0fc8926e3633c2b521383bbd0
2015-01-16 15:35:48 -05:00
Brad Miller (WPI)
081d7f7361 Merge "Applied updated DIOJNI file from Ron Rossbach. Fixes artf3982." 2015-01-16 07:36:17 -08:00
Brad Miller (WPI)
352c021b17 Merge "Updated the Java CameraServer to use the new USBCamera and prevent large camera data copies. Fixed a small bug in USBCamera to prevent reinitializing a camera if it is already initialized. Also fixed some issues with the getJpegSize function to correct for Java incorrectly casting 0xff to an integer, and the byte buffer limit being set incorrectly." 2015-01-16 07:35:32 -08:00
Brad Miller (WPI)
5f90bf167e Merge "Enable nivision Java wrappers to be generated with Python 3." 2015-01-16 07:35:17 -08:00
Brad Miller (WPI)
445eafefb3 Merge "More Java nivision wrapper fixes." 2015-01-16 07:34:33 -08:00
Brad Miller (WPI)
a917f63e7d Merge "2015 Color and Retroreflective vision samples for C++ and Java" 2015-01-16 07:33:21 -08:00
Brad Miller (WPI)
2228361f39 Merge "Add SetCANJaguarSyncGroup to RobotDrive" 2015-01-16 07:32:57 -08:00
Fredric Silberberg
aaa599fa28 Updated the Java CameraServer to use the new USBCamera and prevent large
camera data copies. Fixed a small bug in USBCamera to prevent
reinitializing a camera if it is already initialized. Also fixed some
issues with the getJpegSize function to correct for Java incorrectly
casting 0xff to an integer, and the byte buffer limit being set incorrectly.

Change-Id: I184efd265c617b02523dd9c5d347cc7ca5b4a77b
2015-01-15 19:27:00 -05:00
Peter Johnson
5d95bbb33f Enable nivision Java wrappers to be generated with Python 3.
Change-Id: I8ce57874e4730ed10dd0093c147b14c22f141201
2015-01-15 00:04:23 -08:00
Peter Johnson
d0258923e8 More Java nivision wrapper fixes.
- Fix sliceByteBuffer, getBytes, and putBytes implementations, which had
  functional errors.  Also, getBytes and putBytes now use the ByteBuffer
  get/put byte[] functions, which should improve performance.

- Don't generate wrappers for functions that are not available in the
  shared library.

Change-Id: Iaf45814b34720d3fdcd58adf99ad9c3ff2703bc3
2015-01-14 23:49:37 -08:00
Kevin O'Connor
91ccc5d10b 2015 Color and Retroreflective vision samples for C++ and Java
Change-Id: Id95925ced100b25d591c40995bb016780737312d
2015-01-14 12:45:17 -05:00
Brad Miller (WPI)
9fda920055 Merge "Add @file annotation so files are picked up in doxygen" 2015-01-14 07:54:34 -08:00
Brad Miller (WPI)
e9dd72ac77 Merge changes I0ec40c14,I4d099e62
* changes:
  nivision Java wrappers: implement our own error text function.
  Fix a few major nivision Java wrapper issues.
2015-01-14 07:53:48 -08:00
Brad Miller (WPI)
cce1bbc1f2 Merge "Update to point to Gazebo3.2 header location." 2015-01-14 07:41:18 -08:00
Peter Johnson
9fc79c41d1 nivision Java wrappers: implement our own error text function.
Change-Id: I0ec40c143b1c5a5fff8495643f83ad494ab32e57
2015-01-14 01:08:29 -08:00
Joe Ross
1dba916887 Add @file annotation so files are picked up in doxygen
Change-Id: Ie2e0bdd23d29dbf91600a25e3c0ae0228519b41a
2015-01-13 22:44:54 -08:00
Peter Johnson
ce7a56284f Fix a few major nivision Java wrapper issues.
- sliceByteBuffer() was not setting native order on the duplicated buffer.
  This caused all array-copyin functions to generate bad values.
- Correctly handle unsigned byte and unsigned short values.  These could
  read/write to bad locations previously.
- Implement custom version of imaqReadFile() to always pass in NULL for
  the colorTable.  Eventually a more-complete version should be written.

Also this works around a crash in imaqGetErrorText() by not calling it from
throwJavaException().  It's not clear why imaqGetErrorText() is crashing at
present (my best guess is there's still something fishy with multiple C++
lib versions getting loaded somehow), as this used to work.  Instead,
the exception now just gives the error code without the error message,
which is not user friendly but at least doesn't crash.  This will be fixed
in a future commit by creating our own version of imaqGetErrorText() based
on the information available in the header file.

Change-Id: I4d099e62ee41f8e2a50089806561be191cb5d9d7
2015-01-13 22:18:17 -08:00
Joe Ross
34d515debb Make sure Utility file is included in doxygen output.
Fixes http://www.chiefdelphi.com/forums/showpost.php?p=1427109&postcount=3

Change-Id: I716cd6be21980945c4a7846f5c32e50e040be3e9
2015-01-12 22:44:02 -08:00
Brad Miller (WPI)
cff103d15e Merge "Add encoder indexing in Java" 2015-01-12 12:48:39 -08:00
Brad Miller (WPI)
1b5cabc0d1 Merge "Add encoder indexing support in C++" 2015-01-12 12:48:23 -08:00
Brad Miller (WPI)
9fcfc5b3b7 Merge "Added the C++ implementation of Peter Johnson's UsbCamera. Rewrote CameraServer to use the new USBCamera implementation and get rid of some unnecessary copying of the entire image." 2015-01-12 10:45:57 -08:00
Brad Miller (WPI)
f181c70134 Merge "Add USBCamera class." 2015-01-12 10:45:41 -08:00
Brad Miller (WPI)
46c40da539 Merge "NIVision: Add dx functions." 2015-01-12 10:45:20 -08:00
Brad Miller (WPI)
1c05a982e1 Merge "Synchronize CANTalon documentation between languages." 2015-01-12 10:43:37 -08:00
Thomas Clark
ba7f56833b Add SetCANJaguarSyncGroup to RobotDrive
Manually specifying a sync group causes that value to be
passed in all of the speed controller Set() calls, and
CANJaguar::UpdateSyncGroup() to be called afterwards.

Change-Id: I365216463e3dd57b3fafb1bed898fb0da4b08793
2015-01-12 01:27:53 -05:00
Fredric Silberberg
7600473da6 Applied updated DIOJNI file from Ron Rossbach. Fixes artf3982.
Change-Id: Ibf20e833d7ab5b1ca80239ad5b8bb116c1624fca
2015-01-11 14:34:26 -05:00
Peter Johnson
9f04b79580 Fix Timer.hasPeriodPassed().
It was incorrectly using seconds instead of milliseconds.

Change-Id: Iecd2802c548caee4a5185f00a2b785143d6b1b16
2015-01-11 01:55:33 -08:00
Fredric Silberberg
2282a11a79 Added the C++ implementation of Peter Johnson's UsbCamera.
Rewrote CameraServer to use the new USBCamera implementation and get rid
of some unnecessary copying of the entire image.

Change-Id: I877750e990b6159c0aaf829df62b253a171fbada
2015-01-09 14:39:47 -05:00
Peter Johnson
1a2344bddc Add USBCamera class.
Change-Id: Ie7dfa679d9eeb7d55613ac1694a63ce70161d76c
2015-01-08 21:14:32 -08:00
Fred Silberberg (WPI)
ae9a7d19f1 Merge "Miscellaneous AnalogTrigger fixes" 2015-01-08 14:07:45 -08:00
Fred Silberberg (WPI)
e1141b9f27 Merge "Disable C optimize setting so better C++ doc is generated" 2015-01-08 13:47:10 -08:00
Fred Silberberg (WPI)
ff71aca572 Merge "Update docs to add missing channel numbers" 2015-01-08 13:44:32 -08:00
Fred Silberberg (WPI)
837671e95f Merge "Document that PDP must be address 0 and add/fix measurement units" 2015-01-08 13:43:36 -08:00
Fred Silberberg (WPI)
38c0308fc7 Merge "Correct path of sfx so that it can be launched from eclipse menu" 2015-01-08 13:42:43 -08:00
Thomas Clark
f21e4a9da5 Miscellaneous AnalogTrigger fixes
AnalogTrigger.createOutput is now public.  It was mistakenly made
package local before.

The AnalogTriggerType enum now uses the same naming convension
as other enumerations in WPILib.  There's no way that this breaks
existing code, since AnalogTrigger.createOutput wasn't public before
this commit.

Change-Id: I9a2b921a996012f61dac0e395602f8cc429d7611
2015-01-08 00:31:36 -05:00
Thomas Clark
e13720bb94 Add encoder indexing in Java
Change-Id: I7d6a7da4301703aafab9d63ce67b6c88c62647c9
2015-01-08 00:23:32 -05:00
Joe Ross
0cf7d6f457 Update docs to add missing channel numbers
Change-Id: I2ffcc84c4801c5bd1062b74f36dd35e06b4834e6
2015-01-07 20:15:26 -08:00
Thomas Clark
a2dfffeddc Add encoder indexing support in C++
Java will be done tonight or tomorrow

Change-Id: I3a3287a197b6f071c261172eb8ec930693e8b3c7
2015-01-07 00:06:45 -05:00
Brad Miller
87e1df068c Fixed a null pointer exception in the mecanum drive sample program (Fixes artf3974)
Change-Id: I9518cd49ca815b9e1dc3ab63b7a4ee7034e5b444
2015-01-05 17:34:13 -05:00
Peter Johnson
f19c290fde NIVision: Add dx functions.
This includes getters, setters, video mode enumerate, and get image data.

These are necessary to improve the CameraServer code performance.

Also clean up unused return generation.

Change-Id: I3e7365e046d0ea9370586c5158138a5b07e20218
2015-01-05 01:11:49 -08:00
Joe Ross
5c342a8e1a Document that PDP must be address 0 and add/fix measurement units
Change-Id: I4864e3242d8a19ad3dfb7740f23632e2b939ca90
2015-01-02 16:08:19 -08:00
Joe Ross
f7117aac4b Correct path of sfx so that it can be launched from eclipse menu
Change-Id: I54f35d480afbe1d356ee5a55e8c04e62f94ee757
2015-01-02 15:41:04 -08:00
Alex Henning
05cd0627b2 Update to point to Gazebo3.2 header location.
Change-Id: Ifebb31a375e8b7a6136115748c3634757fb732b8
2015-01-02 18:34:35 -05:00
Joe Ross
2bc83bd80a Disable C optimize setting so better C++ doc is generated
Change-Id: I9cc98c83f47013e174835a6e418c49305ef360e5
2014-12-31 20:03:44 -08:00
Joe Ross
79fbbbc0dd Synchronize CANTalon documentation between languages.
Still lots of documentation needed.

Change-Id: I122d00fb0f4a9f57f3d479749ec02b2249856d2b
2014-12-31 19:18:52 -08:00
Brad Miller (WPI)
359a155915 Merge "Make 3 axis Accelerometers work in LiveWindow. Fixes artf3902." 2014-12-30 21:05:26 -08:00
Brad Miller
fb7f5e9de8 Add methods to retreive the FPGA index for counters and encoders and return the encoding type as an integer
Change-Id: Iaa4062ec124b968b27e7c812cc754032fcb354d2

Add methods to retrieve the FPGA index for counters and encoders and return the encoding type as an integer

Change-Id: If04dc291f39a9b331495d2b97a8b87d3ded71280
2014-12-30 23:23:04 -05:00
Joe Ross
7db63055f6 Make 3 axis Accelerometers work in LiveWindow. Fixes artf3902.
Change-Id: Iced12b3c408b0d7b8fe822a9f17a7992293bae7d
2014-12-30 19:59:25 -08:00
Thomas Clark (WPI)
b94341a23e Merge "Update nivision JNI generator to correctly gen Priv_ReadJPEGString_C." 2014-12-30 14:18:00 -08:00
Peter Johnson
afbd70d393 Update nivision JNI generator to correctly gen Priv_ReadJPEGString_C.
Change-Id: I206da9f3f660b4d567a3b535702b70e5f967b071
2014-12-30 13:24:30 -08:00
Joe Ross
ceccd95084 Add PDP to LiveWindow for C++
Change-Id: I45967739b81090e809b9e8f1c31ad7ff58554ec1
2014-12-30 12:31:35 -08:00
Brad Miller (WPI)
91b9812482 Merge "Add PDP LiveWindow code" 2014-12-30 11:57:28 -08:00
Brad Miller
0dbc40e515 Added missing .java file
Change-Id: I96aa235960bc59f435b7b1b55a29462f8f8052e4
2014-12-30 14:35:06 -05:00
Brad Miller
5ce89b3382 Added a Java AxisCamera sample program
Change-Id: Iba0eb9f06a91f577323cefd695f8dd601a96db97
2014-12-30 10:27:20 -05:00
Thomas Clark
8ccf3d9c14 Add AxisCamera Java class
The API is basically the same as the C++ one.

The JNI function for Priv_ReadJPEGString_C was manually renamed, since the
python scripts don't name the C++ functions correctly, causing an
UnsatisfiedLinkError at runtime. If further changes are made to the bindings,
either the method will have to be manually renamed again after the code is
regenerated, or the python scripts will have to be updated.

The old ignored edu.wpi.first.wpilibj.camera package was removed.

Change-Id: Icd37fc15c7bb41061568c3b2f580c6765cbf0300
2014-12-30 02:17:03 -05:00
Joe Ross
230fa2d168 Add PDP LiveWindow code
Change-Id: Ia3f4d8118d9068d021994fd2e5aca676d7dfa979
2014-12-29 21:10:21 -08:00
Joe Ross
d165f57e6e Clean up misc documentation
Change-Id: Ib0a4a7a389fb657d78d8b8bce4fcaeed67c3693d
2014-12-29 15:10:41 -08:00
Brad Miller (WPI)
2d15b6b03e Merge "Update Java install URL to the new URL with the java installer." 2014-12-29 13:38:47 -08:00
Brad Miller (WPI)
5d9baa44ee Merge changes Ie40db6c9,I0b5e752e
* changes:
  Write lib version from Java (fixes artf3788)
  Update Javadocs for Java (fixes artf3761 and artf3953)
2014-12-29 13:35:52 -08:00
Brad Miller (WPI)
822416d2f7 Merge "Write lib version from C++ (fixes artf3788)" 2014-12-29 13:35:04 -08:00
Brad Miller (WPI)
3fe726d851 Merge "Update docs for C++ (fixes artf3761 and artf3953)" 2014-12-29 13:26:13 -08:00
Kevin O'Connor
4c0b2c18ab Write lib version from Java (fixes artf3788)
Change-Id: Ie40db6c993d12aadb66b07fcfdc0a62b87a2e2ed
2014-12-29 16:06:11 -05:00
Kevin O'Connor
b4c5a3af77 Update Javadocs for Java (fixes artf3761 and artf3953)
Change-Id: I0b5e752e8f6377770163dcdc61aa79ad4c7cbe94
2014-12-29 16:02:07 -05:00
Kevin O'Connor
eddb0b20b0 Write lib version from C++ (fixes artf3788)
Change-Id: Ia11c2dab2050ffe4299d1ccd68c986573f0a05e3
2014-12-29 14:15:55 -05:00
Kevin O'Connor
6d8e782f53 Update docs for C++ (fixes artf3761 and artf3953)
Change-Id: Ic0c4ac8494cadff13461d9bb8b5943cd87619f0a
2014-12-29 14:09:37 -05:00
Joe Ross
0368322385 Update Camera templates to make C++ and Java more similar.
Include delays and template code from other examples to show how to use
these examples in a full robot program. Change Java example in example
finder to Simple Vision to match C++. Add comments about how to find cam
number and change default to cam0.

Change-Id: I85846ccfaf016c538a750b057a7fd766cdff9447
2014-12-29 13:48:11 -05:00
Joe Ross
19e05ff52b Update Java install URL to the new URL with the java installer.
Change-Id: Id554d0e2251d9efd7f06466bd2e093602911dc54
2014-12-28 20:23:48 -08:00
Brad Miller (WPI)
a6aef54ef4 Merge "Axis camera C++ example program" 2014-12-28 13:15:54 -08:00
Brad Miller
32f3bea465 Axis camera C++ example program
Change-Id: I60a14ce91fc09831b497ccdaaa7bb1bb26c8d945
2014-12-28 15:47:08 -05:00
Brad Miller (WPI)
9aacf5eb29 Merge "Artifact artf3925 : PCM : Can't find any user facing java/C++ API for getting/clearing PCM faults" 2014-12-28 10:58:12 -08:00
Thomas Clark
f3484686c9 Fix some typos in AxixCamera.cpp
There were some mistakes in comments left over from copying and pasting
comments from pre-2015 code, a couple formatting issues, and one getter
that wasn't implemented

Change-Id: I2e9d19be15445717cce175902c42e7e0932b56ad
2014-12-28 02:31:17 -05:00
Brad Miller (WPI)
b78b14bf5f Merge "Add AxisCamera C++ class" 2014-12-27 19:37:49 -08:00
Brad Miller (WPI)
c08dc98650 Merge "Add the 2014 C++ vision classes back in" 2014-12-27 19:37:29 -08:00
Brad Miller (WPI)
9fbffd88cb Merge "Change the java intermediate vision filename to match c++" 2014-12-27 18:38:11 -08:00
Brad Miller
6c15a3600a Change the java intermediate vision filename to match c++
Change-Id: Iadd173a6ea6089203103f0ca9c220a0b4ff5b286
2014-12-27 21:35:33 -05:00
Omar Zrien
548941dd99 Artifact artf3925 : PCM : Can't find any user facing java/C++ API for getting/clearing PCM faults
Change-Id: If5cb5b08f685158c5317233c4d9bc8e688138df7
2014-12-26 19:40:39 -05:00
Thomas Clark
9d8418c14e Add AxisCamera C++ class
Change-Id: I927334753027b519214d7541497f6c7f6d698163
2014-12-26 16:36:55 -05:00
Brad Miller (WPI)
326bf4fc9c Merge "Updates the InterrupatableSensorBase documentation to reflect the bug described in artf3623." 2014-12-26 13:28:20 -08:00
Fredric Silberberg
3c4a1d9a1a NIVision Forward Port
Ported the NIVision libraries from the old NIVision implementation to
the new autogenerated JNI bindings.

Change-Id: I7c68ca6abef1185d59a9787e9a269d720c825e2f
2014-12-24 16:39:46 -05:00
Fredric Silberberg
7687028269 Updates the InterrupatableSensorBase documentation to reflect the bug
described in artf3623.

Change-Id: I5f93dea65202cf30ba67c063eb8c90bedbfe43ae
2014-12-24 14:19:01 -05:00
Brad Miller
a55f34646d Encoder/Counter Fixes
This fixes all encoder variants with the getRate and getPeriod methods.
The clock speed in the HAL was updated, as was the scaling factors for setting
the stall periods. A default of .5 seconds is now set for the max period.
Additionally, a long standing bug was fixed with Java 2x encoders.

Changed tests to take into account the increased default timeout on encoders

Change-Id: I8b54c07ea467154be94d7ae7e9ada1775933dee4
2014-12-23 20:13:41 -05:00
Thomas Clark
53473e21be Add the 2014 C++ vision classes back in
Most of the old vision code still compiles with minimal changes. I haven't
tested it extensively, since the AxisCamera class isn't done, but it
should work, as it was barely modified.

Java bindings are still TODO, since they used some JNA stuff that probably
won't work now.

Change-Id: I8edf991410cb30b932379f277cee9d329ee35009
2014-12-23 17:42:14 -05:00
Brad Miller (WPI)
b4097fbd58 Merge "ClearStickyFaults() should not take a param, just clears sticky flags in a one shot manner. GetCompressorFault() => GetCompressorCurrentTooHighFault() There are now three compressor related faults so getters needed to be more verbose. New getters()... GetCompressorCurrentTooHighStickyFault GetCompressorShortedStickyFault GetCompressorShortedFault GetCompressorNotConnectedStickyFault GetCompressorNotConnectedFault" 2014-12-22 09:20:31 -08:00
Brad Miller (WPI)
3b72114555 Merge "Fix imports on vision examples so they compile. Fix Typo." 2014-12-22 09:16:42 -08:00
Brad Miller (WPI)
cc36454b90 Merge "Add C interface for CanTalonSRX::SetModeSelect(modeSelect, demand)." 2014-12-22 08:45:10 -08:00
Omar Zrien
aae20ddbff Artifact artf3945 : CANTalon : Motor Safety Object never feed
Change-Id: I6894399d0eb7c36ff698639862fa6ad045a70db8
2014-12-21 16:47:03 -05:00
Joe Ross
ffd9061766 Fix imports on vision examples so they compile. Fix Typo.
Change-Id: I1d6ebf47c824fa93d8a312882cddc778f340009e
2014-12-20 20:47:09 -08:00
Peter Johnson
9ffdea188b Add C interface for CanTalonSRX::SetModeSelect(modeSelect, demand).
Change-Id: Ic8305ec283ddb89afc60d6bc5226411b1f8cc18b
2014-12-20 12:46:05 -08:00
Patrick Plenefisch
46dc99a115 Adding SFX to tools zip
Change-Id: I09a04506682a5d0ccbe8e556285de587915f7383
2014-12-19 09:52:25 -08:00
Brad Miller (WPI)
91d714d2e9 Merge "Single line bug in CanTalonSRX::GetAnalogInVel(). return value was not being sign-extended." 2014-12-19 07:02:09 -08:00
Brad Miller (WPI)
9a28aaaa7c Merge "Change expected voltage on CAN tests" 2014-12-19 07:01:20 -08:00
Omar Zrien
96a76ba89e Single line bug in CanTalonSRX::GetAnalogInVel(). return value was not being sign-extended.
Change-Id: I44271726ece9aaa7b94f35e611f24a18dbb53825
2014-12-19 03:27:29 -05:00
Brad Miller
d26059a4fb Change expected voltage on CAN tests
Change-Id: I8c4533c7bcc81e7904d10792316382d4c01a840a
2014-12-18 21:22:31 -05:00
Brad Miller
ee0d835304 Remove an extra constructor from a bad merge
Change-Id: I0475eef143814ebf8ee4ec71a019872420442c4f
2014-12-18 18:28:15 -05:00
James Kuszmaul
6080a3b186 Duplicate of gerrit 739; changed method from public to private.
Change-Id: Ib15210ff0e5d8d99a649397499bab4737a1a489e
2014-12-18 16:08:46 -05:00
Omar Zrien
3d06a763a2 CanTalon : Adding config routines for limit switch normally open vs normally closed.
They already existed in Labview, so this will keep parity
New C++/Java funcs
ConfigFwdLimitSwitchNormallyOpen
ConfigRevLimitSwitchNormallyOpen

Change-Id: Ifd65ead827838e7158f7261c67adc3738c72eabf
2014-12-18 15:57:26 -05:00
Omar Zrien
e1480ec798 Noticed that if changeControlMode() is called every teleop loop, it causes motor to stutter as it enters and immediately leaves kDisabled.
A simple improvement was to only perform the disable-before-next-set strategy if the caller's request mode is not equal to the current mode.

To keep things simple, SetControlMode was renamed to private method ApplyControlMode so we can still invoke it from c'tor.
Then, the new impl'n of SetControlMode() just calls ApplyControlMode() when caller's request mode is different.  That takes care of direct-calls from team source, and indirect calls through enableControl().

Applied to both c++ and java.
Tested in java so far...

Change-Id: I934c06c5339d933918470659acd635e12eb4d113
2014-12-18 15:54:47 -05:00
Omar Zrien
a5d9ba412c Second pass through all the HAL functions and cpp/java API. Filled in some parity holes between java and cpp.
Java...
added setStatusFrameRateMs() to modify the frame rate for status frames
added missing func that already exists in c++
	isFwdLimitSwitchClosed()
	isRevLimitSwitchClosed()
	getNumberOfQuadIdxRises()
	getPinStateQuadA()
	getPinStateQuadB()
	getPinStateQuadIdx()
added getAnalogInRaw() that doesn't count overflows (for potentiometers).
added setStatusFrameRateMs() to modify the frame rate for status frames
added getBrakeEnableDuringNeutral()

C++...
added GetAnalogInRaw() that doesn't count overflows (for potentiometers).
added SetStatusFrameRateMs() to modify the frame rate for status frames
added GetBrakeEnableDuringNeutral()
added kLimitMode_SrxDisableSwitchInputs to CANSpeedController::LimitMode

Patch set 2: Joe Ross, fixed two javadoc errors

Change-Id: I0bf871e138953de60eeacb547dc359f2125b1327
2014-12-18 15:51:47 -05:00
Omar Zrien
2434515d41 artf3913
Increased wait delay to 4ms to cover worst case delays for solicted signal getters.
Specifically....
-Get firmware vers
-Get P,I,D,F gains
-Get IZone, Get CloseLoopRampRate
-Get IAccum (integral accumulator)

Change-Id: I313ea984832cce5182af8e5af5e775837fd54fdc
2014-12-18 15:49:29 -05:00
Brad Miller (WPI)
741618250b Merge "C++ CANTalon was missing SetIzone. Added SetIzone to match java, and made the set/get Izone integral." 2014-12-18 12:45:34 -08:00
Omar Zrien
8b8d7e77cd C++ CANTalon was missing SetIzone. Added SetIzone to match java, and made the set/get Izone integral.
Change-Id: I264ac8faaab0ebd208062923f6da2094e7e28b0a
2014-12-18 15:16:10 -05:00
Omar Zrien
c093a553ee changed variable type of closeLoopRampRate in setpid to double from int. It's represents V per sec since it calls setCloseLoopRampRate() underneath.
The other remaining closeloopramprate changes are also merged into this commit, so they may be redundant on gerrit.

Change-Id: Ic3108bb3669e487009b8f52412da3c2f44c42f6f
2014-12-18 15:11:39 -05:00
Fred Silberberg (WPI)
a1375e58cd Merge "Don't fail silently if DIO or PWM allocation fails" 2014-12-18 11:25:39 -08:00
Brad Miller (WPI)
15ff7f5038 Merge "Added the getButtons method back that reads all the buttons at the same time" 2014-12-18 10:33:11 -08:00
Brad Miller
c17ba98f72 Added the getButtons method back that reads all the buttons at the same time
Change-Id: I0f7f35b6a70f861911166de7be3802547ff4b2eb
2014-12-18 10:57:11 -05:00
Brad Miller (WPI)
dee755ab19 Merge "renamed param to match function name." 2014-12-18 07:06:20 -08:00
Brad Miller (WPI)
92c54f5f5d Merge "Image v23" 2014-12-17 15:10:36 -08:00
Fred Silberberg (WPI)
1fde00643f Merge "Fixed post4066 bug: Prestart() inaccessible." 2014-12-17 14:19:03 -08:00
Colby Skeggs
47443b4e1e Fixed post4066 bug: Prestart() inaccessible.
Change-Id: Ie179453b038458e77257c1b2d0acba7a4224f6c4
2014-12-17 13:39:54 -08:00
PetaroMitaro
f01e5b5570 fixed robotCommand in src
Change-Id: I591939301da4427e9139b824b016bb00d4b24485
2014-12-17 16:11:48 -05:00
Omar Zrien
198e2eed14 ClearStickyFaults() should not take a param, just clears sticky flags in a one shot manner.
GetCompressorFault() => GetCompressorCurrentTooHighFault()
	There are now three compressor related faults so getters needed to be more verbose.
New getters()...
	GetCompressorCurrentTooHighStickyFault
	GetCompressorShortedStickyFault
	GetCompressorShortedFault
	GetCompressorNotConnectedStickyFault
	GetCompressorNotConnectedFault

Fire and forget api added. Likely not used any time soon, BUT having it ready in HAL is harmless.
	FireOneShotSolenoid()
	SetOneShotDurationMs()

Solenoid fuse and compressor current too high fault bits were flipped in decoder

Change-Id: Ib47dddddd8e4cc22149de1b583968d99919b00af
2014-12-17 15:05:46 -05:00
Fredric Silberberg
22c4207553 Image v23
This updates the image version to version 23. It also moves the vision libraries
to follow the same conventions as the rest of the ni libraries.

Change-Id: I39e6fb3d8bbd2fd3141c2a43a5bae2fd15149003
2014-12-17 11:04:21 -05:00
Omar Zrien
bea9eb0efa renamed param to match function name.
Change-Id: I89c483691e0f99a6d20bed1271209a8141e71c0e
2014-12-16 20:05:30 -05:00
Brad Miller (WPI)
b72eb4b812 Merge "added Java vision example programs" 2014-12-16 11:43:02 -08:00
Dustin Spicuzza
0d8c454727 Don't fail silently if DIO or PWM allocation fails
Change-Id: I800c429507c3436c2d49561ba279700ad52569fe
2014-12-16 14:24:14 -05:00
PetaroMitaro
d61d491a02 added Java vision example programs
Change-Id: Icd99f53cc544c2609a333f0a86f4eac064d565bd
2014-12-16 11:14:37 -05:00
Brad Miller (WPI)
786e844a9f Merge "Fix ControllerPower 5v faults and add javadocs. Fixes artf3918." 2014-12-16 08:07:30 -08:00
Joe Ross
170b5860ee Fix javadoc compile errors that broke build.
Change-Id: Ie110743154f842dc3a2e756f7917e3aa131c87bd
2014-12-15 19:03:27 -08:00
PetaroMitaro
26c50ebe02 fixed java CameraServer
Change-Id: I34b8c1e2ff05199afdcab579f7ac7188fbe40fd7
2014-12-15 19:45:56 -05:00
Joe Ross
46c659d6b6 Enable Java 8 doclint checking (except for missing tags).
Change-Id: Iebfc7b99cbe43375f9cc067cca322244af44395b
2014-12-15 15:50:44 -08:00
Joe Ross
6fdd491081 Fix javadoc warnings.
Change-Id: I37049f234c6dfddc138121822525794d74e1b74c
2014-12-15 18:48:46 -05:00
Fred Silberberg (WPI)
fe4535dfa0 Merge "Resolved artf3579: robot can no longer be enabled until robotInit() finishes in IterativeRobot; similar options available by overriding prestart() for other base classes." 2014-12-15 15:39:21 -08:00
Brad Miller
636e2e13ad Wrong package declaration in camera server
Change-Id: Ia35d7f78d37aa0db51eb98901364fc228dabaa53
2014-12-15 13:40:25 -05:00
PetaroMitaro
d3f5b74668 added CameraServer.java
Change-Id: I4c41b560d879ffc6d8aa4681cad8f75297fe6cda

Fixed some issues with the camera server class

Change-Id: Ifda524b55f84053be004a404a2890905ded7b266
2014-12-15 11:00:49 -05:00
Brad Miller (WPI)
8116bbd15b Merge "Fix various bugs in nivision wrappers." 2014-12-15 05:42:07 -08:00
Peter Johnson
37052246a5 Fix various bugs in nivision wrappers.
- IMAQdx typedef overrides were being ignored, resulting in incorrect types
(e.g. IMAQdxSession was a long instead of an int).

- Allocated byte buffers byte order was not being set.

- imaqDispose was incorrectly named.

Change-Id: I5d038d45e82755615f0a5bb928defb98f557f93e
2014-12-15 02:44:07 -08:00
Joe Ross
a649d3b553 Fix ControllerPower 5v faults and add javadocs. Fixes artf3918.
5V faults was returning count of 3.3V faults. Copied javadocs from
C++.

Change-Id: I95b5c6ed1213ed235ecde11ef7e28ad05aabca6e
2014-12-14 16:55:22 -08:00
Omar Zrien
6a7e7cf611 Two param constructor added to C++/java CANTalon so caller can optionally specify the periodMs at which the talon control frame is sent.
The param is capped in the HAL C++ class to [1ms, 95ms] so that zero and negative periods are caped to 1ms, and so that caller can't pass an absurdly large value, which causes TALON is appear disabled.

Change-Id: I4207194be25a33bbd6ad281a75301ce6684659a5
2014-12-14 17:09:52 -05:00
Colby Skeggs
1c24096cc9 Resolved artf3579: robot can no longer be enabled until robotInit() finishes in IterativeRobot; similar options available by overriding prestart() for other base classes.
Change-Id: I07fde4b1bd2fae0c2e2a04336639b44ec715628a
2014-12-14 01:22:41 +00:00
244 changed files with 13549 additions and 7189 deletions

2
.gitignore vendored
View File

@@ -15,6 +15,8 @@ wpilibj/wpilibJavaJNI/nivision/*.cpp
wpilibj/wpilibJavaJNI/nivision/*.s
wpilibj/wpilibJavaJNI/nivision/*_arm.ini
wpilibj/wpilibJavaJNI/nivision/*.java
wpilibj/wpilibJavaJNI/nivision/nivision_funcs.txt
wpilibj/wpilibJavaJNI/nivision/imaqdx_funcs.txt
# Created by the jenkins test script
test-reports

View File

@@ -85,6 +85,14 @@
<outputDirectory>${tools-zip}</outputDirectory>
<destFileName>SmartDashboard.jar</destFileName>
</artifactItem>
<artifactItem>
<groupId>edu.wpi.first.wpilib</groupId>
<artifactId>sfx</artifactId>
<type>zip</type>
<classifier>zip</classifier>
<outputDirectory>${tools-zip}/../</outputDirectory>
<destFileName>sfx.zip</destFileName>
</artifactItem>
<artifactItem>
<groupId>edu.wpi.first.wpilib.networktables</groupId>
<artifactId>OutlineViewer</artifactId>
@@ -143,6 +151,7 @@
</goals>
<configuration>
<target>
<unzip src="${tools-zip}/../sfx.zip" dest="${tools-zip}"/>
<zip destfile="${project.build.directory}/classes/resources/tools.zip"
basedir="${tools-zip}"
update="true" />
@@ -208,6 +217,12 @@
<artifactId>SmartDashboard</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>edu.wpi.first.wpilib</groupId>
<artifactId>sfx</artifactId>
<type>zip</type>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>edu.wpi.first.wpilib.networktables</groupId>
<artifactId>OutlineViewer</artifactId>

View File

@@ -34,7 +34,7 @@ public class RunSFXDashboardAction implements IWorkbenchWindowActionDelegate {
* @see IWorkbenchWindowActionDelegate#run
*/
public void run(IAction action) {
File dir = new File(WPILibCore.getDefault().getWPILibBaseDir()+File.separator+"tools");
File dir = new File(WPILibCore.getDefault().getWPILibBaseDir()+File.separator+"tools"+File.separator+"sfx-2014.11.01");
File[] files = dir.listFiles(new FilenameFilter() {
@Override public boolean accept(File dir, String name) {
return name.startsWith("sfx") && name.endsWith(".jar");

View File

@@ -81,7 +81,7 @@
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/src&quot;"/>
<listOptionValue builtIn="false" value="${WPILIB}/cpp/current/sim/include"/>
<listOptionValue builtIn="false" value="/usr/include"/>
<listOptionValue builtIn="false" value="/usr/include/gazebo-3.1"/>
<listOptionValue builtIn="false" value="/usr/include/gazebo-3.2"/>
<listOptionValue builtIn="false" value="/usr/include/sdformat-2.2"/>
</option>
<option id="gnu.cpp.compiler.option.optimization.level.1648211502" name="Optimization Level" superClass="gnu.cpp.compiler.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>

View File

@@ -0,0 +1,237 @@
#include "WPILib.h"
#include <vector>
#include <cmath>
/**
* Example of finding yellow totes based on color.
* This example utilizes an image file, which you need to copy to the roboRIO
* To use a camera you will have to integrate the appropriate camera details with this example.
* To use a USB camera instead, see the IntermediateVision example for details
* on using the USB camera. To use an Axis Camera, see the AxisCamera example for details on
* using an Axis Camera.
*
* Sample images can be found here: http://wp.wpi.edu/wpilib/2015/01/16/sample-images-for-vision-projects/
*/
class VisionColor2015Sample : public SampleRobot
{
//A structure to hold measurements of a particle
struct ParticleReport {
double PercentAreaToImageArea;
double Area;
double ConvexHullArea;
double BoundingRectLeft;
double BoundingRectTop;
double BoundingRectRight;
double BoundingRectBottom;
};
//Structure to represent the scores for the various tests used for target identification
struct Scores {
double Trapezoid;
double LongAspect;
double ShortAspect;
double AreaToConvexHullArea;
};
//Images
Image *frame;
Image *binaryFrame;
int imaqError;
//Constants
Range TOTE_HUE_RANGE = {24, 49}; //Default hue range for yellow tote
Range TOTE_SAT_RANGE = {67, 255}; //Default saturation range for yellow tote
Range TOTE_VAL_RANGE = {49, 255}; //Default value range for yellow tote
double AREA_MINIMUM = 2; //Default Area minimum for particle as a percentage of total image area
double LONG_RATIO = 2.22; //Tote long side = 26.9 / Tote height = 12.1 = 2.22
double SHORT_RATIO = 1.4; //Tote short side = 16.9 / Tote height = 12.1 = 1.4
double SCORE_MIN = 75.0; //Minimum score to be considered a tote
double VIEW_ANGLE = 49.4; //View angle fo camera, set to Axis m1011 by default, 64 for m1013, 51.7 for 206, 52 for HD3000 square, 60 for HD3000 640x480
ParticleFilterCriteria2 criteria[1];
ParticleFilterOptions2 filterOptions = {0,0,1,1};
Scores scores;
public:
void RobotInit() override {
// create images
frame = imaqCreateImage(IMAQ_IMAGE_RGB, 0);
binaryFrame = imaqCreateImage(IMAQ_IMAGE_U8, 0);
//Put default values to SmartDashboard so fields will appear
SmartDashboard::PutNumber("Tote hue min", TOTE_HUE_RANGE.minValue);
SmartDashboard::PutNumber("Tote hue max", TOTE_HUE_RANGE.maxValue);
SmartDashboard::PutNumber("Tote sat min", TOTE_SAT_RANGE.minValue);
SmartDashboard::PutNumber("Tote sat max", TOTE_SAT_RANGE.maxValue);
SmartDashboard::PutNumber("Tote val min", TOTE_VAL_RANGE.minValue);
SmartDashboard::PutNumber("Tote val max", TOTE_VAL_RANGE.maxValue);
SmartDashboard::PutNumber("Area min %", AREA_MINIMUM);
}
void Autonomous() override {
while (IsAutonomous() && IsEnabled())
{
//read file in from disk. For this example to run you need to copy image20.jpg from the SampleImages folder to the
//directory shown below using FTP or SFTP: http://wpilib.screenstepslive.com/s/4485/m/24166/l/282299-roborio-ftp
imaqError = imaqReadFile(frame, "//home//lvuser//SampleImages//image20.jpg", NULL, NULL);
//Update threshold values from SmartDashboard. For performance reasons it is recommended to remove this after calibration is finished.
TOTE_HUE_RANGE.minValue = SmartDashboard::GetNumber("Tote hue min", TOTE_HUE_RANGE.minValue);
TOTE_HUE_RANGE.maxValue = SmartDashboard::GetNumber("Tote hue max", TOTE_HUE_RANGE.maxValue);
TOTE_SAT_RANGE.minValue = SmartDashboard::GetNumber("Tote sat min", TOTE_SAT_RANGE.minValue);
TOTE_SAT_RANGE.maxValue = SmartDashboard::GetNumber("Tote sat max", TOTE_SAT_RANGE.maxValue);
TOTE_VAL_RANGE.minValue = SmartDashboard::GetNumber("Tote val min", TOTE_VAL_RANGE.minValue);
TOTE_VAL_RANGE.maxValue = SmartDashboard::GetNumber("Tote val max", TOTE_VAL_RANGE.maxValue);
//Threshold the image looking for yellow (tote color)
imaqError = imaqColorThreshold(binaryFrame, frame, 255, IMAQ_HSV, &TOTE_HUE_RANGE, &TOTE_SAT_RANGE, &TOTE_VAL_RANGE);
//Send particle count to dashboard
int numParticles = 0;
imaqError = imaqCountParticles(binaryFrame, 1, &numParticles);
SmartDashboard::PutNumber("Masked particles", numParticles);
//Send masked image to dashboard to assist in tweaking mask.
SendToDashboard(binaryFrame, imaqError);
//filter out small particles
float areaMin = SmartDashboard::GetNumber("Area min %", AREA_MINIMUM);
criteria[0] = {IMAQ_MT_AREA_BY_IMAGE_AREA, areaMin, 100, false, false};
imaqError = imaqParticleFilter4(binaryFrame, binaryFrame, criteria, 1, &filterOptions, NULL, NULL);
//Send particle count after filtering to dashboard
imaqError = imaqCountParticles(binaryFrame, 1, &numParticles);
SmartDashboard::PutNumber("Filtered particles", numParticles);
if(numParticles > 0)
{
//Measure particles and sort by particle size
std::vector<ParticleReport> particles;
for(int particleIndex = 0; particleIndex < numParticles; particleIndex++)
{
ParticleReport par;
imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_AREA_BY_IMAGE_AREA, &(par.PercentAreaToImageArea));
imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_AREA, &(par.Area));
imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_CONVEX_HULL_AREA, &(par.ConvexHullArea));
imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_BOUNDING_RECT_TOP, &(par.BoundingRectTop));
imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_BOUNDING_RECT_LEFT, &(par.BoundingRectLeft));
imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_BOUNDING_RECT_BOTTOM, &(par.BoundingRectBottom));
imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_BOUNDING_RECT_RIGHT, &(par.BoundingRectRight));
particles.push_back(par);
}
sort(particles.begin(), particles.end(), CompareParticleSizes);
//This example only scores the largest particle. Extending to score all particles and choosing the desired one is left as an exercise
//for the reader. Note that the long and short side scores expect a single tote and will not work for a stack of 2 or more totes.
//Modification of the code to accommodate 2 or more stacked totes is left as an exercise for the reader.
scores.Trapezoid = TrapezoidScore(particles.at(0));
SmartDashboard::PutNumber("Trapezoid", scores.Trapezoid);
scores.LongAspect = LongSideScore(particles.at(0));
SmartDashboard::PutNumber("Long Aspect", scores.LongAspect);
scores.ShortAspect = ShortSideScore(particles.at(0));
SmartDashboard::PutNumber("Short Aspect", scores.ShortAspect);
scores.AreaToConvexHullArea = ConvexHullAreaScore(particles.at(0));
SmartDashboard::PutNumber("Convex Hull Area", scores.AreaToConvexHullArea);
bool isTote = scores.Trapezoid > SCORE_MIN && (scores.LongAspect > SCORE_MIN || scores.ShortAspect > SCORE_MIN) && scores.AreaToConvexHullArea > SCORE_MIN;
bool isLong = scores.LongAspect > scores.ShortAspect;
//Send distance and tote status to dashboard. The bounding rect, particularly the horizontal center (left - right) may be useful for rotating/driving towards a tote
SmartDashboard::PutBoolean("IsTote", isTote);
SmartDashboard::PutNumber("Distance", computeDistance(binaryFrame, particles.at(0), isLong));
} else {
SmartDashboard::PutBoolean("IsTote", false);
}
Wait(0.005); // wait for a motor update time
}
}
void OperatorControl() override {
while(IsOperatorControl() && IsEnabled()) {
Wait(0.005); // wait for a motor update time
}
}
//Send image to dashboard if IMAQ has not thrown an error
void SendToDashboard(Image *image, int error)
{
if(error < ERR_SUCCESS) {
DriverStation::ReportError("Send To Dashboard error: " + std::to_string((long)imaqError) + "\n");
} else {
CameraServer::GetInstance()->SetImage(image);
}
}
//Comparator function for sorting particles. Returns true if particle 1 is larger
static bool CompareParticleSizes(ParticleReport particle1, ParticleReport particle2)
{
//we want descending sort order
return particle1.PercentAreaToImageArea > particle2.PercentAreaToImageArea;
}
/**
* Converts a ratio with ideal value of 1 to a score. The resulting function is piecewise
* linear going from (0,0) to (1,100) to (2,0) and is 0 for all inputs outside the range 0-2
*/
double ratioToScore(double ratio)
{
return (fmax(0, fmin(100*(1-fabs(1-ratio)), 100)));
}
/**
* Method to score convex hull area. This scores how "complete" the particle is. Particles with large holes will score worse than a filled in shape
*/
double ConvexHullAreaScore(ParticleReport report)
{
return ratioToScore((report.Area/report.ConvexHullArea)*1.18);
}
/**
* Method to score if the particle appears to be a trapezoid. Compares the convex hull (filled in) area to the area of the bounding box.
* The expectation is that the convex hull area is about 95.4% of the bounding box area for an ideal tote.
*/
double TrapezoidScore(ParticleReport report)
{
return ratioToScore(report.ConvexHullArea/((report.BoundingRectRight-report.BoundingRectLeft)*(report.BoundingRectBottom-report.BoundingRectTop)*.954));
}
/**
* Method to score if the aspect ratio of the particle appears to match the long side of a tote.
*/
double LongSideScore(ParticleReport report)
{
return ratioToScore(((report.BoundingRectRight-report.BoundingRectLeft)/(report.BoundingRectBottom-report.BoundingRectTop))/LONG_RATIO);
}
/**
* Method to score if the aspect ratio of the particle appears to match the short side of a tote.
*/
double ShortSideScore(ParticleReport report){
return ratioToScore(((report.BoundingRectRight-report.BoundingRectLeft)/(report.BoundingRectBottom-report.BoundingRectTop))/SHORT_RATIO);
}
/**
* Computes the estimated distance to a target using the width of the particle in the image. For more information and graphics
* showing the math behind this approach see the Vision Processing section of the ScreenStepsLive documentation.
*
* @param image The image to use for measuring the particle estimated rectangle
* @param report The Particle Analysis Report for the particle
* @param isLong Boolean indicating if the target is believed to be the long side of a tote
* @return The estimated distance to the target in feet.
*/
double computeDistance (Image *image, ParticleReport report, bool isLong) {
double normalizedWidth, targetWidth;
int xRes, yRes;
imaqGetImageSize(image, &xRes, &yRes);
normalizedWidth = 2*(report.BoundingRectRight - report.BoundingRectLeft)/xRes;
SmartDashboard::PutNumber("Width", normalizedWidth);
targetWidth = isLong ? 26.9 : 16.9;
return targetWidth/(normalizedWidth*12*tan(VIEW_ANGLE*M_PI/(180*2)));
}
};
START_ROBOT_CLASS(VisionColor2015Sample);

View File

@@ -0,0 +1,210 @@
#include "WPILib.h"
#include <vector>
#include <cmath>
/**
* Example of finding yellow totes based on retroreflective target.
* This example utilizes an image file, which you need to copy to the roboRIO
* To use a camera you will have to integrate the appropriate camera details with this example.
* To use a USB camera instead, see the IntermediateVision example for details
* on using the USB camera. To use an Axis Camera, see the AxisCamera example for details on
* using an Axis Camera.
*
* Sample images can be found here: http://wp.wpi.edu/wpilib/2015/01/16/sample-images-for-vision-projects/
*/
class VisionRetro2015Sample : public SampleRobot
{
//A structure to hold measurements of a particle
struct ParticleReport {
double PercentAreaToImageArea;
double Area;
double BoundingRectLeft;
double BoundingRectTop;
double BoundingRectRight;
double BoundingRectBottom;
};
//Structure to represent the scores for the various tests used for target identification
struct Scores {
double Area;
double Aspect;
};
//Images
Image *frame;
Image *binaryFrame;
int imaqError;
//Constants
Range RING_HUE_RANGE = {101, 64}; //Default hue range for ring light
Range RING_SAT_RANGE = {88, 255}; //Default saturation range for ring light
Range RING_VAL_RANGE = {134, 255}; //Default value range for ring light
double AREA_MINIMUM = 0.5; //Default Area minimum for particle as a percentage of total image area
double LONG_RATIO = 2.22; //Tote long side = 26.9 / Tote height = 12.1 = 2.22
double SHORT_RATIO = 1.4; //Tote short side = 16.9 / Tote height = 12.1 = 1.4
double SCORE_MIN = 75.0; //Minimum score to be considered a tote
double VIEW_ANGLE = 49.4; //View angle fo camera, set to Axis m1011 by default, 64 for m1013, 51.7 for 206, 52 for HD3000 square, 60 for HD3000 640x480
ParticleFilterCriteria2 criteria[1];
ParticleFilterOptions2 filterOptions = {0,0,1,1};
Scores scores;
public:
void RobotInit() override {
// create images
frame = imaqCreateImage(IMAQ_IMAGE_RGB, 0);
binaryFrame = imaqCreateImage(IMAQ_IMAGE_U8, 0);
//Put default values to SmartDashboard so fields will appear
SmartDashboard::PutNumber("Tote hue min", RING_HUE_RANGE.minValue);
SmartDashboard::PutNumber("Tote hue max", RING_HUE_RANGE.maxValue);
SmartDashboard::PutNumber("Tote sat min", RING_SAT_RANGE.minValue);
SmartDashboard::PutNumber("Tote sat max", RING_SAT_RANGE.maxValue);
SmartDashboard::PutNumber("Tote val min", RING_VAL_RANGE.minValue);
SmartDashboard::PutNumber("Tote val max", RING_VAL_RANGE.maxValue);
SmartDashboard::PutNumber("Area min %", AREA_MINIMUM);
}
void Autonomous() override {
while (IsAutonomous() && IsEnabled())
{
//read file in from disk. For this example to run you need to copy image.jpg from the SampleImages folder to the
//directory shown below using FTP or SFTP: http://wpilib.screenstepslive.com/s/4485/m/24166/l/282299-roborio-ftp
imaqError = imaqReadFile(frame, "//home//lvuser//SampleImages//image.jpg", NULL, NULL);
//Update threshold values from SmartDashboard. For performance reasons it is recommended to remove this after calibration is finished.
RING_HUE_RANGE.minValue = SmartDashboard::GetNumber("Tote hue min", RING_HUE_RANGE.minValue);
RING_HUE_RANGE.maxValue = SmartDashboard::GetNumber("Tote hue max", RING_HUE_RANGE.maxValue);
RING_SAT_RANGE.minValue = SmartDashboard::GetNumber("Tote sat min", RING_SAT_RANGE.minValue);
RING_SAT_RANGE.maxValue = SmartDashboard::GetNumber("Tote sat max", RING_SAT_RANGE.maxValue);
RING_VAL_RANGE.minValue = SmartDashboard::GetNumber("Tote val min", RING_VAL_RANGE.minValue);
RING_VAL_RANGE.maxValue = SmartDashboard::GetNumber("Tote val max", RING_VAL_RANGE.maxValue);
//Threshold the image looking for ring light color
imaqError = imaqColorThreshold(binaryFrame, frame, 255, IMAQ_HSV, &RING_HUE_RANGE, &RING_SAT_RANGE, &RING_VAL_RANGE);
//Send particle count to dashboard
int numParticles = 0;
imaqError = imaqCountParticles(binaryFrame, 1, &numParticles);
SmartDashboard::PutNumber("Masked particles", numParticles);
//Send masked image to dashboard to assist in tweaking mask.
SendToDashboard(binaryFrame, imaqError);
//filter out small particles
float areaMin = SmartDashboard::GetNumber("Area min %", AREA_MINIMUM);
criteria[0] = {IMAQ_MT_AREA_BY_IMAGE_AREA, areaMin, 100, false, false};
imaqError = imaqParticleFilter4(binaryFrame, binaryFrame, criteria, 1, &filterOptions, NULL, NULL);
//Send particle count after filtering to dashboard
imaqError = imaqCountParticles(binaryFrame, 1, &numParticles);
SmartDashboard::PutNumber("Filtered particles", numParticles);
if(numParticles > 0) {
//Measure particles and sort by particle size
std::vector<ParticleReport> particles;
for(int particleIndex = 0; particleIndex < numParticles; particleIndex++)
{
ParticleReport par;
imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_AREA_BY_IMAGE_AREA, &(par.PercentAreaToImageArea));
imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_AREA, &(par.Area));
imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_BOUNDING_RECT_TOP, &(par.BoundingRectTop));
imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_BOUNDING_RECT_LEFT, &(par.BoundingRectLeft));
imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_BOUNDING_RECT_BOTTOM, &(par.BoundingRectBottom));
imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_BOUNDING_RECT_RIGHT, &(par.BoundingRectRight));
particles.push_back(par);
}
sort(particles.begin(), particles.end(), CompareParticleSizes);
//This example only scores the largest particle. Extending to score all particles and choosing the desired one is left as an exercise
//for the reader. Note that this scores and reports information about a single particle (single L shaped target). To get accurate information
//about the location of the tote (not just the distance) you will need to correlate two adjacent targets in order to find the true center of the tote.
scores.Aspect = AspectScore(particles.at(0));
SmartDashboard::PutNumber("Aspect", scores.Aspect);
scores.Area = AreaScore(particles.at(0));
SmartDashboard::PutNumber("Area", scores.Area);
bool isTarget = scores.Area > SCORE_MIN && scores.Aspect > SCORE_MIN;
//Send distance and tote status to dashboard. The bounding rect, particularly the horizontal center (left - right) may be useful for rotating/driving towards a tote
SmartDashboard::PutBoolean("IsTarget", isTarget);
SmartDashboard::PutNumber("Distance", computeDistance(binaryFrame, particles.at(0)));
} else {
SmartDashboard::PutBoolean("IsTarget", false);
}
Wait(0.005); // wait for a motor update time
}
}
void OperatorControl() override {
while(IsOperatorControl() && IsEnabled()) {
Wait(0.005); // wait for a motor update time
}
}
//Send image to dashboard if IMAQ has not thrown an error
void SendToDashboard(Image *image, int error)
{
if(error < ERR_SUCCESS) {
DriverStation::ReportError("Send To Dashboard error: " + std::to_string((long)imaqError) + "\n");
} else {
CameraServer::GetInstance()->SetImage(binaryFrame);
}
}
//Comparator function for sorting particles. Returns true if particle 1 is larger
static bool CompareParticleSizes(ParticleReport particle1, ParticleReport particle2)
{
//we want descending sort order
return particle1.PercentAreaToImageArea > particle2.PercentAreaToImageArea;
}
/**
* Converts a ratio with ideal value of 1 to a score. The resulting function is piecewise
* linear going from (0,0) to (1,100) to (2,0) and is 0 for all inputs outside the range 0-2
*/
double ratioToScore(double ratio)
{
return (fmax(0, fmin(100*(1-fabs(1-ratio)), 100)));
}
double AreaScore(ParticleReport report)
{
double boundingArea = (report.BoundingRectBottom - report.BoundingRectTop) * (report.BoundingRectRight - report.BoundingRectLeft);
//Tape is 7" edge so 49" bounding rect. With 2" wide tape it covers 24" of the rect.
return ratioToScore((49/24)*report.Area/boundingArea);
}
/**
* Method to score if the aspect ratio of the particle appears to match the retro-reflective target. Target is 7"x7" so aspect should be 1
*/
double AspectScore(ParticleReport report)
{
return ratioToScore(((report.BoundingRectRight-report.BoundingRectLeft)/(report.BoundingRectBottom-report.BoundingRectTop)));
}
/**
* Computes the estimated distance to a target using the width of the particle in the image. For more information and graphics
* showing the math behind this approach see the Vision Processing section of the ScreenStepsLive documentation.
*
* @param image The image to use for measuring the particle estimated rectangle
* @param report The Particle Analysis Report for the particle
* @return The estimated distance to the target in feet.
*/
double computeDistance (Image *image, ParticleReport report) {
double normalizedWidth, targetWidth;
int xRes, yRes;
imaqGetImageSize(image, &xRes, &yRes);
normalizedWidth = 2*(report.BoundingRectRight - report.BoundingRectLeft)/xRes;
SmartDashboard::PutNumber("Width", normalizedWidth);
targetWidth = 7;
return targetWidth/(normalizedWidth*12*tan(VIEW_ANGLE*M_PI/(180*2)));
}
};
START_ROBOT_CLASS(VisionRetro2015Sample);

View File

@@ -0,0 +1,37 @@
#include "WPILib.h"
/**
* Uses AxisCamera class to manually acquire a new image each frame, and annotate the image by drawing
* a circle on it, and show it on the FRC Dashboard.
*/
class AxisCameraSample : public SampleRobot
{
IMAQdxSession session;
Image *frame;
IMAQdxError imaqError;
AxisCamera *camera;
public:
void RobotInit() override {
// create an image
frame = imaqCreateImage(IMAQ_IMAGE_RGB, 0);
// open the camera at the IP address assigned. This is the IP address that the camera
// can be accessed through the web interface.
camera = new AxisCamera("10.1.91.103");
}
void OperatorControl() override {
// grab an image, draw the circle, and provide it for the camera server which will
// in turn send it to the dashboard.
while(IsOperatorControl() && IsEnabled()) {
camera->GetImage(frame);
imaqDrawShapeOnImage(frame, frame, { 10, 10, 100, 100 }, DrawMode::IMAQ_DRAW_VALUE, ShapeMode::IMAQ_SHAPE_OVAL, 0.0f);
CameraServer::GetInstance()->SetImage(frame);
Wait(0.05);
}
}
};
START_ROBOT_CLASS(AxisCameraSample);

View File

@@ -14,7 +14,7 @@ public:
void RobotInit() override {
// create an image
frame = imaqCreateImage(IMAQ_IMAGE_RGB, 0);
// open the camera
//the camera name (ex "cam0") can be found through the roborio web interface
imaqError = IMAQdxOpenCamera("cam0", IMAQdxCameraControlModeController, &session);
if(imaqError != IMAQdxErrorSuccess) {
DriverStation::ReportError("IMAQdxOpenCamera error: " + std::to_string((long)imaqError) + "\n");
@@ -39,6 +39,7 @@ public:
imaqDrawShapeOnImage(frame, frame, { 10, 10, 100, 100 }, DrawMode::IMAQ_DRAW_VALUE, ShapeMode::IMAQ_SHAPE_OVAL, 0.0f);
CameraServer::GetInstance()->SetImage(frame);
}
Wait(0.005); // wait for a motor update time
}
// stop image acquisition
IMAQdxStopAcquisition(session);

View File

@@ -10,11 +10,18 @@ class QuickVisionRobot : public SampleRobot
{
public:
void RobotInit() override {
CameraServer::GetInstance()->SetQuality(75);
CameraServer::GetInstance()->StartAutomaticCapture();
CameraServer::GetInstance()->SetQuality(50);
//the camera name (ex "cam0") can be found through the roborio web interface
CameraServer::GetInstance()->StartAutomaticCapture("cam0");
}
void OperatorControl() override {
void OperatorControl()
{
while (IsOperatorControl() && IsEnabled())
{
/** robot code here! **/
Wait(0.005); // wait for a motor update time
}
}
};

View File

@@ -281,7 +281,7 @@
</example>
<example>
<name>Simple vision program</name>
<name>Simple Vision</name>
<description>The minimal program to acquire images from an attached USB camera on the robot
and send them to the dashboard.</description>
<tags>
@@ -298,7 +298,7 @@
</example>
<example>
<name>Intermediate vision</name>
<name>Intermediate Vision</name>
<description>An example program that acquires images from an attached USB camera and adds some
annotation to the image as you might do for showing operators the result of some image
recognition, and sends it to the dashboard for display.
@@ -316,6 +316,65 @@
</files>
</example>
<example>
<name>Axis Camera Sample</name>
<description>An example program that acquires images from an Axis network camera and adds some
annotation to the image as you might do for showing operators the result of some image
recognition, and sends it to the dashboard for display. This demonstrates the use of the
AxisCamera class.
</description>
<tags>
<tag>Vision</tag>
<tag>Complete List</tag>
</tags>
<packages>
<package>src</package>
</packages>
<files>
<file source="examples/AxisCameraSample/src/Robot.cpp"
destination="src/Robot.cpp"></file>
</files>
</example>
<example>
<name>2015 Vision Color Sample</name>
<description>An example program that demonstrates image processing to locate Yellow totes by color.
This example uses a file which must be copied over to the roboRIO via FTP to demonstrate processing.
To use this code with a camera, you must integrate the code for image acquisition from the appropriate
camera example;
</description>
<tags>
<tag>Vision</tag>
<tag>Complete List</tag>
</tags>
<packages>
<package>src</package>
</packages>
<files>
<file source="examples/2015Vision/Color_src/Robot.cpp"
destination="src/Robot.cpp"></file>
</files>
</example>
<example>
<name>2015 Vision Retro Sample</name>
<description>An example program that demonstrates image processing to locate Yellow totes by the retroreflective target.
This example uses a file which must be copied over to the roboRIO via FTP to demonstrate processing.
To use this code with a camera, you must integrate the code for image acquisition from the appropriate
camera example;
</description>
<tags>
<tag>Vision</tag>
<tag>Complete List</tag>
</tags>
<packages>
<package>src</package>
</packages>
<files>
<file source="examples/2015Vision/Retro_src/Robot.cpp"
destination="src/Robot.cpp"></file>
</files>
</example>
<example>
<name>GearsBot</name>

View File

@@ -8,7 +8,7 @@ command.dir=/home/lvuser/
# Libraries to use
wpilib=${user.home}/wpilib/cpp/${cpp-version}
wpilib.lib=${wpilib}/lib
roboRIOAllowedImages=22
roboRIOAllowedImages=23
# Ant support
wpilib.ant.dir=${wpilib}/ant

View File

@@ -64,6 +64,15 @@
<echo>[athena-deploy] Copying code over.</echo>
<scp file="${out.exe}" sftp="true" todir="${username}@${target}:${deploy.dir}" password="${password}" trust="true"/>
<sshexec host="${target}"
username="admin"
password="${password}"
trust="true"
failonerror="false"
command="killall netconsole-host"/>
<scp file="${wpilib.ant.dir}/netconsole-host" todir="admin@${target}:/usr/local/frc/bin" password="${password}" trust="true"/>
<scp file="${wpilib.ant.dir}/robotCommand" todir="${username}@${target}:/home/lvuser/" password="${password}" trust="true"/>
<echo>[athena-deploy] Starting program.</echo>

View File

@@ -0,0 +1,240 @@
package $package;
import java.lang.Math;
import java.util.Comparator;
import java.util.Vector;
import com.ni.vision.NIVision;
import com.ni.vision.NIVision.Image;
import com.ni.vision.NIVision.ImageType;
import edu.wpi.first.wpilibj.CameraServer;
import edu.wpi.first.wpilibj.SampleRobot;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
/**
* Example of finding yellow totes based on color.
* This example utilizes an image file, which you need to copy to the roboRIO
* To use a camera you will have to integrate the appropriate camera details with this example.
* To use a USB camera instead, see the SimpelVision and AdvancedVision examples for details
* on using the USB camera. To use an Axis Camera, see the AxisCamera example for details on
* using an Axis Camera.
*
* Sample omages can be found here: http://wp.wpi.edu/wpilib/2015/01/16/sample-images-for-vision-projects/
*/
public class Robot extends SampleRobot {
//A structure to hold measurements of a particle
public class ParticleReport implements Comparator<ParticleReport>, Comparable<ParticleReport>{
double PercentAreaToImageArea;
double Area;
double ConvexHullArea;
double BoundingRectLeft;
double BoundingRectTop;
double BoundingRectRight;
double BoundingRectBottom;
public int compareTo(ParticleReport r)
{
return (int)(r.Area - this.Area);
}
public int compare(ParticleReport r1, ParticleReport r2)
{
return (int)(r1.Area - r2.Area);
}
};
//Structure to represent the scores for the various tests used for target identification
public class Scores {
double Trapezoid;
double LongAspect;
double ShortAspect;
double AreaToConvexHullArea;
};
//Images
Image frame;
Image binaryFrame;
int imaqError;
//Constants
NIVision.Range TOTE_HUE_RANGE = new NIVision.Range(24, 49); //Default hue range for yellow tote
NIVision.Range TOTE_SAT_RANGE = new NIVision.Range(67, 255); //Default saturation range for yellow tote
NIVision.Range TOTE_VAL_RANGE = new NIVision.Range(49, 255); //Default value range for yellow tote
double AREA_MINIMUM = 0.5; //Default Area minimum for particle as a percentage of total image area
double LONG_RATIO = 2.22; //Tote long side = 26.9 / Tote height = 12.1 = 2.22
double SHORT_RATIO = 1.4; //Tote short side = 16.9 / Tote height = 12.1 = 1.4
double SCORE_MIN = 75.0; //Minimum score to be considered a tote
double VIEW_ANGLE = 49.4; //View angle fo camera, set to Axis m1011 by default, 64 for m1013, 51.7 for 206, 52 for HD3000 square, 60 for HD3000 640x480
NIVision.ParticleFilterCriteria2 criteria[] = new NIVision.ParticleFilterCriteria2[1];
NIVision.ParticleFilterOptions2 filterOptions = new NIVision.ParticleFilterOptions2(0,0,1,1);
Scores scores = new Scores();
public void robotInit() {
// create images
frame = NIVision.imaqCreateImage(ImageType.IMAGE_RGB, 0);
binaryFrame = NIVision.imaqCreateImage(ImageType.IMAGE_U8, 0);
criteria[0] = new NIVision.ParticleFilterCriteria2(NIVision.MeasurementType.MT_AREA_BY_IMAGE_AREA, AREA_MINIMUM, 100.0, 0, 0);
//Put default values to SmartDashboard so fields will appear
SmartDashboard.putNumber("Tote hue min", TOTE_HUE_RANGE.minValue);
SmartDashboard.putNumber("Tote hue max", TOTE_HUE_RANGE.maxValue);
SmartDashboard.putNumber("Tote sat min", TOTE_SAT_RANGE.minValue);
SmartDashboard.putNumber("Tote sat max", TOTE_SAT_RANGE.maxValue);
SmartDashboard.putNumber("Tote val min", TOTE_VAL_RANGE.minValue);
SmartDashboard.putNumber("Tote val max", TOTE_VAL_RANGE.maxValue);
SmartDashboard.putNumber("Area min %", AREA_MINIMUM);
}
public void autonomous() {
while (isAutonomous() && isEnabled())
{
//read file in from disk. For this example to run you need to copy image20.jpg from the SampleImages folder to the
//directory shown below using FTP or SFTP: http://wpilib.screenstepslive.com/s/4485/m/24166/l/282299-roborio-ftp
NIVision.imaqReadFile(frame, "/home/lvuser/SampleImages/image20.jpg");
//Update threshold values from SmartDashboard. For performance reasons it is recommended to remove this after calibration is finished.
TOTE_HUE_RANGE.minValue = (int)SmartDashboard.getNumber("Tote hue min", TOTE_HUE_RANGE.minValue);
TOTE_HUE_RANGE.maxValue = (int)SmartDashboard.getNumber("Tote hue max", TOTE_HUE_RANGE.maxValue);
TOTE_SAT_RANGE.minValue = (int)SmartDashboard.getNumber("Tote sat min", TOTE_SAT_RANGE.minValue);
TOTE_SAT_RANGE.maxValue = (int)SmartDashboard.getNumber("Tote sat max", TOTE_SAT_RANGE.maxValue);
TOTE_VAL_RANGE.minValue = (int)SmartDashboard.getNumber("Tote val min", TOTE_VAL_RANGE.minValue);
TOTE_VAL_RANGE.maxValue = (int)SmartDashboard.getNumber("Tote val max", TOTE_VAL_RANGE.maxValue);
//Threshold the image looking for yellow (tote color)
NIVision.imaqColorThreshold(binaryFrame, frame, 255, NIVision.ColorMode.HSV, TOTE_HUE_RANGE, TOTE_SAT_RANGE, TOTE_VAL_RANGE);
//Send particle count to dashboard
int numParticles = NIVision.imaqCountParticles(binaryFrame, 1);
SmartDashboard.putNumber("Masked particles", numParticles);
//Send masked image to dashboard to assist in tweaking mask.
CameraServer.getInstance().setImage(binaryFrame);
//filter out small particles
float areaMin = (float)SmartDashboard.getNumber("Area min %", AREA_MINIMUM);
criteria[0].lower = areaMin;
imaqError = NIVision.imaqParticleFilter4(binaryFrame, binaryFrame, criteria, filterOptions, null);
//Send particle count after filtering to dashboard
numParticles = NIVision.imaqCountParticles(binaryFrame, 1);
SmartDashboard.putNumber("Filtered particles", numParticles);
if(numParticles > 0)
{
//Measure particles and sort by particle size
Vector<ParticleReport> particles = new Vector<ParticleReport>();
for(int particleIndex = 0; particleIndex < numParticles; particleIndex++)
{
ParticleReport par = new ParticleReport();
par.PercentAreaToImageArea = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_AREA_BY_IMAGE_AREA);
par.Area = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_AREA);
par.ConvexHullArea = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_CONVEX_HULL_AREA);
par.BoundingRectTop = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_BOUNDING_RECT_TOP);
par.BoundingRectLeft = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_BOUNDING_RECT_LEFT);
par.BoundingRectBottom = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_BOUNDING_RECT_BOTTOM);
par.BoundingRectRight = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_BOUNDING_RECT_RIGHT);
particles.add(par);
}
particles.sort(null);
//This example only scores the largest particle. Extending to score all particles and choosing the desired one is left as an exercise
//for the reader. Note that the long and short side scores expect a single tote and will not work for a stack of 2 or more totes.
//Modification of the code to accommodate 2 or more stacked totes is left as an exercise for the reader.
scores.Trapezoid = TrapezoidScore(particles.elementAt(0));
SmartDashboard.putNumber("Trapezoid", scores.Trapezoid);
scores.LongAspect = LongSideScore(particles.elementAt(0));
SmartDashboard.putNumber("Long Aspect", scores.LongAspect);
scores.ShortAspect = ShortSideScore(particles.elementAt(0));
SmartDashboard.putNumber("Short Aspect", scores.ShortAspect);
scores.AreaToConvexHullArea = ConvexHullAreaScore(particles.elementAt(0));
SmartDashboard.putNumber("Convex Hull Area", scores.AreaToConvexHullArea);
boolean isTote = scores.Trapezoid > SCORE_MIN && (scores.LongAspect > SCORE_MIN || scores.ShortAspect > SCORE_MIN) && scores.AreaToConvexHullArea > SCORE_MIN;
boolean isLong = scores.LongAspect > scores.ShortAspect;
//Send distance and tote status to dashboard. The bounding rect, particularly the horizontal center (left - right) may be useful for rotating/driving towards a tote
SmartDashboard.putBoolean("IsTote", isTote);
SmartDashboard.putNumber("Distance", computeDistance(binaryFrame, particles.elementAt(0), isLong));
} else {
SmartDashboard.putBoolean("IsTote", false);
}
Timer.delay(0.005); // wait for a motor update time
}
}
public void operatorControl() {
while(isOperatorControl() && isEnabled()) {
Timer.delay(0.005); // wait for a motor update time
}
}
//Comparator function for sorting particles. Returns true if particle 1 is larger
static boolean CompareParticleSizes(ParticleReport particle1, ParticleReport particle2)
{
//we want descending sort order
return particle1.PercentAreaToImageArea > particle2.PercentAreaToImageArea;
}
/**
* Converts a ratio with ideal value of 1 to a score. The resulting function is piecewise
* linear going from (0,0) to (1,100) to (2,0) and is 0 for all inputs outside the range 0-2
*/
double ratioToScore(double ratio)
{
return (Math.max(0, Math.min(100*(1-Math.abs(1-ratio)), 100)));
}
/**
* Method to score convex hull area. This scores how "complete" the particle is. Particles with large holes will score worse than a filled in shape
*/
double ConvexHullAreaScore(ParticleReport report)
{
return ratioToScore((report.Area/report.ConvexHullArea)*1.18);
}
/**
* Method to score if the particle appears to be a trapezoid. Compares the convex hull (filled in) area to the area of the bounding box.
* The expectation is that the convex hull area is about 95.4% of the bounding box area for an ideal tote.
*/
double TrapezoidScore(ParticleReport report)
{
return ratioToScore(report.ConvexHullArea/((report.BoundingRectRight-report.BoundingRectLeft)*(report.BoundingRectBottom-report.BoundingRectTop)*.954));
}
/**
* Method to score if the aspect ratio of the particle appears to match the long side of a tote.
*/
double LongSideScore(ParticleReport report)
{
return ratioToScore(((report.BoundingRectRight-report.BoundingRectLeft)/(report.BoundingRectBottom-report.BoundingRectTop))/LONG_RATIO);
}
/**
* Method to score if the aspect ratio of the particle appears to match the short side of a tote.
*/
double ShortSideScore(ParticleReport report){
return ratioToScore(((report.BoundingRectRight-report.BoundingRectLeft)/(report.BoundingRectBottom-report.BoundingRectTop))/SHORT_RATIO);
}
/**
* Computes the estimated distance to a target using the width of the particle in the image. For more information and graphics
* showing the math behind this approach see the Vision Processing section of the ScreenStepsLive documentation.
*
* @param image The image to use for measuring the particle estimated rectangle
* @param report The Particle Analysis Report for the particle
* @param isLong Boolean indicating if the target is believed to be the long side of a tote
* @return The estimated distance to the target in feet.
*/
double computeDistance (Image image, ParticleReport report, boolean isLong) {
double normalizedWidth, targetWidth;
NIVision.GetImageSizeResult size;
size = NIVision.imaqGetImageSize(image);
normalizedWidth = 2*(report.BoundingRectRight - report.BoundingRectLeft)/size.width;
targetWidth = isLong ? 26.0 : 16.9;
return targetWidth/(normalizedWidth*12*Math.tan(VIEW_ANGLE*Math.PI/(180*2)));
}
}

View File

@@ -0,0 +1,214 @@
package $package;
import java.lang.Math;
import java.util.Comparator;
import java.util.Vector;
import com.ni.vision.NIVision;
import com.ni.vision.NIVision.Image;
import com.ni.vision.NIVision.ImageType;
import edu.wpi.first.wpilibj.CameraServer;
import edu.wpi.first.wpilibj.SampleRobot;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
/**
* Example of finding yellow totes based on retroreflective target.
* This example utilizes an image file, which you need to copy to the roboRIO
* To use a camera you will have to integrate the appropriate camera details with this example.
* To use a USB camera instead, see the SimpelVision and AdvancedVision examples for details
* on using the USB camera. To use an Axis Camera, see the AxisCamera example for details on
* using an Axis Camera.
*
* Sample images can found here: http://wp.wpi.edu/wpilib/2015/01/16/sample-images-for-vision-projects/
*/
public class Robot extends SampleRobot {
//A structure to hold measurements of a particle
public class ParticleReport implements Comparator<ParticleReport>, Comparable<ParticleReport>{
double PercentAreaToImageArea;
double Area;
double BoundingRectLeft;
double BoundingRectTop;
double BoundingRectRight;
double BoundingRectBottom;
public int compareTo(ParticleReport r)
{
return (int)(r.Area - this.Area);
}
public int compare(ParticleReport r1, ParticleReport r2)
{
return (int)(r1.Area - r2.Area);
}
};
//Structure to represent the scores for the various tests used for target identification
public class Scores {
double Area;
double Aspect;
};
//Images
Image frame;
Image binaryFrame;
int imaqError;
//Constants
NIVision.Range TOTE_HUE_RANGE = new NIVision.Range(101, 64); //Default hue range for yellow tote
NIVision.Range TOTE_SAT_RANGE = new NIVision.Range(88, 255); //Default saturation range for yellow tote
NIVision.Range TOTE_VAL_RANGE = new NIVision.Range(134, 255); //Default value range for yellow tote
double AREA_MINIMUM = 0.5; //Default Area minimum for particle as a percentage of total image area
double LONG_RATIO = 2.22; //Tote long side = 26.9 / Tote height = 12.1 = 2.22
double SHORT_RATIO = 1.4; //Tote short side = 16.9 / Tote height = 12.1 = 1.4
double SCORE_MIN = 75.0; //Minimum score to be considered a tote
double VIEW_ANGLE = 49.4; //View angle fo camera, set to Axis m1011 by default, 64 for m1013, 51.7 for 206, 52 for HD3000 square, 60 for HD3000 640x480
NIVision.ParticleFilterCriteria2 criteria[] = new NIVision.ParticleFilterCriteria2[1];
NIVision.ParticleFilterOptions2 filterOptions = new NIVision.ParticleFilterOptions2(0,0,1,1);
Scores scores = new Scores();
public void robotInit() {
// create images
frame = NIVision.imaqCreateImage(ImageType.IMAGE_RGB, 0);
binaryFrame = NIVision.imaqCreateImage(ImageType.IMAGE_U8, 0);
criteria[0] = new NIVision.ParticleFilterCriteria2(NIVision.MeasurementType.MT_AREA_BY_IMAGE_AREA, AREA_MINIMUM, 100.0, 0, 0);
//Put default values to SmartDashboard so fields will appear
SmartDashboard.putNumber("Tote hue min", TOTE_HUE_RANGE.minValue);
SmartDashboard.putNumber("Tote hue max", TOTE_HUE_RANGE.maxValue);
SmartDashboard.putNumber("Tote sat min", TOTE_SAT_RANGE.minValue);
SmartDashboard.putNumber("Tote sat max", TOTE_SAT_RANGE.maxValue);
SmartDashboard.putNumber("Tote val min", TOTE_VAL_RANGE.minValue);
SmartDashboard.putNumber("Tote val max", TOTE_VAL_RANGE.maxValue);
SmartDashboard.putNumber("Area min %", AREA_MINIMUM);
}
public void autonomous() {
while (isAutonomous() && isEnabled())
{
//read file in from disk. For this example to run you need to copy image.jpg from the SampleImages folder to the
//directory shown below using FTP or SFTP: http://wpilib.screenstepslive.com/s/4485/m/24166/l/282299-roborio-ftp
NIVision.imaqReadFile(frame, "/home/lvuser/SampleImages/image.jpg");
//Update threshold values from SmartDashboard. For performance reasons it is recommended to remove this after calibration is finished.
TOTE_HUE_RANGE.minValue = (int)SmartDashboard.getNumber("Tote hue min", TOTE_HUE_RANGE.minValue);
TOTE_HUE_RANGE.maxValue = (int)SmartDashboard.getNumber("Tote hue max", TOTE_HUE_RANGE.maxValue);
TOTE_SAT_RANGE.minValue = (int)SmartDashboard.getNumber("Tote sat min", TOTE_SAT_RANGE.minValue);
TOTE_SAT_RANGE.maxValue = (int)SmartDashboard.getNumber("Tote sat max", TOTE_SAT_RANGE.maxValue);
TOTE_VAL_RANGE.minValue = (int)SmartDashboard.getNumber("Tote val min", TOTE_VAL_RANGE.minValue);
TOTE_VAL_RANGE.maxValue = (int)SmartDashboard.getNumber("Tote val max", TOTE_VAL_RANGE.maxValue);
//Threshold the image looking for yellow (tote color)
NIVision.imaqColorThreshold(binaryFrame, frame, 255, NIVision.ColorMode.HSV, TOTE_HUE_RANGE, TOTE_SAT_RANGE, TOTE_VAL_RANGE);
//Send particle count to dashboard
int numParticles = NIVision.imaqCountParticles(binaryFrame, 1);
SmartDashboard.putNumber("Masked particles", numParticles);
//Send masked image to dashboard to assist in tweaking mask.
CameraServer.getInstance().setImage(binaryFrame);
//filter out small particles
float areaMin = (float)SmartDashboard.getNumber("Area min %", AREA_MINIMUM);
criteria[0].lower = areaMin;
imaqError = NIVision.imaqParticleFilter4(binaryFrame, binaryFrame, criteria, filterOptions, null);
//Send particle count after filtering to dashboard
numParticles = NIVision.imaqCountParticles(binaryFrame, 1);
SmartDashboard.putNumber("Filtered particles", numParticles);
if(numParticles > 0)
{
//Measure particles and sort by particle size
Vector<ParticleReport> particles = new Vector<ParticleReport>();
for(int particleIndex = 0; particleIndex < numParticles; particleIndex++)
{
ParticleReport par = new ParticleReport();
par.PercentAreaToImageArea = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_AREA_BY_IMAGE_AREA);
par.Area = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_AREA);
par.BoundingRectTop = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_BOUNDING_RECT_TOP);
par.BoundingRectLeft = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_BOUNDING_RECT_LEFT);
par.BoundingRectBottom = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_BOUNDING_RECT_BOTTOM);
par.BoundingRectRight = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_BOUNDING_RECT_RIGHT);
particles.add(par);
}
particles.sort(null);
//This example only scores the largest particle. Extending to score all particles and choosing the desired one is left as an exercise
//for the reader. Note that this scores and reports information about a single particle (single L shaped target). To get accurate information
//about the location of the tote (not just the distance) you will need to correlate two adjacent targets in order to find the true center of the tote.
scores.Aspect = AspectScore(particles.elementAt(0));
SmartDashboard.putNumber("Aspect", scores.Aspect);
scores.Area = AreaScore(particles.elementAt(0));
SmartDashboard.putNumber("Area", scores.Area);
boolean isTote = scores.Aspect > SCORE_MIN && scores.Area > SCORE_MIN;
//Send distance and tote status to dashboard. The bounding rect, particularly the horizontal center (left - right) may be useful for rotating/driving towards a tote
SmartDashboard.putBoolean("IsTote", isTote);
SmartDashboard.putNumber("Distance", computeDistance(binaryFrame, particles.elementAt(0)));
} else {
SmartDashboard.putBoolean("IsTote", false);
}
Timer.delay(0.005); // wait for a motor update time
}
}
public void operatorControl() {
while(isOperatorControl() && isEnabled()) {
Timer.delay(0.005); // wait for a motor update time
}
}
//Comparator function for sorting particles. Returns true if particle 1 is larger
static boolean CompareParticleSizes(ParticleReport particle1, ParticleReport particle2)
{
//we want descending sort order
return particle1.PercentAreaToImageArea > particle2.PercentAreaToImageArea;
}
/**
* Converts a ratio with ideal value of 1 to a score. The resulting function is piecewise
* linear going from (0,0) to (1,100) to (2,0) and is 0 for all inputs outside the range 0-2
*/
double ratioToScore(double ratio)
{
return (Math.max(0, Math.min(100*(1-Math.abs(1-ratio)), 100)));
}
double AreaScore(ParticleReport report)
{
double boundingArea = (report.BoundingRectBottom - report.BoundingRectTop) * (report.BoundingRectRight - report.BoundingRectLeft);
//Tape is 7" edge so 49" bounding rect. With 2" wide tape it covers 24" of the rect.
return ratioToScore((49/24)*report.Area/boundingArea);
}
/**
* Method to score if the aspect ratio of the particle appears to match the retro-reflective target. Target is 7"x7" so aspect should be 1
*/
double AspectScore(ParticleReport report)
{
return ratioToScore(((report.BoundingRectRight-report.BoundingRectLeft)/(report.BoundingRectBottom-report.BoundingRectTop)));
}
/**
* Computes the estimated distance to a target using the width of the particle in the image. For more information and graphics
* showing the math behind this approach see the Vision Processing section of the ScreenStepsLive documentation.
*
* @param image The image to use for measuring the particle estimated rectangle
* @param report The Particle Analysis Report for the particle
* @param isLong Boolean indicating if the target is believed to be the long side of a tote
* @return The estimated distance to the target in feet.
*/
double computeDistance (Image image, ParticleReport report) {
double normalizedWidth, targetWidth;
NIVision.GetImageSizeResult size;
size = NIVision.imaqGetImageSize(image);
normalizedWidth = 2*(report.BoundingRectRight - report.BoundingRectLeft)/size.width;
targetWidth = 7;
return targetWidth/(normalizedWidth*12*Math.tan(VIEW_ANGLE*Math.PI/(180*2)));
}
}

View File

@@ -0,0 +1,55 @@
package $package;
import com.ni.vision.NIVision;
import com.ni.vision.NIVision.DrawMode;
import com.ni.vision.NIVision.Image;
import com.ni.vision.NIVision.ShapeMode;
import edu.wpi.first.wpilibj.CameraServer;
import edu.wpi.first.wpilibj.SampleRobot;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.vision.AxisCamera;
/**
* This demo shows the use of the AxisCamera class.
* Uses AxisCamera class to manually acquire a new image each frame, and annotate the image by drawing
* a circle on it, and show it on the FRC Dashboard.
*/
public class Robot extends SampleRobot {
int session;
Image frame;
AxisCamera camera;
public void robotInit() {
frame = NIVision.imaqCreateImage(NIVision.ImageType.IMAGE_RGB, 0);
// open the camera at the IP address assigned. This is the IP address that the camera
// can be accessed through the web interface.
camera = new AxisCamera("10.1.91.100");
}
public void operatorControl() {
/**
* grab an image from the camera, draw the circle, and provide it for the camera server
* which will in turn send it to the dashboard.
*/
NIVision.Rect rect = new NIVision.Rect(10, 10, 100, 100);
while (isOperatorControl() && isEnabled()) {
camera.getImage(frame);
NIVision.imaqDrawShapeOnImage(frame, frame, rect,
DrawMode.DRAW_VALUE, ShapeMode.SHAPE_OVAL, 0.0f);
CameraServer.getInstance().setImage(frame);
/** robot code here! **/
Timer.delay(0.005); // wait for a motor update time
}
}
public void test() {
}
}

View File

@@ -0,0 +1,57 @@
package $package;
import com.ni.vision.NIVision;
import com.ni.vision.NIVision.DrawMode;
import com.ni.vision.NIVision.Image;
import com.ni.vision.NIVision.ShapeMode;
import edu.wpi.first.wpilibj.CameraServer;
import edu.wpi.first.wpilibj.SampleRobot;
import edu.wpi.first.wpilibj.Timer;
/**
* This is a demo program showing the use of the NIVision class to do vision processing.
* The image is acquired from the USB Webcam, then a circle is overlayed on it.
* The NIVision class supplies dozens of methods for different types of processing.
* The resulting image can then be sent to the FRC PC Dashboard with setImage()
*/
public class Robot extends SampleRobot {
int session;
Image frame;
public void robotInit() {
frame = NIVision.imaqCreateImage(NIVision.ImageType.IMAGE_RGB, 0);
// the camera name (ex "cam0") can be found through the roborio web interface
session = NIVision.IMAQdxOpenCamera("cam0",
NIVision.IMAQdxCameraControlMode.CameraControlModeController);
NIVision.IMAQdxConfigureGrab(session);
}
public void operatorControl() {
NIVision.IMAQdxStartAcquisition(session);
/**
* grab an image, draw the circle, and provide it for the camera server
* which will in turn send it to the dashboard.
*/
NIVision.Rect rect = new NIVision.Rect(10, 10, 100, 100);
while (isOperatorControl() && isEnabled()) {
NIVision.IMAQdxGrab(session, frame, 1);
NIVision.imaqDrawShapeOnImage(frame, frame, rect,
DrawMode.DRAW_VALUE, ShapeMode.SHAPE_OVAL, 0.0f);
CameraServer.getInstance().setImage(frame);
/** robot code here! **/
Timer.delay(0.005); // wait for a motor update time
}
NIVision.IMAQdxStopAcquisition(session);
}
public void test() {
}
}

View File

@@ -25,10 +25,10 @@ public class Robot extends SampleRobot {
final int joystickChannel = 0;
public Robot() {
robotDrive.setExpiration(0.1);
robotDrive = new RobotDrive(frontLeftChannel, rearLeftChannel, frontRightChannel, rearRightChannel);
robotDrive.setInvertedMotor(MotorType.kFrontLeft, true); // invert the left side motors
robotDrive.setInvertedMotor(MotorType.kRearLeft, true); // you may need to change or remove this to match your robot
robotDrive.setExpiration(0.1);
stick = new Joystick(joystickChannel);
}

View File

@@ -0,0 +1,35 @@
package $package;
import edu.wpi.first.wpilibj.CameraServer;
import edu.wpi.first.wpilibj.SampleRobot;
import edu.wpi.first.wpilibj.Timer;
/**
* This is a demo program showing the use of the CameraServer class.
* With start automatic capture, there is no opportunity to process the image.
* Look at the IntermediateVision sample for how to process the image before sending it to the FRC PC Dashboard.
*/
public class Robot extends SampleRobot {
CameraServer server;
public Robot() {
server = CameraServer.getInstance();
server.setQuality(50);
//the camera name (ex "cam0") can be found through the roborio web interface
server.startAutomaticCapture("cam0");
}
/**
* start up automatic capture you should see the video stream from the
* webcam in your FRC PC Dashboard.
*/
public void operatorControl() {
while (isOperatorControl() && isEnabled()) {
/** robot code here! **/
Timer.delay(0.005); // wait for a motor update time
}
}
}

View File

@@ -81,12 +81,18 @@
<description>Example programs that demonstrate the use of the various commonly used sensors on FRC robots</description>
</tagDescription>
<tagDescription>
<name>Vision</name>
<description>Example programs that demonstrate the use of USB Cameras and image processing</description>
</tagDescription>
<example>
<name>Getting Started</name>
<description>An example program which demonstrates the simplest autonomous and
teleoperated routines.</description>
<tags>
<tag>Getting Started with Java</tag>
<tag>Complete List</tag>
</tags>
<packages>
<package>src/$package-dir</package>
@@ -287,4 +293,97 @@
destination="src/$package-dir/triggers/DoubleButton.java"></file>
</files>
</example>
<example>
<name>Simple Vision</name>
<description>Demonstrate the use of the CameraServer class to stream from a USB Webcam without processing the images.</description>
<tags>
<tag>Vision</tag>
<tag>Complete List</tag>
</tags>
<packages>
<package>src/$package-dir</package>
</packages>
<files>
<file source="examples/QuickVision/src/org/usfirst/frc/team190/robot/Robot.java"
destination="src/$package-dir/Robot.java"></file>
</files>
</example>
<example>
<name>Intermediate Vision</name>
<description>Demonstrate the use of the NIVision class to capture image from a Webcam, process them, and then send them to the dashboard.</description>
<tags>
<tag>Vision</tag>
<tag>Complete List</tag>
</tags>
<packages>
<package>src/$package-dir</package>
</packages>
<files>
<file source="examples/IntermediateVision/src/org/usfirst/frc/team190/robot/Robot.java"
destination="src/$package-dir/Robot.java"></file>
</files>
</example>
<example>
<name>2015 Vision Color Sample</name>
<description>An example program that demonstrates image processing to locate Yellow totes by color.
This example uses a file which must be copied over to the roboRIO via FTP to demonstrate processing.
To use this code with a camera, you must integrate the code for image acquisition from the appropriate
camera example;
</description>
<tags>
<tag>Vision</tag>
<tag>Complete List</tag>
</tags>
<packages>
<package>src/$package-dir</package>
</packages>
<files>
<file source="examples/2015Vision/Color_src/Robot.java"
destination="src/$package-dir/Robot.java"></file>
</files>
</example>
<example>
<name>2015 Vision Retro Sample</name>
<description>An example program that demonstrates image processing to locate Yellow totes by the retroreflective target.
This example uses a file which must be copied over to the roboRIO via FTP to demonstrate processing.
To use this code with a camera, you must integrate the code for image acquisition from the appropriate
camera example;
</description>
<tags>
<tag>Vision</tag>
<tag>Complete List</tag>
</tags>
<packages>
<package>src/$package-dir</package>
</packages>
<files>
<file source="examples/2015Vision/Retro_src/Robot.java"
destination="src/$package-dir/Robot.java"></file>
</files>
</example>
<example>
<name>Axis Camera Sample</name>
<description>An example program that acquires images from an Axis network camera and adds some
annotation to the image as you might do for showing operators the result of some image
recognition, and sends it to the dashboard for display. This demonstrates the use of the
AxisCamera class.
</description>
<tags>
<tag>Vision</tag>
<tag>Complete List</tag>
</tags>
<packages>
<package>src/$package-dir</package>
</packages>
<files>
<file source="examples/AxisCameraSample/src/org/usfirst/frc/team190/robot/Robot.java"
destination="src/$package-dir/Robot.java"></file>
</files>
</example>
</examples>

View File

@@ -20,7 +20,7 @@ networktables.sources=${wpilib.lib}/NetworkTables-sources.jar
#jnaerator.jar=${wpilib.lib}/jnaerator-runtime.jar
#classpath=${wpilib.jar}:${networktables.jar}:${jna.jar}:${jnaerator.jar}
classpath=${wpilib.jar}:${networktables.jar}
roboRIOAllowedImages=22
roboRIOAllowedImages=23
# Ant support
wpilib.ant.dir=${wpilib}/ant

View File

@@ -104,7 +104,16 @@
<target name="deploy" depends="clean,jar,get-target-ip,dependencies" description="Deploy the jar and start the program running.">
<echo>[athena-deploy] Copying code over.</echo>
<scp file="${dist.jar}" todir="${username}@${target}:${deploy.dir}" password="${password}" trust="true"/>
<scp file="${wpilib.ant.dir}/robotCommand" todir="${username}@${target}:${command.dir}" password="${password}" trust="true"/>
<sshexec host="${target}"
username="admin"
password="${password}"
trust="true"
failonerror="false"
command="killall netconsole-host"/>
<scp file="${wpilib.ant.dir}/netconsole-host" todir="admin@${target}:/usr/local/frc/bin" password="${password}" trust="true"/>
<scp file="${wpilib.ant.dir}/robotCommand" todir="${username}@${target}:${command.dir}" password="${password}" trust="true"/>
<echo>[athena-deploy] Starting program.</echo>
<sshexec host="${target}"
@@ -221,7 +230,7 @@
</bool>
</assert>
<echo>roboRIO image version validated</echo>
<echo>Checking for JRE. If this fails install the JRE using these instructions: http://wpilib.screenstepslive.com/s/4485/m/13809/l/243933-installing-java-8-on-the-roborio-java-only</echo>
<echo>Checking for JRE. If this fails install the JRE using these instructions: https://wpilib.screenstepslive.com/s/4485/m/13503/l/288822-installing-java-8-on-the-roborio-using-the-frc-roborio-java-installer-java-only</echo>
<sshexec host="${target}"
username="${username}"
password="${password}"

View File

@@ -1,2 +1,2 @@
/usr/local/frc/bin/netconsole-host /usr/local/frc/JRE/bin/java -jar /home/lvuser/FRCUserProgram.jar
env LD_PRELOAD=/lib/libstdc++.so.6.0.20 /usr/local/frc/bin/netconsole-host /usr/local/frc/JRE/bin/java -jar /home/lvuser/FRCUserProgram.jar

View File

@@ -1,2 +1,2 @@
/usr/local/frc/bin/netconsole-host /usr/local/frc/JRE/bin/java -XX:+UsePerfData -agentlib:jdwp=transport=dt_socket,address=8348,server=y,suspend=y -jar /home/lvuser/FRCUserProgram.jar
env LD_PRELOAD=/lib/libstdc++.so.6.0.20 /usr/local/frc/bin/netconsole-host /usr/local/frc/JRE/bin/java -XX:+UsePerfData -agentlib:jdwp=transport=dt_socket,address=8348,server=y,suspend=y -jar /home/lvuser/FRCUserProgram.jar

View File

@@ -23,6 +23,14 @@ extern "C" {
bool getPressureSwitch(void *pcm_pointer, int32_t *status);
float getCompressorCurrent(void *pcm_pointer, int32_t *status);
bool getCompressorCurrentTooHighFault(void *pcm_pointer, int32_t *status);
bool getCompressorCurrentTooHighStickyFault(void *pcm_pointer, int32_t *status);
bool getCompressorShortedStickyFault(void *pcm_pointer, int32_t *status);
bool getCompressorShortedFault(void *pcm_pointer, int32_t *status);
bool getCompressorNotConnectedStickyFault(void *pcm_pointer, int32_t *status);
bool getCompressorNotConnectedFault(void *pcm_pointer, int32_t *status);
void clearAllPCMStickyFaults(void *pcm_pointer, int32_t *status);
}
#endif

View File

@@ -86,6 +86,8 @@ extern "C"
void setEncoderSamplesToAverage(void* encoder_pointer, uint32_t samplesToAverage,
int32_t *status);
uint32_t getEncoderSamplesToAverage(void* encoder_pointer, int32_t *status);
void setEncoderIndexSource(void *encoder_pointer, uint32_t pin, bool analogTrigger, bool activeHigh,
bool edgeSensitive, int32_t *status);
uint16_t getLoopTiming(int32_t *status);

View File

@@ -47,6 +47,8 @@
#define ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE "HAL: Attempted to read AnalogTrigger pulse output."
#define PARAMETER_OUT_OF_RANGE -1028
#define PARAMETER_OUT_OF_RANGE_MESSAGE "HAL: A parameter is out of range."
#define RESOURCE_IS_ALLOCATED -1029
#define RESOURCE_IS_ALLOCATED_MESSAGE "HAL: Resource already allocated"
#define VI_ERROR_SYSTEM_ERROR_MESSAGE "HAL - VISA: System Error";
#define VI_ERROR_INV_OBJECT_MESSAGE "HAL - VISA: Invalid Object"

View File

@@ -13,4 +13,9 @@ extern "C"
bool getSolenoid(void* solenoid_port_pointer, int32_t *status);
void setSolenoid(void* solenoid_port_pointer, bool value, int32_t *status);
int getPCMSolenoidBlackList(void* solenoid_port_pointer, int32_t *status);
bool getPCMSolenoidVoltageStickyFault(void* solenoid_port_pointer, int32_t *status);
bool getPCMSolenoidVoltageFault(void* solenoid_port_pointer, int32_t *status);
void clearAllPCMStickyFaults_sol(void *solenoid_port_pointer, int32_t *status);
}

View File

@@ -61,4 +61,56 @@ float getCompressorCurrent(void *pcm_pointer, int32_t *status) {
return value;
}
bool getCompressorCurrentTooHighFault(void *pcm_pointer, int32_t *status) {
PCM *module = (PCM *)pcm_pointer;
bool value;
*status = module->GetCompressorCurrentTooHighFault(value);
return value;
}
bool getCompressorCurrentTooHighStickyFault(void *pcm_pointer, int32_t *status) {
PCM *module = (PCM *)pcm_pointer;
bool value;
*status = module->GetCompressorCurrentTooHighStickyFault(value);
return value;
}
bool getCompressorShortedStickyFault(void *pcm_pointer, int32_t *status) {
PCM *module = (PCM *)pcm_pointer;
bool value;
*status = module->GetCompressorShortedStickyFault(value);
return value;
}
bool getCompressorShortedFault(void *pcm_pointer, int32_t *status) {
PCM *module = (PCM *)pcm_pointer;
bool value;
*status = module->GetCompressorShortedFault(value);
return value;
}
bool getCompressorNotConnectedStickyFault(void *pcm_pointer, int32_t *status) {
PCM *module = (PCM *)pcm_pointer;
bool value;
*status = module->GetCompressorNotConnectedStickyFault(value);
return value;
}
bool getCompressorNotConnectedFault(void *pcm_pointer, int32_t *status) {
PCM *module = (PCM *)pcm_pointer;
bool value;
*status = module->GetCompressorNotConnectedFault(value);
return value;
}
void clearAllPCMStickyFaults(void *pcm_pointer, int32_t *status) {
PCM *module = (PCM *)pcm_pointer;
*status = module->ClearStickyFaults();
}

View File

@@ -384,7 +384,11 @@ bool allocateDIO(void* digital_port_pointer, bool input, int32_t *status) {
DigitalPort* port = (DigitalPort*) digital_port_pointer;
char buf[64];
snprintf(buf, 64, "DIO %d", port->port.pin);
if (DIOChannels->Allocate(port->port.pin, buf) == ~0ul) return false;
if (DIOChannels->Allocate(port->port.pin, buf) == ~0ul) {
*status = RESOURCE_IS_ALLOCATED;
return false;
}
{
Synchronized sync(digitalDIOSemaphore);
@@ -420,7 +424,11 @@ bool allocatePWMChannel(void* digital_port_pointer, int32_t *status) {
DigitalPort* port = (DigitalPort*) digital_port_pointer;
char buf[64];
snprintf(buf, 64, "PWM %d", port->port.pin);
if (PWMChannels->Allocate(port->port.pin, buf) == ~0ul) return false;
if (PWMChannels->Allocate(port->port.pin, buf) == ~0ul) {
*status = RESOURCE_IS_ALLOCATED;
return false;
}
if (port->port.pin > tPWM::kNumHdrRegisters-1) {
snprintf(buf, 64, "PWM %d and DIO %d", port->port.pin, remapMXPPWMChannel(port->port.pin) + 10);
if (DIOChannels->Allocate(remapMXPPWMChannel(port->port.pin) + 10, buf) == ~0ul) return false;
@@ -830,7 +838,7 @@ double getCounterPeriod(void* counter_pointer, int32_t *status) {
// output.Period is a fixed point number that counts by 2 (24 bits, 25 integer bits)
period = (double)(output.Period << 1) / (double)output.Count;
}
return period * 1.0e-6;
return period * 2.5e-8; // result * timebase (currently 40ns)
}
/**
@@ -842,7 +850,7 @@ double getCounterPeriod(void* counter_pointer, int32_t *status) {
*/
void setCounterMaxPeriod(void* counter_pointer, double maxPeriod, int32_t *status) {
Counter* counter = (Counter*) counter_pointer;
counter->counter->writeTimerConfig_StallPeriod((uint32_t)(maxPeriod * 1.0e6), status);
counter->counter->writeTimerConfig_StallPeriod((uint32_t)(maxPeriod * 4.0e8), status);
}
/**
@@ -992,7 +1000,7 @@ double getEncoderPeriod(void* encoder_pointer, int32_t *status) {
// output.Period is a fixed point number that counts by 2 (24 bits, 25 integer bits)
value = (double)(output.Period << 1) / (double)output.Count;
}
double measuredPeriod = value * 1.0e-6;
double measuredPeriod = value * 2.5e-8;
return measuredPeriod / DECODING_SCALING_FACTOR;
}
@@ -1010,7 +1018,7 @@ double getEncoderPeriod(void* encoder_pointer, int32_t *status) {
*/
void setEncoderMaxPeriod(void* encoder_pointer, double maxPeriod, int32_t *status) {
Encoder* encoder = (Encoder*) encoder_pointer;
encoder->encoder->writeTimerConfig_StallPeriod((uint32_t)(maxPeriod * 1.0e6 * DECODING_SCALING_FACTOR), status);
encoder->encoder->writeTimerConfig_StallPeriod((uint32_t)(maxPeriod * 4.0e8 * DECODING_SCALING_FACTOR), status);
}
/**
@@ -1070,6 +1078,20 @@ uint32_t getEncoderSamplesToAverage(void* encoder_pointer, int32_t *status) {
return encoder->encoder->readTimerConfig_AverageSize(status);
}
/**
* Set an index source for an encoder, which is an input that resets the
* encoder's count.
*/
void setEncoderIndexSource(void *encoder_pointer, uint32_t pin, bool analogTrigger, bool activeHigh,
bool edgeSensitive, int32_t *status) {
Encoder* encoder = (Encoder*) encoder_pointer;
encoder->encoder->writeConfig_IndexSource_Channel((unsigned char)pin, status);
encoder->encoder->writeConfig_IndexSource_Module((unsigned char)0, status);
encoder->encoder->writeConfig_IndexSource_AnalogTrigger(analogTrigger, status);
encoder->encoder->writeConfig_IndexActiveHigh(activeHigh, status);
encoder->encoder->writeConfig_IndexEdgeSensitive(edgeSensitive, status);
}
/**
* Get the loop timing of the PWM system
*

View File

@@ -52,3 +52,33 @@ void setSolenoid(void* solenoid_port_pointer, bool value, int32_t *status) {
port->module->SetSolenoid(port->pin, value);
}
int getPCMSolenoidBlackList(void* solenoid_port_pointer, int32_t *status){
solenoid_port_t* port = (solenoid_port_t*) solenoid_port_pointer;
UINT8 value;
*status = port->module->GetSolenoidBlackList(value);
return value;
}
bool getPCMSolenoidVoltageStickyFault(void* solenoid_port_pointer, int32_t *status){
solenoid_port_t* port = (solenoid_port_t*) solenoid_port_pointer;
bool value;
*status = port->module->GetSolenoidStickyFault(value);
return value;
}
bool getPCMSolenoidVoltageFault(void* solenoid_port_pointer, int32_t *status){
solenoid_port_t* port = (solenoid_port_t*) solenoid_port_pointer;
bool value;
*status = port->module->GetSolenoidFault(value);
return value;
}
void clearAllPCMStickyFaults_sol(void *solenoid_port_pointer, int32_t *status){
solenoid_port_t* port = (solenoid_port_t*) solenoid_port_pointer;
*status = port->module->ClearStickyFaults();
}

View File

@@ -242,6 +242,11 @@ typedef struct _TALON_Param_Response_t {
CanTalonSRX::CanTalonSRX(int deviceNumber,int controlPeriodMs): CtreCanNode(deviceNumber), _can_h(0), _can_stat(0)
{
/* bound period to be within [1 ms,95 ms] */
if(controlPeriodMs < 1)
controlPeriodMs = 1;
else if(controlPeriodMs > 95)
controlPeriodMs = 95;
RegisterRx(STATUS_1 | (UINT8)deviceNumber );
RegisterRx(STATUS_2 | (UINT8)deviceNumber );
RegisterRx(STATUS_3 | (UINT8)deviceNumber );
@@ -566,6 +571,11 @@ CTR_Code CanTalonSRX::GetReverseSoftEnable(int & enable)
CTR_Code CanTalonSRX::SetStatusFrameRate(unsigned frameEnum, unsigned periodMs)
{
int32_t status = 0;
/* bounds check the period */
if(periodMs < 1)
periodMs = 1;
else if (periodMs > 255)
periodMs = 255;
uint8_t period = (uint8_t)periodMs;
/* tweak just the status messsage rate the caller cares about */
switch(frameEnum){
@@ -866,9 +876,9 @@ CTR_Code CanTalonSRX::GetAnalogInVel(int &param)
raw |= rx->AnalogInVelH;
raw <<= 8;
raw |= rx->AnalogInVelL;
param = (int)raw;
raw <<= (32-16); /* sign extend */
raw >>= (32-16); /* sign extend */
param = (int)raw;
return rx.err;
}
CTR_Code CanTalonSRX::GetTemp(double &param)
@@ -1212,6 +1222,10 @@ CTR_Code c_TalonSRX_SetModeSelect(void *handle, int param)
{
return ((CanTalonSRX*)handle)->SetModeSelect(param);
}
CTR_Code c_TalonSRX_SetModeSelect2(void *handle, int modeSelect, int demand)
{
return ((CanTalonSRX*)handle)->SetModeSelect(modeSelect, demand);
}
CTR_Code c_TalonSRX_SetProfileSlotSelect(void *handle, int param)
{
return ((CanTalonSRX*)handle)->SetProfileSlotSelect(param);

View File

@@ -366,6 +366,7 @@ extern "C" {
CTR_Code c_TalonSRX_SetRevMotDuringCloseLoopEn(void *handle, int param);
CTR_Code c_TalonSRX_SetOverrideBrakeType(void *handle, int param);
CTR_Code c_TalonSRX_SetModeSelect(void *handle, int param);
CTR_Code c_TalonSRX_SetModeSelect2(void *handle, int modeSelect, int demand);
CTR_Code c_TalonSRX_SetProfileSlotSelect(void *handle, int param);
CTR_Code c_TalonSRX_SetRampThrottle(void *handle, int param);
CTR_Code c_TalonSRX_SetRevFeedbackSensor(void *handle, int param);

View File

@@ -17,7 +17,9 @@ static const INT32 kCANPeriod = 20;
#define GET_PCM_SOL_FAULTS() CtreCanNode::recMsg<PcmStatusFault_t> rx = GetRx<PcmStatusFault_t> (STATUS_SOL_FAULTS,EXPECTED_RESPONSE_TIMEOUT_MS)
#define GET_PCM_DEBUG() CtreCanNode::recMsg<PcmDebug_t> rx = GetRx<PcmDebug_t> (STATUS_DEBUG,EXPECTED_RESPONSE_TIMEOUT_MS)
#define CONTROL_1 0x09041C00
#define CONTROL_1 0x09041C00 /* PCM_Control */
#define CONTROL_2 0x09041C40 /* PCM_SupplemControl */
#define CONTROL_3 0x09041C80 /* PcmControlSetOneShotDur_t */
/* encoder/decoders */
typedef struct _PcmStatus_t{
@@ -27,8 +29,8 @@ typedef struct _PcmStatus_t{
unsigned compressorOn:1;
unsigned stickyFaultFuseTripped:1;
unsigned stickyFaultCompCurrentTooHigh:1;
unsigned faultCompCurrentTooHigh:1;
unsigned faultFuseTripped:1;
unsigned faultCompCurrentTooHigh:1;
unsigned faultHardwareFailure:1;
unsigned isCloseloopEnabled:1;
unsigned pressureSwitchEn:1;
@@ -40,7 +42,8 @@ typedef struct _PcmStatus_t{
unsigned compressorCurrentTop6:6;
unsigned solenoidVoltageBtm2:2;
/* Byte 5 */
unsigned reserved:2;
unsigned StickyFault_dItooHigh :1;
unsigned Fault_dItooHigh :1;
unsigned moduleEnabled:1;
unsigned closedLoopOutput:1;
unsigned compressorCurrentBtm4:4;
@@ -63,19 +66,28 @@ typedef struct _PcmControl_t{
unsigned compressorOn:1;
unsigned closedLoopEnable:1;
unsigned clearStickyFaults:1;
/* Byte 4 */
unsigned OneShotField_h8:8;
/* Byte 5 */
unsigned OneShotField_l8:8;
}PcmControl_t;
typedef struct _PcmControlSetOneShotDur_t{
uint8_t sol10MsPerUnit[8];
}PcmControlSetOneShotDur_t;
typedef struct _PcmStatusFault_t{
/* Byte 0 */
unsigned SolenoidBlacklist:8;
/* Byte 1 */
unsigned reserved1:8;
unsigned reserved2:8;
unsigned reserved3:8;
unsigned reserved4:8;
unsigned reserved5:8;
unsigned reserved6:8;
unsigned reserved7:8;
unsigned reserved_bit0 :1;
unsigned reserved_bit1 :1;
unsigned reserved_bit2 :1;
unsigned reserved_bit3 :1;
unsigned StickyFault_CompNoCurrent :1;
unsigned Fault_CompNoCurrent :1;
unsigned StickyFault_SolenoidJumper :1;
unsigned Fault_SolenoidJumper :1;
}PcmStatusFault_t;
typedef struct _PcmDebug_t{
@@ -135,12 +147,13 @@ CTR_Code PCM::SetSolenoid(unsigned char idx, bool en)
*
* @Param - clr - Clear / do not clear faults
*/
CTR_Code PCM::ClearStickyFaults(bool clr)
CTR_Code PCM::ClearStickyFaults()
{
CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
if(toFill.IsEmpty())return CTR_UnexpectedArbId;
toFill->clearStickyFaults = clr;
FlushTx(toFill);
int32_t status = 0;
uint8_t pcmSupplemControl[] = { 0, 0, 0, 0x80 }; /* only bit set is ClearStickyFaults */
FRC_NetworkCommunication_CANSessionMux_sendMessage(CONTROL_2 | GetDeviceNumber(), pcmSupplemControl, sizeof(pcmSupplemControl), 0, &status);
if(status)
return CTR_TxFailed;
return CTR_OKAY;
}
@@ -158,6 +171,59 @@ CTR_Code PCM::SetClosedLoopControl(bool en)
FlushTx(toFill);
return CTR_OKAY;
}
/* Get solenoid Blacklist status
* @Return - CTR_Code - Error code (if any)
* @Param - idx - ID of solenoid [0,7] to fire one shot pulse.
*/
CTR_Code PCM::FireOneShotSolenoid(UINT8 idx)
{
CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
if(toFill.IsEmpty())return CTR_UnexpectedArbId;
/* grab field as it is now */
uint16_t oneShotField;
oneShotField = toFill->OneShotField_h8;
oneShotField <<= 8;
oneShotField |= toFill->OneShotField_l8;
/* get the caller's channel */
uint16_t shift = 2*idx;
uint16_t mask = 3; /* two bits wide */
uint8_t chBits = (oneShotField >> shift) & mask;
/* flip it */
chBits = (chBits)%3 + 1;
/* clear out 2bits for this channel*/
oneShotField &= ~(mask << shift);
/* put new field in */
oneShotField |= chBits << shift;
/* apply field as it is now */
toFill->OneShotField_h8 = oneShotField >> 8;
toFill->OneShotField_l8 = oneShotField;
FlushTx(toFill);
return CTR_OKAY;
}
/* Configure the pulse width of a solenoid channel for one-shot pulse.
* Preprogrammed pulsewidth is 10ms resolute and can be between 20ms and 5.1s.
* @Return - CTR_Code - Error code (if any)
* @Param - idx - ID of solenoid [0,7] to configure.
* @Param - durMs - pulse width in ms.
*/
CTR_Code PCM::SetOneShotDurationMs(UINT8 idx,uint32_t durMs)
{
/* sanity check caller's param */
if(idx > 8)
return CTR_InvalidParamValue;
/* get latest tx frame */
CtreCanNode::txTask<PcmControlSetOneShotDur_t> toFill = GetTx<PcmControlSetOneShotDur_t>(CONTROL_3 | GetDeviceNumber());
if(toFill.IsEmpty()){
/* only send this out if caller wants to do one-shots */
RegisterTx(CONTROL_3 | _deviceNumber, kCANPeriod);
/* grab it */
toFill = GetTx<PcmControlSetOneShotDur_t>(CONTROL_3 | GetDeviceNumber());
}
toFill->sol10MsPerUnit[idx] = std::min(durMs/10,(uint32_t)0xFF);
/* apply the new data bytes */
FlushTx(toFill);
return CTR_OKAY;
}
/* Get solenoid state
*
@@ -248,12 +314,36 @@ CTR_Code PCM::GetHardwareFault(bool &status)
*
* @Return - True/False - True if shorted compressor detected, false if otherwise
*/
CTR_Code PCM::GetCompressorFault(bool &status)
CTR_Code PCM::GetCompressorCurrentTooHighFault(bool &status)
{
GET_PCM_STATUS();
status = rx->faultCompCurrentTooHigh;
return rx.err;
}
CTR_Code PCM::GetCompressorShortedStickyFault(bool &status)
{
GET_PCM_STATUS();
status = rx->StickyFault_dItooHigh;
return rx.err;
}
CTR_Code PCM::GetCompressorShortedFault(bool &status)
{
GET_PCM_STATUS();
status = rx->Fault_dItooHigh;
return rx.err;
}
CTR_Code PCM::GetCompressorNotConnectedStickyFault(bool &status)
{
GET_PCM_SOL_FAULTS();
status = rx->StickyFault_CompNoCurrent;
return rx.err;
}
CTR_Code PCM::GetCompressorNotConnectedFault(bool &status)
{
GET_PCM_SOL_FAULTS();
status = rx->Fault_CompNoCurrent;
return rx.err;
}
/* Get solenoid fault value
*
@@ -271,7 +361,7 @@ CTR_Code PCM::GetSolenoidFault(bool &status)
* @Return - True/False - True if solenoid had previously been shorted
* (and sticky fault was not cleared), false if otherwise
*/
CTR_Code PCM::GetCompressorStickyFault(bool &status)
CTR_Code PCM::GetCompressorCurrentTooHighStickyFault(bool &status)
{
GET_PCM_STATUS();
status = rx->stickyFaultCompCurrentTooHigh;
@@ -369,7 +459,7 @@ extern "C" {
return ((PCM*) handle)->SetClosedLoopControl(param);
}
CTR_Code c_ClearStickyFaults(void * handle, INT8 param) {
return ((PCM*) handle)->ClearStickyFaults(param);
return ((PCM*) handle)->ClearStickyFaults();
}
CTR_Code c_GetSolenoid(void * handle, UINT8 idx, INT8 * status) {
bool bstatus;
@@ -410,7 +500,7 @@ extern "C" {
}
CTR_Code c_GetCompressorFault(void * handle, INT8*status) {
bool bstatus;
CTR_Code retval = ((PCM*) handle)->GetCompressorFault(bstatus);
CTR_Code retval = ((PCM*) handle)->GetCompressorCurrentTooHighFault(bstatus);
*status = bstatus;
return retval;
}
@@ -422,7 +512,7 @@ extern "C" {
}
CTR_Code c_GetCompressorStickyFault(void * handle, INT8*status) {
bool bstatus;
CTR_Code retval = ((PCM*) handle)->GetCompressorStickyFault(bstatus);
CTR_Code retval = ((PCM*) handle)->GetCompressorCurrentTooHighStickyFault(bstatus);
*status = bstatus;
return retval;
}

View File

@@ -26,9 +26,8 @@ public:
/* Clears PCM sticky faults (indicators of past faults
* @Return - CTR_Code - Error code (if any) for setting solenoid
* @Param - clr - Clear / do not clear faults
*/
CTR_Code ClearStickyFaults(bool clr);
CTR_Code ClearStickyFaults();
/* Get solenoid state
*
@@ -76,9 +75,9 @@ public:
/* Get compressor fault value
* @Return - CTR_Code - Error code (if any)
* @Param - status - True if shorted compressor detected, false if otherwise
* @Param - status - True if abnormally high compressor current detected, false if otherwise
*/
CTR_Code GetCompressorFault(bool &status);
CTR_Code GetCompressorCurrentTooHighFault(bool &status);
/* Get solenoid fault value
* @Return - CTR_Code - Error code (if any)
@@ -91,7 +90,29 @@ public:
* @Param - status - True if solenoid had previously been shorted
* (and sticky fault was not cleared), false if otherwise
*/
CTR_Code GetCompressorStickyFault(bool &status);
CTR_Code GetCompressorCurrentTooHighStickyFault(bool &status);
/* Get compressor shorted sticky fault value
* @Return - CTR_Code - Error code (if any)
* @Param - status - True if compressor output is shorted, false if otherwise
*/
CTR_Code GetCompressorShortedStickyFault(bool &status);
/* Get compressor shorted fault value
* @Return - CTR_Code - Error code (if any)
* @Param - status - True if compressor output is shorted, false if otherwise
*/
CTR_Code GetCompressorShortedFault(bool &status);
/* Get compressor is not connected sticky fault value
* @Return - CTR_Code - Error code (if any)
* @Param - status - True if compressor current is too low,
* indicating compressor is not connected, false if otherwise
*/
CTR_Code GetCompressorNotConnectedStickyFault(bool &status);
/* Get compressor is not connected fault value
* @Return - CTR_Code - Error code (if any)
* @Param - status - True if compressor current is too low,
* indicating compressor is not connected, false if otherwise
*/
CTR_Code GetCompressorNotConnectedFault(bool &status);
/* Get solenoid sticky fault value
* @Return - CTR_Code - Error code (if any)
@@ -146,6 +167,21 @@ public:
* @Param - status - Returns TRUE if PCM is enabled, FALSE if disabled
*/
CTR_Code isModuleEnabled(bool &status);
/* Get solenoid Blacklist status
* @Return - CTR_Code - Error code (if any)
* @Param - idx - ID of solenoid [0,7] to fire one shot pulse.
*/
CTR_Code FireOneShotSolenoid(UINT8 idx);
/* Configure the pulse width of a solenoid channel for one-shot pulse.
* Preprogrammed pulsewidth is 10ms resolute and can be between 20ms and 5.1s.
* @Return - CTR_Code - Error code (if any)
* @Param - idx - ID of solenoid [0,7] to configure.
* @Param - durMs - pulse width in ms.
*/
CTR_Code SetOneShotDurationMs(UINT8 idx,uint32_t durMs);
};
//------------------ C interface --------------------------------------------//
extern "C" {

View File

@@ -178,7 +178,8 @@ CTR_Code PDP::GetTotalEnergy(double &energyJoules)
raw <<= 8;
raw |= rx->Energy_125mWPerUnitXTmeas_l8;
energyJoules = 0.125 * raw; /* mW integrated every TmeasMs */
energyJoules *= rx->TmeasMs_likelywillbe20ms_; /* multiplied by TmeasMs = joules */
energyJoules *= 0.001; /* convert from mW to W */
energyJoules *= rx->TmeasMs_likelywillbe20ms_; /* multiplied by TmeasMs = joules */
return rx.err;
}
/* Clear sticky faults.

View File

@@ -234,7 +234,7 @@ TCL_SUBST =
# members will be omitted, etc.
# The default value is: NO.
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_FOR_C = NO
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
# Python sources only. Doxygen will then generate output that is more tailored

View File

@@ -35,6 +35,8 @@ public:
class AbstractNetworkTableEntryStore : public IncomingEntryReceiver{
protected:
NTReentrantSemaphore block_namedEntries;
std::map<EntryId,NetworkTableEntry*> idEntries;
std::map<std::string,NetworkTableEntry*> namedEntries;
TableListenerManager& listenerManager;
@@ -45,10 +47,10 @@ protected:
OutgoingEntryReceiver* incomingReceiver;
virtual bool addEntry(NetworkTableEntry* entry) = 0;
virtual bool updateEntry(NetworkTableEntry* entry, SequenceNumber sequenceNumber, EntryValue value) = 0;
public:
virtual ~AbstractNetworkTableEntryStore();
@@ -62,14 +64,14 @@ public:
void SetOutgoingReceiver(OutgoingEntryReceiver* receiver);
void SetIncomingReceiver(OutgoingEntryReceiver* receiver);
void PutOutgoing(std::string& name, NetworkTableEntryType* type, EntryValue value);
void PutOutgoing(NetworkTableEntry* tableEntry, EntryValue value);
void offerIncomingAssignment(NetworkTableEntry* entry);
void offerIncomingUpdate(NetworkTableEntry* entry, EntryId sequenceNumber, EntryValue value);
void notifyEntries(ITable* table, ITableListener* listener);
};

View File

@@ -42,6 +42,7 @@ public:
NetworkTableEntry(std::string& name, NetworkTableEntryType* type, EntryValue value);
NetworkTableEntry(EntryId id, std::string& name, SequenceNumber sequenceNumber, NetworkTableEntryType* type, EntryValue value);
NetworkTableEntry(const NetworkTableEntry &);
virtual ~NetworkTableEntry();
EntryId GetId();

View File

@@ -15,6 +15,7 @@
#include <iolib.h>
#else
#include <unistd.h>
#include <fcntl.h>
#endif
#include <stdio.h>
@@ -24,6 +25,13 @@ FDIOStream::FDIOStream(int _fd){
// f = fdopen(_fd, "rbwb");
// if(f==NULL)
// throw IOException("Could not open stream from file descriptor", errno);
// Set the TCP socket to be non-blocking
int flags = fcntl(fd, F_GETFL, 0);
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
{
::close(fd);
throw IOException("Could not set socket to non-blocking mode");
}
}
FDIOStream::~FDIOStream(){
close();
@@ -66,14 +74,35 @@ int FDIOStream::read(void* ptr, int numbytes){
return totalRead;
}
int FDIOStream::write(const void* ptr, int numbytes){
int numWrote = ::write(fd, (char*)ptr, numbytes);//TODO: this is bad
//int numWrote = fwrite(ptr, 1, numbytes, f);
if(numWrote==numbytes)
return numWrote;
perror("write error: ");
fflush(stderr);
throw IOException("Could not write all bytes to fd stream");
int numWrote = ::write(fd, (char*)ptr, numbytes);
if(numWrote==numbytes)
return numWrote;
if (numWrote == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
{
// see if write timeout expires
struct timeval timeout;
fd_set fdSet;
FD_ZERO(&fdSet);
FD_SET(fd, &fdSet);
timeout.tv_sec = 1; // wait 1 second for the other side to connect
timeout.tv_usec = 0;
int select_result = select(FD_SETSIZE, NULL, &fdSet, NULL, &timeout);
if ( select_result < 0)
throw IOException("Select returned an error on write");
if (FD_ISSET(fd, &fdSet)) {
numWrote = ::write(fd, (char*)ptr, numbytes);
if(numWrote==numbytes)
return numWrote;
}
}
perror("write error: ");
fflush(stderr);
throw IOException("Could not write all bytes to fd stream");
}
void FDIOStream::flush(){
//if(fflush(f)==EOF)

View File

@@ -1,6 +1,8 @@
#include "stdafx.h"
#include "OSAL/Task.h"
#include "NetworkCommunication/UsageReporting.h"
#include "WPIErrors.h"
#include <string.h>
#include <Windows.h>
@@ -55,7 +57,7 @@ DWORD thread_proc( void *p_ptr )
//This sets the name of the thread, which can help to identify threads in win32
#define MS_VC_EXCEPTION 0x406D1388
static void set_thread_name( const char *p_thread_name, DWORD ID )
{
{
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{ DWORD dwType; // Must be 0x1000.
@@ -162,7 +164,7 @@ bool NTTask::Stop()
::TerminateThread( m_Handle, 0 );
// Free the memory
::VirtualFree( Info_.AllocationBase, 0, MEM_RELEASE );
::VirtualFree( Info_.AllocationBase, 0, MEM_RELEASE );
}
//if (Verify())
@@ -289,19 +291,19 @@ bool NTTask::HandleError(STATUS results)
//case S_objLib_OBJ_ID_ERROR:
// wpi_setWPIErrorWithContext(TaskIDError, m_taskName);
// break;
//
//
//case S_objLib_OBJ_DELETED:
// wpi_setWPIErrorWithContext(TaskDeletedError, m_taskName);
// break;
//
//
//case S_taskLib_ILLEGAL_OPTIONS:
// wpi_setWPIErrorWithContext(TaskOptionsError, m_taskName);
// break;
//
//
//case S_memLib_NOT_ENOUGH_MEMORY:
// wpi_setWPIErrorWithContext(TaskMemoryError, m_taskName);
// break;
//
//
//case S_taskLib_ILLEGAL_PRIORITY:
// wpi_setWPIErrorWithContext(TaskPriorityError, m_taskName);
// break;
@@ -312,4 +314,3 @@ bool NTTask::HandleError(STATUS results)
//}
return false;
}

View File

@@ -20,6 +20,13 @@
FDIOStream::FDIOStream(int _fd){
fd = _fd;
// Set the TCP socket to be non-blocking
u_long on = 1;
if (ioctlsocket(fd, FIONBIO, &on))
{
::close(fd);
throw IOException("Could not set socket to non-blocking mode");
}
}
FDIOStream::~FDIOStream(){
@@ -79,13 +86,35 @@ int Send( int sockfd,char* Data, size_t sizeData )
int FDIOStream::write(const void* ptr, int numbytes)
{
int numWrote = Send(fd,(char *)ptr,numbytes);
if(numWrote==numbytes)
return numWrote;
perror("write error: ");
fflush(stderr);
throw IOException("Could not write all bytes to fd stream");
int numWrote = ::write(fd, (char*)ptr, numbytes);
if(numWrote==numbytes)
return numWrote;
if (numWrote == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
{
// see if write timeout expires
struct timeval timeout;
fd_set fdSet;
FD_ZERO(&fdSet);
FD_SET(fd, &fdSet);
timeout.tv_sec = 1; // wait 1 second for the other side to connect
timeout.tv_usec = 0;
int select_result = select(FD_SETSIZE, NULL, &fdSet, NULL, &timeout);
if ( select_result < 0)
throw IOException("Select returned an error on write");
if (FD_ISSET(fd, &fdSet)) {
numWrote = ::write(fd, (char*)ptr, numbytes);
if(numWrote==numbytes)
return numWrote;
}
}
perror("write error: ");
fflush(stderr);
throw IOException("Could not write all bytes to fd stream");
}
void FDIOStream::flush(){

View File

@@ -12,10 +12,10 @@
#include <iostream>
#include <stdio.h>
AbstractNetworkTableEntryStore::AbstractNetworkTableEntryStore(TableListenerManager& lstnManager):
AbstractNetworkTableEntryStore::AbstractNetworkTableEntryStore(TableListenerManager& lstnManager):
listenerManager(lstnManager){
}
AbstractNetworkTableEntryStore::~AbstractNetworkTableEntryStore(){
LOCK.take();
std::map<std::string, NetworkTableEntry*>::iterator itr;
@@ -24,15 +24,15 @@
namedEntries.erase(itr++);
}
}
/**
* Get an entry based on it's name
* @param name the name of the entry to look for
* @return the entry or null if the entry does not exist
*/
NetworkTableEntry* AbstractNetworkTableEntryStore::GetEntry(std::string& name){
{
NTSynchronized sync(LOCK);
{
NTSynchronized sync(block_namedEntries);
std::map<std::string, NetworkTableEntry*>::iterator value_itr = namedEntries.find(name);
if(value_itr != namedEntries.end()) {
return value_itr->second;
@@ -40,11 +40,11 @@
return NULL;
}
}
NetworkTableEntry* AbstractNetworkTableEntryStore::GetEntry(EntryId entryId){
{
NTSynchronized sync(LOCK);
{
NTSynchronized sync(block_namedEntries);
std::map<EntryId, NetworkTableEntry*>::iterator value_itr = idEntries.find(entryId);
if(value_itr != idEntries.end()) {
return value_itr->second;
@@ -52,74 +52,74 @@
return NULL;
}
}
std::vector<std::string>* AbstractNetworkTableEntryStore::keys(){
{
NTSynchronized sync(LOCK);
{
NTSynchronized sync(block_namedEntries);
std::vector<std::string>* keys = new std::vector<std::string>();
std::map<std::string, NetworkTableEntry*>::iterator itr;
for(itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
{
std::string key = (*itr).first;
keys->push_back(key);
}
return (keys);
}
}
/**
* Remove all entries
* NOTE: This method should not be used with applications which cache entries which would lead to unknown results
* This method is for use in testing only
*/
void AbstractNetworkTableEntryStore::clearEntries(){
{
NTSynchronized sync(LOCK);
{
NTSynchronized sync(block_namedEntries);
namedEntries.clear();
idEntries.clear();
}
}
/**
* clear the id's of all entries
*/
void AbstractNetworkTableEntryStore::clearIds(){
{
NTSynchronized sync(LOCK);
{
NTSynchronized sync(block_namedEntries);
std::map<std::string, NetworkTableEntry*>::iterator itr;
idEntries.clear();
for(itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
{
((NetworkTableEntry*)(*itr).second)->ClearId();
}
}
}
void AbstractNetworkTableEntryStore::SetOutgoingReceiver(OutgoingEntryReceiver* receiver){
outgoingReceiver = receiver;
}
void AbstractNetworkTableEntryStore::SetIncomingReceiver(OutgoingEntryReceiver* receiver){
incomingReceiver = receiver;
}
/**
* Stores the given value under the given name and queues it for
* Stores the given value under the given name and queues it for
* transmission to the server.
*
*
* @param name The name under which to store the given value.
* @param type The type of the given value.
* @param value The value to store.
* @throws TableKeyExistsWithDifferentTypeException Thrown if an
* @throws TableKeyExistsWithDifferentTypeException Thrown if an
* entry already exists with the given name and is of a different type.
*/
void AbstractNetworkTableEntryStore::PutOutgoing(std::string& name, NetworkTableEntryType* type, EntryValue value){
{
NTSynchronized sync(LOCK);
{
NTSynchronized sync(block_namedEntries);
std::map<std::string, NetworkTableEntry*>::iterator index = namedEntries.find(name);
NetworkTableEntry* tableEntry;
if(index == namedEntries.end())//if the name does not exist in the current entries
@@ -137,21 +137,21 @@
if(tableEntry->GetType()->id != type->id){
throw TableKeyExistsWithDifferentTypeException(name, tableEntry->GetType());
}
EntryValue oldValue = tableEntry->GetValue();
if(!type->areEqual(value, oldValue)){
if(updateEntry(tableEntry, (SequenceNumber)(tableEntry->GetSequenceNumber() + 1), value)){
outgoingReceiver->offerOutgoingUpdate(tableEntry);
}
tableEntry->FireListener(listenerManager);
}
}
}
}
void AbstractNetworkTableEntryStore::PutOutgoing(NetworkTableEntry* tableEntry, EntryValue value){
{
{
NTSynchronized sync(LOCK);
NetworkTableEntryType* type = tableEntry->GetType();
EntryValue oldValue = tableEntry->GetValue();
@@ -159,15 +159,15 @@
if(updateEntry(tableEntry, (SequenceNumber)(tableEntry->GetSequenceNumber() + 1), value)){
outgoingReceiver->offerOutgoingUpdate(tableEntry);
}
tableEntry->FireListener(listenerManager);
}
}
}
void AbstractNetworkTableEntryStore::offerIncomingAssignment(NetworkTableEntry* entry){
{
NTSynchronized sync(LOCK);
{
NTSynchronized sync(block_namedEntries);
std::map<std::string, NetworkTableEntry*>::iterator itr = namedEntries.find(entry->name);
NetworkTableEntry* tableEntry;
if(addEntry(entry)){
@@ -177,7 +177,7 @@
else{
tableEntry = entry;
}
tableEntry->FireListener(listenerManager);//if we didnt have a pointer, then the copy of the version in the list would call this method, however with the pointer we are updating the version in the list
incomingReceiver->offerOutgoingAssignment(tableEntry);
}
@@ -185,9 +185,9 @@
delete entry;
}
}
void AbstractNetworkTableEntryStore::offerIncomingUpdate(NetworkTableEntry* entry, SequenceNumber squenceNumber, EntryValue value){
{
{
NTSynchronized sync(LOCK);
if(updateEntry(entry, squenceNumber, value)){
entry->FireListener(listenerManager);
@@ -195,15 +195,15 @@
}
}
}
/**
* Called to say that a listener should notify the listener manager of all of the entries
* @param listener
* @param table
* @param table
*/
void AbstractNetworkTableEntryStore::notifyEntries(ITable* table, ITableListener* listener){
{
NTSynchronized sync(LOCK);
{
NTSynchronized sync(block_namedEntries);
std::map<std::string, NetworkTableEntry*>::iterator itr;
for(itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
{

View File

@@ -20,6 +20,17 @@ NetworkTableEntry::NetworkTableEntry(EntryId _id, std::string& _name, SequenceNu
m_isDirty = false;
}
NetworkTableEntry::NetworkTableEntry(const NetworkTableEntry &other) :
name(other.name),
id(other.id),
sequenceNumber(other.sequenceNumber),
type(other.type),
m_isNew(other.m_isNew),
m_isDirty(other.m_isDirty)
{
value = type->copyValue(other.value);
}
NetworkTableEntry::~NetworkTableEntry(){
type->deleteValue(value);
}

View File

@@ -54,10 +54,15 @@ void WriteManager::stop(){
void WriteManager::offerOutgoingAssignment(NetworkTableEntry* entry) {
{
NTSynchronized sync(transactionsLock);
((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->push(entry);
if(((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->size()>=queueSize){
bool test_queue_overflow=false;
{
NTSynchronized sync(transactionsLock);
((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->push(entry);
test_queue_overflow=(((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->size()>=queueSize);
}
if (test_queue_overflow)
{
run();
writeWarning("assignment queue overflowed. decrease the rate at which you create new entries or increase the write buffer size");
}
@@ -67,9 +72,15 @@ void WriteManager::offerOutgoingAssignment(NetworkTableEntry* entry) {
void WriteManager::offerOutgoingUpdate(NetworkTableEntry* entry) {
{
NTSynchronized sync(transactionsLock);
((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->push(entry);
if(((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->size()>=queueSize){
bool test_queue_overflow=false;
{
NTSynchronized sync(transactionsLock);
((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->push(entry);
test_queue_overflow=(((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->size()>=queueSize);
}
if (test_queue_overflow)
{
run();
writeWarning("update queue overflowed. decrease the rate at which you update entries or increase the write buffer size");
}
@@ -97,10 +108,17 @@ void WriteManager::run() {
entry = ((std::queue<NetworkTableEntry*>*)outgoingAssignmentQueue)->front();
((std::queue<NetworkTableEntry*>*)outgoingAssignmentQueue)->pop();
{
NTSynchronized sync(entryStore.LOCK);
entry->MakeClean();
wrote = true;
receiver.offerOutgoingAssignment(entry);
NetworkTableEntry * entryCopy;
{
NTSynchronized sync(entryStore.LOCK);
entry->MakeClean();
wrote = true;
entryCopy = new NetworkTableEntry(*entry);
}
receiver.offerOutgoingAssignment(entryCopy);
delete entryCopy;
}
}
@@ -108,10 +126,17 @@ void WriteManager::run() {
entry = ((std::queue<NetworkTableEntry*>*)outgoingUpdateQueue)->front();
((std::queue<NetworkTableEntry*>*)outgoingUpdateQueue)->pop();
{
NTSynchronized sync(entryStore.LOCK);
entry->MakeClean();
wrote = true;
receiver.offerOutgoingUpdate(entry);
NetworkTableEntry * entryCopy;
{
NTSynchronized sync(entryStore.LOCK);
entry->MakeClean();
wrote = true;
entryCopy = new NetworkTableEntry(*entry);
}
receiver.offerOutgoingUpdate(entryCopy);
delete entryCopy;
}
}

View File

@@ -17,7 +17,7 @@ ClientNetworkTableEntryStore::~ClientNetworkTableEntryStore(){}
bool ClientNetworkTableEntryStore::addEntry(NetworkTableEntry* newEntry){
{
NTSynchronized sync(LOCK);
NTSynchronized sync(block_namedEntries);
NetworkTableEntry* entry = (NetworkTableEntry*)namedEntries[newEntry->name];
if(entry!=NULL){
@@ -28,7 +28,7 @@ bool ClientNetworkTableEntryStore::addEntry(NetworkTableEntry* newEntry){
idEntries[newEntry->GetId()] = entry;
}
}
entry->ForcePut(newEntry->GetSequenceNumber(), newEntry->GetType(), newEntry->GetValue());
}
else{
@@ -41,7 +41,7 @@ bool ClientNetworkTableEntryStore::addEntry(NetworkTableEntry* newEntry){
}
bool ClientNetworkTableEntryStore::updateEntry(NetworkTableEntry* entry, SequenceNumber sequenceNumber, EntryValue value) {
{
{
NTSynchronized sync(LOCK);
entry->ForcePut(sequenceNumber, value);
if(entry->GetId()==NetworkTableEntry::UNKNOWN_ID){
@@ -57,7 +57,7 @@ bool ClientNetworkTableEntryStore::updateEntry(NetworkTableEntry* entry, Sequenc
* @throws IOException
*/
void ClientNetworkTableEntryStore::sendUnknownEntries(NetworkTableConnection& connection) {
{
{
NTSynchronized sync(LOCK);
std::map<std::string, NetworkTableEntry*>::iterator itr;
for(itr = namedEntries.begin(); itr != namedEntries.end(); itr++)

View File

@@ -1,6 +1,6 @@
/**
* An abstraction for the NetworkTable protocol
*
*
* @author mwills
*
*/
@@ -19,6 +19,7 @@ NetworkTableConnection::~NetworkTableConnection(){
void NetworkTableConnection::SetIOStream(IOStream* stream)
{
isValid=(stream!=NULL);
ioStream->SetIOStream(stream); //just passing through
}
@@ -102,7 +103,7 @@ void NetworkTableConnection::sendEntryUpdate(NetworkTableEntry& entry) {
}
void NetworkTableConnection::read(ConnectionAdapter& adapter) {
int messageType = ioStream->readByte();
int messageType = (isValid)?ioStream->readByte():(int)KEEP_ALIVE;
switch (messageType) {
case KEEP_ALIVE:
adapter.keepAlive();

View File

@@ -17,10 +17,10 @@ NetworkTableServer::NetworkTableServer(IOStreamProvider& _streamProvider, Networ
connectionList(&incomingStreamMonitor),
writeManager(connectionList, threadManager, GetEntryStore(), ULONG_MAX),
continuingReceiver(writeManager){
GetEntryStore().SetIncomingReceiver(&continuingReceiver);
GetEntryStore().SetOutgoingReceiver(&continuingReceiver);
incomingStreamMonitor.start();
writeManager.start();
}
@@ -35,6 +35,9 @@ NetworkTableServer::~NetworkTableServer(){
void NetworkTableServer::Close(){
try{
//Note: streamProvider must come before the incomingStreamMonitor so the that task can complete first for the thread to close
// [9/1/2013 Terminator]
streamProvider.close();
incomingStreamMonitor.stop();
writeManager.stop();
connectionList.closeAll();

View File

@@ -36,6 +36,9 @@ void ServerConnectionAdapter::badMessage(BadMessageException& e) {
gotoState(new ServerConnectionState_Error(e));
adapterListener.close(*this, true);
m_IsAdapterListenerClosed=true;
if (readThread) {
readThread->stop();
}
}
void ServerConnectionAdapter::ioException(IOException& e) {
@@ -46,6 +49,9 @@ void ServerConnectionAdapter::ioException(IOException& e) {
else
gotoState(new ServerConnectionState_Error(e));
adapterListener.close(*this, false);
if (readThread) {
readThread->stop();
}
m_IsAdapterListenerClosed=true;
}

View File

@@ -7,6 +7,7 @@
#include "networktables2/server/ServerIncomingStreamMonitor.h"
#include "networktables2/stream/IOStream.h"
#include "networktables2/util/System.h"
ServerIncomingStreamMonitor::ServerIncomingStreamMonitor(IOStreamProvider& _streamProvider, ServerNetworkTableEntryStore& _entryStore,
ServerIncomingConnectionListener& _incomingListener, ServerAdapterManager& _adapterListener, NetworkTableEntryTypeManager& _typeManager,
@@ -69,6 +70,7 @@ void ServerIncomingStreamMonitor::run()
ServerConnectionAdapter* connectionAdapter = new ServerConnectionAdapter(newStream, entryStore, entryStore, adapterListener, typeManager, threadManager);
incomingListener.OnNewConnection(*connectionAdapter);
}
sleep_ms(100); //avoid busy wait
}
}
catch (IOException& e)

View File

@@ -18,9 +18,9 @@ ServerNetworkTableEntryStore::~ServerNetworkTableEntryStore()
bool ServerNetworkTableEntryStore::addEntry(NetworkTableEntry* newEntry)
{
NTSynchronized sync(LOCK);
NTSynchronized sync(block_namedEntries);
NetworkTableEntry* entry = namedEntries[newEntry->name];
if (entry == NULL)
{
newEntry->SetId(nextId++);
@@ -44,13 +44,19 @@ bool ServerNetworkTableEntryStore::updateEntry(NetworkTableEntry* entry, Sequenc
*/
void ServerNetworkTableEntryStore::sendServerHello(NetworkTableConnection& connection)
{
NTSynchronized sync(LOCK);
std::map<std::string, NetworkTableEntry*>::iterator itr;
for (itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
std::vector<NetworkTableEntry *> entry_list;
{
NetworkTableEntry* entry = itr->second;
connection.sendEntryAssignment(*entry);
NTSynchronized sync(block_namedEntries);
std::map<std::string, NetworkTableEntry*>::iterator itr;
for (itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
{
NetworkTableEntry* entry = itr->second;
entry_list.push_back(entry);
}
}
for (size_t i=0;i<entry_list.size();i++)
connection.sendEntryAssignment(*(entry_list[i]));
connection.sendServerHelloComplete();
connection.flush();
}

BIN
ni-libraries/libniimaqdx.so Executable file → Normal file

Binary file not shown.

View File

@@ -0,0 +1,2 @@
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( libniimaqdx.so.14.0 )

View File

@@ -0,0 +1,2 @@
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( libniimaqdx.so.14.0.0 )

Binary file not shown.

BIN
ni-libraries/libnivision.so Executable file → Normal file

Binary file not shown.

View File

@@ -0,0 +1,2 @@
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( libnivision.so.14.0 )

View File

@@ -0,0 +1,2 @@
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( libnivision.so.14.0.0 )

Binary file not shown.

BIN
ni-libraries/libnivissvc.so Executable file → Normal file

Binary file not shown.

View File

@@ -0,0 +1,2 @@
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( libnivissvc.so.14.0 )

View File

@@ -0,0 +1,2 @@
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( libnivissvc.so.14.0.0 )

Binary file not shown.

View File

@@ -5,6 +5,10 @@
/*---------------------------------------------------------------------------*/
#pragma once
/** @file
* Contains global utility functions
*/
#include <stdint.h>
#include <string>

View File

@@ -7,6 +7,7 @@
#include "interfaces/Accelerometer.h"
#include "I2C.h"
#include "LiveWindow/LiveWindowSendable.h"
/**
* ADXL345 Accelerometer on I2C.
@@ -14,7 +15,7 @@
* This class allows access to a Analog Devices ADXL345 3-axis accelerometer on an I2C bus.
* This class assumes the default (not alternate) sensor address of 0x1D (7-bit address).
*/
class ADXL345_I2C : public Accelerometer, public I2C
class ADXL345_I2C : public Accelerometer, public I2C, public LiveWindowSendable
{
protected:
static const uint8_t kAddress = 0x1D;
@@ -48,6 +49,15 @@ public:
virtual double GetAcceleration(Axes axis);
virtual AllAxes GetAccelerations();
virtual std::string GetSmartDashboardType();
virtual void InitTable(ITable *subtable);
virtual void UpdateTable();
virtual ITable* GetTable();
virtual void StartLiveWindowMode() {}
virtual void StopLiveWindowMode() {}
protected:
//I2C* m_i2c;
private:
ITable *m_table;
};

View File

@@ -8,6 +8,7 @@
#include "interfaces/Accelerometer.h"
#include "SensorBase.h"
#include "SPI.h"
#include "LiveWindow/LiveWindowSendable.h"
class DigitalInput;
class DigitalOutput;
@@ -18,7 +19,7 @@ class DigitalOutput;
* This class allows access to an Analog Devices ADXL345 3-axis accelerometer via SPI.
* This class assumes the sensor is wired in 4-wire SPI mode.
*/
class ADXL345_SPI : public Accelerometer, public SensorBase
class ADXL345_SPI : public Accelerometer, public SensorBase, public LiveWindowSendable
{
protected:
static const uint8_t kPowerCtlRegister = 0x2D;
@@ -52,9 +53,18 @@ public:
virtual double GetAcceleration(Axes axis);
virtual AllAxes GetAccelerations();
virtual std::string GetSmartDashboardType();
virtual void InitTable(ITable *subtable);
virtual void UpdateTable();
virtual ITable* GetTable();
virtual void StartLiveWindowMode() {}
virtual void StopLiveWindowMode() {}
protected:
void Init(Range range);
SPI* m_spi;
SPI::Port m_port;
private:
ITable *m_table;
};

View File

@@ -54,7 +54,10 @@ public:
/** Only use switches for limits */
kLimitMode_SwitchInputsOnly = 0,
/** Use both switches and soft limits */
kLimitMode_SoftPositionLimits = 1
kLimitMode_SoftPositionLimits = 1,
/* SRX extensions */
/** Disable switches and disable soft limits */
kLimitMode_SrxDisableSwitchInputs = 2,
};
virtual float Get() = 0;

View File

@@ -26,8 +26,15 @@ public:
AnalogEncoder=3,
EncRising=4,
EncFalling=5
};
enum StatusFrameRate {
StatusFrameRateGeneral=0,
StatusFrameRateFeedback=1,
StatusFrameRateQuadEncoder=2,
StatusFrameRateAnalogTempVbat=3,
};
explicit CANTalon(int deviceNumber);
explicit CANTalon(int deviceNumber,int controlPeriodMs);
virtual ~CANTalon();
// PIDController interface
@@ -51,6 +58,7 @@ public:
virtual void SetI(double i) override;
virtual void SetD(double d) override;
void SetF(double f);
void SetIzone(unsigned iz);
virtual void SetPID(double p, double i, double d) override;
void SetPID(double p, double i, double d, double f);
virtual double GetP() override;
@@ -66,6 +74,7 @@ public:
virtual double GetSpeed() override;
virtual int GetClosedLoopError();
virtual int GetAnalogIn();
virtual int GetAnalogInRaw();
virtual int GetAnalogInVel();
virtual int GetEncPosition();
virtual int GetEncVel();
@@ -91,17 +100,41 @@ public:
virtual void ConfigLimitMode(LimitMode mode) override;
virtual void ConfigForwardLimit(double forwardLimitPosition) override;
virtual void ConfigReverseLimit(double reverseLimitPosition) override;
/**
* Change the fwd limit switch setting to normally open or closed.
* Talon will disable momentarilly if the Talon's current setting
* is dissimilar to the caller's requested setting.
*
* Since Talon saves setting to flash this should only affect
* a given Talon initially during robot install.
*
* @param normallyOpen true for normally open. false for normally closed.
*/
void ConfigFwdLimitSwitchNormallyOpen(bool normallyOpen);
/**
* Change the rev limit switch setting to normally open or closed.
* Talon will disable momentarilly if the Talon's current setting
* is dissimilar to the caller's requested setting.
*
* Since Talon saves setting to flash this should only affect
* a given Talon initially during robot install.
*
* @param normallyOpen true for normally open. false for normally closed.
*/
void ConfigRevLimitSwitchNormallyOpen(bool normallyOpen);
virtual void ConfigMaxOutputVoltage(double voltage) override;
virtual void ConfigFaultTime(float faultTime) override;
virtual void SetControlMode(ControlMode mode);
void SetFeedbackDevice(FeedbackDevice device);
void SetStatusFrameRateMs(StatusFrameRate stateFrame, int periodMs);
virtual ControlMode GetControlMode();
void SetSensorDirection(bool reverseSensor);
void SetCloseLoopRampRate(double rampRate);
void SelectProfileSlot(int slotIdx);
double GetIzone();
int GetIzone();
int GetIaccum();
void ClearIaccum();
int GetBrakeEnableDuringNeutral();
bool IsControlEnabled();
double GetSetpoint();
@@ -127,4 +160,12 @@ private:
TalonControlMode m_sendMode;
double m_setPoint;
static const unsigned int kDelayForSolicitedSignalsUs = 4000;
/**
* Fixup the sendMode so Set() serializes the correct demand value.
* Also fills the modeSelecet in the control frame to disabled.
* @param mode Control mode to ultimately enter once user calls Set().
* @see Set()
*/
void ApplyControlMode(CANSpeedController::ControlMode mode);
};

View File

@@ -6,54 +6,76 @@
/*----------------------------------------------------------------------------*/
#pragma once
#include "USBCamera.h"
#include "ErrorBase.h"
#include "nivision.h"
#include "NIIMAQdx.h"
#include <vector>
#include <thread>
#include <mutex>
#include <thread>
#include <memory>
#include <condition_variable>
#include <tuple>
#include <vector>
/**
* Class that runs a TCP server that serves an M-JPEG stream to the dashboard.
*/
class CameraServer : public ErrorBase {
static constexpr uint16_t kPort = 1180;
static constexpr uint8_t kMagicNumber[] = { 0x01, 0x00, 0x00, 0x00 };
static constexpr uint32_t kSize640x480 = 0;
static constexpr uint32_t kSize320x240 = 1;
static constexpr uint32_t kSize160x120 = 2;
static constexpr int32_t kHardwareCompression = -1;
static constexpr char const *kDefaultCameraName = "cam0";
private:
static constexpr uint16_t kPort = 1180;
static constexpr uint8_t kMagicNumber[] = { 0x01, 0x00, 0x00, 0x00 };
static constexpr uint32_t kSize640x480 = 0;
static constexpr uint32_t kSize320x240 = 1;
static constexpr uint32_t kSize160x120 = 2;
static constexpr int32_t kHardwareCompression = -1;
static constexpr uint32_t kMaxImageSize = 200000;
public:
static CameraServer *GetInstance();
protected:
CameraServer();
std::shared_ptr<USBCamera> m_camera;
std::thread m_serverThread;
std::thread m_captureThread;
std::recursive_mutex m_imageMutex;
std::condition_variable_any m_newImageVariable;
std::vector<uint8_t*> m_dataPool;
unsigned int m_quality;
bool m_autoCaptureStarted;
bool m_hwClient;
std::tuple<uint8_t*, unsigned int, unsigned int, bool> m_imageData;
void SetImage(Image const *image);
void Serve();
void AutoCapture();
void SetImageData(uint8_t* data, unsigned int size, unsigned int start = 0, bool imaqData = false);
void FreeImageData(std::tuple<uint8_t*, unsigned int, unsigned int, bool> imageData);
void StartAutomaticCapture(char const *cameraName = kDefaultCameraName);
struct Request {
uint32_t fps;
int32_t compression;
uint32_t size;
};
void SetQuality(unsigned int quality);
unsigned int GetQuality() const;
static CameraServer* s_instance;
public:
static CameraServer* GetInstance();
void SetImage(Image const *image);
protected:
CameraServer();
void serve();
void StartAutomaticCapture(char const *cameraName = USBCamera::kDefaultCameraName);
std::thread m_serverThread;
std::recursive_mutex m_imageMutex;
std::condition_variable_any m_newImageReady;
std::vector<uint8_t> m_imageData;
unsigned int m_quality;
bool m_autoCaptureStarted;
/**
* Start automatically capturing images to send to the dashboard.
*
* You should call this method to just see a camera feed on the
* dashboard without doing any vision processing on the roboRIO.
* {@link #SetImage} should not be called after this is called.
*
* @param camera The camera interface (eg. USBCamera)
*/
void StartAutomaticCapture(std::shared_ptr<USBCamera> camera);
struct Request {
uint32_t fps;
int32_t compression;
uint32_t size;
};
bool IsAutoCaptureStarted();
static CameraServer *s_instance;
void SetQuality(unsigned int quality);
unsigned int GetQuality();
void SetSize(unsigned int size);
};

View File

@@ -32,6 +32,14 @@ public:
void SetClosedLoopControl(bool on);
bool GetClosedLoopControl();
bool GetCompressorCurrentTooHighFault();
bool GetCompressorCurrentTooHighStickyFault();
bool GetCompressorShortedStickyFault();
bool GetCompressorShortedFault();
bool GetCompressorNotConnectedStickyFault();
bool GetCompressorNotConnectedFault();
void ClearAllPCMStickyFaults();
void UpdateTable();
void StartLiveWindowMode();
void StopLiveWindowMode();

View File

@@ -67,7 +67,7 @@ public:
bool GetDirection();
void SetSamplesToAverage(int samplesToAverage);
int GetSamplesToAverage();
uint32_t GetIndex()
uint32_t GetFPGAIndex()
{
return m_index;
}

View File

@@ -31,6 +31,8 @@ public:
virtual ~DoubleSolenoid();
virtual void Set(Value value);
virtual Value Get();
bool IsFwdSolenoidBlackListed();
bool IsRevSolenoidBlackListed();
void ValueChanged(ITable* source, const std::string& key, EntryValue value, bool isNew);
void UpdateTable();

View File

@@ -34,6 +34,7 @@ public:
float GetStickAxis(uint32_t stick, uint32_t axis);
int GetStickPOV(uint32_t stick, uint32_t pov);
uint32_t GetStickButtons(uint32_t stick);
bool GetStickButton(uint32_t stick, uint8_t button);
int GetStickAxisCount(uint32_t stick);

View File

@@ -29,6 +29,7 @@ class DigitalSource;
class Encoder : public SensorBase, public CounterBase, public PIDSource, public LiveWindowSendable
{
public:
enum IndexingType { kResetWhileHigh, kResetWhileLow, kResetOnFallingEdge, kResetOnRisingEdge };
Encoder(uint32_t aChannel, uint32_t bChannel, bool reverseDirection = false,
EncodingType encodingType = k4X);
@@ -41,6 +42,7 @@ public:
// CounterBase interface
int32_t Get();
int32_t GetRaw();
int32_t GetEncodingScale();
void Reset();
double GetPeriod();
void SetMaxPeriod(double maxPeriod);
@@ -56,6 +58,10 @@ public:
void SetPIDSourceParameter(PIDSourceParameter pidSource);
double PIDGet();
void SetIndexSource(uint32_t channel, IndexingType type = kResetOnRisingEdge);
void SetIndexSource(DigitalSource *source, IndexingType type = kResetOnRisingEdge);
void SetIndexSource(DigitalSource &source, IndexingType type = kResetOnRisingEdge);
void UpdateTable();
void StartLiveWindowMode();
void StopLiveWindowMode();
@@ -63,6 +69,11 @@ public:
void InitTable(ITable *subTable);
ITable * GetTable();
int32_t GetFPGAIndex()
{
return m_index;
}
private:
void InitEncoder(bool _reverseDirection, EncodingType encodingType);
double DecodingScaleFactor();
@@ -72,9 +83,11 @@ private:
bool m_allocatedASource; // was the A source allocated locally?
bool m_allocatedBSource; // was the B source allocated locally?
void* m_encoder;
int32_t m_index; // The encoder's FPGA index.
double m_distancePerPulse; // distance of travel for each encoder tick
Counter *m_counter; // Counter object for 1x and 2x encoding
EncodingType m_encodingType; // Encoding type
int32_t m_encodingScale; // 1x, 2x, or 4x, per the encodingType
PIDSourceParameter m_pidSource; // Encoder parameter that sources a PID controller
ITable *m_table;

View File

@@ -60,6 +60,8 @@ public:
virtual void TestPeriodic();
protected:
virtual void Prestart();
virtual ~IterativeRobot();
IterativeRobot();

View File

@@ -13,16 +13,16 @@
* Class implements the PWM generation in the FPGA.
*
* The values supplied as arguments for PWM outputs range from -1.0 to 1.0. They are mapped
* to the hardware dependent values, in this case 0-255 for the FPGA.
* to the hardware dependent values, in this case 0-2000 for the FPGA.
* Changes are immediately sent to the FPGA, and the update occurs at the next
* FPGA cycle. There is no delay.
*
* As of revision 0.1.10 of the FPGA, the FPGA interprets the 0-255 values as follows:
* - 255 = full "forward"
* - 254 to 129 = linear scaling from "full forward" to "center"
* - 128 = center value
* - 127 to 2 = linear scaling from "center" to "full reverse"
* - 1 = full "reverse"
* As of revision 0.1.10 of the FPGA, the FPGA interprets the 0-2000 values as follows:
* - 2000 = maximum pulse width
* - 1999 to 1001 = linear scaling from "full forward" to "center"
* - 1000 = center value
* - 999 to 2 = linear scaling from "center" to "full reverse"
* - 1 = minimum pulse width (currently .5ms)
* - 0 = disabled (i.e. PWM output is held low)
*/
class PWM : public SensorBase, public ITableListener, public LiveWindowSendable

View File

@@ -9,12 +9,14 @@
#define __WPILIB_POWER_DISTRIBUTION_PANEL_H__
#include "SensorBase.h"
#include "LiveWindow/LiveWindowSendable.h"
/**
* Class for getting voltage, current, and temperature from the CAN PDP
* Class for getting voltage, current, temperature, power and energy from the CAN PDP.
* The PDP must be at CAN Address 0.
* @author Thomas Clark
*/
class PowerDistributionPanel : public SensorBase {
class PowerDistributionPanel : public SensorBase, public LiveWindowSendable {
public:
PowerDistributionPanel();
@@ -26,6 +28,16 @@ class PowerDistributionPanel : public SensorBase {
double GetTotalEnergy();
void ResetTotalEnergy();
void ClearStickyFaults();
void UpdateTable();
void StartLiveWindowMode();
void StopLiveWindowMode();
std::string GetSmartDashboardType();
void InitTable(ITable *subTable);
ITable * GetTable();
private:
ITable *m_table;
};
#endif /* __WPILIB_POWER_DISTRIBUTION_PANEL_H__ */

View File

@@ -14,9 +14,9 @@ class DriverStation;
int main() \
{ \
if (!HALInitialize()){std::cerr<<"FATAL ERROR: HAL could not be initialized"<<std::endl;return -1;} \
HALNetworkCommunicationObserveUserProgramStarting(); \
HALReport(HALUsageReporting::kResourceType_Language, HALUsageReporting::kLanguage_CPlusPlus); \
(new _ClassName_())->StartCompetition(); \
_ClassName_ *robot = new _ClassName_(); \
RobotBase::robotSetup(robot); \
return 0; \
}
@@ -44,11 +44,15 @@ public:
static void startRobotTask(FUNCPTR factory);
static void robotTask(FUNCPTR factory, Task *task);
virtual void StartCompetition() = 0;
static void robotSetup(RobotBase *robot);
protected:
virtual ~RobotBase();
RobotBase();
virtual void Prestart();
Task *m_task;
DriverStation *m_ds;

View File

@@ -67,6 +67,7 @@ public:
void SetInvertedMotor(MotorType motor, bool isInverted);
void SetSensitivity(float sensitivity);
void SetMaxOutput(double maxOutput);
void SetCANJaguarSyncGroup(uint8_t syncGroup);
void SetExpiration(float timeout);
float GetExpiration();
@@ -93,6 +94,7 @@ protected:
SpeedController *m_rearLeftMotor;
SpeedController *m_rearRightMotor;
MotorSafetyHelper *m_safetyHelper;
uint8_t m_syncGroup;
private:
int32_t GetNumMotors()

View File

@@ -23,6 +23,7 @@ public:
virtual ~Solenoid();
virtual void Set(bool on);
virtual bool Get();
bool IsBlackListed();
void ValueChanged(ITable* source, const std::string& key, EntryValue value, bool isNew);
void UpdateTable();

View File

@@ -20,6 +20,10 @@ public:
virtual ~SolenoidBase();
uint8_t GetAll();
uint8_t GetPCMSolenoidBlackList();
bool GetPCMSolenoidVoltageStickyFault();
bool GetPCMSolenoidVoltageFault();
void ClearAllPCMStickyFaults();
protected:
explicit SolenoidBase(uint8_t pcmID);
void Set(uint8_t value, uint8_t mask);

View File

@@ -0,0 +1,111 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "ErrorBase.h"
#include "nivision.h"
#include "NIIMAQdx.h"
#include <mutex>
#include <string>
typedef enum whiteBalance_enum {
kFixedIndoor = 3000,
kFixedOutdoor1 = 4000,
kFixedOutdoor2 = 5000,
kFixedFluorescent1 = 5100,
kFixedFlourescent2 = 5200
} whiteBalance;
class USBCamera : public ErrorBase {
private:
static constexpr char const *ATTR_WB_MODE = "CameraAttributes::WhiteBalance::Mode";
static constexpr char const *ATTR_WB_VALUE = "CameraAttributes::WhiteBalance::Value";
static constexpr char const *ATTR_EX_MODE = "CameraAttributes::Exposure::Mode";
static constexpr char const *ATTR_EX_VALUE = "CameraAttributes::Exposure::Value";
static constexpr char const *ATTR_BR_MODE = "CameraAttributes::Brightness::Mode";
static constexpr char const *ATTR_BR_VALUE = "CameraAttributes::Brightness::Value";
protected:
IMAQdxSession m_id;
std::string m_name;
bool m_useJpeg;
bool m_active;
bool m_open;
std::recursive_mutex m_mutex;
unsigned int m_width;
unsigned int m_height;
double m_fps;
std::string m_whiteBalance;
unsigned int m_whiteBalanceValue;
bool m_whiteBalanceValuePresent;
std::string m_exposure;
unsigned int m_exposureValue;
bool m_exposureValuePresent;
unsigned int m_brightness;
bool m_needSettingsUpdate;
unsigned int GetJpegSize(void* buffer, unsigned int buffSize);
public:
static constexpr char const *kDefaultCameraName = "cam0";
USBCamera(std::string name, bool useJpeg);
void OpenCamera();
void CloseCamera();
void StartCapture();
void StopCapture();
void SetFPS(double fps);
void SetSize(unsigned int width, unsigned int height);
void UpdateSettings();
/**
* Set the brightness, as a percentage (0-100).
*/
void SetBrightness(unsigned int brightness);
/**
* Get the brightness, as a percentage (0-100).
*/
unsigned int GetBrightness();
/**
* Set the white balance to auto
*/
void SetWhiteBalanceAuto();
/**
* Set the white balance to hold current
*/
void SetWhiteBalanceHoldCurrent();
/**
* Set the white balance to manual, with specified color temperature
*/
void SetWhiteBalanceManual(unsigned int wbValue);
/**
* Set the exposure to auto exposure
*/
void SetExposureAuto();
/**
* Set the exposure to hold current
*/
void SetExposureHoldCurrent();
/**
* Set the exposure to manual, with a given percentage (0-100)
*/
void SetExposureManual(unsigned int expValue);
void GetImage(Image* image);
unsigned int GetImageData(void* buffer, unsigned int bufferSize);
};

View File

@@ -0,0 +1,127 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <thread>
#include <string>
#include <mutex>
#include "ErrorBase.h"
#include "Vision/ColorImage.h"
#include "Vision/HSLImage.h"
#include "nivision.h"
/**
* Axis M1011 network camera
*/
class AxisCamera: public ErrorBase
{
public:
enum WhiteBalance
{
kWhiteBalance_Automatic,
kWhiteBalance_Hold,
kWhiteBalance_FixedOutdoor1,
kWhiteBalance_FixedOutdoor2,
kWhiteBalance_FixedIndoor,
kWhiteBalance_FixedFluorescent1,
kWhiteBalance_FixedFluorescent2
};
enum ExposureControl
{
kExposureControl_Automatic,
kExposureControl_Hold,
kExposureControl_FlickerFree50Hz,
kExposureControl_FlickerFree60Hz
};
enum Resolution
{
kResolution_640x480,
kResolution_480x360,
kResolution_320x240,
kResolution_240x180,
kResolution_176x144,
kResolution_160x120,
};
enum Rotation
{
kRotation_0, kRotation_180
};
explicit AxisCamera(std::string const& cameraHost);
virtual ~AxisCamera();
bool IsFreshImage() const;
int GetImage(Image *image);
int GetImage(ColorImage *image);
HSLImage *GetImage();
int CopyJPEG(char **destImage, unsigned int &destImageSize, unsigned int &destImageBufferSize);
void WriteBrightness(int brightness);
int GetBrightness();
void WriteWhiteBalance(WhiteBalance whiteBalance);
WhiteBalance GetWhiteBalance();
void WriteColorLevel(int colorLevel);
int GetColorLevel();
void WriteExposureControl(ExposureControl exposureControl);
ExposureControl GetExposureControl();
void WriteExposurePriority(int exposurePriority);
int GetExposurePriority();
void WriteMaxFPS(int maxFPS);
int GetMaxFPS();
void WriteResolution(Resolution resolution);
Resolution GetResolution();
void WriteCompression(int compression);
int GetCompression();
void WriteRotation(Rotation rotation);
Rotation GetRotation();
private:
std::thread m_captureThread;
std::string m_cameraHost;
int m_cameraSocket;
std::mutex m_captureMutex;
std::mutex m_imageDataMutex;
std::vector<uint8_t> m_imageData;
bool m_freshImage;
int m_brightness;
WhiteBalance m_whiteBalance;
int m_colorLevel;
ExposureControl m_exposureControl;
int m_exposurePriority;
int m_maxFPS;
Resolution m_resolution;
int m_compression;
Rotation m_rotation;
bool m_parametersDirty;
bool m_streamDirty;
std::mutex m_parametersMutex;
bool m_done;
void Capture();
void ReadImagesFromCamera();
bool WriteParameters();
int CreateCameraSocket(std::string const& requestString, bool setError);
DISALLOW_COPY_AND_ASSIGN(AxisCamera);
};

View File

@@ -0,0 +1,57 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#pragma once
/* Constants */
#define LOG_DEBUG __FILE__,__FUNCTION__,__LINE__,DEBUG_TYPE
#define LOG_INFO __FILE__,__FUNCTION__,__LINE__,INFO_TYPE
#define LOG_ERROR __FILE__,__FUNCTION__,__LINE__,ERROR_TYPE
#define LOG_CRITICAL __FILE__,__FUNCTION__,__LINE__,CRITICAL_TYPE
#define LOG_FATAL __FILE__,__FUNCTION__,__LINE__,FATAL_TYPE
#define LOG_DEBUG __FILE__,__FUNCTION__,__LINE__,DEBUG_TYPE
/* Enumerated Types */
/** debug levels */
enum dprint_type {DEBUG_TYPE, INFO_TYPE, ERROR_TYPE, CRITICAL_TYPE, FATAL_TYPE};
/** debug output setting */
typedef enum DebugOutputType_enum {
DEBUG_OFF, DEBUG_MOSTLY_OFF, DEBUG_SCREEN_ONLY, DEBUG_FILE_ONLY, DEBUG_SCREEN_AND_FILE
}DebugOutputType;
/* Enumerated Types */
/* Utility functions */
/* debug */
void SetDebugFlag ( DebugOutputType flag );
void dprintf ( const char * tempString, ... ); /* Variable argument list */
/* set FRC ranges for drive */
double RangeToNormalized(double pixel, int range);
/* change normalized value to any range - used for servo */
float NormalizeToRange(float normalizedValue, float minRange, float maxRange);
float NormalizeToRange(float normalizedValue);
/* system utilities */
void ShowActivity (char *fmt, ...);
double ElapsedTime (double startTime);
/* servo panning utilities */
class Servo;
double SinPosition (double *period, double sinStart);
void panInit();
void panInit(double period);
void panForTarget(Servo *panServo);
void panForTarget(Servo *panServo, double sinStart);
/* config file read utilities */
int processFile(char *inputFile, char *outputString, int lineNumber);
int emptyString(char *string);
void stripString(char *string);

View File

@@ -0,0 +1,39 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "MonoImage.h"
/**
* Included for ParticleAnalysisReport definition
* TODO: Eliminate this dependency!
*/
#include "Vision/VisionAPI.h"
#include <vector>
#include <algorithm>
class BinaryImage : public MonoImage
{
public:
BinaryImage();
virtual ~BinaryImage();
int GetNumberParticles();
ParticleAnalysisReport GetParticleAnalysisReport(int particleNumber);
void GetParticleAnalysisReport(int particleNumber, ParticleAnalysisReport *par);
std::vector<ParticleAnalysisReport>* GetOrderedParticleAnalysisReports();
BinaryImage *RemoveSmallObjects(bool connectivity8, int erosions);
BinaryImage *RemoveLargeObjects(bool connectivity8, int erosions);
BinaryImage *ConvexHull(bool connectivity8);
BinaryImage *ParticleFilter(ParticleFilterCriteria2 *criteria, int criteriaCount);
virtual void Write(const char *fileName);
private:
bool ParticleMeasurement(int particleNumber, MeasurementType whatToMeasure, int *result);
bool ParticleMeasurement(int particleNumber, MeasurementType whatToMeasure, double *result);
static double NormalizeFromRange(double position, int range);
static bool CompareParticleSizes(ParticleAnalysisReport particle1, ParticleAnalysisReport particle2);
};

View File

@@ -0,0 +1,65 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "ImageBase.h"
#include "BinaryImage.h"
#include "Threshold.h"
class ColorImage : public ImageBase
{
public:
ColorImage(ImageType type);
virtual ~ColorImage();
BinaryImage *ThresholdRGB(int redLow, int redHigh, int greenLow, int greenHigh, int blueLow, int blueHigh);
BinaryImage *ThresholdHSL(int hueLow, int hueHigh, int saturationLow, int saturationHigh, int luminenceLow, int luminenceHigh);
BinaryImage *ThresholdHSV(int hueLow, int hueHigh, int saturationLow, int saturationHigh, int valueHigh, int valueLow);
BinaryImage *ThresholdHSI(int hueLow, int hueHigh, int saturationLow, int saturationHigh, int intensityLow, int intensityHigh);
BinaryImage *ThresholdRGB(Threshold &threshold);
BinaryImage *ThresholdHSL(Threshold &threshold);
BinaryImage *ThresholdHSV(Threshold &threshold);
BinaryImage *ThresholdHSI(Threshold &threshold);
MonoImage *GetRedPlane();
MonoImage *GetGreenPlane();
MonoImage *GetBluePlane();
MonoImage *GetHSLHuePlane();
MonoImage *GetHSVHuePlane();
MonoImage *GetHSIHuePlane();
MonoImage *GetHSLSaturationPlane();
MonoImage *GetHSVSaturationPlane();
MonoImage *GetHSISaturationPlane();
MonoImage *GetLuminancePlane();
MonoImage *GetValuePlane();
MonoImage *GetIntensityPlane();
void ReplaceRedPlane(MonoImage *plane);
void ReplaceGreenPlane(MonoImage *plane);
void ReplaceBluePlane(MonoImage *plane);
void ReplaceHSLHuePlane(MonoImage *plane);
void ReplaceHSVHuePlane(MonoImage *plane);
void ReplaceHSIHuePlane(MonoImage *plane);
void ReplaceHSLSaturationPlane(MonoImage *plane);
void ReplaceHSVSaturationPlane(MonoImage *plane);
void ReplaceHSISaturationPlane(MonoImage *plane);
void ReplaceLuminancePlane(MonoImage *plane);
void ReplaceValuePlane(MonoImage *plane);
void ReplaceIntensityPlane(MonoImage *plane);
void ColorEqualize();
void LuminanceEqualize();
private:
BinaryImage *ComputeThreshold(ColorMode colorMode, int low1, int high1, int low2, int high2, int low3, int high3);
void Equalize(bool allPlanes);
MonoImage * ExtractColorPlane(ColorMode mode, int planeNumber);
MonoImage * ExtractFirstColorPlane(ColorMode mode);
MonoImage * ExtractSecondColorPlane(ColorMode mode);
MonoImage * ExtractThirdColorPlane(ColorMode mode);
void ReplacePlane(ColorMode mode, MonoImage *plane, int planeNumber);
void ReplaceFirstColorPlane(ColorMode mode, MonoImage *plane);
void ReplaceSecondColorPlane(ColorMode mode, MonoImage *plane);
void ReplaceThirdColorPlane(ColorMode mode, MonoImage *plane);
};

View File

@@ -0,0 +1,30 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#pragma once
/* Error Codes */
#define ERR_VISION_GENERAL_ERROR 166000 //
#define ERR_COLOR_NOT_FOUND 166100 // TrackAPI.cpp
#define ERR_PARTICLE_TOO_SMALL 166101 // TrackAPI.cpp
#define ERR_CAMERA_FAILURE 166200 // AxisCamera.cpp
#define ERR_CAMERA_SOCKET_CREATE_FAILED 166201 // AxisCamera.cpp
#define ERR_CAMERA_CONNECT_FAILED 166202 // AxisCamera.cpp
#define ERR_CAMERA_STALE_IMAGE 166203 // AxisCamera.cpp
#define ERR_CAMERA_NOT_INITIALIZED 166204 // AxisCamera.cpp
#define ERR_CAMERA_NO_BUFFER_AVAILABLE 166205 // AxisCamera.cpp
#define ERR_CAMERA_HEADER_ERROR 166206 // AxisCamera.cpp
#define ERR_CAMERA_BLOCKING_TIMEOUT 166207 // AxisCamera.cpp
#define ERR_CAMERA_AUTHORIZATION_FAILED 166208 // AxisCamera.cpp
#define ERR_CAMERA_TASK_SPAWN_FAILED 166209 // AxisCamera.cpp
#define ERR_CAMERA_TASK_INPUT_OUT_OF_RANGE 166210 // AxisCamera.cpp
#define ERR_CAMERA_COMMAND_FAILURE 166211 // AxisCamera.cpp
/* error handling functions */
int GetLastVisionError();
const char* GetVisionErrorText(int errorCode);

View File

@@ -0,0 +1,22 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "ColorImage.h"
/**
* A color image represented in HSL color space at 3 bytes per pixel.
*/
class HSLImage : public ColorImage
{
public:
HSLImage();
HSLImage(const char *fileName);
virtual ~HSLImage();
};

View File

@@ -0,0 +1,27 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <stdio.h>
#include "nivision.h"
#include "ErrorBase.h"
#define DEFAULT_BORDER_SIZE 3
class ImageBase : public ErrorBase
{
public:
ImageBase(ImageType type);
virtual ~ImageBase();
virtual void Write(const char *fileName);
int GetHeight();
int GetWidth();
Image *GetImaqImage();
protected:
Image *m_imaqImage;
};

View File

@@ -0,0 +1,25 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "ImageBase.h"
#include <vector>
class MonoImage : public ImageBase
{
public:
MonoImage();
virtual ~MonoImage();
std::vector<EllipseMatch> *DetectEllipses(EllipseDescriptor *ellipseDescriptor,
CurveOptions *curveOptions,
ShapeDetectionOptions *shapeDetectionOptions,
ROI *roi);
std::vector<EllipseMatch> * DetectEllipses(EllipseDescriptor *ellipseDescriptor);
};

View File

@@ -0,0 +1,21 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "ColorImage.h"
/**
* A color image represented in RGB color space at 3 bytes per pixel.
*/
class RGBImage : public ColorImage
{
public:
RGBImage();
RGBImage(const char *fileName);
virtual ~RGBImage();
};

View File

@@ -0,0 +1,28 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#pragma once
/**
* Color threshold values.
* This object represnts the threshold values for any type of color object
* that is used in a threshhold operation. It simplifies passing values
* around in a program for color detection.
*/
class Threshold
{
public:
int plane1Low;
int plane1High;
int plane2Low;
int plane2High;
int plane3Low;
int plane3High;
Threshold(int plane1Low, int plane1High,
int plane2Low, int plane2High,
int plane3Low, int plane3High);
};

View File

@@ -0,0 +1,148 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "nivision.h"
/* Constants */
#define DEFAULT_BORDER_SIZE 3 //VisionAPI.frcCreateImage
#define DEFAULT_SATURATION_THRESHOLD 40 //TrackAPI.FindColor
/* Forward Declare Data Structures */
typedef struct FindEdgeOptions_struct FindEdgeOptions;
typedef struct CircularEdgeReport_struct CircularEdgeReport;
/* Data Structures */
/** frcParticleAnalysis returns this structure */
typedef struct ParticleAnalysisReport_struct {
int imageHeight;
int imageWidth;
double imageTimestamp;
int particleIndex; // the particle index analyzed
/* X-coordinate of the point representing the average position of the
* total particle mass, assuming every point in the particle has a constant density */
int center_mass_x; // MeasurementType: IMAQ_MT_CENTER_OF_MASS_X
/* Y-coordinate of the point representing the average position of the
* total particle mass, assuming every point in the particle has a constant density */
int center_mass_y; // MeasurementType: IMAQ_MT_CENTER_OF_MASS_Y
double center_mass_x_normalized; //Center of mass x value normalized to -1.0 to +1.0 range
double center_mass_y_normalized; //Center of mass y value normalized to -1.0 to +1.0 range
/* Area of the particle */
double particleArea; // MeasurementType: IMAQ_MT_AREA
/* Bounding Rectangle */
Rect boundingRect; // left/top/width/height
/* Percentage of the particle Area covering the Image Area. */
double particleToImagePercent; // MeasurementType: IMAQ_MT_AREA_BY_IMAGE_AREA
/* Percentage of the particle Area in relation to its Particle and Holes Area */
double particleQuality; // MeasurementType: IMAQ_MT_AREA_BY_PARTICLE_AND_HOLES_AREA
} ParticleAnalysisReport;
/** Tracking functions return this structure */
typedef struct ColorReport_struct {
int numberParticlesFound; // Number of particles found for this color
int largestParticleNumber; // The particle index of the largest particle
/* Color information */
float particleHueMax; // HistogramReport: hue max
float particleHueMin; // HistogramReport: hue max
float particleHueMean; // HistogramReport: hue mean
float particleSatMax; // HistogramReport: saturation max
float particleSatMin; // HistogramReport: saturation max
float particleSatMean; // HistogramReport: saturation mean
float particleLumMax; // HistogramReport: luminance max
float particleLumMin; // HistogramReport: luminance max
float particleLumMean; // HistogramReport: luminance mean
} ColorReport;
/* Image Management functions */
/* Create: calls imaqCreateImage. Border size is set to some default value */
Image* frcCreateImage( ImageType type );
/* Dispose: calls imaqDispose */
int frcDispose( void* object );
int frcDispose( const char* filename, ... ) ;
/* Copy: calls imaqDuplicateImage */
int frcCopyImage( Image* dest, const Image* source );
/* Image Extraction: Crop: calls imaqScale */
int frcCrop( Image* dest, const Image* source, Rect rect );
/* Image Extraction: Scale: calls imaqScale. Scales entire image */
int frcScale(Image* dest, const Image* source, int xScale, int yScale, ScalingMode scaleMode );
/* Read Image : calls imaqReadFile */
int frcReadImage( Image* image, const char* fileName );
/* Write Image : calls imaqWriteFile */
int frcWriteImage( const Image* image, const char* fileName);
/* Measure Intensity functions */
/* Histogram: calls imaqHistogram */
HistogramReport* frcHistogram( const Image* image, int numClasses, float min, float max, Rect rect );
/* Color Histogram: calls imaqColorHistogram2 */
ColorHistogramReport* frcColorHistogram(const Image* image, int numClasses, ColorMode mode, Image* mask);
/* Get Pixel Value: calls imaqGetPixel */
int frcGetPixelValue( const Image* image, Point pixel, PixelValue* value );
/* Particle Analysis functions */
/* Particle Filter: calls imaqParticleFilter3 */
int frcParticleFilter(Image* dest, Image* source, const ParticleFilterCriteria2* criteria,
int criteriaCount, const ParticleFilterOptions* options, Rect rect, int* numParticles);
int frcParticleFilter(Image* dest, Image* source, const ParticleFilterCriteria2* criteria,
int criteriaCount, const ParticleFilterOptions* options, int* numParticles);
/* Morphology: calls imaqMorphology */
int frcMorphology(Image* dest, Image* source, MorphologyMethod method);
int frcMorphology(Image* dest, Image* source, MorphologyMethod method, const StructuringElement* structuringElement);
/* Reject Border: calls imaqRejectBorder */
int frcRejectBorder(Image* dest, Image* source);
int frcRejectBorder(Image* dest, Image* source, int connectivity8);
/* Count Particles: calls imaqCountParticles */
int frcCountParticles(Image* image, int* numParticles);
/* Particle Analysis Report: calls imaqMeasureParticle */
int frcParticleAnalysis(Image* image, int particleNumber, ParticleAnalysisReport* par);
/* Image Enhancement functions */
/* Equalize: calls imaqEqualize */
int frcEqualize(Image* dest, const Image* source, float min, float max);
int frcEqualize(Image* dest, const Image* source, float min, float max, const Image* mask);
/* Color Equalize: calls imaqColorEqualize */
int frcColorEqualize(Image* dest, const Image* source);
int frcColorEqualize(Image* dest, const Image* source, int colorEqualization);
/* Image Thresholding & Conversion functions */
/* Smart Threshold: calls imaqLocalThreshold */
int frcSmartThreshold(Image* dest, const Image* source, unsigned int windowWidth, unsigned int windowHeight,
LocalThresholdMethod method, double deviationWeight, ObjectType type);
int frcSmartThreshold(Image* dest, const Image* source, unsigned int windowWidth, unsigned int windowHeight,
LocalThresholdMethod method, double deviationWeight, ObjectType type, float replaceValue);
/* Simple Threshold: calls imaqThreshold */
int frcSimpleThreshold(Image* dest, const Image* source, float rangeMin, float rangeMax, float newValue);
int frcSimpleThreshold(Image* dest, const Image* source, float rangeMin, float rangeMax);
/* Color/Hue Threshold: calls imaqColorThreshold */
int frcColorThreshold(Image* dest, const Image* source, ColorMode mode,
const Range* plane1Range, const Range* plane2Range, const Range* plane3Range);
int frcColorThreshold(Image* dest, const Image* source, int replaceValue, ColorMode mode,
const Range* plane1Range, const Range* plane2Range, const Range* plane3Range);
int frcHueThreshold(Image* dest, const Image* source, const Range* hueRange);
int frcHueThreshold(Image* dest, const Image* source, const Range* hueRange, int minSaturation);
/* Extract ColorHue Plane: calls imaqExtractColorPlanes */
int frcExtractColorPlanes(const Image* image, ColorMode mode, Image* plane1, Image* plane2, Image* plane3);
int frcExtractHuePlane(const Image* image, Image* huePlane);
int frcExtractHuePlane(const Image* image, Image* huePlane, int minSaturation);

View File

@@ -85,5 +85,13 @@
#include "Utility.h"
#include "Victor.h"
#include "VictorSP.h"
#include "Vision/AxisCamera.h"
#include "Vision/BinaryImage.h"
#include "Vision/ColorImage.h"
#include "Vision/HSLImage.h"
#include "Vision/ImageBase.h"
#include "Vision/MonoImage.h"
#include "Vision/RGBImage.h"
#include "Vision/Threshold.h"
// XXX: #include "Vision/AxisCamera.h"
#include "WPIErrors.h"

View File

@@ -5339,5 +5339,7 @@ IMAQ_FUNC ReadTextReport* IMAQ_STDCALL imaqReadText(const Image* image, c
IMAQ_FUNC ThresholdData* IMAQ_STDCALL imaqAutoThreshold(Image* dest, Image* source, int numClasses, ThresholdMethod method);
IMAQ_FUNC ColorHistogramReport* IMAQ_STDCALL imaqColorHistogram(Image* image, int numClasses, ColorMode mode, const Image* mask);
IMAQ_FUNC RakeReport* IMAQ_STDCALL imaqRake(const Image* image, const ROI* roi, RakeDirection direction, EdgeProcess process, const RakeOptions* options);
IMAQ_FUNC int IMAQ_STDCALL Priv_ReadJPEGString_C(Image* image, const unsigned char* string, unsigned int stringLength);
#endif

View File

@@ -7,6 +7,7 @@
#include "ADXL345_I2C.h"
#include "I2C.h"
#include "HAL/HAL.hpp"
#include "LiveWindow/LiveWindow.h"
const uint8_t ADXL345_I2C::kAddress;
const uint8_t ADXL345_I2C::kPowerCtlRegister;
@@ -17,6 +18,7 @@ constexpr double ADXL345_I2C::kGsPerLSB;
/**
* Constructor.
*
* @param port The I2C port the accelerometer is attached to
* @param range The range (+ or -) that the accelerometer will measure.
*/
ADXL345_I2C::ADXL345_I2C(Port port, Range range):
@@ -30,6 +32,7 @@ ADXL345_I2C::ADXL345_I2C(Port port, Range range):
SetRange(range);
HALReport(HALUsageReporting::kResourceType_ADXL345, HALUsageReporting::kADXL345_I2C, 0);
LiveWindow::GetInstance()->AddSensor("ADXL345_I2C", port, this);
}
/**
@@ -84,7 +87,7 @@ double ADXL345_I2C::GetAcceleration(ADXL345_I2C::Axes axis)
/**
* Get the acceleration of all axes in Gs.
*
* @return Acceleration measured on all axes of the ADXL345 in Gs.
* @return An object containing the acceleration measured on each axis of the ADXL345 in Gs.
*/
ADXL345_I2C::AllAxes ADXL345_I2C::GetAccelerations()
{
@@ -100,3 +103,24 @@ ADXL345_I2C::AllAxes ADXL345_I2C::GetAccelerations()
//}
return data;
}
std::string ADXL345_I2C::GetSmartDashboardType() {
return "3AxisAccelerometer";
}
void ADXL345_I2C::InitTable(ITable *subtable) {
m_table = subtable;
UpdateTable();
}
void ADXL345_I2C::UpdateTable() {
if (m_table != NULL) {
m_table->PutNumber("X", GetX());
m_table->PutNumber("Y", GetY());
m_table->PutNumber("Z", GetZ());
}
}
ITable* ADXL345_I2C::GetTable() {
return m_table;
}

View File

@@ -8,16 +8,25 @@
#include "DigitalInput.h"
#include "DigitalOutput.h"
#include "SPI.h"
#include "LiveWindow/LiveWindow.h"
const uint8_t ADXL345_SPI::kPowerCtlRegister;
const uint8_t ADXL345_SPI::kDataFormatRegister;
const uint8_t ADXL345_SPI::kDataRegister;
constexpr double ADXL345_SPI::kGsPerLSB;
/**
* Constructor.
*
* @param port The SPI port the accelerometer is attached to
* @param range The range (+ or -) that the accelerometer will measure.
*/
ADXL345_SPI::ADXL345_SPI(SPI::Port port, ADXL345_SPI::Range range)
{
m_port = port;
Init(range);
LiveWindow::GetInstance()->AddSensor("ADXL345_SPI", port, this);
}
/**
@@ -106,7 +115,7 @@ double ADXL345_SPI::GetAcceleration(ADXL345_SPI::Axes axis)
/**
* Get the acceleration of all axes in Gs.
*
* @return Acceleration measured on all axes of the ADXL345 in Gs.
* @return An object containing the acceleration measured on each axis of the ADXL345 in Gs.
*/
ADXL345_SPI::AllAxes ADXL345_SPI::GetAccelerations()
{
@@ -131,3 +140,24 @@ ADXL345_SPI::AllAxes ADXL345_SPI::GetAccelerations()
}
return data;
}
std::string ADXL345_SPI::GetSmartDashboardType() {
return "3AxisAccelerometer";
}
void ADXL345_SPI::InitTable(ITable *subtable) {
m_table = subtable;
UpdateTable();
}
void ADXL345_SPI::UpdateTable() {
if (m_table != NULL) {
m_table->PutNumber("X", GetX());
m_table->PutNumber("Y", GetY());
m_table->PutNumber("Z", GetZ());
}
}
ITable* ADXL345_SPI::GetTable() {
return m_table;
}

Some files were not shown because too many files have changed in this diff Show More