Toying (some more) with an industrial robot at the office 😉
Merry Christmas and a Happy 2019 from the Allseas R&D Eindhoven (a.k.a. Inspection & Robotics) office.
R&D Eindhoven is part of the Innovation Department of Allseas Engineering B.V.
Toying (some more) with an industrial robot at the office 😉
Merry Christmas and a Happy 2019 from the Allseas R&D Eindhoven (a.k.a. Inspection & Robotics) office.
R&D Eindhoven is part of the Innovation Department of Allseas Engineering B.V.
Created an easy to use XBox 360 Controller library in C# (with a sample application) using the SharpDX.XInput managed .NET wrapper of the DirectX API.
https://github.com/okmer/XBoxController
A BUG in SharpDX.XInput ci-ci217, resulting in issues with the left Thumb Stick, Left Trigger, and Right Trigger! Please stick to SharpDX.XInput v4.1.0-ci184 for now.
using System; using Com.Okmer.GameController; namespace XBoxSampleConsole { class Program { static void Main(string[] args) { XBoxController controller = new XBoxController(); Console.WriteLine("XBox 360 Controller (Press ENTER to exit...)"); //Connection controller.Connection.ValueChanged += (s, e) => Console.WriteLine($"Connection state: {e.Value}"); //Battery controller.Battery.ValueChanged += (s, e) => Console.WriteLine($"Battery level: {e.Value}"); //Buttons A, B, X, Y controller.A.ValueChanged += (s, e) => Console.WriteLine($"A state: {e.Value}"); controller.B.ValueChanged += (s, e) => Console.WriteLine($"B state: {e.Value}"); controller.X.ValueChanged += (s, e) => Console.WriteLine($"X state: {e.Value}"); controller.Y.ValueChanged += (s, e) => Console.WriteLine($"Y state: {e.Value}"); //Buttons Start, Back controller.Start.ValueChanged += (s, e) => Console.WriteLine($"Start state: {e.Value}"); controller.Back.ValueChanged += (s, e) => Console.WriteLine($"Back state: {e.Value}"); //Buttons D-Pad Up, Down, Left, Right controller.Up.ValueChanged += (s, e) => Console.WriteLine($"Up state: {e.Value}"); controller.Down.ValueChanged += (s, e) => Console.WriteLine($"Down state: {e.Value}"); controller.Left.ValueChanged += (s, e) => Console.WriteLine($"Left state: {e.Value}"); controller.Right.ValueChanged += (s, e) => Console.WriteLine($"Right state: {e.Value}"); //Buttons Shoulder Left, Right controller.LeftShoulder.ValueChanged += (s, e) => Console.WriteLine($"Left shoulder state: {e.Value}"); controller.RightShoulder.ValueChanged += (s, e) => Console.WriteLine($"Right shoulder state: {e.Value}"); //Buttons Thumb Left, Right controller.LeftThumbclick.ValueChanged += (s, e) => Console.WriteLine($"Left thumb state: {e.Value}"); controller.RightThumbclick.ValueChanged += (s, e) => Console.WriteLine($"Right thumb state: {e.Value}"); //Trigger Position Left, Right controller.LeftTrigger.ValueChanged += (s, e) => Console.WriteLine($"Left trigger position: {e.Value}"); controller.RightTrigger.ValueChanged += (s, e) => Console.WriteLine($"Right trigger position: {e.Value}"); //Thumb Positions Left, Right controller.LeftThumbstick.ValueChanged += (s, e) => Console.WriteLine($"Left thumb X: {e.Value.X}, Y: {e.Value.Y}"); controller.RightThumbstick.ValueChanged += (s, e) => Console.WriteLine($"Right thumb X: {e.Value.X}, Y: {e.Value.Y}"); //Rumble Left, Right controller.LeftRumble.ValueChanged += (s, e) => Console.WriteLine($"Left rumble speed: {e.Value}"); controller.RightRumble.ValueChanged += (s, e) => Console.WriteLine($"Right rumble speed: {e.Value}"); //Rumble 0.25f speed for 500 milliseconds when the A or B button is pushed controller.A.ValueChanged += (s, e) => controller.LeftRumble.Rumble(0.25f, 500); controller.B.ValueChanged += (s, e) => controller.RightRumble.Rumble(0.25f, 500); //Rumble at 1.0f speed for 1000 milliseconds when the X or Y button is pushed controller.X.ValueChanged += (s, e) => controller.LeftRumble.Rumble(1.0f, 1000); controller.Y.ValueChanged += (s, e) => controller.RightRumble.Rumble(1.0f, 1000); //Rumble at the speed of the trigger position controller.LeftTrigger.ValueChanged += (s, e) => controller.LeftRumble.Rumble(e.Value); controller.RightTrigger.ValueChanged += (s, e) => controller.RightRumble.Rumble(e.Value); //Wait on ENTER to exit... Console.ReadLine(); } } }
Toying with an industrial robot at the office 😉
R&D Eindhoven (a.k.a. Inspection & Robotics) opens the Friday “borrel” beers with their new Fanuc M-710iC/45M Robot in combination with a Cognex In-Sight 2000 Vision Sensor.
R&D Eindhoven is part of the Innovation Department of Allseas Engineering B.V.
This is a nice review of (my) Duck Hunt VR Alpha 04 by Nathie.
My first little Unity 3D Virtual Reality project, inspired by my old friend the Nintendo Entertainment System. Please keep in mind the I have never used Unity 3D before, so this is my first sandbox application…
Download link to DuckHuntVR Alpha 04: http://tinyurl.com/hb3u42x
This Alpha 04 release incorporated a lot of used feedback from the Vive subreddit: https://www.reddit.com/r/Vive/
In particular the feedback gathered during this live coding session: https://www.reddit.com/r/Vive/comments/4pbx4x/duck_hunt_vr_for_the_htc_vive_alpha_03_this_is_a/
This is a little playful MutableWhenAny and MutableWhenAll extension for the Task Parallel Library (TPL), using a ObservableCollection.
The extension makes it possible to add or removed tasks to/from an ObservableCollection<Task> while the MutableWhenAny or MutableWhenAll is used to wait on the tasks in this (mutable) collection.
https://github.com/okmer/MutableWhen
It’s not super useful in practice, but a nice little exercise that combines to cool C# features into a fun asynchronous “magic” trick.
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Threading; using System.Threading.Tasks; namespace Com.Okmer.Extensions.ObservableCollectionOfTask { public static class ObservableCollectionOfTaskExtention { private const int INFINITE = -1; public static async Task MutableWhenAll(this ObservableCollection<Task> collection) { await MutableWhenSomething(collection, Task.WhenAll); } public static async Task MutableWhenAny(this ObservableCollection<Task> collection) { await MutableWhenSomething(collection, Task.WhenAny); } private static async Task MutableWhenSomething(this ObservableCollection<Task> collection, Func<IEnumerable<Task>, Task> whenSomething) { Task waitAllTask = null; Task helperTask = null; bool isCollectionChanged = false; do { //Cancellation on collection changed event var cts = new CancellationTokenSource(); var cancelActionHandler = (sender, arg) => cts.Cancel(false); collection.CollectionChanged += cancelActionHandler; //Current collection waitAllTask = whenSomething(collection); //Wait on current collection or collection changed event try { helperTask = Task.Delay(INFINITE, cts.Token); await Task.WhenAny(waitAllTask, helperTask); } finally { isCollectionChanged = cts.IsCancellationRequested; cts.Cancel(false); cts.Dispose(); collection.CollectionChanged -= cancelActionHandler; } } while (isCollectionChanged); //Return the WaitAll on collection results await waitAllTask; } } }
A simple example application that demonstrates the MutableWhenAll extension on an observable collection of tasks. The longest running task is added to the observable collection after MutableWhenAll is called, but the MutableWhenAll will complete only when all tasks (included this longest running task) are completed.
using System; using System.Collections.ObjectModel; using System.Threading.Tasks; using Com.Okmer.Extensions.ObservableCollectionOfTask; namespace MutableWhenAllTest { class Program { static void Main(string[] args) { ObservableCollection<Task> tasks = new ObservableCollection<Task>(); Task t1 = Task.Run(async () => { await Task.Delay(1000); Console.WriteLine("t1"); }); Task t2 = Task.Run(async () => { await Task.Delay(2000); Console.WriteLine("t2"); }); Task t3 = Task.Run(async () => { await Task.Delay(3000); Console.WriteLine("t3"); }); tasks.Add(t1); tasks.Add(t2); Task a1 = tasks.MutableWhenAll(); tasks.Add(t3); a1.ContinueWith(t => { if (t.IsCanceled) { Console.WriteLine("Canceled"); } if (t.IsFaulted) { Console.WriteLine("Faulted"); } if (t.IsCompleted) { Console.WriteLine("Completed"); } }); a1.Wait(); Console.ReadLine(); } } }
DynamicBag is a toy project that used a Dictionary<string, dynamic> to create a dynamic storage class.
using System; using System.Collections.Generic; using System.Runtime.Serialization; namespace Com.Okmer.DynamicTypes { [Serializable] public class DynamicBag : Dictionary<string, dynamic> { public DynamicBag() { } public DynamicBag(int capacity) : base(capacity) { } public DynamicBag(IDictionary<string, dynamic> dictionary) : base(dictionary) { } public DynamicBag(SerializationInfo info, StreamingContext context) : base(info, context) { } public void ToBinaryFile(string fileName) { BinarySerialization.ToFile(this, fileName); } public static DynamicBag FromBinaryFile(string fileName) { return BinarySerialization.FromFile<DynamicBag>(fileName); } } }
These DynamicBag(s) can be serialized to and deserialized from a file using BinarySerialization.
using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; namespace Com.Okmer.DynamicTypes { public static class BinarySerialization { public static void ToFile<T>(T value, string fileName) where T : ISerializable { IFormatter formatter = new BinaryFormatter(); using (Stream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) { formatter.Serialize(stream, value); } } public static T FromFile<T>(string fileName) where T : ISerializable, new() { T result = new T(); IFormatter formatter = new BinaryFormatter(); using (Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { result = (T)formatter.Deserialize(stream); } return result; } } }
The simple example application uses polymorphism to print the content of the DynamicBag(s) to the console.
using System; using System.Collections.Generic; using Com.Okmer.DynamicTypes; namespace SampleApplication { class Program { static void Main(string[] args) { DynamicBag shoppingBag = new DynamicBag(); DynamicBag spareBag = new DynamicBag(); shoppingBag.Add("spareBag", spareBag); shoppingBag.Add("shoppingList", new string[] { "eggs", "milk", "cheese" }); spareBag.Add("carCoin", "50ct"); spareBag.Add("carValue", 50); Print(shoppingBag); Console.Write("---------------------------> ENTER <----: "); Console.ReadLine(); shoppingBag.ToBinaryFile("shoppingBag.bin"); DynamicBag shoppingBagFromBinaryFile = DynamicBag.FromBinaryFile("shoppingBag.bin"); Print(shoppingBagFromBinaryFile); Console.Write("---------------------------> ENTER <----: "); Console.ReadLine(); } private static void Print(DynamicBag bag) { Console.WriteLine("BAG BEGIN"); foreach (string key in bag.Keys) { Console.WriteLine(key + ": "); Print(bag[key]); } Console.WriteLine("BAG END"); } private static void Print(IEnumerable<dynamic> values) { Console.WriteLine("ENUMERABLE BEGIN"); foreach (dynamic value in values) { Print(value); } Console.WriteLine("ENUMERABLE END"); } private static void Print(bool value) => Console.WriteLine("bool -> " + value.ToString()); private static void Print(int value) => Console.WriteLine("int -> " + value.ToString()); private static void Print(double value) => Console.WriteLine("double -> " + value.ToString()); private static void Print(string value) => Console.WriteLine("string -> " + value.ToString()); private static void Print(object value) => Console.WriteLine("object-> " + value.ToString()); } }
SVG vector bases, touchscreen enabled, animated, and 3D.js driven front-end, running on an “embedded” Raspberry-Pi that is sampling 21 USB connected skin moisture sensors (each containing an array of 256×300 sample points).
The system is running battery power in a bag pack, carried by the human test subject. De system is hosting a live measurement data as a web service using a Wifi AP hosted by WiFi USB dongle connected to the Raspberry Pi, in connection with the 21 USB connected skin moisture sensors.
System status (including the external battery) can also be monitored through the same web interface (running fullscreen on a iPad).
A little “fun” Qt5 console application to create a directory (a.k.a. folder) ending with a space character (” “). This directory can not be removed with standard Windows tools, including most console applications.
#include <QCoreApplication> #include <QDir> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QString evil_dir_name("Remko is a little Evil !!! "); for(int i=1; i<a.arguments().count(); i++) { if(a.arguments().at(i).compare("-d", Qt::CaseInsensitive) != 0) { evil_dir_name = a.arguments().at(i); evil_dir_name.append(" "); break; } } if(a.arguments().contains("-d")) { if(QDir(evil_dir_name).exists()) { QDir().rmdir(evil_dir_name); } } else { QDir().mkdir(evil_dir_name); } return 0; }
The skin diagnostics suite bundled with the OBSERV 520. This iPad based skin diagnostics suite uses the Bluetooth 4.0 Low Energy (BLE) to communicate with the OBSERV 520 by Sylton, and uses the iPad camera in combination with GPU accelerated image filters to visualise a broad range of skin concerns.
App Store link: https://itunes.apple.com/us/app/observ-520/id781554722
Sylton (InnoFaith) product information: https://www.sylton.com/observ-