Compare commits

...

188 Commits

Author SHA1 Message Date
cf40f311a8 Remove Unity DigitlaSensor 2025-05-01 15:16:19 +02:00
631c3e00b2 Unit test improvement 2025-05-01 14:35:31 +02:00
405fef13b7 Precent double participant entry for site servers 2025-05-01 14:35:22 +02:00
da1bd1fc61 Fixed tests 2025-05-01 11:33:55 +02:00
e92edbc381 Aligned the Messages 2025-05-01 11:00:08 +02:00
36740cf598 Aligned Participants 2025-04-30 17:00:21 +02:00
09783d2103 Completed things docs 2025-04-30 11:41:10 +02:00
346263d311 Aligned Thing implementation 2025-04-29 11:46:57 +02:00
052620c0f0 Unit test fixes 2025-04-28 18:14:32 +02:00
68b0622a1f Align participant documentation 2025-04-28 18:14:23 +02:00
e0c5d86fab Added link to docs in readme 2025-04-28 11:02:52 +02:00
b2b5ebbce0 Update documentation 2025-04-28 10:59:29 +02:00
76f28e10b7 Merge branch 'main2' 2025-04-24 17:35:23 +02:00
3d2374436c Added wal texutre & minor improvements 2025-04-24 12:59:05 +02:00
a6d6ec1948 Added remote mouth support 2025-04-24 12:07:33 +02:00
fd8215cc7e Binary msg receiving fix 2025-04-23 17:51:10 +02:00
1225ee1097 Object creatation/destruction works 2025-04-23 15:05:56 +02:00
6e85ef163d Steps toward hierarchy changes 2025-04-23 12:49:14 +02:00
be167722e7 Improved network sync 2025-04-22 17:47:22 +02:00
86b12a7326 Static participant list 2025-04-22 12:00:27 +02:00
97fdd74950 Handle name msg 2025-04-22 09:39:42 +02:00
62cc00b694 Improved compatibility with C++ 2025-04-18 17:25:07 +02:00
83159b487d Compatibility Fixes 2025-04-17 09:38:15 +02:00
4ef3b24eae Merge commit '67cf8b31fb9c6d4ec4c053da39ea1162f0e066f8' into V2 2025-04-17 09:35:26 +02:00
3eaa1ba31b Compatibility fixes 2025-04-17 09:35:23 +02:00
67cf8b31fb Fixes 2025-04-17 09:33:17 +02:00
db36669afb Merge commit 'b21ca6b4fb3ba19766b50407ef0a919c03ce65d1' 2025-04-17 09:33:09 +02:00
b21ca6b4fb Added degrees/radians 2025-04-17 09:22:09 +02:00
b3975ed256 Merge commit '36f56c49564ba5c559894cfb6c748dd87adab867' 2025-04-17 09:14:46 +02:00
19b4c33e05 Merge commit '8357c5d6231947a3ecd32a81b723506640fff441' into V2 2025-04-17 08:48:30 +02:00
8357c5d623 Improved debug logging 2025-04-11 11:54:54 +02:00
6699200195 Communication improvements, adding gyro msg 2025-04-10 17:35:26 +02:00
05d4a2acd9 Added gyroscope thing 2025-04-09 17:46:08 +02:00
6d58b741e1 ESP32 tracker sync. 2025-04-09 11:07:43 +02:00
e51159bd1b initial ESP32 tracker support 2025-04-09 09:06:05 +02:00
64864afcb4 Cleanup 2025-04-07 09:45:34 +02:00
d82388fc45 Migrating from ControlCore to RoboidControl 2025-04-07 09:36:22 +02:00
Pascal Serrarens
2ebf4b4040 Migrated to RoboidControl 2025-04-05 17:06:40 +02:00
390f7807cd Fix roboidcontrol repo issue 2025-03-19 17:35:21 +01:00
33ae03bd83 Rename remote_participant to owner 2025-03-12 15:50:24 +01:00
9a13a2de12 Fix ambiguity 2025-03-12 15:34:43 +01:00
5ab59b9d1b Merge branch 'main' of https://git.passer.life/RoboidControl/RoboidControl-Csharp 2025-03-12 15:32:30 +01:00
f1f98189ae Cleanup 2025-03-12 14:59:52 +01:00
f07a2f0b8b Merge commit '1f5e57112b18970a1862f103b1b50b0770f12de3' into V2 2025-03-12 14:56:07 +01:00
1f5e57112b Added BB2B example script 2025-03-12 14:55:55 +01:00
9a2eaae182 Migrated to RoboidControl 2025-03-12 14:52:14 +01:00
Pascal Serrarens
608b40fa86 Improvements, alignmet with Cpp/Python 2025-03-11 17:35:03 +01:00
36f56c4956 Restore test name 2025-03-07 15:31:28 +01:00
2c498a6dd9 Merge commit 'efa9ba852266380641e078741e3f6752c9f0faa7' 2025-03-07 15:23:08 +01:00
efa9ba8522 Updated namespace 2025-03-07 15:20:05 +01:00
c7bce31f34 Restructuring 2025-03-07 14:48:03 +01:00
9ad1ec24d0 Restructuring 2025-03-07 14:48:03 +01:00
6a443e111c Re-organised the repo 2025-03-07 14:32:18 +01:00
f1a550e7f3 Removed dependecies on UnityEngine 2025-03-07 12:23:15 +01:00
Pascal Serrarens
78d0e179df ESP32 ant following trails 2025-02-27 11:19:50 +01:00
Pascal Serrarens
0d115ee65a touch sensor is sending correctly 2025-02-25 17:42:54 +01:00
Pascal Serrarens
6dfbdc7316 Fixed incompatibilities 2025-02-25 16:53:27 +01:00
Pascal Serrarens
15ac8a399b Merge commit 'ac376338de4df35266136050d49e37c4c3f03180' into V2 2025-02-25 16:50:24 +01:00
Pascal Serrarens
f9103758e2 Touch sensor improvements 2025-02-25 16:45:29 +01:00
Pascal Serrarens
ac376338de Implemented all tests, some are failing 2025-02-25 15:46:58 +01:00
Pascal Serrarens
05cdf0328d namespace update 2025-02-25 11:32:34 +01:00
Pascal Serrarens
7d2ffeb11c Merge commit '28d3a98bea156585c804417f43fe49a3b09d88fb' 2025-02-25 11:25:31 +01:00
Pascal Serrarens
f33b105f50 First MSCKF test passed 2025-02-25 11:08:29 +01:00
Pascal Serrarens
28d3a98bea Arduino Ant random walk 2025-02-24 17:42:09 +01:00
Pascal Serrarens
c42c253362 Merge commit '8369450d222e304da8eb2d9e345bd8dd894c917f' into V2 2025-02-24 12:57:01 +01:00
Pascal Serrarens
eca5e698cd First UDP communication is working 2025-02-24 12:54:25 +01:00
Pascal Serrarens
8369450d22 Improved documentation 2025-02-21 15:49:41 +01:00
Pascal Serrarens
c1b9a8c5e6 Port MSCKF complete (from now) 2025-02-21 12:21:12 +01:00
Pascal Serrarens
b628a0c718 Updated Doxyfile 2025-02-19 17:21:39 +01:00
Pascal Serrarens
122ac3360b Remove #nullable 2025-02-19 17:02:30 +01:00
Pascal Serrarens
cd9b4a1e9e namespace change, added doc 2025-02-19 17:01:00 +01:00
Pascal Serrarens
4eb65f1312 Merge commit '383f0c179303e58d859ffe4fb4c05170bed3b1ed' into V2 2025-02-19 16:51:51 +01:00
Pascal Serrarens
383f0c1793 Init Unity documentation 2025-02-19 16:49:54 +01:00
Pascal Serrarens
7b21331afb Completed core documentation 2025-02-19 15:57:44 +01:00
Pascal Serrarens
a1d89ff1f7 Updated namespaces 2025-02-19 14:50:09 +01:00
Pascal Serrarens
d3e12c16f2 Merge commit '9e85419e35233598ba347f4af7da6f5ec033d1d2' into V2 2025-02-19 14:13:39 +01:00
Pascal Serrarens
9e85419e35 Namespace -> RoboidControl, added doc 2025-02-19 13:08:32 +01:00
Pascal Serrarens
a7f6aecb5a Fix Unity errors 2025-02-19 12:27:38 +01:00
Pascal Serrarens
6d37d8cec9 Merge commit 'dcccef221b999eb9cabe377b803fa8d92536ef63' into V2 2025-02-19 12:26:33 +01:00
Pascal Serrarens
dcccef221b Make the unit tests work again (2 are still failing) 2025-02-19 12:23:55 +01:00
Pascal Serrarens
0a75c7f4fd Downgraded to C# 9 2025-02-19 11:21:12 +01:00
Pascal Serrarens
4044b86a9d Unity Compatibility 2025-02-19 11:04:56 +01:00
Pascal Serrarens
062aafd19a Merge commit '0f844f5fad764e47bcd3c5634239e30492405fce' into V2 2025-02-19 11:04:38 +01:00
Pascal Serrarens
0f844f5fad Fixed errors and warnings in generic C# 2025-02-19 10:01:22 +01:00
Pascal Serrarens
f28aea5441 Merge branch 'main' of http://gitlab.passervr.com/passer/csharp/controlcore 2025-02-19 08:53:29 +01:00
Pascal Serrarens
5059dfbe6e Fix Unity references 2025-02-19 08:53:07 +01:00
Pascal Serrarens
86ff02a110 Working ants 2025-02-18 15:05:07 +01:00
Pascal Serrarens
923cb317af Grabbing food 2025-02-17 16:02:29 +01:00
Pascal Serrarens
6551c653c3 Touch & smell sensors 2025-02-17 12:56:39 +01:00
Pascal Serrarens
b10929619d Added initial imu processing 2025-02-17 11:53:32 +01:00
Pascal Serrarens
87744740d4 Fix merge error 2025-02-17 09:05:10 +01:00
Pascal Serrarens
458f256c47 Merge commit '24285831109e32989d22ed58121c9f09d5db940b' 2025-02-17 09:01:47 +01:00
Pascal Serrarens
d88d3a879d Fix merge error 2025-02-17 08:59:22 +01:00
Pascal Serrarens
2428583110 Merge commit '8dab67f620ebd8597b633cae4ce55b3a98f6a922' into V2 2025-02-17 08:58:46 +01:00
Pascal Serrarens
30496197ec Migrated to smell 2025-02-14 17:42:50 +01:00
Pascal Serrarens
8a709e0fd2 Fix all matrix errors 2025-02-14 13:18:23 +01:00
Pascal Serrarens
8dab67f620 completed ComputeResidualAndJacobian 2025-02-14 12:29:38 +01:00
Pascal Serrarens
d96cf9fdb2 Merge commit 'c5dc3b6bf5b8f39e91df49bdfb16fc9d68518679' 2025-02-14 11:07:59 +01:00
Pascal Serrarens
dd23355554 Residual & Jacobian progress 2025-02-14 11:07:30 +01:00
Pascal Serrarens
c5dc3b6bf5 fixed double ToVector3 2025-02-14 11:02:44 +01:00
Pascal Serrarens
1677e64d19 Merge commit 'ed128a443a787ee9f58098631106ef46db816461' into V2 2025-02-14 11:01:54 +01:00
Pascal Serrarens
a017c4de18 Aded focus 2025-02-14 10:56:44 +01:00
Pascal Serrarens
78aed40a9b Multiple ant support 2025-02-14 09:08:08 +01:00
Pascal Serrarens
3e5da90f47 Basic ant behaviour 2025-02-13 12:57:05 +01:00
Pascal Serrarens
8ea28beb42 Ported UpdateEKF 2025-02-12 12:50:53 +01:00
Pascal Serrarens
d337fba6fd completed UpdateWithGoodIds 2025-02-12 11:57:46 +01:00
Pascal Serrarens
b991153b8b Add ChiSquareTest 2025-02-12 11:38:15 +01:00
Pascal Serrarens
ed128a443a Fixes 2025-02-12 09:48:06 +01:00
Pascal Serrarens
5a9d92002d Merge commit '623d3d6156bc2cba12d5846f9e341f157d8ddd79' 2025-02-12 09:41:28 +01:00
Pascal Serrarens
623d3d6156 DistanceSensor working locally 2025-02-11 17:56:01 +01:00
Pascal Serrarens
85a19faeb4 First step to ControlCore 2025-02-11 16:02:28 +01:00
Pascal Serrarens
0307a62ed8 Merge commit '3538b7dcc0710bd848de97e738afe6a34cdba78b' 2025-02-11 14:33:38 +01:00
Pascal Serrarens
0366989199 Extended code 2025-02-11 14:25:57 +01:00
Pascal Serrarens
b56a010725 Ported LinearTriangulate 2025-02-11 11:58:21 +01:00
Pascal Serrarens
f479cfc8fa fixed Vector2Int Distance issue 2025-02-07 14:51:31 +01:00
Pascal Serrarens
dfb5a5af40 Refactoring 2025-02-06 17:33:21 +01:00
Pascal Serrarens
40d542fdc7 Acc is publishing right values 2025-02-05 11:37:22 +01:00
Pascal Serrarens
ac2785a440 Simulation basics 2025-02-05 09:34:54 +01:00
Pascal Serrarens
b1c324f36c Participant things 2025-02-04 17:25:51 +01:00
Pascal Serrarens
425cd8d6f9 Unity thing are starting to work 2025-02-04 17:15:00 +01:00
Pascal Serrarens
246a2b9a3a Simulartion env setup (WIP) 2025-02-04 16:28:20 +01:00
Pascal Serrarens
b2591ca5cc Good SVD from MathNet 2025-01-28 11:43:07 +01:00
Pascal Serrarens
caa53749f3 Further refactoring 2025-01-27 12:13:05 +01:00
Pascal Serrarens
b9d668926c Stuck a essential matrix decomposition 2025-01-24 17:40:12 +01:00
Pascal Serrarens
bed6d95916 Lots of improvements, but RANSAC still does not give the right results 2025-01-23 15:07:24 +01:00
Pascal Serrarens
e178306128 Added RANSAC 2025-01-22 15:39:15 +01:00
Pascal Serrarens
941cdd17db All pipline components present (but untested) 2025-01-21 14:57:48 +01:00
Pascal Serrarens
3538b7dcc0 Performance is better, but score is lower (<1%) 2025-01-16 17:47:45 +01:00
Pascal Serrarens
49f5011823 Bytes -> Binary 2025-01-16 09:24:49 +01:00
Pascal Serrarens
c2aff1ee9a Added AirZeroG Sim, Acc is working properly now 2025-01-15 17:50:05 +01:00
Pascal Serrarens
502a68eaff Added initial Accelerometer 2025-01-15 14:13:51 +01:00
Pascal Serrarens
958cbbd2ed Updated gitignore 2025-01-14 12:08:08 +01:00
Pascal Serrarens
b28a6bd3d9 Merge commit 'a8983f5a7a1bff05017b592a6e8b23208f2aac3c' 2025-01-14 12:06:50 +01:00
Pascal Serrarens
a8983f5a7a thing constuction registration 2025-01-14 09:11:13 +01:00
Pascal Serrarens
e562e2433c Cleanup 2025-01-14 09:10:55 +01:00
Pascal Serrarens
97afb3b730 Cleanup 2025-01-14 09:10:27 +01:00
Pascal Serrarens
dc165edf79 NW PoC works 2025-01-08 17:11:54 +01:00
Pascal Serrarens
735ad3b6dc Added Control Core 2025-01-06 10:35:00 +01:00
Pascal Serrarens
338936ace5 Improve unit tests, cleanup 2025-01-02 10:17:09 +01:00
Pascal Serrarens
02920a56e2 Client/NwId exchange works 2025-01-02 09:30:33 +01:00
Pascal Serrarens
b9e28dc421 Alinged with Python code 2025-01-01 09:58:15 +01:00
Pascal Serrarens
f99d4fb1b7 Fixed issues, added test project 2024-12-31 10:11:08 +01:00
Pascal Serrarens
dd2cbf1646 Merge branch 'main' of http://gitlab.passervr.com/passer/csharp/controlcore 2024-12-31 09:05:00 +01:00
Pascal Serrarens
8bfa6dcea9 Exclude doxygen lof 2024-12-31 09:04:57 +01:00
Pascal Serrarens
d6203e1dd1 ClientMsg code optimization 2024-12-31 09:03:21 +01:00
Pascal Serrarens
478d028c09 Merge commit 'cceba4bbcf61a4ca66eacb5fa5b41de1c99c7da6' into V2 2024-12-31 08:52:32 +01:00
Pascal Serrarens
49920220c3 Local playback is working a bit 2024-12-31 08:46:53 +01:00
Pascal Serrarens
cceba4bbcf Merge branch 'main' of http://gitlab.passervr.com/passer/csharp/controlcore 2024-12-30 15:37:05 +01:00
Pascal Serrarens
2f7bc564a8 Added doxygen 2024-12-30 15:36:29 +01:00
Pascal Serrarens
1429f0a9d6 Make the local things work (somewhat) 2024-12-30 15:35:06 +01:00
Pascal Serrarens
e532f31236 Completed migration to controlcore 2024-12-18 17:02:12 +01:00
Pascal Serrarens
ae6f9fa395 Support Destroy 2024-12-17 12:11:02 +01:00
Pascal Serrarens
9b44918eaf Client->Participant
Custom msg is working now
2024-12-16 12:48:59 +01:00
Pascal Serrarens
b34c536c68 Fixed field order in spherical values in messages 2024-12-14 12:42:14 +01:00
Pascal Serrarens
e975f219f4 Merge commit '17fa48a26673454f22f9c48f76efb5a36c9ffc5a' into V2 2024-12-14 11:51:19 +01:00
Pascal Serrarens
17fa48a266 Ant is hopping around (pose does not look right yet...) 2024-12-13 13:37:53 +01:00
Pascal Serrarens
0d022c26ef Spawned a GLB ant! 2024-12-12 17:42:45 +01:00
Pascal Serrarens
87fbddb2b5 Merge commit '7e80a360274abb6d8f8299cdd2f6ada26bb5ce3c' into pascalV3 2024-12-12 15:46:57 +01:00
Pascal Serrarens
7e80a36027 Improved ControlCore 2024-12-11 15:23:32 +01:00
Pascal Serrarens
1d2da54a17 ControlCore improvements 2024-12-11 14:53:18 +01:00
Pascal Serrarens
0f0fcfdfbf Improved reloading support 2024-12-11 11:29:01 +01:00
Pascal Serrarens
cdd1a7a53f Fix name message 2024-12-09 17:22:30 +01:00
Pascal Serrarens
6e5b923f97 Add networkId to msg constructors 2024-12-09 17:13:38 +01:00
Pascal Serrarens
71ca0eb1f8 Fix modelURl message 2024-12-09 17:03:30 +01:00
Pascal Serrarens
e9a29f253c Added networkId to all relevant messages 2024-12-09 16:59:26 +01:00
Pascal Serrarens
2e4e4c4693 Multiclient is working 2024-12-09 14:02:32 +01:00
Pascal Serrarens
aebe4c0f8e Arduino Ant now works. 2024-12-09 12:06:12 +01:00
Pascal Serrarens
d3cb4c1e47 Merge commit 'fbeed8e80922152c3404fbd5d2b243ae95792ec1' into V2 2024-12-09 10:04:55 +01:00
Pascal Serrarens
fbeed8e809 Used Client override for processing messages 2024-12-09 10:02:19 +01:00
Pascal Serrarens
394dc220ca Merge commit '355dd5c1c519cf07cfb6b9f9200f7f7311e68f20' into V2 2024-12-06 17:50:43 +01:00
Pascal Serrarens
355dd5c1c5 Fixed ThingMsg format 2024-12-06 17:48:55 +01:00
Pascal Serrarens
becb194d64 Merge commit 'f35d60369daf41a4fcd987ef8b31bd384b9536ba' into V2 2024-12-06 17:41:13 +01:00
Pascal Serrarens
9b53eee21e Merge commit 'a48ae12fc2f6d4a99119c128e78bf4b103e607c3' into V2 2024-12-06 17:40:17 +01:00
Pascal Serrarens
f35d60369d Further improvements 2024-12-06 17:38:17 +01:00
Pascal Serrarens
a48ae12fc2 ControlCore mostly works (but I don't see a model on the site server yet) 2024-12-06 16:30:24 +01:00
Pascal Serrarens
d8fc41f1c4 First step for ControlCore support 2024-12-06 15:39:36 +01:00
Pascal Serrarens
673fd3d258 Reimplemented almost everything in C# 2024-12-05 18:06:19 +01:00
Pascal Serrarens
9919aa6578 Replaced use of Thing type with the values 2024-12-05 14:11:58 +01:00
Pascal Serrarens
6f12854d4f Completed messages from Unity Ants 2024-12-05 14:05:54 +01:00
Pascal Serrarens
97ad80e805 Added namespace 2024-12-05 10:41:12 +01:00
Pascal Serrarens
8e6f1b6518 First attempt Messages.cs 2024-12-05 09:55:53 +01:00
Pascal Serrarens
224dd52363 Updated Messages.cs 2024-12-05 09:36:39 +01:00
Pascal Serrarens
7275471e4f Merge commit 'ad6c93258b7441218eca11c9c2aa1fcfbf4a3177' into pascalV3 2024-12-05 09:31:16 +01:00
Pascal Serrarens
ad6c93258b Initial commit 2024-12-05 09:26:20 +01:00
Pascal Serrarens
b16a561587 Removed file again 2024-12-05 09:24:01 +01:00
Pascal Serrarens
2fb932c4cb Add file to subtree? 2024-12-05 09:22:34 +01:00
Pascal Serrarens
4de97dace7 Configure SAST in .gitlab-ci.yml, creating this file if it does not already exist 2024-12-05 07:49:42 +00:00
Pascal Serrarens
8b009003c4 Initial commit 2024-12-05 07:49:41 +00:00
24 changed files with 655 additions and 490 deletions

8
DoxyGen.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4b081f36574e30442818c4087c3324c1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

7
DoxyGen/Doxyfile.meta Normal file
View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f7566f52e6a505b439792756759e12e5
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 083f532f0c28cc648816ade951aa9d1e
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d8fca5c59f506a347804140dd15492fb
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -3,8 +3,11 @@
Roboid Control support for C# applications.
Includes support for the Unity game engine.
# Documentation
The documentation for Roboid Control for C# is found at https://docs.roboidcontrol.com/Csharp/
# Basic components
- RoboidControl::Thing
- RoboidControl::LocalParticipant
- RoboidControl::SiteServer
- RoboidControl::Participant

View File

@ -142,4 +142,4 @@ namespace RoboidControl.Unity {
}
}
#endif
#endif

View File

@ -9,7 +9,7 @@ namespace RoboidControl {
/// </summary>
public const byte Id = 0xB1;
/// <summary>
/// The length of the message, excluding the binary data
/// The length of the message in bytes, excluding the binary data
/// </summary>
/// For the total size of the message this.bytes.Length should be added to this value.
public const byte length = 4;

View File

@ -9,7 +9,7 @@ namespace RoboidControl {
/// </summary>
public const byte Id = 0x20;
/// <summary>
/// The length of the message
/// The length of the message in bytres
/// </summary>
public const byte length = 3;
/// <summary>
@ -34,13 +34,16 @@ namespace RoboidControl {
public DestroyMsg(byte[] buffer) : base(buffer) {
this.networkId = buffer[1];
this.thingId = buffer[2];
}
}
/// @copydoc Passer::RoboidControl::IMessage::Serialize
public override byte Serialize(ref byte[] buffer) {
if (buffer.Length < DestroyMsg.length)
return 0;
#if DEBUG
System.Console.WriteLine($"Send DestroyMsg [{this.networkId}/{this.thingId}]");
#endif
byte ix = 0;
buffer[ix++] = DestroyMsg.Id;
buffer[ix++] = this.networkId;

View File

@ -11,7 +11,6 @@ namespace RoboidControl {
/// </summary>
/// <param name="buffer">The byte array to parse</param>
public IMessage(byte[] buffer) {
//Deserialize(buffer);
}
/// <summary>

View File

@ -9,7 +9,7 @@ namespace RoboidControl {
/// </summary>
public const byte Id = 0x81;
/// <summary>
/// The length of the message
/// /// The length of the message
/// </summary>
public const byte length = 3;
/// <summary>
@ -22,13 +22,13 @@ namespace RoboidControl {
public byte thingId;
/// <summary>
/// Create a new message for sending
/// Create an investigate message
/// </summary>
/// <param name="networkId">The network ID for the thing</param>
/// <param name="thingId">The ID of the thing</param>
public InvestigateMsg(byte networkId, byte thingId) {
/// <param name="thing">The thing for which the details are requested</param>
public InvestigateMsg(byte networkId, Thing thing) {
this.networkId = networkId;
this.thingId = thingId;
this.thingId = thing.id;
}
/// @copydoc Passer::RoboidControl::IMessage::IMessage(byte[] buffer)
public InvestigateMsg(byte[] buffer) : base(buffer) { }

View File

@ -8,7 +8,6 @@ namespace RoboidControl {
SendAngle8(buffer, ref ix, v.direction.horizontal);
SendAngle8(buffer, ref ix, v.direction.vertical);
}
public static Spherical ReceiveSpherical(byte[] data, ref byte ix) {
float distance = ReceiveFloat16(data, ref ix);
float horizontal = ReceiveAngle8(data, ref ix);
@ -17,11 +16,6 @@ namespace RoboidControl {
return v;
}
public static void SendQuat32(byte[] buffer, ref byte ix, SwingTwist s) {
Quat32 q32 = Quat32.FromSwingTwist(s);
SendQuat32(buffer, ref ix, q32);
}
public static void SendQuat32(byte[] buffer, ref byte ix, Quat32 q) {
int qx = (int)(q.x * 127 + 128);
int qy = (int)(q.y * 127 + 128);
@ -48,6 +42,11 @@ namespace RoboidControl {
return q;
}
public static void SendQuat32(byte[] buffer, ref byte ix, SwingTwist s) {
Quat32 q32 = Quat32.FromSwingTwist(s);
SendQuat32(buffer, ref ix, q32);
}
public static SwingTwist ReceiveSwingTwist(byte[] data, ref byte ix) {
Quat32 q32 = ReceiveQuat32(data, ref ix);
// UnityEngine.Quaternion q = new(q32.x, q32.y, q32.z, q32.w);
@ -66,7 +65,6 @@ namespace RoboidControl {
sbyte value = (sbyte)(angle / 360.0f * 256.0f);
buffer[ix++] = (byte)value;
}
public static float ReceiveAngle8(byte[] data, ref byte ix) {
float value = (data[ix++] * 180) / 128.0F;
return value;
@ -83,7 +81,6 @@ namespace RoboidControl {
data[ix++] = (byte)((binary >> 8) & 0xFF);
data[ix++] = (byte)(binary & 0xFF);
}
public static float ReceiveFloat16(byte[] data, ref byte ix) {
byte msb = data[ix++];
byte lsb = data[ix++];

View File

@ -40,18 +40,6 @@ namespace RoboidControl {
this.urlLength = (byte)thing.modelUrl.Length;
this.url = thing.modelUrl;
}
/// <summary>
/// Create a new message for sending
/// </summary>
/// <param name="networkId">The network ID of the thing</param>
/// <param name="thingId">The ID of the thing</param>
/// <param name="url">The URL to send</param>
// public ModelUrlMsg(byte networkId, byte thingId, string url) {
// this.networkId = networkId;
// this.thingId = thingId;
// this.urlLength = (byte)url.Length;
// this.url = url;
// }
/// @copydoc Passer::RoboidControl::IMessage::IMessage(byte[] buffer)
public ModelUrlMsg(byte[] buffer) {
byte ix = 1;

View File

@ -66,28 +66,8 @@ namespace RoboidControl {
/// Create a new message for sending
/// </summary>
/// <param name="networkId">The network ID of the thing</param>
/// <param name="thingId">The ID of the thing</param>
/// <param name="position">The position of the thing in local space in meters</param>
/// <param name="orientation">The orientation of the thing in local space</param>
public PoseMsg(byte networkId, byte thingId, Spherical position, SwingTwist orientation, Spherical linearVelocity = null, Spherical angularVelocity = null) {
this.networkId = networkId;
this.thingId = thingId;
this.poseType = 0;
if (this.position != null)
this.poseType |= Pose_Position;
if (this.orientation != null)
this.poseType |= Pose_Orientation;
if (this.linearVelocity != null)
this.poseType |= Pose_LinearVelocity;
if (this.angularVelocity != null)
this.poseType |= Pose_AngularVelocity;
this.position = position;
this.orientation = orientation;
this.linearVelocity = linearVelocity;
this.angularVelocity = angularVelocity;
}
/// <param name="thing">The thing for which the pose should be sent</param>
/// <param name="force">If true, position and orientation are always included, even when they are not updated</param>
public PoseMsg(byte networkId, Thing thing, bool force = false) {
this.networkId = networkId;
this.thingId = thing.id;

View File

@ -1,7 +1,7 @@
namespace RoboidControl {
/// <summary>
/// Message providing generic information about a Thing
/// Message providing generic details about a Thing
/// </summary>
public class ThingMsg : IMessage {
/// <summary>
@ -21,11 +21,11 @@ namespace RoboidControl {
/// </summary>
public byte thingId;
/// <summary>
/// The Thing.Type of the thing
/// The type of thing
/// </summary>
public byte thingType;
/// <summary>
/// The parent of the thing in the hierarachy. This is null for root Things
/// The ID of the parent thing in the hierarchy. This is zero for root things
/// </summary>
public byte parentId;
@ -44,19 +44,6 @@ namespace RoboidControl {
this.parentId = 0;
}
/// <summary>
/// Create a message for sending
/// </summary>
/// <param name="networkId">The network ID of the thing</param>
/// <param name="thingId">The ID of the thing</param>
/// <param name="thingType">The type of thing</param>
/// <param name="parentId">The parent of the thing</param>
public ThingMsg(byte networkId, byte thingId, byte thingType, byte parentId) {
this.networkId = networkId;
this.thingId = thingId;
this.thingType = thingType;
this.parentId = parentId;
}
/// <summary>
/// Create a message for receiving
/// </summary>
/// <param name="buffer">The byte array to parse</param>

View File

@ -11,10 +11,6 @@ namespace RoboidControl {
/// It also maintains the communcation information to contact the participant.
/// It is used as a basis for the local participant, but also as a reference to remote participants.
public class Participant {
/// <summary>
/// Default constructor
/// </summary>
public Participant() { }
/// <summary>
/// Create a new participant with the given communcation info
/// </summary>
@ -35,64 +31,21 @@ namespace RoboidControl {
public int port = 0;
/// <summary>
/// The network ID of the participant
/// he network Id to identify the participant
/// </summary>
public byte networkId;
public byte networkId = 0;
/// <summary>
/// The things managed by this participant
/// </summary>
public readonly List<Thing> things = new List<Thing>();
public virtual void Update(ulong currentTimeMS = 0) {
int n = this.things.Count;
for (int ix = 0; ix < n; ix++) {
Thing thing = this.things[ix];
if (thing != null)
thing.Update(currentTimeMS, true);
}
}
public static List<Participant> participants = new List<Participant>();
public static Participant GetParticipant(string ipAddress, int port) {
//Console.WriteLine($"Get Participant {ipAddress}:{port}");
foreach (Participant participant in Participant.participants) {
if (participant.ipAddress == ipAddress && participant.port == port)
return participant;
}
return null;
}
public static Participant GetParticipant(int participantId) {
//Console.WriteLine($"Get Participant [participantId]");
foreach (Participant participant in Participant.participants) {
if (participant.networkId == participantId)
return participant;
}
return null;
}
public static Participant AddParticipant(string ipAddress, int port) {
Console.WriteLine($"New Participant {ipAddress}:{port}");
Participant participant = new(ipAddress, port) {
networkId = (byte)(Participant.participants.Count + 1)
};
Participant.participants.Add(participant);
return participant;
}
public static void AddParticipant(Participant participant) {
Participant foundParticipant = Participant.GetParticipant(participant.networkId);
if (foundParticipant == null)
Participant.participants.Add(participant);
}
public readonly List<Thing> things = new();
/// <summary>
/// Get a thing with the given ids
/// Get the thing with the given properties
/// </summary>
/// <param name="networkId">The network ID of the thing</param>
/// <param name="thingId">The ID of the thing</param>
/// <returns>The thing when it is found, null in other cases.</returns>
public Thing Get(byte networkId, byte thingId) {
public Thing Get(byte thingId) {
Thing thing = things.Find(aThing => aThing.id == thingId);
//Thing thing = things.Find(aThing => Thing.IsThing(aThing, networkId, thingId));
// if (thing == null)
@ -104,30 +57,17 @@ namespace RoboidControl {
/// Add a new thing for this participant
/// </summary>
/// <param name="thing">The thing to add</param>
/// <param name="invokeEvent">Invoke an notification event when the thing has been added</param>
public void Add(Thing thing, bool checkId = true, bool invokeEvent = true) {
/// <param name="checkId">If true, the thing.id is regenerated if it is zero
public void Add(Thing thing, bool checkId = true) {
if (checkId && thing.id == 0) {
thing.id = (byte)(this.things.Count + 1);
this.things.Add(thing);
}
// Console.WriteLine($"added thing [{thing.networkId}/{thing.id}]");
Thing foundThing = Get(thing.networkId, thing.id);
if (foundThing == null) {
this.things.Add(thing);
// if (invokeEvent)
// Thing.InvokeNewThing(thing);
// Console.Write($"Add thing {ipAddress}:{port}[{networkId}/{thing.id}]");
else {
Thing foundThing = Get(thing.id);
if (foundThing == null)
this.things.Add(thing);
}
// else {
// if (thing != foundThing) {
// // should be: find first non-existing id...
// thing.id = (byte)this.things.Count;
// things.Add(thing);
// // Console.Write($"Add thing, updated thing id to [{thing.networkId}/{thing.id}]");
// }
// }
}
/// <summary>
@ -138,6 +78,77 @@ namespace RoboidControl {
this.things.Remove(thing);
}
/// <summary>
/// Update all things for this participant
/// </summary>
/// <param name="currentTimeMS">The current time in milliseconds (optional)</param>
public virtual void Update(ulong currentTimeMS = 0) {
int n = this.things.Count;
for (int ix = 0; ix < n; ix++) {
Thing thing = this.things[ix];
if (thing != null)
thing.Update(currentTimeMS, true);
}
}
/// <summary>
/// The collection of known participants.
/// </summary>
public readonly static List<Participant> participants = new();
/// <summary>
/// Retrieve a participant using ip address and port number
/// </summary>
/// <param name="ipAddress">The ip address of the participant</param>
/// <param name="port">The port number used to send messages to the participant</param>
/// <returns>The participant or null if it is not found.</returns>
public static Participant GetParticipant(string ipAddress, int port) {
//Console.WriteLine($"Get Participant {ipAddress}:{port}");
foreach (Participant participant in Participant.participants) {
if (participant.ipAddress == ipAddress && participant.port == port)
return participant;
}
return null;
}
/// <summary>
/// Retrieve a participant using a network ID
/// </summary>
/// <param name="networkId">The network ID of the participant</param>
/// <returns>The participant or null if it is not found.</returns>
public static Participant GetParticipant(int networkId) {
//Console.WriteLine($"Get Participant [networkId]");
foreach (Participant participant in Participant.participants) {
if (participant.networkId == networkId)
return participant;
}
return null;
}
/// <summary>
/// Add a new participant to the collection of participants
/// </summary>
/// <param name="ipAddress">The IP address of the participant</param>
/// <param name="port">The port used to send messages to this participant</param>
/// <returns>The added participant</returns>
public static Participant AddParticipant(string ipAddress, int port) {
Console.WriteLine($"New Participant {ipAddress}:{port}");
Participant participant = new(ipAddress, port) {
networkId = (byte)(Participant.participants.Count + 1)
};
Participant.participants.Add(participant);
return participant;
}
/// <summary>
/// Add a new participant to the collection of participants
/// </summary>
/// <param name="participant">The participant to add</param>
/// <note>This function only adds the participant if it is not yet in the collection</note>
public static void AddParticipant(Participant participant) {
Participant foundParticipant = Participant.GetParticipant(participant.networkId);
if (foundParticipant == null)
Participant.participants.Add(participant);
}
}
}

View File

@ -7,40 +7,41 @@ using System.Net.NetworkInformation;
namespace RoboidControl {
/// <summary>
/// A participant is used for communcation between things
/// A participant using UDP communication
/// </summary>
/// A local participant is the local device which can communicate with
/// other participants It manages all local things and communcation with other
/// participants. Each application has a local participant which is usually
/// explicit in the code. An participant can be isolated. In that case it is
/// standalong and does not communicate with other participants.
///
/// It is possible to work with an hidden participant by creating things without
/// specifying a participant in the constructor. In that case an hidden isolated
/// participant is created which can be obtained using
/// RoboidControl::IsolatedParticipant::Isolated().
/// @sa RoboidControl::Thing::Thing()
public class ParticipantUDP : Participant {
public byte[] buffer = new byte[1024];
public ulong publishInterval = 3000; // = 3 seconds
public string name = "Participant";
public bool isIsolated = false;
public Participant remoteSite;
public IPEndPoint endPoint = null;
public UdpClient udpClient = null;
public string broadcastIpAddress = "255.255.255.255";
public readonly ConcurrentQueue<IMessage> messageQueue = new ConcurrentQueue<IMessage>();
#region Init
/// <summary>
/// Create a participant with the give UDP port
/// Create a participant without connecting to a site
/// </summary>
/// <param name="port">The port number on which to communicate</param>
/// These participant typically broadcast Participant messages to let site
/// servers on the local network know their presence. Alternatively they can
/// broadcast information which can be used directly by other participants.
public ParticipantUDP(int port = 0) : base("127.0.0.1", port) {
if (this.port == 0)
this.isIsolated = true;
Participant.AddParticipant(this);
}
/// <summary>
/// Create a new participant for a site at the given address and port
/// Create a participant which will try to connect to a site.
/// </summary>
/// <param name="ipAddress">The ip address of the site server</param>
/// <param name="port">The port number of the site server</param>
/// <param name="localPort">The port used by the local participant</param>
public ParticipantUDP(string ipAddress, int port = 7681, int localPort = 7681) : base("127.0.0.1", localPort) {
if (this.port == 0)
this.isIsolated = true;
@ -81,16 +82,48 @@ namespace RoboidControl {
}
private static ParticipantUDP isolatedParticipant = null;
/// <summary>
/// Create a participant using the given udp client
/// Isolated participant is used when the application is run without networking
/// </summary>
/// <param name="udpClient">UDP client to use for communication</param>
/// <param name="port">The port number on which to communicate</param>
public ParticipantUDP(UdpClient udpClient, int port) : this() {
this.udpClient = udpClient;
this.port = port;
/// <returns>A participant without networking support</returns>
public static ParticipantUDP Isolated() {
if (isolatedParticipant == null)
isolatedParticipant = new ParticipantUDP(0);
return isolatedParticipant;
}
#endregion Init
/// <summary>
/// The name of the participant
/// </summary>
public string name = "ParticipantUDP";
/// <summary>
/// True if the participant is running isolated.
/// </summary>
/// Isolated participants do not communicate with other participants
public bool isIsolated = false;
/// <summary>
/// The remote site when this participant is connected to a site
/// </summary>
public Participant remoteSite = null;
/// <summary>
/// The interval in milliseconds for publishing (broadcasting) data on the local network
/// </summary>
public ulong publishInterval = 3000; // = 3 seconds
public byte[] buffer = new byte[1024];
public IPEndPoint endPoint = null;
public UdpClient udpClient = null;
public string broadcastIpAddress = "255.255.255.255";
public readonly ConcurrentQueue<IMessage> messageQueue = new ConcurrentQueue<IMessage>();
protected void GetBroadcastAddress(IPAddress ip, IPAddress subnetMask) {
byte[] ipBytes = ip.GetAddressBytes();
byte[] maskBytes = subnetMask.GetAddressBytes();
@ -110,14 +143,6 @@ namespace RoboidControl {
Console.WriteLine($"Broadcast address: {this.broadcastIpAddress}");
}
private static ParticipantUDP isolatedParticipant = null;
public static ParticipantUDP Isolated() {
if (isolatedParticipant == null)
isolatedParticipant = new ParticipantUDP(0);
return isolatedParticipant;
}
#endregion Init
#region Update
protected ulong nextPublishMe = 0;
@ -208,9 +233,19 @@ namespace RoboidControl {
this.Send(owner, new ThingMsg(this.networkId, thing));
this.Send(owner, new NameMsg(this.networkId, thing));
this.Send(owner, new ModelUrlMsg(this.networkId, thing));
this.Send(owner, new PoseMsg(this.networkId, thing));
this.Send(owner, new BinaryMsg(this.networkId, thing));
}
public void PublishThingInfo(Thing thing) {
// Console.WriteLine("Publish thing info");
this.Publish(new ThingMsg(this.networkId, thing));
this.Publish(new NameMsg(this.networkId, thing));
this.Publish(new ModelUrlMsg(this.networkId, thing));
this.Publish(new PoseMsg(this.networkId, thing));
this.Publish(new BinaryMsg(this.networkId, thing));
}
public bool Send(Participant owner, IMessage msg) {
int bufferSize = msg.Serialize(ref this.buffer);
if (bufferSize <= 0)
@ -222,14 +257,6 @@ namespace RoboidControl {
return true;
}
public void PublishThingInfo(Thing thing) {
// Console.WriteLine("Publish thing info");
this.Publish(new ThingMsg(this.networkId, thing));
this.Publish(new NameMsg(this.networkId, thing));
this.Publish(new ModelUrlMsg(this.networkId, thing));
this.Publish(new BinaryMsg(this.networkId, thing));
}
public bool Publish(IMessage msg) {
int bufferSize = msg.Serialize(ref this.buffer);
if (bufferSize <= 0)
@ -240,24 +267,6 @@ namespace RoboidControl {
return true;
}
// public bool SendBuffer(int bufferSize) {
// //if (this.ipAddress == null)
// // return false;
// // UnityEngine.Debug.Log($"Send msg {buffer[0]} to {ipAddress}");
// //this.udpClient.Send(this.buffer, bufferSize, this.ipAddress, this.port);
// this.udpClient?.Send(this.buffer, bufferSize, this.endPoint);
// return true;
// }
// public bool PublishBuffer(int bufferSize) {
// if (this.broadcastIpAddress == null)
// return false;
// this.udpClient?.Send(this.buffer, bufferSize, this.broadcastIpAddress, this.port);
// return true;
// }
#endregion
#region Receive
@ -350,62 +359,63 @@ namespace RoboidControl {
protected virtual void Process(Participant sender, InvestigateMsg msg) {
#if DEBUG
Console.WriteLine($"Participant: InvestigateMsg [{msg.networkId}/{msg.thingId}]");
Console.WriteLine($"{this.name}: Process InvestigateMsg [{msg.networkId}/{msg.thingId}]");
#endif
}
protected virtual void Process(Participant sender, ThingMsg msg) {
#if DEBUG
Console.WriteLine($"Participant: Process ThingMsg [{msg.networkId}/{msg.thingId}] {msg.thingType} {msg.parentId}");
Console.WriteLine($"{this.name}: Process ThingMsg [{msg.networkId}/{msg.thingId}] {msg.thingType} {msg.parentId}");
#endif
}
protected virtual void Process(Participant sender, NameMsg msg) {
#if DEBUG
Console.WriteLine($"Participant: Process NameMsg [{msg.networkId}/{msg.thingId}] {msg.nameLength} {msg.name}");
Console.WriteLine($"{this.name}: Process NameMsg [{msg.networkId}/{msg.thingId}] {msg.nameLength} {msg.name}");
#endif
Thing thing = sender.Get(msg.networkId, msg.thingId);
Thing thing = sender.Get(msg.thingId);
if (thing != null)
thing.name = msg.name;
}
protected virtual void Process(Participant sender, ModelUrlMsg msg) {
#if DEBUG
Console.WriteLine($"Participant: Process ModelUrlMsg [{msg.networkId}/{msg.thingId}] {msg.urlLength} {msg.url}");
Console.WriteLine($"{this.name}: Process ModelUrlMsg [{msg.networkId}/{msg.thingId}] {msg.urlLength} {msg.url}");
#endif
Thing thing = sender.Get(msg.networkId, msg.thingId);
Thing thing = sender.Get(msg.thingId);
if (thing != null)
thing.modelUrl = msg.url;
}
protected virtual void Process(Participant sender, PoseMsg msg) {
#if DEBUG
Console.WriteLine($"Participant: Process PoseMsg [{msg.networkId}/{msg.thingId}] {msg.poseType}");
Console.WriteLine($"{this.name}: Process PoseMsg [{msg.networkId}/{msg.thingId}] {msg.poseType}");
#endif
Thing thing = sender.Get(msg.networkId, msg.thingId);
if (thing != null) {
if ((msg.poseType & PoseMsg.Pose_Position) != 0)
thing.position = msg.position;
if ((msg.poseType & PoseMsg.Pose_Orientation) != 0)
thing.orientation = msg.orientation;
if ((msg.poseType & PoseMsg.Pose_LinearVelocity) != 0) {
thing.linearVelocity = msg.linearVelocity;
//Console.Write($"linear velocity = {thing.linearVelocity.ToVector3()}");
}
if ((msg.poseType & PoseMsg.Pose_AngularVelocity) != 0) {
thing.angularVelocity = msg.angularVelocity;
//Console.Write($"angular velocity = {thing.angularVelocity.ToVector3()}");
}
}
Participant owner = Participant.GetParticipant(msg.networkId);
if (owner == null)
return;
Thing thing = owner.Get(msg.thingId);
if (thing == null)
return;
if ((msg.poseType & PoseMsg.Pose_Position) != 0)
thing.position = msg.position;
if ((msg.poseType & PoseMsg.Pose_Orientation) != 0)
thing.orientation = msg.orientation;
if ((msg.poseType & PoseMsg.Pose_LinearVelocity) != 0)
thing.linearVelocity = msg.linearVelocity;
if ((msg.poseType & PoseMsg.Pose_AngularVelocity) != 0)
thing.angularVelocity = msg.angularVelocity;
}
protected virtual void Process(Participant sender, BinaryMsg msg) {
#if DEBUG
Console.WriteLine($"Participant: Process BinaryMsg [{msg.networkId}/{msg.thingId}] {msg.dataLength}");
Console.WriteLine($"{this.name}: Process BinaryMsg [{msg.networkId}/{msg.thingId}] {msg.dataLength}");
#endif
Thing thing = sender.Get(msg.networkId, msg.thingId);
Thing thing = sender.Get(msg.thingId);
thing?.ProcessBinary(msg.data);
}
@ -420,10 +430,12 @@ namespace RoboidControl {
#if DEBUG
Console.WriteLine($"Participant: Process Destroy Msg [{msg.networkId}/{msg.thingId}]");
#endif
Thing thing = sender.Get(msg.networkId, msg.thingId);
Thing thing = sender.Get(msg.thingId);
if (thing != null)
this.Remove(thing);
#if UNITY_5_3_OR_NEWER
thing.component.core = null;
#endif
}
private void ForwardMessage(IMessage msg) {

View File

@ -10,13 +10,14 @@ namespace RoboidControl {
/// </summary>
public class SiteServer : ParticipantUDP {
#region Init
/// <summary>
/// Create a new site server
/// </summary>
/// <param name="port"></param>
/// <param name="port">The port of which to receive the messages</param>
public SiteServer(int port = 7681) : base(port) {
this.name = "Site Server";
Participant.AddParticipant(this);
// Determine local IP address
IPAddress localIpAddress = null;
@ -51,6 +52,8 @@ namespace RoboidControl {
}
#endregion Init
/// <summary>
/// Close the site
/// </summary>
@ -105,20 +108,20 @@ namespace RoboidControl {
protected override void Process(Participant sender, ThingMsg msg) {
Console.WriteLine($"SiteServer: Process thing [{msg.networkId}/{msg.thingId}] {msg.thingType} {msg.parentId} ");
Thing thing = sender.Get(msg.networkId, msg.thingId);
Thing thing = sender.Get(msg.thingId);
if (thing == null) {
switch (msg.thingType) {
case (byte)Thing.Type.TouchSensor:
new TouchSensor(sender, msg.networkId, msg.thingId);
new TouchSensor(sender, msg.thingId);
break;
}
}
if (thing == null)
thing = new Thing(sender, msg.networkId, msg.thingId, msg.thingType);
thing = new Thing(sender, msg.thingType, msg.thingId);
if (msg.parentId != 0) {
thing.parent = sender.Get(msg.networkId, msg.parentId);
thing.parent = sender.Get(msg.parentId);
if (thing.parent == null)
Console.WriteLine($"Could not find parent [{msg.networkId}/{msg.parentId}]");
}

View File

@ -10,90 +10,84 @@ namespace RoboidControl {
[Serializable]
public class Thing {
#region Types
/// <summary>
/// Predefined thing types
/// </summary>
public enum Type {
Undetermined,
// Sensor
Switch,
DistanceSensor,
DirectionalSensor,
TemperatureSensor,
TouchSensor,
public static class Type {
public const byte Undetermined = 0x00;
// sensor
public const byte Switch = 0x01;
public const byte DistanceSensor = 0x02;
public const byte DirectionalSensor = 0x03;
public const byte TemperatureSensor = 0x04;
public const byte TouchSensor = 0x05;
// Motor
ControlledMotor,
UncontrolledMotor,
Servo,
public const byte ControlledMotor = 0x06;
public const byte UncontrolledMotor = 0x07;
public const byte Servo = 0x08;
// Other
Roboid,
Humanoid,
ExternalSensor
};
public delegate void ChangeHandler();
public delegate void SphericalHandler(Spherical v);
public delegate void ThingHandler(Thing t);
#endregion Types
public const byte Roboid = 0x09;
public const byte HUmanoid = 0x0A;
public const byte ExternalSensor = 0x0B;
public const byte Animator = 0x0C;
public const byte DifferentialDrive = 0x0D;
}
#region Init
/// <summary>
/// Create a new thing without communication abilities
/// </summary>
/// <param name="thingType">The type of thing (can use \ref RoboidControl::Thing::Type "Thing.Type")</param>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public Thing(byte thingType = Type.Undetermined, bool invokeEvent = true) : this(ParticipantUDP.Isolated(), thingType, 0, invokeEvent) {
}
/// <summary>
/// Create a new thing for a participant
/// </summary>
/// <param name="owner">The participant owning the thing</param>
/// <param name="thingType">The type of thing</param>
public Thing(Participant owner, byte thingType = (byte)Type.Undetermined, bool invokeEvent = true) {
/// <param name="owner">The owning participant</param>
/// <param name="thingType">The type of thing (can use \ref RoboidControl::Thing::Type "Thing.Type")</param>
/// <param name="thingId">The ID of the thing, leave out or set to zero to generate an ID</param>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public Thing(Participant owner, byte thingType = Type.Undetermined, byte thingId = 0, bool invokeEvent = true) {
this.owner = owner;
this.id = thingId;
this.type = thingType;
if (this.owner != null)
this.owner.Add(this);
if (invokeEvent)
InvokeNewThing(this);
}
public Thing(Participant owner) : this(owner, Type.Undetermined) { }
/// <summary>
/// Create a new thing for a participant
/// </summary>
/// <param name="owner">The participant owning the thing</param>
/// <param name="thingType">The type of thing</param>
public Thing(Participant owner, Type thingType = Type.Undetermined, bool invokeEvent = true) : this(owner, (byte)thingType, invokeEvent) {
}
/// <summary>
/// Create a new thing without communication abilities
/// </summary>
/// <param name="thingType">The type of thing</param>
public Thing(byte thingType = (byte)Type.Undetermined, bool invokeEvent = true) : this(ParticipantUDP.Isolated(), thingType, invokeEvent) {
}
/// <summary>
/// Create a new thing as a child of another thing
/// Create a new child thing
/// </summary>
/// <param name="parent">The parent thing</param>
/// <param name="thingType">The type of thing</param>
public Thing(Thing parent, byte thingType = (byte)Type.Undetermined, bool invokeEvent = true) : this(parent.owner, thingType, invokeEvent) {
/// <param name="thingType">The type of thing (can use \ref RoboidControl::Thing::Type "Thing.Type")</param>
/// <param name="thingId">The ID of the thing, leave out or set to zero to generate an ID</param>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
/// <note>The owner will be the same as the owner of the parent thing</note>
public Thing(Thing parent, byte thingType = Type.Undetermined, byte thingId = 0, bool invokeEvent = true) : this(parent.owner, thingType, thingId, invokeEvent) {
this.parent = parent;
}
/// <summary>
/// Create a new thing for the given participant
/// </summary>
/// <param name="owner">The participant owning the thing</param>
/// <param name="networkId">The network ID of the thing</param>
/// <param name="thingId">The ID of the thing</param>
/// <param name="thingType">The type of thing</param>
public Thing(Participant owner, byte networkId, byte thingId, byte thingType = 0) {
this.owner = owner;
this.id = thingId;
this.type = thingType;
this.networkId = networkId;
// Console.Write($"New thing added to {owner}");
this.owner.Add(this);
InvokeNewThing(this);
}
// /// <summary>
// /// Create a new thing for the given participant
// /// </summary>
// /// <param name="owner">The participant owning the thing</param>
// /// <param name="networkId">The network ID of the thing</param>
// /// <param name="thingId">The ID of the thing</param>
// /// <param name="thingType">The type of thing</param>
// public Thing(Participant owner, byte networkId, byte thingId, byte thingType = 0) {
// this.owner = owner;
// this.id = thingId;
// this.type = thingType;
// this.networkId = networkId;
// // Console.Write($"New thing added to {owner}");
// this.owner.Add(this);
// InvokeNewThing(this);
// }
/// <summary>
/// Function which can be used to create components in external engines.
@ -108,6 +102,8 @@ namespace RoboidControl {
#endregion Init
public bool terminate = false;
#region Properties
/// <summary>
@ -115,11 +111,6 @@ namespace RoboidControl {
/// </summary>
public Participant owner = null;
/// <summary>
/// The network ID of this thing.
/// </summary>
/// @note This field will likely disappear in future versions
public byte networkId = 0;
/// <summary>
/// The ID of this thing
/// </summary>
public byte id = 0;
@ -127,105 +118,8 @@ namespace RoboidControl {
/// <summary>
/// The type of this thing.
/// </summary>
/// This can be either a Thing::Type (needs casting) or a byte value for custom types.
public byte type = (byte)Type.Undetermined;
private Thing _parent;
/// <summary>
/// The parent of this thing
/// </summary>
public Thing parent {
get => _parent;
set {
if (_parent == value)
return;
if (value == null) {
_parent?.RemoveChild(this);
_parent = null;
}
else {
value.AddChild(this);
}
this.hierarchyChanged = true;
}
}
/// <summary>
/// Add a child Thing to this Thing
/// </summary>
/// <param name="child">The Thing which should become a child</param>
/// @remark When the Thing is already a child, it will not be added again
public void AddChild(Thing child) {
if (children.Find(thing => thing == child) != null)
return;
child._parent = this;
children.Add(child);
}
/// <summary>
/// Remove the given thing as a child of this thing
/// </summary>
/// <param name="child">The child to remove</param>
/// <returns>True when the child was present or false when it was not found</returns>
public bool RemoveChild(Thing child) {
return children.Remove(child);
}
/// <summary>
/// Get a child by thing Id
/// </summary>
/// <param name="thingId"></param>
/// <param name="recursively"></param>
/// <returns></returns>
Thing GetChild(byte thingId, bool recursively = false) {
foreach (Thing child in this.children) {
if (child == null)
continue;
if (child.id == thingId)
return child;
if (recursively) {
Thing foundChild = child.GetChild(thingId, recursively);
if (foundChild != null)
return foundChild;
}
}
return null;
}
/// <summary>
/// Find a child by name
/// </summary>
/// <param name="name">The name of the child thing</param>
/// <param name="recursively">If true, the name will be searched through descendants recursively</param>
/// <returns>The found thing or null when nothing is found</returns>
Thing FindChild(string name, bool recursively = true) {
foreach (Thing child in this.children) {
if (child == null)
continue;
if (child.name == name)
return child;
if (recursively) {
Thing foundChild = child.FindChild(name, recursively);
if (foundChild != null)
return foundChild;
}
}
return null;
}
/// <summary>
/// Indicator that the hierarchy of the thing has changed
/// </summary>
public bool hierarchyChanged = true;
/// <summary>
/// The children of this thing
/// </summary>
[NonSerialized]
protected List<Thing> children = new();
/// This can be either a \ref RoboidControl::Thing::Type "Thing.Type" or a byte value for custom types.
public byte type = Type.Undetermined;
private string _name = "";
/// <summary>
@ -252,6 +146,120 @@ namespace RoboidControl {
/// </summary>
public string modelUrl = "";
#if UNITY_5_3_OR_NEWER
/// <summary>
/// A reference to the representation of the thing in Unity
/// </summary>
[NonSerialized]
public Unity.Thing component = null;
#endif
#endregion Properties
#region Hierarchy
private Thing _parent;
/// <summary>
/// The parent of this thing
/// </summary>
public Thing parent {
get => _parent;
set {
if (_parent == value)
return;
if (value == null) {
_parent?.RemoveChild(this);
_parent = null;
}
else {
value.AddChild(this);
}
this.hierarchyChanged = true;
}
}
/// <summary>
/// The children of this thing
/// </summary>
[NonSerialized]
protected List<Thing> children = new();
/// <summary>
/// Add a child Thing to this Thing
/// </summary>
/// <param name="child">The Thing which should become a child</param>
/// @remark When the Thing is already a child, it will not be added again
public void AddChild(Thing child) {
if (children.Find(thing => thing == child) != null)
return;
child._parent = this;
children.Add(child);
}
/// <summary>
/// Remove the given thing as a child of this thing
/// </summary>
/// <param name="child">The child to remove</param>
/// <returns>True when the child was present or false when it was not found</returns>
public bool RemoveChild(Thing child) {
return children.Remove(child);
}
/// <summary>
/// Get a child by thing Id
/// </summary>
/// <param name="thingId">The thing ID to find</param>
/// <param name="recurse">Look recursively through all descendants</param>
/// <returns></returns>
Thing GetChild(byte thingId, bool recurse = false) {
foreach (Thing child in this.children) {
if (child == null)
continue;
if (child.id == thingId)
return child;
if (recurse) {
Thing foundChild = child.GetChild(thingId, recurse);
if (foundChild != null)
return foundChild;
}
}
return null;
}
/// <summary>
/// Find a child by name
/// </summary>
/// <param name="name">The name of the child thing</param>
/// <param name="recurse">Look recursively through all descendants</param>
/// <returns>The found thing or null when nothing is found</returns>
Thing FindChild(string name, bool recurse = true) {
foreach (Thing child in this.children) {
if (child == null)
continue;
if (child.name == name)
return child;
if (recurse) {
Thing foundChild = child.FindChild(name, recurse);
if (foundChild != null)
return foundChild;
}
}
return null;
}
/// <summary>
/// Indicator that the hierarchy of the thing has changed
/// </summary>
public bool hierarchyChanged = true;
#endregion Hierarchy
#region Pose
private Spherical _position = Spherical.zero;
/// <summary>
/// The position of the thing in local space, in meters.
@ -269,7 +277,7 @@ namespace RoboidControl {
/// <summary>
/// Event triggered when the pose has changed
/// </summary>
public event ChangeHandler OnPoseChanged = null; //delegate { };
public event ChangeHandler OnPoseChanged = delegate { };
/// <summary>
/// Boolean indicating that the thing has an updated position
/// </summary>
@ -340,39 +348,36 @@ namespace RoboidControl {
/// </summary>
public bool angularVelocityUpdated = false;
#if UNITY_5_3_OR_NEWER
#endregion Pose
#region Update
/// <summary>
/// A reference to the representation of the thing in Unity
/// Get the current time in milliseconds
/// </summary>
[NonSerialized]
public Unity.Thing component = null;
#endif
public bool terminate = false;
#endregion Properties
#region Methods
/// <returns>The current time in milliseconds</returns>
public static ulong GetTimeMs() {
#if UNITY_5_3_OR_NEWER
return (ulong)(UnityEngine.Time.time * 1000);
#else
return TimeManager.GetCurrentTimeMilliseconds();
#endif
}
/// <summary>
/// Update de state of the thing
/// </summary>
/// <param name="recursively">When true, this will Update the descendants recursively</param>
public void Update(bool recursively = false) {
Update(TimeManager.GetCurrentTimeMilliseconds(), recursively);
/// <param name="recurse">When true, this will Update the descendants recursively</param>
public void Update(bool recurse = false) {
Update(GetTimeMs(), recurse);
}
// #endif
/// <summary>
/// Update this thing
/// </summary>
/// <param name="currentTime">The current time in milliseconds</param>
public virtual void Update(ulong currentTimeMs, bool recursively = false) {
/// <param name="currentTime">he current clock time in milliseconds; if this is zero, the current time is retrieved automatically</param>
/// <param name="recurse">When true, this will Update the descendants recursively</param>
public virtual void Update(ulong currentTimeMs, bool recurse = false) {
if (this.positionUpdated || this.orientationUpdated)
OnPoseChanged?.Invoke();
this.positionUpdated = false;
@ -382,31 +387,19 @@ namespace RoboidControl {
//this.hierarchyChanged = false;
// should recurse over children...
if (recursively) {
if (recurse) {
for (byte childIx = 0; childIx < this.children.Count; childIx++) {
Thing child = this.children[childIx];
if (child == null)
continue;
child.Update(currentTimeMs, recursively);
child.Update(currentTimeMs, recurse);
}
}
}
/// <summary>
/// Function used to generate binary data for this thing
/// </summary>
/// <returns>a byte array with the binary data</returns>
/// @sa Passer::RoboidControl::BinaryMsg
public virtual byte[] GenerateBinary() { return Array.Empty<byte>(); }
/// <summary>
/// Function used to process binary data received for this thing
/// </summary>
/// <param name="bytes">The binary data</param>
public virtual void ProcessBinary(byte[] bytes) {
}
#endregion Methods
public delegate void ChangeHandler();
public delegate void SphericalHandler(Spherical v);
public delegate void ThingHandler(Thing t);
/// <summary>
/// Event triggered when a new thing has been created
@ -420,18 +413,20 @@ namespace RoboidControl {
OnNewThing?.Invoke(thing);
}
#endregion Update
/// <summary>
/// Check if the thing has the given properaties
/// Function used to generate binary data for this thing
/// </summary>
/// <param name="thing">The thing to check</param>
/// <param name="networkId">The network ID to compare to</param>
/// <param name="thingId">The thing ID to compare to</param>
/// <returns>True when the thing has the given properties</returns>
public static bool IsThing(Thing thing, byte networkId, byte thingId) {
if (thing == null)
return false;
return (thing.networkId == networkId) && (thing.id == thingId);
//return (thing.id == thingId);
/// <returns>A byte array with the binary data</returns>
/// @sa Passer::RoboidControl::BinaryMsg
public virtual byte[] GenerateBinary() { return Array.Empty<byte>(); }
/// <summary>
/// Function used to process binary data received for this thing
/// </summary>
/// <param name="bytes">The binary data to process</param>
public virtual void ProcessBinary(byte[] bytes) {
}
}

View File

@ -1,14 +1,30 @@
using LinearAlgebra;
namespace RoboidControl {
/// @brief A thing which can move itself using a differential drive system
///
/// @sa @link https://en.wikipedia.org/wiki/Differential_wheeled_robot @endlink
public class DifferentialDrive : Thing {
/// @brief Create a differential drive without networking support
public DifferentialDrive() { }
/// @brief Create a differential drive with networking support
/// @param participant The local participant
public DifferentialDrive(ParticipantUDP participant) : base(participant, Type.Undetermined) { }
/// <summary>
/// Create a differential drive without communication abilities
/// </summary
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public DifferentialDrive(bool invokeEvent = true) : base(Type.DifferentialDrive, invokeEvent) { }
/// <summary>
/// Create a differential drive for a participant
/// </summary>
/// <param name="owner">The owning participant</param>
/// <param name="thingId">The ID of the thing, leave out or set to zero to generate an ID</param>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public DifferentialDrive(ParticipantUDP participant, byte thingId = 0, bool invokeEvent = true) : base(participant, Type.DifferentialDrive, thingId, invokeEvent) { }
/// <summary>
/// Create a new child differential drive
/// </summary>
/// <param name="parent">The parent thing</param>
/// <param name="thingId">The ID of the thing, leave out or set to zero to generate an ID</param>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public DifferentialDrive(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.DifferentialDrive, thingId, invokeEvent) { }
/// @brief Configures the dimensions of the drive
/// @param wheelDiameter The diameter of the wheels in meters
@ -17,21 +33,63 @@ namespace RoboidControl {
/// These values are used to compute the desired wheel speed from the set
/// linear and angular velocity.
/// @sa SetLinearVelocity SetAngularVelocity
public void SetDriveDimensions(float wheelDiameter, float wheelSeparation) { }
public void SetDriveDimensions(float wheelDiameter, float wheelSeparation) {
this.wheelRadius = wheelDiameter > 0 ? wheelDiameter / 2 : -wheelDiameter / 2;
this.wheelSeparation = wheelSeparation > 0 ? wheelSeparation : -wheelSeparation;
this.rpsToMs = wheelDiameter * Angle.pi;
float distance = this.wheelSeparation / 2;
if (this.leftWheel != null)
this.leftWheel.position = new Spherical(distance, Direction.left);
if (this.rightWheel != null)
this.rightWheel.position = new Spherical(distance, Direction.right);
}
/// @brief Congures the motors for the wheels
/// @param leftWheel The motor for the left wheel
/// @param rightWheel The motor for the right wheel
public void SetMotors(Thing leftWheel, Thing rightWheel) { }
public void SetMotors(Thing leftWheel, Thing rightWheel) {
float distance = this.wheelSeparation / 2;
this.leftWheel = leftWheel;
if (this.leftWheel != null)
this.leftWheel.position = new Spherical(distance, Direction.left);
this.rightWheel = rightWheel;
if (this.rightWheel != null)
this.rightWheel.position = new Spherical(distance, Direction.right);
}
/// @brief Directly specify the speeds of the motors
/// @param speedLeft The speed of the left wheel in degrees per second.
/// Positive moves the robot in the forward direction.
/// @param speedRight The speed of the right wheel in degrees per second.
/// Positive moves the robot in the forward direction.
public void SetWheelVelocity(float speedLeft, float speedRight) { }
public void SetWheelVelocity(float speedLeft, float speedRight) {
if (this.leftWheel != null)
this.leftWheel.angularVelocity = new Spherical(speedLeft, Direction.left);
if (this.rightWheel != null)
this.rightWheel.angularVelocity = new Spherical(speedRight, Direction.right);
}
/// @copydoc RoboidControl::Thing::Update(unsigned long)
public override void Update(ulong currentMs, bool recursive = true) { }
public override void Update(ulong currentMs, bool recursive = true) {
if (this.linearVelocityUpdated) {
// this assumes forward velocity only....
float linearVelocity = this.linearVelocity.distance;
Spherical angularVelocity = this.angularVelocity;
float angularSpeed = angularVelocity.distance * Angle.Deg2Rad;
// Determine the rotation direction
if (angularVelocity.direction.horizontal < 0)
angularSpeed = -angularSpeed;
// wheel separation can be replaced by this.leftwheel.position.distance
float speedLeft = (linearVelocity + angularSpeed * this.wheelSeparation / 2) / this.wheelRadius * Angle.Rad2Deg;
float speedRight = (linearVelocity - angularSpeed * this.wheelSeparation / 2) / this.wheelRadius * Angle.Rad2Deg;
this.SetWheelVelocity(speedLeft, speedRight);
}
}
/// @brief The radius of a wheel in meters
protected float wheelRadius = 1.0f;

View File

@ -0,0 +1,67 @@
using System;
namespace RoboidControl {
/// <summary>
/// A sensor which can detect touches
/// </summary>
public class DigitalSensor : Thing {
/// <summary>
/// Create a digital sensor without communication abilities
/// </summary>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public DigitalSensor(bool invokeEvent = true) : base(Type.Switch, invokeEvent) { }
/// <summary>
/// Create a digital sensor for a participant
/// </summary>
/// <param name="owner">The owning participant</param>
/// <param name="thingId">The ID of the thing, leave out or set to zero to generate an ID</param>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public DigitalSensor(Participant owner, byte thingId = 0, bool invokeEvent = true) : base(owner, Type.Switch, thingId, invokeEvent) { }
/// <summary>
/// Create a new child digital sensor
/// </summary>
/// <param name="parent">The parent thing</param>
/// <param name="thingId">The ID of the thing, leave out or set to zero to generate an ID</param>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public DigitalSensor(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.Switch, thingId, invokeEvent) { }
/// <summary>
/// Value which is true when the sensor is touching something, false otherwise
/// </summary>
private bool _state = false;
public bool state {
get { return _state; }
set {
if (_state != value) {
_state = value;
}
stateUpdated = true;
}
}
private bool stateUpdated = false;
/// <summary>
/// Function used to generate binary data for this digital sensor
/// </summary>
/// <returns>A byte array with the binary data</returns>
/// <remark>The byte array will be empty when the digital status has not changed</remark>
public override byte[] GenerateBinary() {
if (!stateUpdated)
return Array.Empty<byte>();
byte[] bytes = new byte[1];
bytes[0] = (byte)(state ? 1 : 0);
stateUpdated = false;
return bytes;
}
/// <summary>
/// Function used to process binary data received for this digital sensor
/// </summary>
/// <param name="bytes">The binary data to process</param>
public override void ProcessBinary(byte[] bytes) {
this.state |= (bytes[0] == 1);
}
}
}

View File

@ -17,10 +17,10 @@ namespace RoboidControl {
/// <summary>
/// Create a distance sensor with the given ID
/// </summary>
/// <param name="participant">The participant for with the sensor is needed</param>
/// <param name="owner">The participant for with the sensor is needed</param>
/// <param name="networkId">The network ID of the sensor</param>
/// <param name="thingId">The ID of the thing</param>
public DistanceSensor(Participant participant, byte networkId, byte thingId) : base(participant, networkId, thingId, (byte)Type.TemperatureSensor) {
public DistanceSensor(Participant owner, byte thingId) : base(owner, Type.TemperatureSensor, thingId) {
}
#if UNITY_5_3_OR_NEWER

View File

@ -1,4 +1,4 @@
//using System;
using System;
namespace RoboidControl {
@ -6,27 +6,50 @@ namespace RoboidControl {
/// A temperature sensor
/// </summary>
public class TemperatureSensor : Thing {
/// <summary>
/// Create a temperature sensor without communication abilities
/// </summary>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public TemperatureSensor(bool invokeEvent = true) : base(Type.TemperatureSensor, invokeEvent) { }
/// <summary>
/// Create a temperature sensor for a participant
/// </summary>
/// <param name="owner">The participant for with the sensor is needed</param>
/// <param name="thingId">The ID of the thing</param>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public TemperatureSensor(Participant owner, byte thingId = 0, bool invokeEvent = true) : base(owner, Type.TemperatureSensor, thingId, invokeEvent) { }
/// <summary>
/// Create a new child temperature sensor
/// </summary>
/// <param name="parent">The parent thing</param>
/// <param name="thingId">The ID of the thing, leave out or set to zero to generate an ID</param>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public TemperatureSensor(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.TemperatureSensor, thingId, invokeEvent) { }
/// <summary>
/// The measured temperature
/// </summary>
public float temperature = 0;
/// <summary>
/// Create a temperature sensor with the given ID
/// Function used to generate binary data for this temperature sensor
/// </summary>
/// <param name="participant">The participant for with the sensor is needed</param>
/// <param name="networkId">The network ID of the sensor</param>
/// <param name="thingId">The ID of the thing</param>
public TemperatureSensor(Participant participant, byte networkId, byte thingId) : base(participant, networkId, thingId, (byte)Type.TemperatureSensor) { }
/// <returns>A byte array with the binary data</returns>
public override byte[] GenerateBinary() {
byte[] bytes = new byte[2];
byte ix = 0;
LowLevelMessages.SendFloat16(bytes, ref ix, this.temperature);
return bytes;
}
/// <summary>
/// Function to extract the temperature received in the binary message
/// Function to process the temperature from the binary data
/// </summary>
/// <param name="bytes">The byte array</param>
/// <param name="bytes">The binary data to process</param>
public override void ProcessBinary(byte[] bytes) {
byte ix = 0;
this.temperature = LowLevelMessages.ReceiveFloat16(bytes, ref ix);
//Console.WriteLine($"temperature {this.name} = {this.temperature} C");
}
}

View File

@ -6,32 +6,29 @@ namespace RoboidControl {
/// A sensor which can detect touches
/// </summary>
public class TouchSensor : Thing {
/// <summary>
/// Create a touch sensor
/// Create a touch sensor without communication abilities
/// </summary>
/// <param name="owner">The participant for with the sensor is needed</param>
/// <param name="invokeEvent">True when the creation should trigger an event</param>
public TouchSensor(Participant owner) : base(owner, Type.TouchSensor) {
Console.Write("TouchSensor constructor");
//touchedSomething = false;
//thisParticipant = owner;
}
public TouchSensor(Participant owner, byte networkId, byte thingId) : base(owner, networkId, thingId) {
// Console.Write("TouchSensor constructor");
//touchedSomething = false;
//thisParticipant = participant;
}
public TouchSensor(Thing parent, bool invokeEvent = true) : base(parent, (byte)Type.TouchSensor, invokeEvent) { }
public ParticipantUDP thisParticipant;
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public TouchSensor(bool invokeEvent = true) : base(Type.TouchSensor, invokeEvent) { }
/// <summary>
/// Create a touch sensor for a participant
/// </summary>
/// <param name="owner">The owning participant</param>
/// <param name="thingId">The ID of the thing, leave out or set to zero to generate an ID</param>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public TouchSensor(Participant owner, byte thingId = 0, bool invokeEvent = true) : base(owner, Type.TouchSensor, thingId, invokeEvent) { }
/// <summary>
/// Create a new child touch sensor
/// </summary>
/// <param name="parent">The parent thing</param>
/// <param name="thingId">The ID of the thing, leave out or set to zero to generate an ID</param>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public TouchSensor(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.TouchSensor, thingId, invokeEvent) { }
/// <summary>
/// Value which is true when the sensor is touching something, false otherwise
/// </summary>
//public bool touchedSomething = false;
private bool _touchedSomething = false;
public bool touchedSomething {
get { return _touchedSomething; }
@ -52,14 +49,27 @@ namespace RoboidControl {
this.component.core = this;
}
#endif
/// <summary>
/// Function used to generate binary data for this touch sensor
/// </summary>
/// <returns>A byte array with the binary data</returns>
/// <remark>The byte array will be empty when the touch status has not changed</remark>
public override byte[] GenerateBinary() {
if (!touchUpdated)
return new byte[0];
return Array.Empty<byte>();
byte[] buffer = new byte[1];
buffer[0] = (byte)(touchedSomething ? 1 : 0);
byte[] bytes = new byte[1];
bytes[0] = (byte)(touchedSomething ? 1 : 0);
touchUpdated = false;
return buffer;
return bytes;
}
/// <summary>
/// Function used to process binary data received for this touch sensor
/// </summary>
/// <param name="bytes">The binary data to process</param>
public override void ProcessBinary(byte[] bytes) {
this.touchedSomething |= (bytes[0] == 1);
}
}
}

View File

@ -29,7 +29,7 @@ namespace RoboidControl.test {
[Test]
public void Test_SiteServer() {
SiteServer siteServer = new SiteServer(7681);
SiteServer siteServer = new();
ulong milliseconds = (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
ulong startTime = milliseconds;
@ -45,8 +45,8 @@ namespace RoboidControl.test {
[Test]
public void Test_SiteParticipant() {
SiteServer siteServer = new SiteServer(7681);
ParticipantUDP participant = new ParticipantUDP("127.0.0.1", 7681);
SiteServer siteServer = new(7681);
ParticipantUDP participant = new("127.0.0.1", 7681, 7682);
ulong milliseconds = (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
ulong startTime = milliseconds;
@ -58,14 +58,14 @@ namespace RoboidControl.test {
milliseconds = (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
}
Assert.That(participant.networkId, Is.EqualTo(1));
Assert.That(participant.networkId, Is.EqualTo(2));
}
[Test]
public void Test_ThingMsg() {
SiteServer siteServer = new SiteServer(7681);
ParticipantUDP participant = new ParticipantUDP("127.0.0.1");
Thing thing = new Thing(participant) {
SiteServer siteServer = new(7681);
ParticipantUDP participant = new("127.0.0.1", 7681, 7682);
Thing thing = new(participant) {
name = "First Thing",
modelUrl = "https://passer.life/extras/ant.jpg"
};
@ -80,7 +80,7 @@ namespace RoboidControl.test {
milliseconds = (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
}
Assert.That(participant.networkId, Is.EqualTo(1));
Assert.That(participant.networkId, Is.EqualTo(2));
}
}
}