├── .resources
├── nuget_icon.png
└── dynamixel_x_04.png
├── DynamixelSDKSharp
├── nuget_pack.bat
├── packages.config
├── ProductDatabase
│ ├── Products.json
│ ├── MX-64_2.0.csv
│ └── MX-64_2.0.json
├── build
│ └── DynamixelSDKSharp.targets
├── DynamixelSDKSharp.nuspec
├── DynamixelSDKSharp.sln
├── Properties
│ └── AssemblyInfo.cs
├── ProductDatabase.cs
├── Servo.cs
├── DynamixelSDKSharp.csproj
├── WorkerThread.cs
├── NativeFunctions.cs
├── Registers.cs
└── Port.cs
├── Samples
├── DynamixelREST
│ ├── DynamixelREST
│ │ ├── network.ico
│ │ ├── network_w.ico
│ │ ├── App.config
│ │ ├── DataLogger.json
│ │ ├── Requests
│ │ │ ├── System
│ │ │ │ ├── GetPorts.cs
│ │ │ │ ├── GetServos.cs
│ │ │ │ ├── ShutdownAll.cs
│ │ │ │ ├── InitialiseAll.cs
│ │ │ │ ├── InitDatabase.cs
│ │ │ │ ├── Refresh.cs
│ │ │ │ ├── Census.cs
│ │ │ │ ├── LogAllServoRegisters.cs
│ │ │ │ └── CheckSafetyConstraints.cs
│ │ │ ├── Scheduler
│ │ │ │ ├── Get.cs
│ │ │ │ ├── Enable.cs
│ │ │ │ └── Disable.cs
│ │ │ ├── API.cs
│ │ │ ├── Index.cs
│ │ │ ├── Servo
│ │ │ │ ├── GetAllRegisters.cs
│ │ │ │ ├── SetRegister.cs
│ │ │ │ ├── GetRegisterValue.cs
│ │ │ │ ├── SetRegisterValue.cs
│ │ │ │ ├── GetRegister.cs
│ │ │ │ ├── GetRegisterValues.cs
│ │ │ │ └── Move.cs
│ │ │ ├── Data
│ │ │ │ ├── HighFrequencyRequest.cs
│ │ │ │ ├── GetFreshestValues.cs
│ │ │ │ ├── LogRegisterAllServos.cs
│ │ │ │ ├── LogServos.cs
│ │ │ │ ├── GetHistoricalValues.cs
│ │ │ │ └── Logger.cs
│ │ │ ├── IRequest.cs
│ │ │ ├── Test
│ │ │ │ ├── NudgeAllServos.cs
│ │ │ │ ├── ZeroAllServos.cs
│ │ │ │ └── IDoForAllServos.cs
│ │ │ └── RestletAPI.cs
│ │ ├── Database
│ │ │ ├── SystemLog.cs
│ │ │ ├── Registers.cs
│ │ │ ├── DataRowAttribute.cs
│ │ │ ├── Models
│ │ │ │ ├── SolarVector.cs
│ │ │ │ └── ManualCalibration.cs
│ │ │ ├── DataRow.cs
│ │ │ ├── HighFrequencyRequests.cs
│ │ │ └── Connection.cs
│ │ ├── Models
│ │ │ ├── HeliostatHAMNavigateResponse.cs
│ │ │ ├── Heliostat.cs
│ │ │ ├── HeliostatHAMVectorToPointRequest.cs
│ │ │ ├── HeliostatHAMParams.cs
│ │ │ ├── HeliostatHAMPointToPointRequest.cs
│ │ │ └── Vector3.cs
│ │ ├── InitialiseRegisters.json
│ │ ├── Schedule.json
│ │ ├── Module.cs
│ │ ├── Utils
│ │ │ └── ExceptionMessage.cs
│ │ ├── Safety
│ │ │ ├── Constraints.json
│ │ │ ├── RestingServos.cs
│ │ │ └── Constraints.cs
│ │ ├── SerialPorts.json
│ │ ├── packages.config
│ │ ├── Properties
│ │ │ └── AssemblyInfo.cs
│ │ ├── Program.cs
│ │ ├── Logger.cs
│ │ ├── Scheduler.cs
│ │ ├── AutoRouting.cs
│ │ ├── PortPool.cs
│ │ └── DynamixelREST.csproj
│ └── DynamixelREST.sln
└── SimpleTest
│ ├── App.config
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── Program.cs
│ ├── SimpleTest.csproj
│ └── SimpleTest.sln
├── LICENSE
├── .gitattributes
├── README.md
└── .gitignore
/.resources/nuget_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elliotwoods/DynamixelSDKSharp/HEAD/.resources/nuget_icon.png
--------------------------------------------------------------------------------
/.resources/dynamixel_x_04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elliotwoods/DynamixelSDKSharp/HEAD/.resources/dynamixel_x_04.png
--------------------------------------------------------------------------------
/DynamixelSDKSharp/nuget_pack.bat:
--------------------------------------------------------------------------------
1 | nuget pack DynamixelSDKSharp.csproj -Prop Platform=x64 -Prop Configuration=Release
2 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/network.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elliotwoods/DynamixelSDKSharp/HEAD/Samples/DynamixelREST/DynamixelREST/network.ico
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/network_w.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elliotwoods/DynamixelSDKSharp/HEAD/Samples/DynamixelREST/DynamixelREST/network_w.ico
--------------------------------------------------------------------------------
/DynamixelSDKSharp/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Samples/SimpleTest/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/DataLogger.json:
--------------------------------------------------------------------------------
1 | {
2 | "Registers": [
3 | "Goal Position",
4 | "Present Position",
5 | "Present Current",
6 | "Present Temperature"
7 |
8 | ],
9 | "Max Servo Count": 32,
10 | "Period" : 10
11 | }
--------------------------------------------------------------------------------
/DynamixelSDKSharp/ProductDatabase/Products.json:
--------------------------------------------------------------------------------
1 | {
2 | "ProductSpecifications": [
3 | {
4 | "Model Number": 311,
5 | "Model Name": "MX-64 (2.0)",
6 | "Config Filename": "MX-64_2.0.json",
7 | "Encoder Resolution" : 4096
8 | }
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/System/GetPorts.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Diagnostics;
4 |
5 | namespace DynamixelREST.Requests.System
6 | {
7 | [Serializable]
8 | class GetPorts : IRequest
9 | {
10 | public object Perform()
11 | {
12 | return PortPool.X.Ports;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/System/GetServos.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Diagnostics;
4 |
5 | namespace DynamixelREST.Requests.System
6 | {
7 | [Serializable]
8 | class GetServos : IRequest
9 | {
10 | public object Perform()
11 | {
12 | return PortPool.X.Servos;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Scheduler/Get.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Diagnostics;
4 |
5 | namespace DynamixelREST.Requests.Scheduler
6 | {
7 | [Serializable]
8 | class Get : IRequest
9 | {
10 | public object Perform()
11 | {
12 | return DynamixelREST.Scheduler.X;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Database/SystemLog.cs:
--------------------------------------------------------------------------------
1 | namespace DynamixelREST.Database
2 | {
3 | [DataRow("SystemLog")]
4 | class SystemLog : DataRow
5 | {
6 | public string Module { get; set; }
7 | public Logger.Level LogLevel { get; set; }
8 | public string Message { get; set; }
9 | public object Exception { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/System/ShutdownAll.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Diagnostics;
4 |
5 | namespace DynamixelREST.Requests.System
6 | {
7 | [Serializable]
8 | class ShutdownAll : IRequest
9 | {
10 | public object Perform()
11 | {
12 | PortPool.X.ShutdownAll();
13 | return new { };
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/System/InitialiseAll.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Diagnostics;
4 |
5 | namespace DynamixelREST.Requests.System
6 | {
7 | [Serializable]
8 | class InitialiseAll : IRequest
9 | {
10 | public object Perform()
11 | {
12 | PortPool.X.InitialiseAll();
13 | return new { };
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Scheduler/Enable.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Diagnostics;
4 |
5 | namespace DynamixelREST.Requests.Scheduler
6 | {
7 | [Serializable]
8 | class Enable : IRequest
9 | {
10 | public object Perform()
11 | {
12 | DynamixelREST.Scheduler.X.Enabled = true;
13 | return new { };
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Database/Registers.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System.Collections.Generic;
3 |
4 | namespace DynamixelREST.Database
5 | {
6 | [DataRow("Registers")]
7 | class Registers : DataRow
8 | {
9 | public int ServoID { get; set; }
10 | public Dictionary RegisterValues { get; set; } = new Dictionary();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/API.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DynamixelREST.Requests
8 | {
9 | [Serializable]
10 | class API : IRequest
11 | {
12 | public object Perform()
13 | {
14 | return AutoRouting.Routes;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Scheduler/Disable.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Diagnostics;
4 |
5 | namespace DynamixelREST.Requests.Scheduler
6 | {
7 | [Serializable]
8 | class Disable : IRequest
9 | {
10 | public object Perform()
11 | {
12 | DynamixelREST.Scheduler.X.Enabled = false;
13 | return new { };
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Database/DataRowAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace DynamixelREST.Database
4 | {
5 | [AttributeUsage(AttributeTargets.Class)]
6 | class DataRowAttribute : Attribute
7 | {
8 | public string Collection { get; set; }
9 |
10 | public DataRowAttribute(string collection)
11 | {
12 | this.Collection = collection;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Models/HeliostatHAMNavigateResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DynamixelREST.Models
8 | {
9 | class HeliostatHAMNavigateResponse
10 | {
11 | public int rotation { get; set; }
12 | public int pitch { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/System/InitDatabase.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Diagnostics;
5 |
6 | namespace DynamixelREST.Requests.System
7 | {
8 | class InitDatabase : IRequest
9 | {
10 | public object Perform()
11 | {
12 | Database.Connection.X.Connect();
13 | return new { };
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/InitialiseRegisters.json:
--------------------------------------------------------------------------------
1 | {
2 | "Registers": [
3 | {
4 | "Register Type": "Profile Acceleration",
5 | "Value": 1
6 | },
7 | {
8 | "Register Type": "Profile Velocity",
9 | "Value": 10
10 | },
11 | {
12 | "Register Type": "Torque Enable",
13 | "Value": 1
14 | },
15 | {
16 | "Register Type": "Position I Gain",
17 | "Value": 100
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Schedule.json:
--------------------------------------------------------------------------------
1 | {
2 | "Settings": {
3 | "Sleep": 100
4 | },
5 | "Schedules": [
6 | {
7 | "Period": 0,
8 | "Action": "System/InitDatabase",
9 | "OnStart": "true"
10 | },
11 | {
12 | "Period": 0.1,
13 | "Action": "System/CheckSafetyConstraints"
14 | },
15 | {
16 | "Period": 10,
17 | "Action": "Data/Logger",
18 | "OnStart": "true"
19 | }
20 | ]
21 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Index.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Diagnostics;
4 |
5 | namespace DynamixelREST.Requests
6 | {
7 | [RequestHandler(CustomAddress = "/")]
8 | [Serializable]
9 | class Index : IRequest
10 | {
11 | public object Perform()
12 | {
13 | return new {
14 | ports = PortPool.X.Ports,
15 | servos = PortPool.X.Servos
16 | };
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/System/Refresh.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Diagnostics;
4 |
5 | namespace DynamixelREST.Requests.System
6 | {
7 | [RequestHandler(ThreadUsage = ThreadUsage.Exclusive)]
8 | [Serializable]
9 | class Refresh : IRequest
10 | {
11 | public object Perform()
12 | {
13 | PortPool.X.Refresh(false);
14 | return new {
15 | servoCount = PortPool.X.Servos.Count,
16 | portCount = PortPool.X.Ports.Count
17 | };
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Database/Models/SolarVector.cs:
--------------------------------------------------------------------------------
1 | using MongoDB.Bson;
2 | using MongoDB.Bson.Serialization.Attributes;
3 | using Sharp3D.Math.Core;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace DynamixelREST.Database.Models
11 | {
12 | class SolarVector
13 | {
14 | [BsonId]
15 | public ObjectId ID { get; set; }
16 |
17 | public DateTime time { get; set; }
18 | public Vector3D vector {get; set;}
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Models/Heliostat.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DynamixelSDKSharp;
3 | using Newtonsoft.Json;
4 |
5 | namespace DynamixelREST.Models
6 | {
7 | public class Heliostat
8 | {
9 | public int ID { get; set; }
10 |
11 | [JsonIgnore]
12 | public Servo axis1Servo { get; set; }
13 |
14 | [JsonIgnore]
15 | public Servo axis2Servo { get; set; }
16 |
17 | public int axis1ServoID { get; set; }
18 |
19 | public int axis2ServoID { get; set; }
20 |
21 | public HeliostatHAMParams hamParameters { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Servo/GetAllRegisters.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Diagnostics;
5 |
6 | namespace DynamixelREST.Requests.Servo
7 | {
8 | [RequestHandler(Method = Method.POST)]
9 | [Serializable]
10 | [DebuggerDisplay("servo = {servo}")]
11 | class GetAllRegisters : IRequest
12 | {
13 | public int servo { get; set; }
14 |
15 | public object Perform()
16 | {
17 | var servo = PortPool.X.FindServo(this.servo);
18 | servo.ReadAll();
19 | return servo.Registers;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Module.cs:
--------------------------------------------------------------------------------
1 | using Nancy;
2 | using Nancy.ModelBinding;
3 | using System;
4 | using Newtonsoft.Json;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.IO;
10 | using DynamixelSDKSharp;
11 | using Nancy.Responses;
12 | using System.Reflection;
13 |
14 | namespace DynamixelREST
15 | {
16 | public class Module : NancyModule
17 | {
18 | public Module()
19 | {
20 | //Module
21 |
22 | //We don't use this any more. But this might be useful for debugging Nancy later
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Database/DataRow.cs:
--------------------------------------------------------------------------------
1 | using MongoDB.Bson;
2 | using MongoDB.Bson.Serialization.Attributes;
3 | using System;
4 | using System.Diagnostics;
5 | using System.Reflection;
6 |
7 | namespace DynamixelREST.Database
8 | {
9 | abstract class DataRow
10 | {
11 | [BsonId]
12 | public ObjectId ID { get; set; }
13 |
14 | public DateTime TimeStamp { get; set; } = DateTime.Now;
15 | public string AssemblyVersion { get; set; } = Assembly.GetExecutingAssembly().GetName().Version.ToString();
16 | public DateTime ProgramStart { get; set; } = Process.GetCurrentProcess().StartTime.ToUniversalTime();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/DynamixelSDKSharp/build/DynamixelSDKSharp.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Servo/SetRegister.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Diagnostics;
4 |
5 | namespace DynamixelREST.Requests.Servo
6 | {
7 | [RequestHandler(Method = Method.POST)]
8 | [Serializable]
9 | [DebuggerDisplay("servo = {servo}, register = {register.RegisterType}, value = {register.Value}")]
10 | class SetRegister : IRequest
11 | {
12 | public int servo { get; set; }
13 | public Register register { get; set; }
14 |
15 | public object Perform()
16 | {
17 | var servo = PortPool.X.FindServo(this.servo);
18 | servo.WriteValue(this.register);
19 |
20 | return new { };
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Data/HighFrequencyRequest.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Diagnostics;
4 | using System.Threading;
5 |
6 | namespace DynamixelREST.Requests.Data
7 | {
8 | [RequestHandler(Method = Method.POST)]
9 | [Serializable]
10 | [DebuggerDisplay("servo = {servo}, duration = {duration}")]
11 | class HighFrequencyRequest : IRequest
12 | {
13 | public int servo { get; set; }
14 | public double duration { get; set; } = 2;
15 |
16 | public object Perform()
17 | {
18 | Database.HighFrequencyRequests.X.AddRequest(this.servo, TimeSpan.FromSeconds(this.duration));
19 | return new { };
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Utils/ExceptionMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DynamixelREST.Utils
8 | {
9 | [Serializable]
10 | class ExceptionMessage
11 | {
12 | public string message { get; set; }
13 | public List stackTrace { get; set; }
14 | public string source { get; set; }
15 |
16 | public ExceptionMessage(Exception e)
17 | {
18 | this.message = e.Message;
19 | this.stackTrace = e.StackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList();
20 | this.source = e.Source;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Models/HeliostatHAMVectorToPointRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | using Newtonsoft.Json;
8 |
9 | namespace DynamixelREST.Models
10 | {
11 |
12 | class HeliostatHAMVectorToPointRequest
13 | {
14 | [JsonProperty(PropertyName = "params")]
15 | public Models.HeliostatHAMParams hamParameters { get; set; }
16 |
17 | public HeliostatHamRequestCurrentPosition currentServoSetting { get; set; } = new HeliostatHamRequestCurrentPosition();
18 |
19 | public Vector3 targetPoint { get; set; }
20 |
21 | public Vector3 source { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Models/HeliostatHAMParams.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 |
8 | namespace DynamixelREST.Models
9 | {
10 | public class HAMAxisCalibration
11 | {
12 | public double m { get; set;} //gradient
13 | public double c { get; set;}
14 | public double pitch { get; set; }
15 | public double rotation { get; set; }
16 | }
17 |
18 | public class HeliostatHAMParams
19 | {
20 |
21 | public Vector3 pivotPoint { get; set; }
22 | public HAMAxisCalibration pitchParameters { get; set; }
23 | public HAMAxisCalibration rotationParameters { get; set; }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/IRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DynamixelREST.Requests
8 | {
9 | public enum Method
10 | {
11 | GET,
12 | POST
13 | }
14 |
15 | public enum ThreadUsage
16 | {
17 | Shared,
18 | Exclusive
19 | }
20 |
21 | [AttributeUsage(AttributeTargets.Class)]
22 | public class RequestHandlerAttribute : Attribute
23 | {
24 | public string CustomAddress { get; set; } = null;
25 | public Method Method { get; set; } = Method.GET;
26 | public ThreadUsage ThreadUsage { get; set; } = ThreadUsage.Shared;
27 | }
28 |
29 | interface IRequest
30 | {
31 | object Perform();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Safety/Constraints.json:
--------------------------------------------------------------------------------
1 | {
2 | "SafetyConstraints": [
3 | {
4 | "RegisterType": "Present Temperature",
5 | "MinValue": 5,
6 | "MaxValue": 70,
7 | "LogLevel": "Warning",
8 | "Action": "LimitCurrent"
9 | },
10 | {
11 | "RegisterType": "Present Temperature",
12 | "MinValue": 3,
13 | "MaxValue": 75,
14 | "LogLevel": "Error",
15 | "Action": "TakeARest"
16 | },
17 | {
18 | "RegisterType": "Present Input Voltage",
19 | "MinValue": 110,
20 | "MaxValue": 130,
21 | "LogLevel": "Error",
22 | "Action": "ShutdownOne"
23 | },
24 | {
25 | "RegisterType": "Profile Velocity",
26 | "MinValue": 0,
27 | "MaxValue": 20,
28 | "LogLevel": "Warning",
29 | "Action": "ClampValue"
30 | }
31 | ]
32 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/SerialPorts.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "PortName": "A",
4 | "PortAddress": "COM11",
5 | "Baud": 115200
6 | },
7 | {
8 | "PortName": "B",
9 | "PortAddress": "COM12",
10 | "Baud": 115200
11 | },
12 | {
13 | "PortName": "C",
14 | "PortAddress": "COM13",
15 | "Baud": 115200
16 | },
17 | {
18 | "PortName": "D",
19 | "PortAddress": "COM14",
20 | "Baud": 115200
21 | },
22 | {
23 | "PortName": "E",
24 | "PortAddress": "COM15",
25 | "Baud": 115200
26 | },
27 | {
28 | "PortName": "F",
29 | "PortAddress": "COM4",
30 | "Baud": 115200
31 | },
32 | {
33 | "PortName": "G",
34 | "PortAddress": "COM7",
35 | "Baud": 115200
36 | },
37 | {
38 | "PortName": "H - Main 3`",
39 | "PortAddress": "COM3",
40 | "Baud": 115200
41 | }
42 | ]
43 |
44 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Servo/GetRegisterValue.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Diagnostics;
4 |
5 | namespace DynamixelREST.Requests.Servo
6 | {
7 | [RequestHandler(Method = Method.POST)]
8 | [Serializable]
9 | [DebuggerDisplay("servo = {servo}, register = {register.RegisterType}, value = {register.Value}")]
10 | class GetRegisterValue : IRequest
11 | {
12 | public int servo { get; set; }
13 | public bool refresh { get; set; } = true;
14 | public RegisterType registerType { get; set; }
15 |
16 | public object Perform()
17 | {
18 | var servo = PortPool.X.FindServo(this.servo);
19 | if(refresh)
20 | {
21 | return servo.ReadValue(this.registerType);
22 | }
23 | else
24 | {
25 | return servo.Registers[this.registerType];
26 | }
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Servo/SetRegisterValue.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Diagnostics;
5 |
6 | namespace DynamixelREST.Requests.Servo
7 | {
8 | [RequestHandler(Method= Method.POST)]
9 | [Serializable]
10 | [DebuggerDisplay("servo = {servo}, register = {register.RegisterType}, value = {register.Value}")]
11 | class SetRegisterValue : IRequest
12 | {
13 | public int servo { get; set; }
14 |
15 | [JsonProperty(PropertyName = "Register Type")]
16 | public RegisterType registerType { get; set; }
17 |
18 | public int Value { get; set; }
19 |
20 | public object Perform()
21 | {
22 | var servo = PortPool.X.FindServo(this.servo);
23 | servo.WriteValue(this.registerType, this.Value);
24 |
25 | return new { };
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/System/Census.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DynamixelREST.Requests.System
8 | {
9 | class Census : IRequest
10 | {
11 | public object Perform()
12 | {
13 | var servos = PortPool.X.Servos;
14 |
15 | //check which indices are missing in continuous count
16 | var missingInidicesList = new List();
17 | {
18 | var maxIndex = servos.Last().Key;
19 | for(int i=0; i goToPosition, int startPosition)
17 | {
18 | //move by wave with amplitude 1/8 of a revolution (+/- 45 degrees)
19 | var movementAmount = (int)((float)servo.ProductSpecification.EncoderResolution / 8);
20 |
21 | //move +
22 | goToPosition(startPosition + (int)movementAmount);
23 |
24 | //move -
25 | goToPosition(startPosition - (int)movementAmount);
26 |
27 | //go back to start
28 | goToPosition(startPosition);
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Test/ZeroAllServos.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.Speech.Synthesis;
6 | using System.Threading;
7 |
8 | namespace DynamixelREST.Requests.Test
9 | {
10 | [RequestHandler(Method = Method.GET | Method.POST, ThreadUsage = ThreadUsage.Exclusive)]
11 | [Serializable]
12 | class ZeroAllServos : IDoForAllServos
13 | {
14 | public bool useMidvalue = true;
15 |
16 | protected override void Perform(DynamixelSDKSharp.Servo servo, Action goToPosition, int startPosition)
17 | {
18 |
19 | if(useMidvalue)
20 | {
21 | //go to middle between limits
22 | var min = servo.ReadValue(RegisterType.MinPositionLimit);
23 | var max = servo.ReadValue(RegisterType.MaxPositionLimit);
24 |
25 | goToPosition((max + min) / 2);
26 | }
27 | else
28 | {
29 | //go to middle of encoder values
30 | goToPosition(servo.ProductSpecification.EncoderResolution / 2);
31 | }
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Models/Vector3.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DynamixelREST.Models
8 | {
9 | //This exists because System.Numeric's vector 3 has uppercase x, y, z components and the HAM needs them to be lower case and I can't be bothered to write custom JsonConverter.
10 | //TODO: Fix.
11 | public class Vector3
12 | {
13 | public float x { get; set; }
14 | public float y { get; set; }
15 | public float z { get; set; }
16 |
17 | public Vector3()
18 | {
19 |
20 | }
21 |
22 | public Vector3(float x, float y, float z)
23 | {
24 | this.x = x;
25 | this.y = y;
26 | this.z = z;
27 | }
28 |
29 | public void convertToUnit()
30 | {
31 | var magnitude = (float) Math.Sqrt((x * x) + (y * y) + (z * z));
32 | x /= magnitude;
33 | y /= magnitude;
34 | z /= magnitude;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Elliot Woods
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/System/CheckSafetyConstraints.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 |
6 | namespace DynamixelREST.Requests.System
7 | {
8 | [Serializable]
9 | class CheckSafetyConstraints : IRequest
10 | {
11 | public object Perform()
12 | {
13 | var constraints = Safety.Constraints.X;
14 | var servos = PortPool.X.Servos.Values;
15 |
16 | var exceptions = new Dictionary();
17 |
18 | foreach (var constraint in constraints)
19 | {
20 | foreach (var servo in servos)
21 | {
22 | if(Safety.ServoRestManager.X.IsResting(servo))
23 | {
24 | //ignore whilst resting
25 | continue;
26 | }
27 |
28 | try
29 | {
30 | //Check if constraint has been performed recently
31 | if (constraint.NeedsPerform(servo))
32 | {
33 | //If not, perform it now
34 | constraint.Perform(servo);
35 | }
36 | }
37 | catch(Exception e)
38 | {
39 | exceptions.Add(servo.ID, e);
40 | }
41 | }
42 | }
43 |
44 | return exceptions;
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Data/GetFreshestValues.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using MongoDB.Bson;
3 | using MongoDB.Driver;
4 | using System;
5 | using System.Linq;
6 | using System.Diagnostics;
7 | using System.Threading;
8 |
9 | namespace DynamixelREST.Requests.Data
10 | {
11 | [RequestHandler(Method = Method.POST)]
12 | [Serializable]
13 | [DebuggerDisplay("servo = {servo}")]
14 | class GetFreshestValues : IRequest
15 | {
16 | public int servo { get; set; }
17 |
18 | public object Perform()
19 | {
20 | //Let's presume that data logging works properly here
21 | var collection = Database.Connection.X.GetCollection();
22 |
23 | var documents = from document in collection.AsQueryable()
24 | where document.ServoID == this.servo
25 | orderby document.TimeStamp descending
26 | select document;
27 |
28 | if (documents.Count() == 0)
29 | {
30 | throw (new Exception(String.Format("No data available for Servo #{0}", this.servo)));
31 | }
32 | else
33 | {
34 | return new
35 | {
36 | isHighFrequency = Database.HighFrequencyRequests.X.IsHighFrequencyNow(this.servo),
37 | document = documents.First()
38 | };
39 | }
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Servo/GetRegisterValues.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 |
7 | namespace DynamixelREST.Requests.Servo
8 | {
9 | [RequestHandler(Method = Method.POST)]
10 | [Serializable]
11 | [DebuggerDisplay("servo = {servo}")]
12 | class GetRegisterValues : IRequest
13 | {
14 | public int servo { get; set; }
15 | public bool refresh { get; set; } = true;
16 | public List registerTypes { get; set; }
17 |
18 | public object Perform()
19 | {
20 | var servo = PortPool.X.FindServo(this.servo);
21 | if (registerTypes == null)
22 | {
23 | throw (new Exception("No registerTypes selected"));
24 | }
25 |
26 | var registerValues = new Dictionary();
27 | if (this.refresh)
28 | {
29 | foreach (var registerType in this.registerTypes)
30 | {
31 | registerValues.Add(registerType, servo.ReadValue(registerType));
32 | }
33 | }
34 | else
35 | {
36 | foreach (var registerType in this.registerTypes)
37 | {
38 | registerValues.Add(registerType, servo.Registers[registerType].Value);
39 | }
40 | }
41 |
42 |
43 |
44 | return registerValues;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/DynamixelSDKSharp/DynamixelSDKSharp.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $id$
5 | $version$
6 | $title$
7 | Elliot Woods
8 | Kimchi and Chips
9 | https://github.com/elliotwoods/DynamixelSDKSharp/blob/master/LICENSE
10 | https://github.com/elliotwoods/DynamixelSDKSharp
11 | https://github.com/elliotwoods/DynamixelSDKSharp/blob/master/.resources/nuget_icon.png?raw=true
12 | false
13 | $description$
14 | First release on NuGet.
15 | Copyright 2018
16 | dynamixel servos actuators robotics motor
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/DynamixelSDKSharp/DynamixelSDKSharp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.106
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamixelSDKSharp", "DynamixelSDKSharp.csproj", "{F79B9599-1D46-4AD1-974C-777B47112FA2}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|x64.ActiveCfg = Debug|x64
17 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|x64.Build.0 = Debug|x64
18 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|x86.ActiveCfg = Debug|x86
19 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|x86.Build.0 = Debug|x86
20 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|x64.ActiveCfg = Release|x64
21 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|x64.Build.0 = Release|x64
22 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|x86.ActiveCfg = Release|x86
23 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|x86.Build.0 = Release|x86
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {A76ED830-1454-4151-B4DF-A1B9676B56E3}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/Samples/SimpleTest/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("SimpleTest")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("SimpleTest")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("b77edb02-0a2b-4d4d-b633-61700c759830")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("DynamixelREST")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Kimchi and Chips")]
12 | [assembly: AssemblyProduct("DynamixelREST")]
13 | [assembly: AssemblyCopyright("Copyright © Kimchi and Chips 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("09800e0e-2108-4af0-a847-db2d5d417307")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.*")]
36 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Data/LogRegisterAllServos.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DynamixelREST.Requests.Group
9 | {
10 | [RequestHandler(Method = Method.POST | Method.GET)]
11 | class LogRegister : IRequest
12 | {
13 | public RegisterType register { get; set; }
14 | public List servoIDs { get; set; }
15 |
16 | public object Perform()
17 | {
18 | //Get database collection
19 | var collection = Database.Connection.X.GetCollection();
20 |
21 | var servos = PortPool.X.Servos;
22 |
23 | if (this.servoIDs == null)
24 | {
25 | throw (new Exception("No list of servos provided. Please set servoIDs"));
26 | }
27 |
28 | //Check we have these servos
29 | foreach (var servoID in this.servoIDs)
30 | {
31 | if (!servos.ContainsKey(servoID))
32 | {
33 | throw (new Exception(String.Format("Cannot find servo {0}", servoID)));
34 | }
35 | }
36 |
37 | foreach (var servo in servos)
38 | {
39 | var servoID = servo.Key;
40 |
41 | var valuesForServo = new Dictionary();
42 | valuesForServo.Add(register.ToString(), servo.Value.ReadValue(register));
43 |
44 | var row = new Database.Registers
45 | {
46 | ServoID = servoID,
47 | TimeStamp = DateTime.Now,
48 | RegisterValues = valuesForServo
49 | };
50 |
51 | collection.InsertOne(row);
52 | }
53 |
54 | return new { };
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/DynamixelSDKSharp/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("DynamixelSDKSharp")]
9 | [assembly: AssemblyDescription("A .NET library for controlling Dynamixel actuator products from Robotis")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("DynamixelSDKSharp")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("f79b9599-1d46-4ad1-974c-777b47112fa2")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.1.*")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Data/LogServos.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DynamixelREST.Requests.Data
8 | {
9 | [Serializable]
10 | [RequestHandler(Method = Method.POST)]
11 | class LogServos : IRequest
12 | {
13 | public List servoIDs { get; set; }
14 |
15 | public object Perform()
16 | {
17 | var logConfig = Logger.FSettings;
18 |
19 | //Get database collection
20 | var collection = Database.Connection.X.GetCollection();
21 |
22 | var servos = PortPool.X.Servos;
23 |
24 | if(this.servoIDs == null)
25 | {
26 | throw (new Exception("No list of servos provided. Please set servoIDs"));
27 | }
28 |
29 | //Check we have these servos
30 | foreach(var servoID in this.servoIDs)
31 | {
32 | if(!servos.ContainsKey(servoID))
33 | {
34 | throw (new Exception(String.Format("Cannot find servo {0}", servoID)));
35 | }
36 | }
37 |
38 | foreach (var servo in servos)
39 | {
40 | var servoID = servo.Key;
41 |
42 | var valuesForServo = new Dictionary();
43 | foreach (var registerType in Logger.FSettings.Registers)
44 | {
45 | valuesForServo.Add(registerType.ToString()
46 | , servo.Value.ReadValue(registerType));
47 | }
48 | var row = new Database.Registers
49 | {
50 | ServoID = servoID,
51 | TimeStamp = DateTime.Now,
52 | RegisterValues = valuesForServo
53 | };
54 |
55 | collection.InsertOne(row);
56 | }
57 |
58 | return new { };
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Database/HighFrequencyRequests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DynamixelREST.Database
8 | {
9 | class HighFrequencyRequests
10 | {
11 | public static HighFrequencyRequests X = new HighFrequencyRequests();
12 |
13 | Dictionary FExpirationPerServo = new Dictionary();
14 | object FExpirationPerServoLock = new object();
15 |
16 | class Request
17 | {
18 | public int ServoID { get; set; }
19 | public DateTime Expiration { get; set; }
20 | }
21 |
22 | HighFrequencyRequests()
23 | {
24 |
25 | }
26 |
27 | public void AddRequest(int servoID, TimeSpan duration)
28 | {
29 | lock(this.FExpirationPerServoLock)
30 | {
31 | var expiration = DateTime.Now + duration;
32 | if (this.FExpirationPerServo.ContainsKey(servoID))
33 | {
34 | this.FExpirationPerServo[servoID] = expiration;
35 | }
36 | else
37 | {
38 | this.FExpirationPerServo.Add(servoID, expiration);
39 | }
40 | }
41 | }
42 |
43 | public bool IsHighFrequencyNow(int servoID)
44 | {
45 | lock(this.FExpirationPerServoLock)
46 | {
47 | //flush expired entries
48 | {
49 | var servoIDsToRemove = this.FExpirationPerServo.Where(pair => pair.Value < DateTime.Now)
50 | .Select(pair => pair.Key)
51 | .ToList();
52 | foreach (var servoIDToRemove in servoIDsToRemove)
53 | {
54 | this.FExpirationPerServo.Remove(servoIDToRemove);
55 | }
56 | }
57 |
58 | return this.FExpirationPerServo.ContainsKey(servoID);
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Database/Models/ManualCalibration.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using MongoDB.Driver;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace DynamixelREST.Database.Models
10 | {
11 | [DataRow("ManualCalibration")]
12 | class ManualCalibration : DataRow
13 | {
14 | public int HeliostatID { get; set; }
15 |
16 | public Dictionary axis1ServoRegisters { get; set; } = new Dictionary();
17 | public Dictionary axis2ServoRegisters { get; set; } = new Dictionary();
18 |
19 | public double InclinometerValue { get; set; }
20 |
21 | public static IEnumerable GetLatestDocs()
22 | {
23 | var collection = Database.Connection.X.GetCollection();
24 | var latestDocs = collection.AsQueryable()
25 | .OrderByDescending(doc => doc.TimeStamp)
26 | .GroupBy(doc => doc.HeliostatID)
27 | .Select(group => new ManualCalibration
28 | {
29 | HeliostatID = group.Key,
30 | axis1ServoRegisters = group.First().axis1ServoRegisters,
31 | axis2ServoRegisters = group.First().axis2ServoRegisters,
32 | InclinometerValue = group.First().InclinometerValue
33 | })
34 | .ToList();
35 | return latestDocs;
36 | }
37 |
38 | public static Dictionary GetLatestPerHeliostat()
39 | {
40 | var latestDocs = ManualCalibration.GetLatestDocs();
41 |
42 | var latestPerHeliostat = new Dictionary();
43 | foreach(var doc in latestDocs)
44 | {
45 | latestPerHeliostat.Add(doc.HeliostatID, doc);
46 | }
47 |
48 | return latestPerHeliostat;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Servo/Move.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Diagnostics;
4 | using System.Threading;
5 |
6 | namespace DynamixelREST.Requests.Servo
7 | {
8 | [RequestHandler(Method = Method.POST)]
9 | [Serializable]
10 | [DebuggerDisplay("servo = {servo}, register = {register.RegisterType}, value = {register.Value}")]
11 | class Move : IRequest
12 | {
13 | public int servo { get; set; }
14 | public int movement { get; set; }
15 | bool blockUntilComplete { get; set; } = true;
16 | int timeoutMS { get; set; } = 5000;
17 | int epsilon { get; set; } = 1;
18 |
19 | public object Perform()
20 | {
21 | var servo = PortPool.X.FindServo(this.servo);
22 | var presentPosition = servo.ReadValue(RegisterType.PresentPosition);
23 | var newPosition = presentPosition + this.movement;
24 |
25 | //clamp the value to valid range
26 | {
27 | if(newPosition < 0)
28 | {
29 | newPosition = 0;
30 | }
31 | else if(newPosition >= servo.ProductSpecification.EncoderResolution)
32 | {
33 | newPosition = servo.ProductSpecification.EncoderResolution - 1;
34 | }
35 | }
36 |
37 | //update goal position
38 | servo.WriteValue(RegisterType.GoalPosition, newPosition);
39 |
40 | //block if we want to until move completed
41 | if (this.blockUntilComplete)
42 | {
43 | var timeStart = DateTime.Now;
44 | while (Math.Abs(servo.ReadValue(RegisterType.PresentPosition) - newPosition) > this.epsilon)
45 | {
46 | //check if we've timed out trying to get there
47 | if(DateTime.Now - timeStart > TimeSpan.FromMilliseconds(this.timeoutMS))
48 | {
49 | throw (new Exception("Timeout moving to goal position"));
50 | }
51 |
52 | Thread.Sleep(10);
53 | }
54 | }
55 |
56 | return new { };
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Threading;
6 | using System.IO;
7 |
8 | using Nancy.Hosting.Self;
9 |
10 | using Newtonsoft.Json;
11 |
12 | using DynamixelSDKSharp;
13 | using System.Windows.Input;
14 | using System.Windows.Threading;
15 |
16 | namespace DynamixelREST
17 | {
18 | class Program
19 | {
20 | public static string HAMBaseURL = "http://10.0.0.27:8080/";
21 |
22 | public static List Heliostats = new List();
23 |
24 | public const int Port = 8000;
25 |
26 | [STAThread]
27 | static void Main()
28 | {
29 | HostConfiguration hostConfiguration = new HostConfiguration();
30 | {
31 | hostConfiguration.UrlReservations.CreateAutomatically = true;
32 | hostConfiguration.RewriteLocalhost = true;
33 | }
34 |
35 | var uriStrings = new List
36 | {
37 | String.Format("http://localhost:{0}", Program.Port)
38 | };
39 |
40 | var uris = uriStrings
41 | .Select(uriString => new Uri(uriString))
42 | .ToArray();
43 |
44 | //start host
45 | using (var host = new NancyHost(hostConfiguration, uris))
46 | {
47 | host.Start();
48 |
49 | Console.WriteLine("Nancy now listening on:");
50 | foreach (var uriString in uriStrings)
51 | {
52 | Console.WriteLine(uriString);
53 | }
54 |
55 | //refresh the ports
56 | var useServoCache = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
57 | PortPool.X.Refresh(useServoCache);
58 |
59 | //start scheduler (it will start with making requests to the host, so must be after host starts)
60 | Scheduler.X.Start();
61 |
62 | while(true)
63 | {
64 | Thread.Sleep(10000);
65 | }
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Logger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DynamixelREST
8 | {
9 | public class Logger
10 | {
11 | public enum Level
12 | {
13 | Trace,
14 | Warning,
15 | Error,
16 | FatalError
17 | };
18 |
19 | public static void Log(Level level, string message)
20 | {
21 | Logger.Log(level, message, typeof(T));
22 | }
23 |
24 | public static void Log(Level level, string message, Type moduleType)
25 | {
26 | var moduleName = moduleType.Name;
27 | Logger.Log(level, message, moduleName);
28 | }
29 |
30 | public static void Log(Level level, string message, string moduleName)
31 | {
32 | Console.WriteLine(String.Format("{0} in [{1}] :\n - {2}", level.ToString(), moduleName, message));
33 |
34 | Database.Connection.X.Log(new Database.SystemLog
35 | {
36 | Module = moduleName,
37 | Message = message
38 | });
39 | }
40 |
41 | public static void Log(Level level, Exception e)
42 | {
43 | Logger.Log(level, e, typeof(T));
44 | }
45 |
46 | public static void Log(Level level, Exception e, Type moduleType)
47 | {
48 | var moduleName = moduleType.FullName;
49 | Logger.Log(level, e, moduleName);
50 | }
51 |
52 | public static void Log(Level level, Exception e, string moduleName)
53 | {
54 | Console.WriteLine(String.Format("{0} in [{1}] :\n - {2}", level.ToString(), moduleName, e.Message));
55 |
56 | Database.Connection.X.Log(new Database.SystemLog
57 | {
58 | Module = moduleName,
59 | Message = e.Message,
60 | LogLevel = level,
61 | Exception = new
62 | {
63 | Traceback = e.StackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList(),
64 | Source = e.Source,
65 | TargetSite = e.TargetSite
66 | }
67 | });
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Safety/RestingServos.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DynamixelREST.Safety
9 | {
10 | class ServoRestManager
11 | {
12 | //Singleton
13 | public static readonly ServoRestManager X = new ServoRestManager();
14 |
15 | public static TimeSpan RestingTime = TimeSpan.FromMinutes(5);
16 |
17 | class ServoRest
18 | {
19 | public DateTime RestTimeBegan = DateTime.Now;
20 | public Servo Servo;
21 | }
22 |
23 | List ServoRests = new List();
24 |
25 | private ServoRestManager()
26 | {
27 |
28 | }
29 |
30 | public void PutToRest(Servo servo)
31 | {
32 | servo.WriteValue(RegisterType.TorqueEnable, 0);
33 |
34 | //check if already exists
35 | var queryExisting = ServoRests.Where(rs => rs.Servo == servo);
36 |
37 | if(queryExisting.Any())
38 | {
39 | queryExisting.First().RestTimeBegan = DateTime.Now;
40 | }
41 | else
42 | {
43 | this.ServoRests.Add(new ServoRest
44 | {
45 | RestTimeBegan = DateTime.Now,
46 | Servo = servo
47 | });
48 | }
49 | }
50 |
51 | public bool IsResting(Servo servo)
52 | {
53 | var queryRestingServos = this.ServoRests.Where(rs => rs.Servo == servo);
54 | if(queryRestingServos.Any())
55 | {
56 | //we have a rest assigned for this servo
57 |
58 | //remove all rests which are stale
59 | this.ServoRests.RemoveAll(rs => DateTime.Now - rs.RestTimeBegan > ServoRestManager.RestingTime);
60 |
61 | //check if we still ahve one for this servo
62 | var newQueryRestingServos = this.ServoRests.Where(rs => rs.Servo == servo);
63 |
64 | if(newQueryRestingServos.Any()) {
65 | return true;
66 | }
67 | else
68 | {
69 | //wake it up
70 | servo.WriteValue(RegisterType.TorqueEnable, 1);
71 |
72 | //no longer resting
73 | return false;
74 | }
75 | }
76 | else
77 | {
78 | return false;
79 | }
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Data/GetHistoricalValues.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using MongoDB.Bson;
3 | using MongoDB.Driver;
4 | using System;
5 | using System.Linq;
6 | using System.Diagnostics;
7 | using System.Threading;
8 |
9 | namespace DynamixelREST.Requests.Data
10 | {
11 | [RequestHandler(Method = Method.POST)]
12 | [Serializable]
13 | [DebuggerDisplay("servo = {servo}")]
14 | class GetHistoricalValues : IRequest
15 | {
16 | public int servo { get; set; }
17 | public DateTime end { get; set; } = DateTime.Now;
18 | public DateTime start { get; set; } = DateTime.MinValue;
19 |
20 | public double duration
21 | {
22 | set
23 | {
24 | this.start = this.end - TimeSpan.FromSeconds(value);
25 | }
26 | }
27 | public double minimumPeriod = 0;
28 |
29 |
30 | public object Perform()
31 | {
32 | //Let's presume that data logging works properly here
33 | var collection = Database.Connection.X.GetCollection();
34 |
35 | var startUTC = this.start.ToUniversalTime();
36 | var endUTC = this.end.ToUniversalTime();
37 |
38 | var documents = from document in collection.AsQueryable()
39 | where document.ServoID == this.servo
40 | where document.TimeStamp <= endUTC
41 | where document.TimeStamp >= startUTC
42 | orderby document.TimeStamp ascending
43 | select document;
44 |
45 | if (documents.Count() == 0)
46 | {
47 | throw (new Exception(String.Format("No data available for Servo #{0}", this.servo)));
48 | }
49 | else
50 | {
51 | if (this.minimumPeriod == 0)
52 | {
53 | return new
54 | {
55 | isHighFrequency = Database.HighFrequencyRequests.X.IsHighFrequencyNow(this.servo),
56 | documents = documents.ToList()
57 | };
58 | } else {
59 | var trimmedList = documents.ToList();
60 | var lastRecordTime = DateTime.MinValue;
61 | var timeSpan = TimeSpan.FromSeconds(this.minimumPeriod);
62 |
63 | trimmedList.RemoveAll(document =>
64 | {
65 | var passes = document.TimeStamp - lastRecordTime >= timeSpan;
66 | if (passes)
67 | {
68 | lastRecordTime = document.TimeStamp;
69 | }
70 | return !passes;
71 | });
72 |
73 | return trimmedList;
74 | }
75 | }
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2000
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamixelREST", "DynamixelREST\DynamixelREST.csproj", "{C2A5D9D2-A628-463A-B3EB-431423712E15}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamixelSDKSharp", "..\..\DynamixelSDKSharp\DynamixelSDKSharp.csproj", "{F79B9599-1D46-4AD1-974C-777B47112FA2}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|x64 = Debug|x64
13 | Debug|x86 = Debug|x86
14 | Release|x64 = Release|x64
15 | Release|x86 = Release|x86
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {C2A5D9D2-A628-463A-B3EB-431423712E15}.Debug|x64.ActiveCfg = Debug|x64
19 | {C2A5D9D2-A628-463A-B3EB-431423712E15}.Debug|x64.Build.0 = Debug|x64
20 | {C2A5D9D2-A628-463A-B3EB-431423712E15}.Debug|x86.ActiveCfg = Debug|x86
21 | {C2A5D9D2-A628-463A-B3EB-431423712E15}.Debug|x86.Build.0 = Debug|x86
22 | {C2A5D9D2-A628-463A-B3EB-431423712E15}.Release|x64.ActiveCfg = Debug|x64
23 | {C2A5D9D2-A628-463A-B3EB-431423712E15}.Release|x64.Build.0 = Debug|x64
24 | {C2A5D9D2-A628-463A-B3EB-431423712E15}.Release|x86.ActiveCfg = Debug|x86
25 | {C2A5D9D2-A628-463A-B3EB-431423712E15}.Release|x86.Build.0 = Debug|x86
26 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|x64.ActiveCfg = Debug|x64
27 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|x64.Build.0 = Debug|x64
28 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|x86.ActiveCfg = Release|x86
29 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|x86.Build.0 = Release|x86
30 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|x64.ActiveCfg = Debug|x64
31 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|x64.Build.0 = Debug|x64
32 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|x86.ActiveCfg = Release|x86
33 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|x86.Build.0 = Release|x86
34 | EndGlobalSection
35 | GlobalSection(SolutionProperties) = preSolution
36 | HideSolutionNode = FALSE
37 | EndGlobalSection
38 | GlobalSection(ExtensibilityGlobals) = postSolution
39 | SolutionGuid = {274D59E1-8AA9-4F1F-A41E-E8B99E489BD5}
40 | EndGlobalSection
41 | EndGlobal
42 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Database/Connection.cs:
--------------------------------------------------------------------------------
1 | using MongoDB.Bson;
2 | using MongoDB.Bson.Serialization.Conventions;
3 | using MongoDB.Driver;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace DynamixelREST.Database
11 | {
12 | class Connection
13 | {
14 | readonly public static Connection X = new Connection();
15 |
16 | public bool Connected { get; private set; } = false;
17 |
18 | MongoClient FClient;
19 | IMongoDatabase FDatabase;
20 |
21 | private Connection()
22 | {
23 |
24 | }
25 |
26 | public void Connect()
27 | {
28 | try
29 | {
30 | //Connect to the server
31 | this.FClient = new MongoClient("mongodb://localhost");
32 | this.FDatabase = this.FClient.GetDatabase("DynamixelREST");
33 |
34 | //Check if connected
35 | {
36 | this.Connected = (bool)this.FDatabase.RunCommandAsync((Command)"{ping:1}").Wait(1000);
37 | }
38 |
39 | //Serialize enums as strings
40 | {
41 | ConventionRegistry.Register("EnumStringConvention"
42 | , new ConventionPack {
43 | new EnumRepresentationConvention(BsonType.String)
44 | }
45 | , t => true);
46 | }
47 |
48 | if (this.Connected)
49 | {
50 | Logger.Log(Logger.Level.Trace, "--------------- SESION START : Database connected");
51 | }
52 | }
53 | catch (Exception e)
54 | {
55 | Logger.Log(Logger.Level.Warning, "Failed to connect to MongoDB for DataLogging : " + e.Message);
56 | this.Connected = false;
57 | Logger.Log(Logger.Level.Trace, "Database not connected for logging. No MongoDB server found");
58 | }
59 | }
60 |
61 | public IMongoCollection GetCollection()
62 | {
63 | if (!this.Connected)
64 | {
65 | throw (new Exception("No database connection"));
66 | }
67 |
68 | var dataRowAttribute = Attribute.GetCustomAttribute(typeof(T), typeof(DataRowAttribute)) as DataRowAttribute;
69 | return this.FDatabase.GetCollection(dataRowAttribute.Collection);
70 | }
71 |
72 | public void Log(T data)
73 | {
74 | if (this.Connected)
75 | {
76 | var collection = this.GetCollection();
77 | collection.InsertOne(data);
78 | }
79 | }
80 |
81 | public IMongoDatabase Database
82 | {
83 | get
84 | {
85 | return this.FDatabase;
86 | }
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/DynamixelSDKSharp/ProductDatabase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Serialization;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using Newtonsoft.Json.Serialization;
10 | using Newtonsoft.Json.Converters;
11 | using Newtonsoft.Json;
12 |
13 | namespace DynamixelSDKSharp
14 | {
15 | public class ProductSpecification
16 | {
17 | [JsonProperty(PropertyName = "Model Number")]
18 | public int ModelNumber { get; set; }
19 |
20 | [JsonProperty(PropertyName = "Model Name")]
21 | public string ModelName { get; set; }
22 |
23 | [JsonProperty(PropertyName = "Config Filename")]
24 | public string ConfigFilename { get; set; }
25 |
26 | [JsonProperty(PropertyName = "Encoder Resolution")]
27 | public int EncoderResolution { get; set; }
28 |
29 | [JsonIgnore]
30 | public Registers Registers { get; set; }
31 | }
32 |
33 | public class ProductDatabase
34 | {
35 | public static ProductDatabase X = new ProductDatabase();
36 |
37 | public static JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings
38 | {
39 | Converters = new List { new StringEnumConverter { CamelCaseText = false } },
40 | NullValueHandling = NullValueHandling.Ignore
41 | };
42 |
43 | public const string PathToProductData = "./ProductDatabase/";
44 |
45 | public List ProductSpecifications { get; private set; } = new List();
46 |
47 | ProductDatabase()
48 | {
49 | this.Load();
50 | }
51 |
52 | void Load()
53 | {
54 | //load list of models
55 | using (StreamReader file = new StreamReader(PathToProductData + "Products.json"))
56 | {
57 | var json = file.ReadToEnd();
58 | JsonConvert.PopulateObject(json, this, ProductDatabase.JsonSerializerSettings);
59 | }
60 |
61 | //load the addresses of each one
62 | foreach (var productSpecificaton in this.ProductSpecifications)
63 | {
64 | //load the config file for the servo
65 | using (StreamReader file = new StreamReader(PathToProductData + productSpecificaton.ConfigFilename))
66 | {
67 | var json = file.ReadToEnd();
68 | productSpecificaton.Registers = JsonConvert.DeserializeObject(json, ProductDatabase.JsonSerializerSettings);
69 | }
70 |
71 | //set the RegisterType enum content
72 | foreach (var register in productSpecificaton.Registers)
73 | {
74 | register.Value.RegisterType = register.Key;
75 | }
76 | }
77 | }
78 |
79 | public ProductSpecification GetProductSpecification(int modelNumber)
80 | {
81 | foreach(var productSpecification in this.ProductSpecifications)
82 | {
83 | if(productSpecification.ModelNumber == modelNumber)
84 | {
85 | return productSpecification;
86 | }
87 | }
88 | throw (new Exception(String.Format("Model Number {0} not found", modelNumber)));
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/DynamixelSDKSharp/Servo.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DynamixelSDKSharp
9 | {
10 | public class ServoHardwareErrorException : Exception
11 | {
12 | public ServoHardwareErrorException()
13 | {
14 |
15 | }
16 | }
17 |
18 | public class Servo
19 | {
20 | public byte ID { get; private set; }
21 | public Port Port { get; private set; }
22 | public ProductSpecification ProductSpecification { get; private set; }
23 |
24 | public bool IsErrorState { get; private set; } = false;
25 |
26 | public Servo(Port port, byte id, int modelNumber)
27 | {
28 | this.Port = port;
29 | this.ID = id;
30 |
31 | this.ProductSpecification = ProductDatabase.X.GetProductSpecification(modelNumber);
32 |
33 | this.Registers = (Registers)this.ProductSpecification.Registers.Clone();
34 |
35 | this.UpdateErrorState();
36 | }
37 |
38 | private void UpdateErrorState()
39 | {
40 |
41 | }
42 |
43 | [JsonIgnore]
44 | public Registers Registers;
45 |
46 | public void Reboot()
47 | {
48 | this.Port.Reboot(this.ID);
49 | }
50 |
51 | public void ReadAll()
52 | {
53 | foreach (var iterator in this.Registers)
54 | {
55 | this.Port.Read(this.ID, iterator.Value);
56 | }
57 | }
58 |
59 | public void WriteAll()
60 | {
61 | foreach (var iterator in this.Registers)
62 | {
63 | this.Port.Write(this.ID, iterator.Value);
64 | }
65 | }
66 |
67 | public void WriteValue(Register newValue, bool sync = false)
68 | {
69 | this.WriteValue(newValue.RegisterType, newValue.Value, sync);
70 | }
71 |
72 | public void WriteRegisters(Registers registers, bool sync = false)
73 | {
74 | var registersToWrite = new Registers();
75 | foreach(var register in registers)
76 | {
77 | //update our local register
78 | var ourRegister = this.Registers[register.Key];
79 | ourRegister.Value = register.Value.Value;
80 |
81 | //use our register for the write operations
82 | registersToWrite.Add(register.Key, ourRegister);
83 | }
84 |
85 | if (sync)
86 | {
87 | this.Port.Write(this.ID, registersToWrite);
88 | }
89 | else
90 | {
91 | this.Port.WriteAsync(this.ID, registersToWrite);
92 | }
93 | }
94 |
95 | public void WriteValue(RegisterType registerType, int value, bool sync = false)
96 | {
97 | var register = this.Registers[registerType];
98 | register.Value = value;
99 | if (sync)
100 | {
101 | this.Port.Write(this.ID, register);
102 | }
103 | else
104 | {
105 | this.Port.WriteAsync(this.ID, register);
106 | }
107 | }
108 |
109 | public Register ReadRegister(RegisterType registerType)
110 | {
111 | var register = this.Registers[registerType];
112 | this.Port.Read(this.ID, register);
113 | return register;
114 | }
115 |
116 | public int ReadValue(RegisterType registerType)
117 | {
118 | var register = this.ReadRegister(registerType);
119 | return register.Value;
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/Samples/SimpleTest/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using DynamixelSDKSharp;
4 |
5 | namespace SimpleTest
6 | {
7 | class Program
8 | {
9 |
10 | static void Main(string[] args)
11 | {
12 | //change these settings
13 | var portName = "COM3";
14 | var baudRate = BaudRate.BaudRate_115200;
15 |
16 | //open the port
17 | Console.WriteLine("Opening port {0} using baud rate {1}", portName, baudRate.ToString());
18 | var port = new Port(portName, baudRate);
19 |
20 | //look for servos
21 | Console.WriteLine("Searching for servos");
22 | port.Refresh();
23 |
24 | //check if we found any servos
25 | if (port.Servos.Count == 0)
26 | {
27 | Console.WriteLine("No servos found. Please check the port settings, servo wiring and if your servo power is on.");
28 | return;
29 | }
30 |
31 | //list out servos we found
32 | foreach (var servoKeyValue in port.Servos)
33 | {
34 | var servoID = servoKeyValue.Key;
35 | var servo = servoKeyValue.Value;
36 | Console.WriteLine("Found servo ID = {0}, Model Name = {1}", servoID, servo.ProductSpecification.ModelName);
37 | }
38 |
39 | //check that ProductSpecification files loaded
40 | foreach (var servo in port.Servos.Values)
41 | {
42 | if(servo.Registers.Count == 0)
43 | {
44 | Console.WriteLine("Failed to load Registers for Model Number = {0}, Model Name = {1}, Config Filename = {2}. Please check file exists in right location."
45 | , servo.ProductSpecification.ModelNumber
46 | , servo.ProductSpecification.ModelName
47 | , servo.ProductSpecification.ConfigFilename);
48 |
49 | }
50 | }
51 |
52 | Console.WriteLine("Press any key to test moving servos. WARNING! Servos may move rapidly...");
53 | Console.ReadKey();
54 |
55 | //iterate through the servos
56 | foreach (var servoKeyValue in port.Servos)
57 | {
58 | var servoID = servoKeyValue.Key;
59 | var servo = servoKeyValue.Value;
60 |
61 | Console.WriteLine("Moving servo {0} to zero position", servoID);
62 |
63 | //set torque on
64 | servo.WriteValue(RegisterType.TorqueEnable, 1);
65 |
66 | //set velocity and acceleration
67 | servo.WriteValue(RegisterType.ProfileVelocity, 100);
68 | servo.WriteValue(RegisterType.ProfileAcceleration, 1000);
69 |
70 | //go to zero
71 | servo.WriteValue(RegisterType.GoalPosition, 0);
72 | while(servo.ReadValue(RegisterType.PresentPosition) > 10)
73 | {
74 | Thread.Sleep(1000);
75 | }
76 |
77 | Console.WriteLine("Moving forwards and backwards...");
78 |
79 | //move through all positions
80 | {
81 | //forwards
82 | for (int i = 0; i < 4096; i += 4)
83 | {
84 | servo.WriteValue(RegisterType.GoalPosition, i);
85 | Thread.Sleep(1);
86 | Console.Write(">");
87 | }
88 |
89 | //forwards
90 | for (int i = 4095; i > 0; i -= 4)
91 | {
92 | servo.WriteValue(RegisterType.GoalPosition, i);
93 | Thread.Sleep(1);
94 | Console.Write("<");
95 | }
96 | }
97 | Console.WriteLine();
98 | }
99 |
100 | Console.WriteLine("Press any key to exit...");
101 | Console.ReadKey();
102 |
103 | //close down cleanly (optional)
104 | port.Dispose();
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DynamixelSDKSharp
2 | 
3 |
4 | ## Introduction
5 |
6 | A .NET library for controlling Dynamixel actuator products from [Robotis](http://www.robotis.com/).
7 |
8 | This library's aims:
9 |
10 | * Easy to use
11 | * Managed and Object Oriented
12 | * Utilities for common use patterns with Dynamixel Servos
13 | * User's code should be the same regardless of which servo products are used
14 |
15 | The library code can be cross-platform, but it has only been tested on Windows.
16 |
17 | ## Sample code
18 |
19 | ```C#
20 | // Open a COM port
21 | var port = new Port("COM6", BaudRate.BaudRate_115200);
22 |
23 | // Search for all servos on this port
24 | port.Refresh();
25 |
26 | // Iterate through servos
27 | foreach (var servoKeyValue in port.Servos)
28 | {
29 | var servoID = servoKeyValue.Key;
30 | var servo = servoKeyValue.Value;
31 |
32 | // Enable torque on this servo
33 | servo.WriteValue(RegisterType.TorqueEnable, 1);
34 |
35 | // Move through range of positions
36 | for (int i = 0; i < 4096; i += 5)
37 | {
38 | servo.WriteValue(RegisterType.GoalPosition, i);
39 | }
40 | }
41 | ```
42 |
43 | ## Features
44 |
45 | * Automatically detect Ports
46 | * Automatically detect Servos
47 | * Ports are threaded safely
48 | * Register address tables can be defined in JSON (we don't need to hard-code address tables for each servo)
49 | * DynamixelREST sample application provides REST API (e.g. can control Servos from remote devices)
50 |
51 | ## Classes
52 |
53 | * Port
54 | * Servo
55 | * Register
56 |
57 | ## DynamixelREST
58 |
59 | This is a standalone application which provides a REST API for manipulating Dynamixel actuator products. With this, it becomes easy to create applications in any language (e.g. JavaScript, Python, Processing, etc) which interact with the Dynamixel hardware.
60 |
61 | To see a full list of REST commands see here:
62 | https://github.com/elliotwoods/DynamixelSDKSharp/tree/master/Samples/Dispatcher/Dispatcher/Requests
63 |
64 | Note that the addresses for each request are shown in the class decorators, or else denoted by the class name and namespace.
65 |
66 | Dispatcher also supports logging to a local MongoDB server if available. If you would like to disable this feature, then please remove this section from the Schedule.json file:
67 |
68 | ```json
69 | {
70 | "Period": 0,
71 | "Action": "initDataLogger",
72 | "OnStart": "true"
73 | },
74 | ```
75 |
76 | The scheduler defines regular tasks which you would like to perform:
77 |
78 | * `Period` defines an interval in seconds between each action. `0` signifies that the schedule is disabled (e.g. used with `OnStart`, this can mean that it only happens on start of application).
79 | * `Action` defines a REST endpoint which will be performed at each schedule interval
80 | * `OnStart` defines whether this endpoint will be performed at application start.
81 |
82 | ## License
83 |
84 | DynamixelSDKSharp is by Kimchi and Chips and is available under the [MIT License](https://github.com/elliotwoods/DynamixelSDKSharp/blob/master/LICENSE)
85 | NativeFunctions.cs and the native DLL's are from the DynamixelSDK by Robotis, made available under the [Apache License 2.0](https://github.com/ROBOTIS-GIT/DynamixelSDK/blob/master/LICENSE)
86 |
87 | Dynamixel is a trademark of Robotis Ltd. (Korea).
88 |
--------------------------------------------------------------------------------
/Samples/SimpleTest/SimpleTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {B77EDB02-0A2B-4D4D-B633-61700C759830}
8 | Exe
9 | SimpleTest
10 | SimpleTest
11 | v4.5
12 | 512
13 |
14 |
15 | AnyCPU
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | AnyCPU
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 | true
35 | bin\x64\Debug\
36 | DEBUG;TRACE
37 | full
38 | x64
39 | prompt
40 | MinimumRecommendedRules.ruleset
41 | true
42 |
43 |
44 | bin\x64\Release\
45 | TRACE
46 | true
47 | pdbonly
48 | x64
49 | prompt
50 | MinimumRecommendedRules.ruleset
51 | true
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | {f79b9599-1d46-4ad1-974c-777b47112fa2}
73 | DynamixelSDKSharp
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/Samples/SimpleTest/SimpleTest.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2026
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleTest", "SimpleTest.csproj", "{B77EDB02-0A2B-4D4D-B633-61700C759830}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamixelSDKSharp", "..\..\DynamixelSDKSharp\DynamixelSDKSharp.csproj", "{F79B9599-1D46-4AD1-974C-777B47112FA2}"
9 | EndProject
10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dxl_x64_c", "..\..\..\DynamixelSDK\c\build\win64\dxl_x64_c\dxl_x64_c.vcxproj", "{AADD25B2-529E-4716-AABF-CB1B2DE3631C}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Debug|x64 = Debug|x64
16 | Debug|x86 = Debug|x86
17 | Release|Any CPU = Release|Any CPU
18 | Release|x64 = Release|x64
19 | Release|x86 = Release|x86
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {B77EDB02-0A2B-4D4D-B633-61700C759830}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {B77EDB02-0A2B-4D4D-B633-61700C759830}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {B77EDB02-0A2B-4D4D-B633-61700C759830}.Debug|x64.ActiveCfg = Debug|x64
25 | {B77EDB02-0A2B-4D4D-B633-61700C759830}.Debug|x64.Build.0 = Debug|x64
26 | {B77EDB02-0A2B-4D4D-B633-61700C759830}.Debug|x86.ActiveCfg = Debug|Any CPU
27 | {B77EDB02-0A2B-4D4D-B633-61700C759830}.Debug|x86.Build.0 = Debug|Any CPU
28 | {B77EDB02-0A2B-4D4D-B633-61700C759830}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {B77EDB02-0A2B-4D4D-B633-61700C759830}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {B77EDB02-0A2B-4D4D-B633-61700C759830}.Release|x64.ActiveCfg = Release|x64
31 | {B77EDB02-0A2B-4D4D-B633-61700C759830}.Release|x64.Build.0 = Release|x64
32 | {B77EDB02-0A2B-4D4D-B633-61700C759830}.Release|x86.ActiveCfg = Release|Any CPU
33 | {B77EDB02-0A2B-4D4D-B633-61700C759830}.Release|x86.Build.0 = Release|Any CPU
34 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|x64.ActiveCfg = Debug|x64
37 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|x64.Build.0 = Debug|x64
38 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|x86.ActiveCfg = Debug|Any CPU
39 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Debug|x86.Build.0 = Debug|Any CPU
40 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|x64.ActiveCfg = Release|x64
43 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|x64.Build.0 = Release|x64
44 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|x86.ActiveCfg = Release|Any CPU
45 | {F79B9599-1D46-4AD1-974C-777B47112FA2}.Release|x86.Build.0 = Release|Any CPU
46 | {AADD25B2-529E-4716-AABF-CB1B2DE3631C}.Debug|Any CPU.ActiveCfg = Debug|Win32
47 | {AADD25B2-529E-4716-AABF-CB1B2DE3631C}.Debug|x64.ActiveCfg = Debug|x64
48 | {AADD25B2-529E-4716-AABF-CB1B2DE3631C}.Debug|x64.Build.0 = Debug|x64
49 | {AADD25B2-529E-4716-AABF-CB1B2DE3631C}.Debug|x86.ActiveCfg = Debug|Win32
50 | {AADD25B2-529E-4716-AABF-CB1B2DE3631C}.Debug|x86.Build.0 = Debug|Win32
51 | {AADD25B2-529E-4716-AABF-CB1B2DE3631C}.Release|Any CPU.ActiveCfg = Release|Win32
52 | {AADD25B2-529E-4716-AABF-CB1B2DE3631C}.Release|x64.ActiveCfg = Release|x64
53 | {AADD25B2-529E-4716-AABF-CB1B2DE3631C}.Release|x64.Build.0 = Release|x64
54 | {AADD25B2-529E-4716-AABF-CB1B2DE3631C}.Release|x86.ActiveCfg = Release|Win32
55 | {AADD25B2-529E-4716-AABF-CB1B2DE3631C}.Release|x86.Build.0 = Release|Win32
56 | EndGlobalSection
57 | GlobalSection(SolutionProperties) = preSolution
58 | HideSolutionNode = FALSE
59 | EndGlobalSection
60 | GlobalSection(ExtensibilityGlobals) = postSolution
61 | SolutionGuid = {363F7F7B-E63C-48A1-9BA8-8D979883A996}
62 | EndGlobalSection
63 | EndGlobal
64 |
--------------------------------------------------------------------------------
/DynamixelSDKSharp/ProductDatabase/MX-64_2.0.csv:
--------------------------------------------------------------------------------
1 | Address Size Data Name Description Access Initial Value
2 | 0 2 Model Number Model Number R
3 | 2 4 Model Information Model Information R -
4 | 6 1 Version of Firmware Firmware Version R -
5 | 7 1 ID Dynamixel ID RW 1
6 | 8 1 Baud Rate Communication Baud Rate RW 1
7 | 9 1 Return Delay Time Response Delay Time RW 250
8 | 10 1 Drive Mode Drive Mode RW 0
9 | 11 1 Operating Mode Operating Mode RW 3
10 | 12 1 Secondary(Shadow) ID Secondary(Shadow) ID RW 255
11 | 13 1 Protocol Version Protocol Version RW 2
12 | 20 4 Homing Offset Home Position Offset RW 0
13 | 24 4 Moving Threshold Velocity Threshold for Movement Detection RW 10
14 | 31 1 Temperature Limit Maximum Internal Temperature Limit RW 80
15 | 32 2 Max Voltage Limit Maximum Voltage Limit RW 160
16 | 34 2 Min Voltage Limit Minimum Voltage Limit RW 95
17 | 36 2 PWM Limit Maximum PWM Limit RW 885
18 | 38 2 Current Limit Maximum Current Limit RW 1941
19 | 40 4 Acceleration Limit Maximum Acceleration Limit RW 32767
20 | 44 4 Velocity Limit Maximum Velocity Limit RW 435
21 | 48 4 Max Position Limit Maximum Position Limit RW 4095
22 | 52 4 Min Position Limit Minimum Position Limit RW 0
23 | 63 1 Shutdown Shutdown Dynamixel RW 52
24 | 64 1 Torque Enable Motor Torque On/Off RW
25 | 65 1 LED Status LED On/Off RW 0
26 | 68 1 Status Return Level Select Types of Status Return RW 2
27 | 69 1 Registered Instruction Check Reception of Instruction R 0
28 | 70 1 Hardware Error Status Hardware Error Status R 0
29 | 76 2 Velocity I Gain I Gain of Velocity RW 1920
30 | 78 2 Velocity P Gain P Gain of Velocity RW 100
31 | 80 2 Position D Gain D Gain of Position RW 0
32 | 82 2 Position I Gain I Gain of Position RW 0
33 | 84 2 Position P Gain P Gain of Position RW 850
34 | 88 2 Feedforward 2nd Gain 2nd Gain of Feed-Forward RW 0
35 | 90 2 Feedforward 1st Gain 1st Gain of Feed-Forward RW 0
36 | 98 1 Bus Watchdog Dynamixel Bus Watchdog RW 0
37 | 100 2 Goal PWM Target PWM Value RW -
38 | 102 2 Goal Current Target Current Value RW -
39 | 104 4 Goal Velocity Target Velocity Value RW -
40 | 108 4 Profile Acceleration Acceleration Value of Profile RW 0
41 | 112 4 Profile Velocity Velocity Value of Profile RW 0
42 | 116 4 Goal Position Target Position Value RW -
43 | 120 2 Realtime Tick Count Time in millisecond R -
44 | 122 1 Moving Movement Status R 0
45 | 123 1 Moving Status Detailed Information of Movement Status R 0
46 | 124 2 Present PWM Current PWM Value R -
47 | 126 2 Present Current Current Current Value R -
48 | 128 4 Present Velocity Current Velocity Value R -
49 | 132 4 Present Position Current Position Value R -
50 | 136 4 Velocity Trajectory Target Velocity Trajectory Generated by Profile R -
51 | 140 4 Position Trajectory Target Position Trajectory Generated by Profile R -
52 | 144 2 Present Input Voltage Current Input Voltage R -
53 | 146 1 Present Temperature Current Internal Temperature R -
54 | 168 2 Indirect Address 1 Indirect Address 1 RW 224
55 | 170 2 Indirect Address 2 Indirect Address 2 RW 225
56 | 172 2 Indirect Address 3 Indirect Address 3 RW 226
57 | 218 2 Indirect Address 26 Indirect Address 26 RW 249
58 | 220 2 Indirect Address 27 Indirect Address 27 RW 250
59 | 222 2 Indirect Address 28 Indirect Address 28 RW 251
60 | 224 1 Indirect Data 1 Indirect Data 1 RW 0
61 | 225 1 Indirect Data 2 Indirect Data 2 RW 0
62 | 226 1 Indirect Data 3 Indirect Data 3 RW 0
63 | 249 1 Indirect Data 26 Indirect Data 26 RW 0
64 | 250 1 Indirect Data 27 Indirect Data 27 RW 0
65 | 251 1 Indirect Data 28 Indirect Data 28 RW 0
66 | 578 2 Indirect Address 29 Indirect Address 29 RW 634
67 | 580 2 Indirect Address 30 Indirect Address 30 RW 635
68 | 582 2 Indirect Address 31 Indirect Address 31 RW 636
69 | 628 2 Indirect Address 54 Indirect Address 54 RW 659
70 | 630 2 Indirect Address 55 Indirect Address 55 RW 660
71 | 632 2 Indirect Address 56 Indirect Address 56 RW 661
72 | 634 1 Indirect Data 29 Indirect Data 29 RW 0
73 | 635 1 Indirect Data 30 Indirect Data 30 RW 0
74 | 636 1 Indirect Data 31 Indirect Data 31 RW 0
75 | 659 1 Indirect Data 54 Indirect Data 54 RW 0
76 | 660 1 Indirect Data 55 Indirect Data 55 RW 0
77 | 661 1 Indirect Data 56 Indirect Data 56 RW 0
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Scheduler.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.IO;
7 | using System.Net;
8 | using System.Threading;
9 |
10 | namespace DynamixelREST
11 | {
12 | [Serializable]
13 | class Scheduler
14 | {
15 | //Singleton
16 | public static readonly Scheduler X = new Scheduler();
17 |
18 | [Serializable]
19 | public class SettingsType
20 | {
21 | public int Sleep { get; set; } = 100;
22 | }
23 |
24 | [Serializable]
25 | [DebuggerDisplay("{Action} : T - {TimeToNextCall}")]
26 | public class Schedule
27 | {
28 | //If Period <= 0, then the Schedule will not be active
29 | public double Period { get; set; } = 0.0;
30 |
31 | public string Action { get; set; }
32 | public bool OnStart { get; set; } = false;
33 |
34 | public DateTime LastAttemptPerformed = DateTime.Now;
35 |
36 | public void Perform()
37 | {
38 | //check if any exclusive locks are blocking requests
39 | if(!PortPool.X.Lock.IsWriterLockHeld)
40 | {
41 | this.LastAttemptPerformed = DateTime.Now;
42 |
43 | var httpRequest = (HttpWebRequest)WebRequest.Create(String.Format("http://localhost:{0}/{1}", Program.Port, this.Action));
44 | httpRequest.Method = "GET";
45 | var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
46 | }
47 | }
48 |
49 | public TimeSpan TimeToNextCall
50 | {
51 | get
52 | {
53 | if (this.Period > 0)
54 | {
55 | return (LastAttemptPerformed + TimeSpan.FromSeconds(this.Period)) - DateTime.Now;
56 | }
57 | else
58 | {
59 | return TimeSpan.Zero;
60 | }
61 | }
62 | }
63 | }
64 |
65 | public const string Filename = "Schedule.json";
66 | Thread Thread;
67 | bool Joining = false;
68 |
69 | public List Schedules { get; private set; } = new List();
70 | public SettingsType Settings { get; private set; } = new SettingsType();
71 | public bool Enabled { get; set; } = true;
72 |
73 | public void Start()
74 | {
75 | try
76 | {
77 | //load the schedule
78 | this.Load(Scheduler.Filename);
79 |
80 | //start the thread
81 | this.Thread = new Thread(this.ThreadedFunction);
82 | this.Thread.IsBackground = true;
83 | this.Thread.Name = "Scheduler";
84 | this.Thread.Start();
85 | }
86 | catch (Exception e)
87 | {
88 | Logger.Log(Logger.Level.Error, e);
89 | }
90 | }
91 |
92 | void Load(string filename)
93 | {
94 | //load list of constraints
95 | using (StreamReader file = new StreamReader(filename))
96 | {
97 | var json = file.ReadToEnd();
98 | JsonConvert.PopulateObject(json, this, ProductDatabase.JsonSerializerSettings);
99 | }
100 | }
101 |
102 |
103 | void ThreadedFunction()
104 | {
105 | //perform any startup actions
106 | foreach(var schedule in this.Schedules)
107 | {
108 | if(schedule.OnStart)
109 | {
110 | try
111 | {
112 | schedule.Perform();
113 | }
114 | catch (Exception e)
115 | {
116 | Logger.Log(Logger.Level.Error, e, "Schedule." + schedule.Action);
117 | }
118 | }
119 | }
120 |
121 | while(!this.Joining)
122 | {
123 | if(this.Enabled)
124 | {
125 | var now = DateTime.Now;
126 |
127 | //perform all schedules
128 | foreach (var schedule in this.Schedules)
129 | {
130 | if(schedule.Period <= 0)
131 | {
132 | //This means that the scheduler doesn't run on timer (e.g. only runs on start)
133 | }
134 | else
135 | {
136 | //check if we need to run this item
137 | if ((now - schedule.LastAttemptPerformed).TotalSeconds > schedule.Period)
138 | {
139 | try
140 | {
141 | schedule.Perform();
142 | }
143 | catch(Exception e)
144 | {
145 | Logger.Log(Logger.Level.Error, e, "Schedule." + schedule.Action);
146 | }
147 | }
148 | }
149 | }
150 | }
151 |
152 | //sleep
153 | Thread.Sleep(this.Settings.Sleep);
154 | }
155 | }
156 | }
157 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Safety/Constraints.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 |
7 | namespace DynamixelREST
8 | {
9 | namespace Safety
10 | {
11 | public class Constraints : List
12 | {
13 | //Singleton
14 | public static readonly Constraints X = new Constraints();
15 |
16 | public const string Filename = "./Safety/Constraints.json";
17 |
18 | Constraints()
19 | {
20 | try
21 | {
22 | this.Load(Constraints.Filename);
23 | }
24 | catch(Exception e)
25 | {
26 | Logger.Log(Logger.Level.Error, e);
27 | }
28 | }
29 |
30 | void Load(string filename)
31 | {
32 | //load list of constraints
33 | var jsonMapping = new
34 | {
35 | SafetyConstraints = this
36 | };
37 | using (StreamReader file = new StreamReader(filename))
38 | {
39 | var json = file.ReadToEnd();
40 | JsonConvert.PopulateObject(json, jsonMapping, ProductDatabase.JsonSerializerSettings);
41 | }
42 | }
43 | }
44 |
45 | [Serializable]
46 | public class Constraint
47 | {
48 | public enum ActionType
49 | {
50 | None,
51 | ShutdownOne,
52 | ShutdownAll,
53 | ClampValue,
54 | MiddleValue,
55 | TakeARest,
56 | LimitCurrent
57 | }
58 |
59 | public RegisterType RegisterType { get; set; }
60 | public int MinValue { get; set; }
61 | public int MaxValue { get; set; }
62 | public ActionType Action { get; set; }
63 | public double Period { get; set; } = 1;
64 | public Logger.Level LogLevel { get; set; } = Logger.Level.Warning;
65 |
66 | public Dictionary LastPerformTime { get; private set; } = new Dictionary();
67 |
68 | public bool NeedsPerform(Servo servo)
69 | {
70 | if (this.LastPerformTime.ContainsKey(servo.ID))
71 | {
72 | //Check if performed recently
73 | return (DateTime.Now - LastPerformTime[servo.ID]).TotalSeconds > this.Period;
74 | }
75 | else
76 | {
77 | //It has never been performed
78 | return true;
79 | }
80 | }
81 |
82 | public void Perform(Servo servo)
83 | {
84 | var value = servo.ReadValue(this.RegisterType);
85 |
86 | bool isTooLow = value < this.MinValue;
87 | bool isTooHigh = value > this.MaxValue;
88 |
89 | if (isTooLow || isTooHigh)
90 | {
91 | //value is outside of range
92 |
93 | //always log
94 | Logger.Log(this.LogLevel, String.Format("Servo {0} register {1} has value {2} which is out of range ({3}->{4}). Performing action {5}."
95 | , servo.ID
96 | , this.RegisterType.ToString()
97 | , value
98 | , this.MinValue
99 | , this.MaxValue
100 | , this.Action.ToString()));
101 |
102 | switch (this.Action)
103 | {
104 | case ActionType.ShutdownOne:
105 | servo.WriteValue(RegisterType.TorqueEnable, 0);
106 | break;
107 | case ActionType.ShutdownAll:
108 | PortPool.X.ShutdownAll();
109 | break;
110 | case ActionType.ClampValue:
111 | if (isTooLow)
112 | {
113 | servo.WriteValue(this.RegisterType, this.MinValue);
114 | }
115 | else
116 | {
117 | servo.WriteValue(this.RegisterType, this.MaxValue);
118 | }
119 | break;
120 | case ActionType.MiddleValue:
121 | {
122 | var middleValue = (this.MaxValue - this.MinValue) / 2 + this.MinValue;
123 | servo.WriteValue(this.RegisterType, middleValue);
124 | }
125 | break;
126 | case ActionType.TakeARest:
127 | {
128 | ServoRestManager.X.PutToRest(servo);
129 | }
130 | break;
131 | case ActionType.LimitCurrent:
132 | {
133 | var torqueWasEnabled = servo.ReadValue(RegisterType.TorqueEnable);
134 | var previousGoalPosition = servo.ReadValue(RegisterType.GoalPosition);
135 |
136 | servo.WriteValue(RegisterType.TorqueEnable, 0);
137 | {
138 | servo.WriteValue(RegisterType.CurrentLimit, 100);
139 | }
140 |
141 | servo.WriteValue(RegisterType.TorqueEnable, torqueWasEnabled);
142 | servo.WriteValue(RegisterType.GoalPosition, previousGoalPosition);
143 | }
144 | break;
145 | default:
146 | break;
147 | }
148 | }
149 |
150 | if(!this.LastPerformTime.ContainsKey(servo.ID))
151 | {
152 | this.LastPerformTime.Add(servo.ID, DateTime.Now);
153 | }
154 | else
155 | {
156 | this.LastPerformTime[servo.ID] = DateTime.Now;
157 | }
158 | }
159 | }
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/DynamixelSDKSharp/DynamixelSDKSharp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {F79B9599-1D46-4AD1-974C-777B47112FA2}
8 | Library
9 | Properties
10 | DynamixelSDKSharp
11 | DynamixelSDKSharp
12 | v4.5
13 | 512
14 |
15 |
16 |
17 | true
18 | bin\x64\Debug\
19 | TRACE;DEBUG;WIN64
20 | true
21 | full
22 | x64
23 | prompt
24 | MinimumRecommendedRules.ruleset
25 | false
26 |
27 |
28 | bin\x64\Release\
29 | TRACE
30 | true
31 | true
32 | pdbonly
33 | x64
34 | prompt
35 | MinimumRecommendedRules.ruleset
36 | false
37 |
38 |
39 | true
40 | bin\x86\Debug\
41 | TRACE;DEBUG;WIN64
42 | true
43 | full
44 | x86
45 | prompt
46 | MinimumRecommendedRules.ruleset
47 | false
48 |
49 |
50 | bin\x86\Release\
51 | TRACE;WIN32
52 | true
53 | true
54 | pdbonly
55 | x86
56 | prompt
57 | MinimumRecommendedRules.ruleset
58 | false
59 |
60 |
61 |
62 | ..\Samples\DynamixelREST\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | Always
86 |
87 |
88 |
89 | Designer
90 |
91 |
92 |
93 |
94 |
95 | Always
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/DynamixelSDKSharp/WorkerThread.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace DynamixelSDKSharp
9 | {
10 | class WorkerThread
11 | {
12 | public delegate void Action();
13 |
14 | class SyncAction
15 | {
16 | public Action Action;
17 | public Exception ExceptionInThread = null;
18 | public Object NotifyCompletion = new object();
19 | };
20 |
21 | Thread Thread;
22 | bool IsJoining = false;
23 |
24 | Queue ActionQueue = new Queue();
25 | Queue SyncActionQueue = new Queue();
26 |
27 | private List ExceptionsInThread = new List();
28 | public List GetExceptionsInThread(bool flushList = true)
29 | {
30 | lock (this.ExceptionsInThread)
31 | {
32 | var list = this.ExceptionsInThread;
33 | if (flushList)
34 | {
35 | this.ExceptionsInThread = new List();
36 | }
37 | return list;
38 | }
39 | }
40 |
41 | readonly object NotifyActionAvailable = new object();
42 |
43 | public WorkerThread(string name)
44 | {
45 | this.Thread = new Thread(new ThreadStart(ThreadedFunction));
46 | this.Thread.Name = name;
47 | this.Thread.IsBackground = true;
48 | this.Thread.Start();
49 | }
50 |
51 | public void Do(Action Action)
52 | {
53 | //first check if we're already inside thread
54 | if (Thread.CurrentThread == this.Thread)
55 | {
56 | Action();
57 | }
58 | else
59 | {
60 | //add action to queue
61 | lock (this.ActionQueue)
62 | {
63 | this.ActionQueue.Enqueue(Action);
64 | }
65 |
66 | //notify thread
67 | lock (this.NotifyActionAvailable)
68 | {
69 | Monitor.Pulse(this.NotifyActionAvailable);
70 | }
71 | }
72 |
73 | }
74 |
75 | public void DoSync(Action Action, TimeSpan timeout)
76 | {
77 | //first check if we're already inside thread
78 | if (Thread.CurrentThread == this.Thread)
79 | {
80 | Action();
81 | }
82 | else
83 | {
84 | var syncAction = new SyncAction
85 | {
86 | Action = Action
87 | };
88 |
89 | //lock the completion messenger (so it can't pulse before we begin wait)
90 | lock (syncAction.NotifyCompletion)
91 | {
92 | //add action to queue
93 | lock (this.SyncActionQueue)
94 | {
95 | this.SyncActionQueue.Enqueue(syncAction);
96 | }
97 |
98 | //notify thread that a new action is available
99 | lock (this.NotifyActionAvailable)
100 | {
101 | Monitor.Pulse(this.NotifyActionAvailable);
102 | }
103 |
104 | //wait for a response from this action
105 | if (timeout == TimeSpan.Zero)
106 | {
107 |
108 | Monitor.Wait(syncAction.NotifyCompletion);
109 | }
110 | else
111 | {
112 | Monitor.Wait(syncAction.NotifyCompletion, timeout);
113 | }
114 | }
115 |
116 | //throw exception if any
117 | if (syncAction.ExceptionInThread != null)
118 | {
119 | throw (syncAction.ExceptionInThread);
120 | }
121 | }
122 | }
123 |
124 | public void DoSync(Action Action)
125 | {
126 | DoSync(Action, TimeSpan.Zero);
127 | }
128 |
129 | private void ThreadedFunction()
130 | {
131 | //loop whilst thread is running
132 | while (!this.IsJoining)
133 | {
134 | // ACTION QUEUE
135 | {
136 | //loop whilst there are actions in the queue (before waiting on the monitor)
137 | while (true)
138 | {
139 | Action action = null;
140 | lock (this.ActionQueue)
141 | {
142 | if (this.ActionQueue.Count > 0)
143 | {
144 | action = this.ActionQueue.Dequeue();
145 | }
146 | }
147 | if (action != null)
148 | {
149 | try
150 | {
151 | action();
152 | }
153 | catch (Exception e)
154 | {
155 | Console.WriteLine("Exception in Worker Thread");
156 | Console.WriteLine(e.Message);
157 | this.ExceptionsInThread.Add(e);
158 | }
159 | }
160 | else
161 | {
162 | break;
163 | }
164 | }
165 | }
166 |
167 | // SYNC ACTION QUEUE
168 | {
169 | //loop whilst there are actions in the queue (before waiting on the monitor)
170 | while (true)
171 | {
172 | SyncAction action = null;
173 | lock (this.SyncActionQueue)
174 | {
175 | if (this.SyncActionQueue.Count > 0)
176 | {
177 | action = this.SyncActionQueue.Dequeue();
178 | }
179 | }
180 | if (action != null)
181 | {
182 | try
183 | {
184 | action.Action();
185 | }
186 | catch (Exception e)
187 | {
188 | action.ExceptionInThread = e;
189 | }
190 | lock (action.NotifyCompletion)
191 | {
192 | Monitor.Pulse(action.NotifyCompletion);
193 | }
194 | }
195 | else
196 | {
197 | break;
198 | }
199 | }
200 | }
201 |
202 | //wait for notification of next action
203 | lock (this.NotifyActionAvailable)
204 | {
205 | Monitor.Wait(NotifyActionAvailable, TimeSpan.FromMilliseconds(10));
206 | }
207 | }
208 | }
209 |
210 | public void Join()
211 | {
212 | this.IsJoining = true;
213 | lock (this.NotifyActionAvailable)
214 | {
215 | Monitor.Pulse(this.NotifyActionAvailable);
216 | }
217 | this.Thread.Join();
218 | }
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Test/IDoForAllServos.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.Speech.Synthesis;
6 | using System.Threading;
7 |
8 | namespace DynamixelREST.Requests.Test
9 | {
10 | [Serializable]
11 | abstract class IDoForAllServos : IRequest
12 | {
13 | public bool voiceEnabled { get; set; } = true;
14 | public float timeout { get; set; } = 20;
15 | Registers registers { get; set; } = null;
16 | public int accuracy { get; set; } = 10;
17 |
18 | protected abstract void Perform(DynamixelSDKSharp.Servo servo, Action goToPosition, int startPosition);
19 |
20 | public object Perform()
21 | {
22 | var results = new Dictionary();
23 |
24 | using (var speechSynthesizer = new SpeechSynthesizer())
25 | {
26 | speechSynthesizer.SelectVoiceByHints(VoiceGender.Female, VoiceAge.Adult);
27 |
28 | DynamixelSDKSharp.Servo servo = null;
29 | DateTime startServoTime = DateTime.Now;
30 |
31 | Action checkTimeout = () =>
32 | {
33 | var didTimeout = (DateTime.Now - startServoTime).TotalSeconds > this.timeout;
34 | if (didTimeout)
35 | {
36 | throw(new Exception(String.Format("Timeout nuding servo {0}", servo.ID)));
37 | }
38 | };
39 |
40 | var servos = PortPool.X.Servos;
41 | foreach (var servoKeyValue in servos)
42 | {
43 | try
44 | {
45 | servo = servoKeyValue.Value;
46 |
47 | //save time for timeout checks
48 | startServoTime = DateTime.Now;
49 |
50 | //speak the servo ID
51 | Prompt speechPrompt = null;
52 | if(this.voiceEnabled)
53 | {
54 | try
55 | {
56 | speechPrompt = speechSynthesizer.SpeakAsync("Servo " + servoKeyValue.Key.ToString());
57 | }
58 | catch
59 | {
60 | speechPrompt = null;
61 | }
62 | }
63 |
64 | //store values before we started
65 | var oldRegisters = new List();
66 | oldRegisters.AddRange(new[] {
67 | servo.ReadRegister(RegisterType.TorqueEnable),
68 | servo.ReadRegister(RegisterType.ProfileVelocity),
69 | servo.ReadRegister(RegisterType.ProfileAcceleration),
70 | servo.ReadRegister(RegisterType.PositionIGain)
71 | });
72 |
73 | //start position
74 | var startPosition = servo.ReadValue(RegisterType.PresentPosition);
75 |
76 | //turn on LED
77 | servo.WriteValue(RegisterType.LED, 1);
78 |
79 | //set movement properties
80 | servo.WriteValue(RegisterType.TorqueEnable, 1);
81 | servo.WriteValue(RegisterType.ProfileVelocity, 20);
82 | servo.WriteValue(RegisterType.ProfileAcceleration, 2);
83 | servo.WriteValue(RegisterType.PositionIGain, 100);
84 |
85 | //set any custom registers
86 | if (this.registers != null)
87 | {
88 | foreach (var register in this.registers.Values)
89 | {
90 | //store old value
91 | //Note : these will enter the FIFO list after the registers above, so will overwrite on the way outs
92 | oldRegisters.Add(register.Clone() as Register);
93 |
94 | //set new value
95 | servo.WriteValue(register);
96 | }
97 | }
98 |
99 | //function for moving to position
100 | Action goToPosition = (int target) =>
101 | {
102 |
103 | //clamp target position to valid range
104 | if (target < 0)
105 | {
106 | target = 0;
107 | }
108 | if (target >= servo.ProductSpecification.EncoderResolution)
109 | {
110 | target = servo.ProductSpecification.EncoderResolution - 1;
111 | }
112 |
113 | servo.WriteValue(RegisterType.GoalPosition, target);
114 |
115 | while (Math.Abs(servo.ReadValue(RegisterType.PresentPosition) - target) > this.accuracy)
116 | {
117 | checkTimeout();
118 | Thread.Sleep(500);
119 | }
120 | };
121 |
122 |
123 |
124 | //----
125 | //Do the action
126 | this.Perform(servo, goToPosition, startPosition);
127 | //
128 | //----
129 |
130 |
131 |
132 | //reset registers
133 | foreach (var register in oldRegisters)
134 | {
135 | servo.WriteValue(register);
136 | }
137 |
138 | //wait for speech to finish
139 | if (speechPrompt != null)
140 | {
141 | while (!speechPrompt.IsCompleted)
142 | {
143 | checkTimeout();
144 | Thread.Sleep(10);
145 | }
146 | }
147 |
148 | //log success
149 | Logger.Log(Logger.Level.Trace, String.Format("Servo {0} success", servo.ID), this.GetType());
150 |
151 | //turn off LED if successful
152 | servo.WriteValue(RegisterType.LED, 0);
153 |
154 | //output success result
155 | results.Add(servo.ID, new
156 | {
157 | success = true
158 | });
159 | }
160 | catch (Exception e)
161 | {
162 | //log fail
163 | Logger.Log(Logger.Level.Error, e);
164 |
165 | //speak fail
166 | if(this.voiceEnabled)
167 | {
168 | speechSynthesizer.Speak(String.Format("Issue with servo {0}", servo.ID));
169 | }
170 |
171 | //output fail result
172 | results.Add(servo.ID, new
173 | {
174 | success = false,
175 | exception = new Utils.ExceptionMessage(e)
176 | });
177 | }
178 | }
179 |
180 | if(voiceEnabled)
181 | {
182 | speechSynthesizer.SpeakAsync("END");
183 | }
184 | }
185 |
186 | return results;
187 | }
188 | }
189 | }
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/RestletAPI.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using Nancy.Responses;
3 | using Newtonsoft.Json;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Diagnostics;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace DynamixelREST.Requests
12 | {
13 | class RestletAPI : IRequest
14 | {
15 | string hostName = "localhost";
16 |
17 | class APIExport
18 | {
19 | [DebuggerDisplay("type = {type}, name = {name}, path = {uri.path}")]
20 | public class Node
21 | {
22 | public enum Type
23 | {
24 | Project,
25 | Service,
26 | Request
27 | }
28 |
29 | public class Uri
30 | {
31 | public class Query
32 | {
33 | public string delimiter { get; set; } = "&";
34 | public List items = new List();
35 | }
36 |
37 | public class Scheme
38 | {
39 | public string name { get; set; } = "http";
40 | public string version { get; set; } = "V11";
41 | }
42 |
43 | public Query query { get; set; } = new Query();
44 | public Scheme scheme { get; set; } = new Scheme();
45 | public string host { get; set; }
46 | public string path { get; set; }
47 | }
48 |
49 | public class Method
50 | {
51 | public enum Type
52 | {
53 | POST,
54 | GET
55 | }
56 |
57 | public bool requestBody { get; set; } = false;
58 | public Type name { get; set; } = Type.GET;
59 | }
60 |
61 | public class Body
62 | {
63 | public string bodyType { get; set; } = "Text";
64 | public bool autoSetLength { get; set; } = true;
65 | public string textBody { get; set; }
66 | }
67 |
68 | public class Header
69 | {
70 | public bool enabled = true;
71 | public string name = "Content-Type";
72 | public string value = "application/json";
73 | };
74 |
75 | public string id { get; set; } = Guid.NewGuid().ToString();
76 | public DateTime lastModified { get; set; } = DateTime.Now;
77 |
78 | public Type type { get; set; }
79 | public string name { get; set; }
80 | public Uri uri { get; set; } = null;
81 | public Method method { get; set; } = null;
82 |
83 | public Body body { get; set; } = null;
84 | public string parentId { get; set; } = null;
85 |
86 | public List headers = null;
87 | }
88 |
89 | public int version { get; } = 3;
90 |
91 | [JsonProperty(PropertyName = "front-version")]
92 | public string front_version { get; } = "2.18.0";
93 |
94 | public List nodes = new List();
95 | }
96 |
97 | public object Perform()
98 | {
99 | var routes = AutoRouting.Routes;
100 | var apiExport = new APIExport();
101 |
102 | foreach(var route in routes)
103 | {
104 | var namespaceHeirarchy = route.Key.Split('/').ToList();
105 | var name = namespaceHeirarchy.Last();
106 | namespaceHeirarchy.RemoveAt(namespaceHeirarchy.Count - 1);
107 |
108 | string currentParentId = null;
109 |
110 | //check if we need to reference any parents
111 | {
112 | foreach (var serviceName in namespaceHeirarchy)
113 | {
114 | //search for service in nodes
115 |
116 | var matchingNodeQuery = apiExport.nodes.AsQueryable()
117 | .Where(x => x.parentId == currentParentId && x.name == serviceName);
118 | if(matchingNodeQuery.Count() >= 1)
119 | {
120 | //Service already exists
121 | var service = matchingNodeQuery.First();
122 | currentParentId = service.id;
123 | }
124 | else
125 | {
126 | //Create service
127 | var service = new APIExport.Node
128 | {
129 | type = APIExport.Node.Type.Service,
130 | name = serviceName,
131 | parentId = currentParentId
132 | };
133 | currentParentId = service.id;
134 | apiExport.nodes.Add(service);
135 | }
136 | }
137 | }
138 |
139 | //build the new node for this request
140 | {
141 | if(route.Value.RequestHandlerAttribute.Method.HasFlag(Method.GET))
142 | {
143 | var node = new APIExport.Node
144 | {
145 | type = APIExport.Node.Type.Request,
146 | name = name + " (GET)",
147 | uri = new APIExport.Node.Uri
148 | {
149 | host = String.Format("{0}:{1}", this.hostName, Program.Port),
150 | path = "/" + route.Key
151 | },
152 | method = new APIExport.Node.Method
153 | {
154 | name = APIExport.Node.Method.Type.GET
155 | },
156 | headers = new List
157 | {
158 | new APIExport.Node.Header()
159 | },
160 | parentId = currentParentId
161 | };
162 | apiExport.nodes.Add(node);
163 | }
164 |
165 | if (route.Value.RequestHandlerAttribute.Method.HasFlag(Method.POST))
166 | {
167 | var defaultRequestParameters = Activator.CreateInstance(route.Value.RequestType);
168 |
169 | var node = new APIExport.Node
170 | {
171 | type = APIExport.Node.Type.Request,
172 | name = name + " (POST)",
173 | uri = new APIExport.Node.Uri
174 | {
175 | host = String.Format("{0}:{1}", this.hostName, Program.Port),
176 | path = "/" + route.Key
177 | },
178 | method = new APIExport.Node.Method
179 | {
180 | name = APIExport.Node.Method.Type.POST,
181 | requestBody = true
182 | },
183 | body = new APIExport.Node.Body
184 | {
185 | textBody = JsonConvert.SerializeObject(defaultRequestParameters
186 | , Formatting.Indented
187 | , ProductDatabase.JsonSerializerSettings)
188 | },
189 | headers = new List
190 | {
191 | new APIExport.Node.Header()
192 | },
193 | parentId = currentParentId
194 | };
195 | apiExport.nodes.Add(node);
196 | }
197 | }
198 | }
199 |
200 | return new TextResponse(JsonConvert.SerializeObject(apiExport, ProductDatabase.JsonSerializerSettings), "application/json");
201 | }
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/Requests/Data/Logger.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using MongoDB.Bson;
3 | using MongoDB.Driver;
4 | using Newtonsoft.Json;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 |
12 | namespace DynamixelREST.Requests.Data
13 | {
14 | [Serializable]
15 | class Logger : IRequest
16 | {
17 | const string ConfigFilename = "DataLogger.json";
18 |
19 | public bool UseGroupSyncRead { get; set; } = false;
20 |
21 | public class Settings
22 | {
23 | public Settings()
24 | {
25 | this.LoadConfig(Logger.ConfigFilename);
26 | }
27 |
28 | void LoadConfig(string filename)
29 | {
30 | using (StreamReader file = new StreamReader(filename))
31 | {
32 | var json = file.ReadToEnd();
33 | JsonConvert.PopulateObject(json
34 | , this
35 | , ProductDatabase.JsonSerializerSettings);
36 | }
37 | }
38 |
39 | public List Registers = null;
40 |
41 | [JsonProperty(PropertyName = "Max Servo Count")]
42 | public int MaxServoCount { get; set; } = 32;
43 |
44 | public double Period { get; set; } = 10.0;
45 | }
46 |
47 | public static Settings FSettings = new Settings();
48 |
49 | public object Perform()
50 | {
51 | //Get ports
52 | var ports = PortPool.X.Ports;
53 |
54 | //Get database collection
55 | var collection = Database.Connection.X.GetCollection();
56 |
57 | //We get the register objects from the first servo we find in order to know addresses and sizes
58 | DynamixelSDKSharp.Servo firstServo = null;
59 |
60 | var report = new Dictionary>();
61 |
62 | Parallel.ForEach(ports, (portIterator) =>
63 | {
64 | var listOfServosToLog = new List();
65 | var port = portIterator.Value;
66 |
67 | // check which servos need to be logged for either high frequency or because they've never been logged
68 | foreach (var servoIterator in port.Servos)
69 | {
70 | var servoID = servoIterator.Key;
71 | var servo = servoIterator.Value;
72 |
73 | // store the first servo
74 | if (firstServo == null)
75 | {
76 | firstServo = servoIterator.Value;
77 | }
78 | else
79 | {
80 | //check all servos are the same model number
81 | if (servoIterator.Value.ProductSpecification.ModelNumber != firstServo.ProductSpecification.ModelNumber)
82 | {
83 | throw (new Exception("Mixed model numbers are not supported"));
84 | }
85 | }
86 |
87 | // get data log entries for this servo
88 | var documents = from document in collection.AsQueryable()
89 | where document.ServoID == servoID
90 | orderby document.TimeStamp descending
91 | select document;
92 |
93 | if (Database.HighFrequencyRequests.X.IsHighFrequencyNow(servoID))
94 | {
95 | // It's on high frequency list
96 | listOfServosToLog.Add(servoID);
97 | }
98 | else if (documents.Count() == 0)
99 | {
100 | // It has never been logged
101 | listOfServosToLog.Add(servoID);
102 | }
103 | }
104 |
105 | if(port.Servos.Count == 0)
106 | {
107 | //quit early if this port has no servos
108 | return;
109 | }
110 |
111 | //check regular logging (choose oldest)
112 | {
113 | var staleTimeForRegularUpdates = DateTime.Now - TimeSpan.FromSeconds(Logger.FSettings.Period);
114 |
115 | var documents = collection.AsQueryable()
116 | .OrderByDescending(row => row.TimeStamp)
117 | .GroupBy(row => row.ServoID)
118 | .Where(group => group.First().TimeStamp < staleTimeForRegularUpdates.ToUniversalTime())
119 | .Select(group => group.Key);
120 |
121 | //Ideally we don't want to call ToList first as this means we perform the following operation locally
122 | var servosWithOldData = documents.Take(Logger.FSettings.MaxServoCount).ToList();
123 |
124 | foreach (var servoWithOldData in servosWithOldData)
125 | {
126 | listOfServosToLog.Add((byte)servoWithOldData);
127 | }
128 | }
129 |
130 | // trim any servos which aren't available on this port
131 | listOfServosToLog.RemoveAll(servoID =>
132 | {
133 | return !port.Servos.ContainsKey(servoID);
134 | });
135 |
136 | // accumulate data logs
137 | var recordedValues = new Dictionary>();
138 |
139 | if (listOfServosToLog.Count > 0)
140 | {
141 | foreach (var registerType in Logger.FSettings.Registers)
142 | {
143 | var registerInfo = firstServo.Registers[registerType];
144 |
145 | if (this.UseGroupSyncRead)
146 | {
147 | recordedValues.Add(registerType
148 | , portIterator.Value.GroupSyncRead(listOfServosToLog
149 | , registerInfo.Address
150 | , registerInfo.Size));
151 | }
152 | else
153 | {
154 | var values = new Dictionary();
155 | foreach (var servoID in listOfServosToLog)
156 | {
157 | values.Add(servoID, port.Read(servoID
158 | , registerInfo.Address
159 | , registerInfo.Size));
160 | }
161 |
162 | recordedValues.Add(registerType, values);
163 | }
164 | }
165 | }
166 |
167 | //save data into database per servo
168 | foreach (var servoID in listOfServosToLog)
169 | {
170 | var valuesForServo = new Dictionary();
171 | foreach (var registerValuesIterator in recordedValues)
172 | {
173 | valuesForServo.Add(registerValuesIterator.Key.ToString()
174 | , registerValuesIterator.Value[servoID]);
175 | }
176 |
177 | var row = new Database.Registers
178 | {
179 | ServoID = servoID,
180 | TimeStamp = DateTime.Now,
181 | RegisterValues = valuesForServo
182 | };
183 |
184 | collection.InsertOne(row);
185 | }
186 |
187 | //accumulate report log
188 | lock(report)
189 | {
190 | report.Add(String.Format("{0} ({1})", port.Name, port.Address), listOfServosToLog);
191 | }
192 | });
193 |
194 | return report;
195 | }
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 |
332 |
--------------------------------------------------------------------------------
/Samples/DynamixelREST/DynamixelREST/AutoRouting.cs:
--------------------------------------------------------------------------------
1 | using DynamixelSDKSharp;
2 | using Nancy;
3 | using Nancy.Responses;
4 | using Newtonsoft.Json;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Reflection;
10 | using System.Text;
11 | using System.Threading;
12 | using System.Threading.Tasks;
13 |
14 | namespace DynamixelREST
15 | {
16 | public class AutoRouting : NancyModule
17 | {
18 | public class Route
19 | {
20 | public Requests.RequestHandlerAttribute RequestHandlerAttribute { get; set; }
21 | public Type RequestType;
22 | }
23 |
24 | public static Dictionary Routes { get; private set; } = null;
25 |
26 | public AutoRouting()
27 | {
28 | //Override default option route - sets CORS headers so that we can make cross domain requests.
29 | {
30 | Options("/", _ =>
31 | {
32 | return new Response();
33 | });
34 |
35 | After.AddItemToEndOfPipeline((ctx) => ctx.Response
36 | .WithHeader("Access-Control-Allow-Origin", "*")
37 | .WithHeader("Access-Control-Allow-Methods", "POST,GET")
38 | .WithHeader("Access-Control-Allow-Headers", "Accept, Origin, Content-type"));
39 | }
40 |
41 |
42 | //Add all IRequests to Routes
43 | {
44 | if (AutoRouting.Routes == null) // check that it's first pass
45 | {
46 | AutoRouting.Routes = new Dictionary();
47 | var assembly = this.GetType().GetTypeInfo().Assembly;
48 |
49 | //get all types inheriting from IRequest
50 | var types = assembly.GetTypes().Where(t => typeof(Requests.IRequest).IsAssignableFrom(t));
51 | foreach (var type in types)
52 | {
53 | if(type.Attributes.HasFlag(TypeAttributes.Abstract))
54 | {
55 | continue;
56 | }
57 |
58 | try
59 | {
60 | string address;
61 | {
62 | var assemblyAddress = type.FullName.Split('.').ToList();
63 | assemblyAddress.RemoveAt(0);
64 | assemblyAddress.RemoveAt(0);
65 | address = String.Join("/", assemblyAddress);
66 | }
67 |
68 | var attribute = type.GetCustomAttribute(typeof(Requests.RequestHandlerAttribute)) as Requests.RequestHandlerAttribute;
69 | if (attribute == null)
70 | {
71 | //if no attribute is set for this class, make a default one
72 | attribute = new Requests.RequestHandlerAttribute();
73 | } else
74 | {
75 | //handle custom addresses
76 | if (attribute.CustomAddress != null)
77 | {
78 | address = attribute.CustomAddress;
79 | }
80 | }
81 |
82 | //add the request to the AutoRouting routes table
83 | AutoRouting.Routes.Add(address, new Route
84 | {
85 | RequestHandlerAttribute = attribute,
86 | RequestType = type
87 | });
88 | }
89 | catch(Exception e)
90 | {
91 | Logger.Log(Logger.Level.Error, e);
92 | }
93 | }
94 | }
95 | }
96 |
97 | //Perform all Routes
98 | foreach (var route in AutoRouting.Routes)
99 | {
100 | if (route.Value.RequestHandlerAttribute.Method.HasFlag(Requests.Method.GET)) {
101 | Get(route.Key, args =>
102 | {
103 | return respond(() =>
104 | {
105 | //make an isntance of the request (no input body)
106 | var request = (Requests.IRequest)Activator.CreateInstance(route.Value.RequestType);
107 | return request.Perform();
108 | }, route.Value);
109 | });
110 | }
111 | if (route.Value.RequestHandlerAttribute.Method.HasFlag(Requests.Method.POST)) {
112 |
113 | Post(route.Key, args =>
114 | {
115 | return respond(() =>
116 | {
117 | //make an isntance of the request from the incoming request body
118 | var getRequestMethod = typeof(AutoRouting).GetMethod("getRequest");
119 | var getRequestMethodSpecific = getRequestMethod.MakeGenericMethod(route.Value.RequestType);
120 | var requestUntyped = getRequestMethodSpecific.Invoke(this, null);
121 | var request = (Requests.IRequest)requestUntyped;
122 | return request.Perform();
123 | }, route.Value);
124 | });
125 | }
126 | }
127 | }
128 |
129 | public T getRequest() where T : new()
130 | {
131 | var incomingStream = Request.Body;
132 | var reader = new StreamReader(incomingStream, Encoding.UTF8);
133 | var requestString = reader.ReadToEnd();
134 | var request = JsonConvert.DeserializeObject(requestString, ProductDatabase.JsonSerializerSettings);
135 |
136 | if (request == null)
137 | {
138 | request = new T();
139 | }
140 |
141 | return request;
142 | }
143 |
144 | public static object respond(Func