FlexSEA Wiki

A WEARABLE ROBOTICS TOOLKIT

User Tools

Site Tools


fxplanstack_newclasshierarchy

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
fxplanstack_newclasshierarchy [2019/07/10 20:59]
yangwill Updating design
fxplanstack_newclasshierarchy [2019/08/15 15:34] (current)
yangwill Added more details about how connecting to the device works
Line 1: Line 1:
-======fxplanstack ​rework======+======Fxplanstack ​rework======
  
-Draw.io ​class diagram+====UML ​class diagram====
  
-Link to most recent diagram[[https://drive.google.com/​file/​d/​1FIUgGi5CHtp5A0vB9QV0MubCDt9zug11/​view?usp=sharing]] (work in progress)+{{:fx_plan_rework_7_30_19.png?800|}}
  
-{{:fx_plan_rework_7_10_19.png?400|}}+====Flowchart==== 
 +{{:fx_plan_rework_7_30_19_flowchart.png?800|}}
  
-Instead of hiding the implementation in layers and layers of inheritance. I propose structuring the planstack under a class hierarchy.+===== CommManager =====
  
-**===First Layer===** (CommWrapper) 
  
-CommWrapper is a wrapper ​class that includes ​the functionality ​of both CommManager and DataLogger. ​+CommManager acts as an aggregator of multiple Device objects and serves as a wrapper ​for the Device objects. It also allows access to the shared global settings ​of DataLogger ​objects. It refers to unopened Devices by their port index (portIdx), but can refer to opened Devices by their device id (devId).
  
-**===Second Layer===** (CommManager and DataLogger)+===== Device =====
  
-I decided to separate CommManager and DataLogger because they are performing completely different tasks. CommManager communicates with and manages multiple devices while DataLogger simply reads the output from each device. These classes can be set up separately and are not dependent on each other to function. 
  
-In addition to CommManager and DataLogger, I propose having a separate thread keep track of new devices and update flexseaDeviceProvider. This functionality was previously owned by FlexseaSerial,​ but I want FlexseaSerial to function as a library for serial communication.+The Device class is where most of the plan stack logic is stored.
  
-**===Third Layer===** (Device)+Device ​can be in one of three states: NODEVICE, OPEN, and CONNECTED. NODEVICE is the default state, this is when the Device'​s serial port has not been opened and the Device has no data except for keeping track of its port index. OPEN is when the serial port has been opened. This causes the Device to actively process incoming data and send commands to the ActPack. CONNECTED is a special case of OPEN, where the Device is actively streaming commands to the ActPack.
  
-It is much more organized to have a device-centric model, where each device owns its own communication settings and commands ​rather than having a centralized queue. However, because both CommManager and DataLogger require access ​to all the Devices, I am keeping the DeviceProvider class as a way to keep track of the available devices.+A Device object performs four main actions: 
 +  * Read serial data from the ActPack (deviceReader) 
 +  * Send commands to the ActPack (commandSender) 
 +  * Process streaming requests (commandStreamer) 
 +  * Populate ​the datalogger file (deviceLogger)
  
-The Device ​class has two main functionalities in addition to keeping track of its communication settings: sending commands to the actual device ​(write) and reading data from the device (read)+Each of these actions is serviced by a separate thread. So for an opened ​Device (ConnectionState >= OPEN), there are four threads running for that Device. The streaming ​and logging threads will always be running even if they are not executing any tasks; <​del>​**this can later be optimized with a condition variable**</​del>​ This has been implemented.
  
-Sending ​commands will be done through ​the FlexseaSerial librarywhich is a wrapper library around SerialDriver ​and Serial.+Commands are packed into individual Message objects and pushed to a queue to be sent. From thorough testing, the queue never grows too large and the latency for sending ​commands ​is between 8 - 12ms. To ensure we send all messages (most importantly that we turn off the controller properly), the commandSender thread ​will not stop running until the queue has been cleared. For this reasonwe must call the stopStreaming() function before the stopThreads() function. Note: if the frequency that we send setPosition commands from the script ​is extremely high ( > 2000Hz), the queue will back up and shutting down the device will not be immediate. **If absolutely necessary, we can adjust the frequency that we clear the queue by changing the sleep duration in the commandSender thread (it's currently set at 500 microseconds).** 
  
-Reading from the devices ​is done through FlexseaDevice.+Opening ​the Device, tryOpen(). tryOpen ​is how we establish a serial connection with the ActPack. The function will open the serial port and then send a CMD_SYSDATA_R to the ActPack. **The next step in connecting to the ActPack is handled in the separate deviceReader thread**. The deviceReader thread will process the ActPack metadata and populate the flexseaDevice and Device fields. Only then will the Device class get a devId. This is better visualized in the flowchart above.
  
-=====Threading======+Optimization: ​  <​del>​The current thread management will start all the threads when the Device is opened and will not stop any of the threads until the Device is closed. The reason I did not incorporate more granularity is because it makes cleaning up the threads far more complicated and will make it much harder to maintain the code base later. The best way to reduce device idling is to incorporate a condition variable for the commandStreamer and deviceLogger threads as stated previously.</​del>​ Implemented
  
-I envision the following threads: 
  
-NOTE: These threads were originally implemented as a PeriodicTask that used a CV to reduce idling. If CPU usage is a concern, we can keep this implementation,​ but my guess is that a simple while(true) loop with a short sleep statement will suffice. 
  
-By having a device specific implementation,​ we can reduce the amount of blocking and bottlenecks. If in our testing, the CommManager'​s incoming queue accumulates too many commands, we can simply add more threads to process that queue.+===== DataLogger =====
  
 +DataLogger writes Device data to a .csv file to be processed by the GUI. It reads the data from a FlexseaDevice object which is given upon construction. Each Device has its own DataLogger object. However, all DataLogger objects share a few parameters such as the folderpath and the additional variables to log. These shared parameters are set from the CommManager class. Because there are shared variables, these variables need to be initialized before any DataLogger objects are created.
  
-**CommManager sendCommand thread** 
  
-CommManager'​s main functionality is to distribute incoming commands to the appropriate Device. There will be a constant thread that moves an incoming command from the CommManager'​s queue to the incomingCommands queue for the appropriate device. 
  
-**DataLogger serviceLogs thread**+===== FlexseaDevice =====
  
-Similar to its previous functionality, DataLogger ​will have a thread that constantly polls every logging device ​and write the result to the appropriate file.+FlexseaDevice is where the returned ActPack data is stored. This data can be accessed by CommWrapper::​fxReadData(), DataLogger::​logDevice(), ​and possibly directly by the GUI
  
-**DeviceFinder thread**+**Might be good to change the name of FlexseaDevice to better reflect its function, I named the instance of it in the Device class as "​serialDevice"​ .**
  
-DeviceFinder is a class pulled out of FlexseaSerial that polls open ports for new devices and after assigning a devID, will add it to flexseaDeviceProvider. 
  
-**Device sendCommand thread** (per Device instance) 
  
-This thread will process ​commands ​from the incomingCommands queue and send them to the physical device+===== FlexseaSerial ===== 
 + 
 +FlexseaSerial handles all packing and unpacking for communicating with the ActPack. It inherits the serial open, close, read, and write from SerialDriver and also has additional functions to process ​the incoming serial data. This abstracts all the serial communication away from the Device class. 
 + 
 + 
 + 
 + 
 +===== Changes to flexsea_comm_multi.c/​h ===== 
 + 
 +The issue we used to face when sending commands too quickly was due to the fact that there was a single shared outgoing MultiWrapper object per port. This caused the message in the MultiWrapper to be corrupted occasionally (this was discovered by printing out all the outgoing bytes to a local file). I addressed this issue by cycling through multiple MultiWrappers instead of a single one. This entailed changing ''​MultiWrapper out''​ to ''​MultiWrapper out[4]''​ and making the appropriate changes inside flexsea_comm_multi.c to reflect this change. 
  
  
fxplanstack_newclasshierarchy.1562792352.txt.gz · Last modified: 2019/07/10 20:59 by yangwill