Blocks
Autodrive
- class crappy.blocks.autoDrive.AutoDrive(*args, **kwargs)[source]
To follow the spots with VideoExtenso.
This blocks takes the output of a VideoExtenso block and uses the spots coordinates to drive an actuator, on which the camera is mounted.
This will allow the camera to follow the spots along an axis.
It is simply a P loop: the difference in pixel between the barycenter of the spots and the middle of the image along the given axis is multiplied by P and set as the speed of the actuator.
- __init__(actuator: Optional[dict] = None, P: float = 2000, direction: str = 'Y-', range: int = 2048, max_speed: float = 200000) None [source]
Sets the args and initializes parent class.
- Parameters
actuator (
dict
, optional) –P (
float
, optional) – The gain for commanding the actuator.direction (
str
, optional) – What axis should be considered, and in which direction ? Astr
whose first character is the axis (X or Y) and second character is the direction (+ or -).range (
int
, optional) – The size in pixel of the image along the chosen axis.max_speed (
float
, optional) – The absolute max value to send to the actuator.
Camera
- class crappy.blocks.camera.Camera(*args, **kwargs)[source]
Reads images from a camera object, saves and/or sends them to another block.
It can be triggered by an other block, internally, or try to run at a given framerate.
- __init__(camera: str, save_folder: Optional[str] = None, verbose: bool = False, labels: Optional[list] = None, fps_label: str = False, img_name: str = '{self.loops:06d}_{t-self.t0:.6f}', ext: str = 'tiff', save_period: int = 1, save_backend: Optional[str] = None, transform: Optional[Callable] = None, input_label: Optional[str] = None, config: bool = True, no_loop: bool = False, **kwargs) None [source]
Sets the args and initializes parent class.
- Parameters
camera (
str
) – The name of the camera to control. See Cameras for an exhaustive list of available ones.save_folder (
str
, optional) – The directory to save images to. If it doesn’t exist it will be created. IfNone
the images won’t be saved.verbose (
bool
, optional) – IfTrue
, the block will print the number of loops/s.labels (
list
, optional) – Names of the labels for respectively time and the frame.fps_label (
str
, optional) – If set,self.max_fps
will be set to the value received by the block with this label.img_name (
str
, optional) – Template for the name of the image to save. It is evaluated as an f-string.ext (
str
, optional) – Extension of the image. Make sure it is supported by the saving backend.save_period (
int
, optional) – Will save only one in x images.save_backend (
str
, optional) – Module to use to save the images. The supported backends are:sitk
(SimpleITK),cv2
(OpenCV) andpil
(Pillow). IfNone
, will trysitk
and thencv2
if not successful.transform (
function
, optional) – Function to be applied on the image before sending. It will not be applied on the saved images.input_label (
str
, optional) – If specified, the image will not be read from a camera object but from this label.config (
bool
, optional) – Show the popup for config ?**kwargs – Any additional specific argument to pass to the camera.
- finish() None [source]
If
main()
is not overridden, this method will be called upon exit or after a crash.
Client Server
- class crappy.blocks.client_server.Client_server(*args, **kwargs)[source]
Block for exchanging data on a local network using the MQTT protocol.
This block can send data to an MQTT broker, receive data from this broker by subscribing to its topics, and also launch the Mosquitto broker.
- __init__(broker: bool = False, address: Any = 'localhost', port: int = 1148, init_output: Optional[Dict[str, Any]] = None, topics: Optional[List[Union[str, Tuple[str, str]]]] = None, cmd_labels: Optional[List[Union[str, Tuple[str, str]]]] = None, labels_to_send: Optional[List[Union[str, Tuple[str, str]]]] = None) None [source]
Checks arguments validity and sets the instance attributes.
- Parameters
broker (
bool
, optional) – IfTrue
, starts the Mosquitto broker during the prepare loop and stops it during the finish loop. If Mosquitto is not installed aFileNotFoundError
is raised.address (optional) – The network address on which the MQTT broker is running.
port (
int
, optional) – A network port on which the MQTT broker is listening.init_output (
dict
, optional) – Adict
containing for each label intopics
the first value to be sent in the output link. Must be given iftopics
is notNone
.topics (
list
, optional) – Alist
ofstr
and/ortuple
ofstr
. Each string corresponds to the name of a crappy label to be received from the broker. Each element of the list is considered to be the name of an MQTT topic, to which the client subscribes. After a message has been received on that topic, the block returns for each label in the topic (i.e. each string in the tuple) the corresponding data from the message. It also returns the current timestamp in the label ‘t(s)’.cmd_labels (
list
, optional) – Alist
ofstr
and/ortuple
ofstr
. Each string corresponds to the name of a crappy label to send to the broker. Each element of the list is considered to be the name of an MQTT topic, in which the client publishes. Grouping labels in a same topic (i.e. strings in a same tuple) allows to keep the synchronization between signals coming from a same block, as they will be published together in a same message. This is mostly useful for sending a signal along with its timeframe.labels_to_send (
list
, optional) – Alist
ofstr
and/ortuple
ofstr
. Allows to rename the labels before publishing data. The structure oflabels_to_send
should be the exact same ascmd_labels
, with each label inlabels_to_send
replacing the corresponding one incmd_labels
. This is especially useful for transferring several signals along with their timestamps, as the label't(s)'
should not appear more than once in the topics list of the receiving block.
Note
broker
: In order for the block to run, an MQTT broker must be running at the specified address on the specified port. If not, anConnectionRefusedError
is raised. The broker can be started and stopped manually by the user independently of the execution of crappy. It also doesn’t need to be Mosquitto, any other MQTT broker can be used.topics
: The presence of the same label in multiple topics will most likely lead to a data loss.cmd_labels
: It is not possible to group signals coming from different blocks in a same topic.labels_to_send
: Differences in the structure oflabels_to_send
andcmd_labels
will not always raise an error, but may lead to a data loss.Single-value tuples: Single-value tuples can be shortened as strings.
topics=[('cmd1',), ('cmd2',)] cmd_labels=[('cmd1',), ('cmd2',)] labels_to_send=[('cmd1',), ('cmd2',)]
is equivalent to
topics=['cmd1', 'cmd2'] cmd_labels=['cmd1', 'cmd2'] labels_to_send=['cmd1', 'cmd2']
Examples
topics
: Iftopics=[('t1', 'cmd1'), 'sign']
the client will subscribe to the topics
('t1', 'cmd1') ('sign',)
The block will return data associated with the labels
't1', 'cmd1' 'sign'
cmd_labels
: Ifcmd_labels=[('t1', 'cmd1'), 'sign']
the client will publish data in the form of
[[t1_0, cmd1_0], [t1_1, cmd1_1], ...] [[sign_0], [sign_1], ...]
in the topics
('t1', 'cmd1') ('sign',)
labels_to_send
: Ifcmd_labels=[('t(s)', 'cmd'), 'sign'] labels_to_send=[('t1', 'cmd1'), 'sign']
the data from labels
't(s)', 'cmd'
will be published in the topic
('t1', 'cmd1')
and the data from label
'sign'
in the topic
('sign',)
Dashboard
- class crappy.blocks.dashboard.Dashboard(*args, **kwargs)[source]
The Dashboard receives data from a Link, and prints it on a new popped window.
It can only display data coming from one block.
Discorrel
More documentation coming soon !
Displayer
Disve
- class crappy.blocks.disve.DISVE(*args, **kwargs)[source]
This block tracks the motion of regions of an image (patches), taking the first image as a reference.
It relies on cross-correlation, and is thus well-suited for tracking speckled patches. The displacement output may then be used to compute strains, and so to perform video-extensometry.
The images may be acquired by a camera, or be sent from another block. Several algorithms are available for tracking the patches, with different characteristics. All the computations are done by the Disve tool.
- __init__(camera: str, patches: List[Tuple[int, int, int, int]], labels: Optional[List[str]] = None, method: Literal['Disflow', 'Pixel precision', 'Parabola', 'Lucas Kanade'] = 'Disflow', alpha: float = 3, delta: float = 1, gamma: float = 0, finest_scale: int = 1, iterations: int = 1, gditerations: int = 10, patch_size: int = 8, patch_stride: int = 3, show_image: bool = False, border: float = 0.2, safe: bool = True, follow: bool = True, **kwargs) None [source]
Sets a few attributes.
- Parameters
camera – The camera to use for acquiring the images. It should be one of the Supported cameras.
patches – A list containing the different patches to track. Each patch should be given as follows :
(y min, x_min, height, width)
.labels – The labels associated with the timestamp and the displacement of the patches. If not given, the time label is
t(s)
, the first patch displacement labels arep0x
andp0y
, the secondp1x
andp1y
, etc.method – The method to use to calculate the displacement. Disflow uses opencv’s DISOpticalFlow and Lucas Kanade uses opencv’s calcOpticalFlowPyrLK, while all other methods are based on a basic cross-correlation in the Fourier domain. Pixel precision calculates the displacement by getting the position of the maximum of the cross-correlation, and has thus a 1-pixel resolution. It is mainly meant for debugging. Parabola refines the result of Pixel precision by interpolating the neighborhood of the maximum, and have thus sub-pixel resolutions.
alpha – Setting for Disflow.
delta – Setting for Disflow.
gamma – Setting for Disflow.
finest_scale – The last scale for Disflow (0 means full scale).
iterations – Variational refinement iterations for Disflow.
gditerations – Gradient descent iterations for Disflow.
patch_size – Correlation patch size for Disflow.
patch_stride – Correlation patch stride for Disflow.
show_image – If
True
, displays the real-time position of the patches on the image. This feature is mainly meant for debugging.border – Crop the patch on each side according to this value before calculating the displacements. 0 means no cropping, 1 means the entire patch is cropped.
safe – Checks whether the patches aren’t exiting the image, and raises an error if that’s the case.
follow – It
True
, the patches will move to follow the displacement of the image.**kwargs – Any additional kwarg to pass to the camera.
- begin() NoReturn [source]
Takes a first image from the camera and uses it to initialize the Disve tool.
Drawing
- class crappy.blocks.drawing.Dot_text(drawing, **kwargs)[source]
Like
Text
, but with a colored dot to visualize a numerical value.- __init__(drawing, **kwargs) None [source]
Sets the args.
- Parameters
drawing – The
Drawing
object.**kwargs –
Contains the coordinates, the text and the label to be displayed. Also contains the type of drawing, but unused.
Important
The value received in label must be a numeric value. It will be normalized on the
crange
of the block and the dot will change color from blue to red depending on this value.
- class crappy.blocks.drawing.Drawing(*args, **kwargs)[source]
Block to make a visual representation of data.
- __init__(image, draw: Optional[list] = None, crange: Optional[list] = None, title: str = 'Drawing', window_size: tuple = (7, 5), freq: float = 2, backend: str = 'TkAgg') None [source]
Sets the args and initializes the parent block.
- Parameters
Note
draw
keys:type
(str
): Mandatory, the type of drawing to display. It can be either ‘Text’, ‘Dot_text’ or ‘’Time.coord
(list
): Mandatory, alist
containing the x and y coordinates where the drawing should be displayed.text
: Mandatory forText
andDot_text
only, the left part of the displayed string.label
(str
): Mandatory forText
andDot_text
only, the label of the data to display. It will be append to thetext
.
Fake machine
- class crappy.blocks.fake_machine.Fake_machine(*args, **kwargs)[source]
Block to simulate the behavior of a tensile testing machine.
By default, it is supposed to represent a material with a plastic behavior.
Generator
- class crappy.blocks.generator.Generator(*args, **kwargs)[source]
This block is used to generate a signal.
It can be used to drive a machine. This block can take inputs, and each path can use these inputs to take decisions.
- __init__(path: Optional[list] = None, freq: float = 200, cmd_label: str = 'cmd', cycle_label: str = 'cycle', cmd: float = 0, repeat: bool = False, trig_link: Optional[str] = None, spam: bool = False, verbose: bool = False, end_delay: float = 2) None [source]
Sets the args and initializes parent class.
- Parameters
path (
list
, optional) –It must be a
list
ofdict
, each dict providing the parameters to generate the path. Each dict MUST have a keytype
.Note
The Generator will then instantiate a generator path with all the other keys as kwargs, adding the current
cmd
and the time.On each round, it will call
Path.get_cmd()
method, passing data until it raiseStopIteration
. It will then skip to the next path.When all paths are over, it will stop Crappy by raising
CrappyStop
unlessrepeat
is set toTrue
. If so, it will start over indefinitely.freq (
float
, optional) – The frequency of the block. If set and positive, the generator will try to send the command at this frequency (in Hz). Else, it will go as fast as possible. It relies on the Block freq control scheme.cmd_label (
str
, optional) – The label of the command to send in the linkscycle_label (
str
, optional) –cmd (
float
, optional) – The first value of the command.repeat (
bool
, optional) – Loop over the paths or stop when done ?trig_link (
str
, optional) – If given, the block will wait until data is received through the input link with this label. IfNone
, it will try loop atfreq
.spam (
bool
, optional) – IfTrue
, the value will be sent on each loop. Else, it will only send it if it was updated or we reached a new step.verbose (
bool
, optional) – ifTrue
, displays a message when switching to the next path.end_delay (
float
, optional) – The delay to wait for before raising theCrappyStop
exception at the end of the path. This is meant to let enough time to the other blocks to properly terminate.
generator path
There are several types of path available for the generator block.
- class crappy.blocks.generator_path.path.Path(time: float, cmd: float)[source]
Parent class for all paths.
constant
- class crappy.blocks.generator_path.constant.Constant(time: float, cmd: float, condition: Union[str, bool, Callable], send_one: bool = True, value: Optional[float] = None)[source]
Simplest condition. It will send value until condition is reached.
- __init__(time: float, cmd: float, condition: Union[str, bool, Callable], send_one: bool = True, value: Optional[float] = None) None [source]
Sets the args and initializes parent class.
- Parameters
time –
cmd –
condition (
str
) – Representing the condition to end this path. See generator path for more info.send_one (
str
, optional) – IfTrue
, this condition will send the value at least once before checking the condition.value – What value must be sent.
custom
cyclic ramp
- class crappy.blocks.generator_path.cyclic_ramp.Cyclic_ramp(time: float, cmd: float, condition1: Union[str, bool, Callable], condition2: Union[str, bool, Callable], speed1: float, speed2: float, cycles: float = 1, verbose: bool = False)[source]
A “boosted” ramp path: will take TWO values and conditions.
Note
It will make a ramp of speed
speed1
, switch to the second when the first condition is reached and return to the first when the second condition is reached.This will be done
cycles
times (supporting half cycles for ending after the first condition)- __init__(time: float, cmd: float, condition1: Union[str, bool, Callable], condition2: Union[str, bool, Callable], speed1: float, speed2: float, cycles: float = 1, verbose: bool = False) None [source]
Sets the args and initializes parent class.
- Parameters
time –
cmd –
condition1 (
str
) – Representing the condition to switch tospeed2
. See generator path for more info.condition2 (
str
) – Representing the condition to switch tospeed1
. See generator path for more info.speed1 – Speed of the first ramp.
speed2 – Speed of the second ramp.
cycles –
Number of time we should be doing this.
Note
cycles = 0
will make it loop forever.verbose –
Note
[{'type': 'cyclic_ramp', 'speed1': 5, 'condition1': 'AIN0>2', 'speed2': -2, 'condition2': 'AIN1<1', 'cycles': 5}]
is equivalent to
[{'type': 'ramp', 'speed': 5,'condition': 'AIN0>2'}, {'type': 'ramp', 'value': -2, 'condition': 'AIN1<1'}] * 5
cyclic
- class crappy.blocks.generator_path.cyclic.Cyclic(time: float, cmd: float, condition1: Union[str, bool, Callable], condition2: Union[str, bool, Callable], value1: float, value2: float, cycles: float = 1, verbose: bool = False)[source]
A “boosted” constant path: will take TWO values and conditions.
Note
It will set the first value, switch to the second when the first condition is reached and return to the first when the second condition is reached.
This will be done
cycles
times (supporting half cycles for ending after the first condition).- __init__(time: float, cmd: float, condition1: Union[str, bool, Callable], condition2: Union[str, bool, Callable], value1: float, value2: float, cycles: float = 1, verbose: bool = False) None [source]
Sets the args and initializes parent class.
- Parameters
time –
cmd –
condition1 (
str
) – Representing the condition to switch tovalue2
. See generator path for more info.condition2 (
str
) – Representing the condition to switch tovalue1
. See generator path for more info.value1 – First value to send.
value2 – Second value to send.
cycles –
Number of time we should be doing this.
Note
cycles = 0
will make it loop forever.verbose –
Note
[{'type': 'cyclic', 'value1': 1, 'condition1': 'AIN0>2', 'value2': 0, 'condition2': 'AIN1<1', 'cycles': 5}]
is equivalent to
[{'type': 'constant', 'value': 1,'condition': 'AIN0>2'}, {'type': 'constant', 'value': 0, 'condition': 'AIN1<1'}] * 5
inertia
- class crappy.blocks.generator_path.inertia.Inertia(time: float, cmd: float, condition: Union[str, bool, Callable], inertia: float, flabel: str, const: float = 9.549296585513721, tlabel: str = 't(s)', value: Optional[float] = None)[source]
Used to lower/higher the output command by integrating an input over time.
Let f(t) be the input signal, v(t) the value of the output, m the inertia and t0 the beginning of this path. K is a chosen constant.
Then the output value for this path will be:
v(t) = v(t0) - K * [I(t0 -> t)f(t)dt] / m
- __init__(time: float, cmd: float, condition: Union[str, bool, Callable], inertia: float, flabel: str, const: float = 9.549296585513721, tlabel: str = 't(s)', value: Optional[float] = None) None [source]
Sets the args and initializes parent class.
- Parameters
time –
cmd –
condition (
str
) – Condition to meet to end this path. See generator path for more info.inertia (
float
) – This is the virtual inertia of the process. The higher it is, the slower the (in/de) crease will be. In the above formula, it is the value of m.flabel (
str
) – The name of the label of the value to integrate.const (
float
, optional) – The value of K in the formula above. The default value is meant to send rpm with inertia in kg.m² and torque in N.m. If sending rad/s, useconst=1
.tlabel (
str
, optional) –The name of the label of time for the integration.
Note
The data received by
flabel
andtlabel
must correspond. In other word, there must be exactly the same number of values received by these two labels at any instant (i.e. they must come from the same parent block).value –
protection
- class crappy.blocks.generator_path.protection.Protection(time: float, cmd: float, condition1: Union[str, bool, Callable], condition2: Union[str, bool, Callable], value1: float, value2: float, value0: float = 0, verbose: bool = False)[source]
Useful to protect samples from being pulled apart when setting up a test.
- __init__(time: float, cmd: float, condition1: Union[str, bool, Callable], condition2: Union[str, bool, Callable], value1: float, value2: float, value0: float = 0, verbose: bool = False) None [source]
Sets the args and initializes parent class.
- Parameters
time –
cmd –
condition1 (
str
) – Representing the first condition. See generator path for more info.condition2 (
str
) – Representing the second condition. See generator path for more info.value1 – Value to send when
condition1
is met.value2 – Value to send when
condition2
is met.value0 – Value to send when no condition is reached.
verbose –
Note
By default will send
value0
.While
condition1
is met, will returnvalue1
.While
condition2
is met, will returnvalue2
.If
condition1
andcondition2
are met simultaneously, the first one met will prevail. If met at the same time,condition1
will prevail.
ramp
- class crappy.blocks.generator_path.ramp.Ramp(time: float, cmd: float, condition: Union[str, bool, Callable], speed: float)[source]
Will make a ramp from previous value until condition is reached.
- __init__(time: float, cmd: float, condition: Union[str, bool, Callable], speed: float)[source]
Sets the args and initializes parent class.
- Parameters
time –
cmd – If specified, will be the starting value of the ramp.
condition (
str
) – Representing the condition to end this path. See generator path for more info.speed – The speed of the ramp in units/s.
sine
- class crappy.blocks.generator_path.sine.Sine(time: float, cmd: float, condition: Union[str, bool, Callable], freq: float, amplitude: float, offset: float = 0, phase: float = 0)[source]
To generate a sine wave.
- __init__(time: float, cmd: float, condition: Union[str, bool, Callable], freq: float, amplitude: float, offset: float = 0, phase: float = 0) None [source]
Sets the args and initializes parent class.
- Parameters
time –
cmd –
condition (
str
) – Representing the condition to end this path. See generator path for more info.freq – Frequency of the sine in Hz.
amplitude – Amplitude of the sine wave.
offset (optional) – Offset of the sine.
phase (optional) – Phase of the sine.
GPUCorrel
- class crappy.blocks.gpucorrel.GPUCorrel(*args, **kwargs)[source]
This block uses the GPU Correl class.
See the documentation of GPU Correl to have more information about the arguments specific to this class.
It will try to identify the deformation parameters for each fields. If you use custom fields, you can use
labels=(...)
to name the data sent through the link. If no labels are specified, custom fields will be named by their position.The reference image is only taken once, when the
start()
method is called (after dropping the first image).- begin() None [source]
If
main()
is not overridden, this method will be called first, before entering the main loop.
GPUve
- class crappy.blocks.gpuve.GPUVE(*args, **kwargs)[source]
An optical Videoextensometry measuring the displacement of small areas using GPU accelerated DIC.
This block simply returns the displacement of each region along x and y in pixel. It will not return the strain as it does not know how the patches are arranged. It should be done by another block or a condition if necessary.
Grapher
- class crappy.blocks.grapher.Grapher(*args, **kwargs)[source]
The grapher receive data from a block and plots it.
Multiple curves can be plotted on a same graph, and the data can come from different blocks.
Note
To reduce the memory and CPU usage of graphs, try lowering the
maxpt
parameter (2-3000 is already enough to follow a short test), or set thelength
parameter to a non-zero value (again, 2-3000 is fine). Lowering thefreq
is also a good option to limit the CPU use.- __init__(*labels: Tuple[str, str], length: int = 0, freq: float = 2, maxpt: int = 20000, window_size: Tuple[int, int] = (8, 8), window_pos: Optional[Tuple[int, int]] = None, interp: bool = True, backend: str = 'TkAgg', verbose: bool = False) None [source]
Sets the args and initializes the parent class.
- Parameters
*labels (
tuple
) – Eachtuple
corresponds to a curve to plot, and should contain two values: the first will be the label of the x values, the second the label of the y values. There’s no limit to the number of curves. Note that all the curves are displayed in a same graph.length (
int
, optional) – If 0 the graph is static and displays all data from the start of the assay. Else only displays the lastlength
received chunks, and drops the previous ones.freq (
float
, optional) – The refresh rate of the graph. May cause high CPU use if set too high.maxpt (
int
, optional) – The maximum number of points displayed on the graph. When reaching this limit, the block deletes one point out of two to avoid using too much memory and CPU.window_size (
tuple
, optional) – The size of the graph, in inches.window_pos (
tuple
, optional) – The position of the graph in pixels. The first value is for the x direction, the second for the y direction. The origin is the top-left corner. Works with multiple screens.interp (
bool
, optional) – IfTrue
, the data points are linked together by straight lines. Else, only the points are displayed.backend (
int
, optional) – Thematplotlib
backend to use. Performance may vary according to the chosen backend. Also, every backend may not be available depending on your machine.verbose (
bool
, optional) – To display the loop frequency of the block.
Example
graph = Grapher(('t(s)', 'F(N)'), ('t(s)', 'def(%)'))
will plot a dynamic graph with two lines plot (F=f(t) and def=f(t)).
graph = Grapher(('def(%)', 'F(N)'), length=0)
will plot a static graph.
graph = Grapher(('t(s)', 'F(N)'), length=30)
will plot a dynamic graph displaying the last 30 chunks of data.
GUI
HDF Recorder
- class crappy.blocks.hdf_recorder.Hdf_recorder(*args, **kwargs)[source]
To save data efficiently in a hdf5 file.
This block is is meant to save data coming by arrays at a high rate (>1kHz). It uses the module
tables
.Important
Do not forget to specify the type of data to be saved (see
atom
parameter) to avoid casting the data into another type, as this could result in data loss or inefficient saving.- __init__(filename: str, node: str = 'table', expected_rows: int = 100000000, atom=None, label: str = 'stream', metadata: Optional[dict] = None) None [source]
Sets the args and initializes the parent class.
- Parameters
filename (
str
) – Path of the file where the data should be saved.node (
str
, optional) – The name of the node where the data will be saved.expected_rows (
int
, optional) – The number of expected rows in the file. It is used to optimize the dumping.atom (optional) – This represent the type of data to be stored in the table. It can be given as a
tables.Atom
instance, as anumpy.array
or as astr
.label (
str
, optional) – The key of thedict
that contains the array to save.metadata (
dict
, optional) – Adict
containing additional info to save in the hdf5 file.
- begin() None [source]
If
main()
is not overridden, this method will be called first, before entering the main loop.
IOBlock
- class crappy.blocks.ioblock.IOBlock(*args, **kwargs)[source]
This block is used to communicate with In / Out objects.
They can be used as sensor, actuators or both.
- __init__(name: str, freq: Optional[float] = None, verbose: bool = False, labels: Optional[list] = None, cmd_labels: Optional[list] = None, trigger: Optional[int] = None, streamer: bool = False, initial_cmd: Union[float, list] = 0, exit_values: Optional[list] = None, spam: bool = False, **kwargs) None [source]
Sets the args and initializes the parent class.
- Parameters
freq (
float
, optional) – The looping frequency of the block, ifNone
will go as fast as possible.verbose (
bool
, optional) – Prints extra information ifTrue
.cmd_labels (
list
, optional) – Thelist
of the labels considered as inputs for this block. Will callset_cmd()
in the In / Out object with the values received on this labels.trigger (
int
, optional) – If the block is triggered by another block, this must specify the index of the input considered as a trigger. The data going through this link is discarded, add another link if the block should also consider it as an input.streamer (
bool
, optional) – IfFalse
, will callget_data()
else, will callget_stream()
in the In / Out object (only if it has these methods, of course).initial_cmd (
list
, optional) – The initial values for the outputs, sent duringprepare()
. If it is a single value, then it will send this same value for all the output labels.exit_values (
list
, optional) – If notNone
, the outputs will be set to these values when Crappy is ending (or crashing).spam (
bool
, optional) – If False (default), the block will only call set_cmd on the InOut object if the command changed**kwargs – The arguments to be passed to the In / Out class.
- finish() None [source]
If
main()
is not overridden, this method will be called upon exit or after a crash.
Machine
- class crappy.blocks.machine.Machine(*args, **kwargs)[source]
To drive a machine with a one or more Actuators.
Takes a
list
ofdict
, containing the information to create each actuator. Each key will either stand for a parameter, or else they are transferred to the actuator.- __init__(actuators: list, common: Optional[dict] = None, freq: float = 200, time_label: str = 't(s)', spam: bool = False) None [source]
Sets the args and initializes the parent class.
- Parameters
actuators (
list
) – Thelist
of the Actuators of the machine. It contains one or severaldict
, whose mandatory keys are described below. The other keys will be passed to the actuator as arguments.common (
dict
, optional) – The keys of thisdict
will be common to all of the actuators. However if this conflicts with an already existing key for an actuator, the latter will prevail.freq (
float
, optional) – The looping frequency of the block.time_label (
str
, optional) – If reading data from one or more actuators, the time will be returned under this label.spam (
bool
, optional) – IfTrue
, a command is sent on each loop of the block, else it is sent every time a value is received.
Note
actuators
keys:type
(str
): The name of the actuator to instantiate.cmd
(str
): The label of the input to drive the axis.mode
(str
, default: ‘speed’): Can be either ‘speed’ or ‘position’. Will either callset_speed()
orset_position()
to drive the actuator.speed
(float
): If mode is ‘position’, the speed of the axis.pos_label
(str
): If set, the block will return the value ofget_position()
with this label.speed_label
(str
): If set, the block will return the value ofget_speed()
with this label.
- begin() None [source]
If
main()
is not overridden, this method will be called first, before entering the main loop.
Mean_block
- class crappy.blocks.mean.Mean_block(*args, **kwargs)[source]
Can take multiple inputs, makes an average and sends the result every
delay
s.- __init__(delay: float, tlabel: str = 't(s)', out_labels: Optional[list] = None, freq: float = 50) None [source]
Sets the args and initializes the parent class.
- Parameters
delay (
float
) – The averaged data will be sent eachdelay
seconds.tlabel (
str
, optional) – The label containing the time information.out_labels (
list
, optional) – If given, only the listed labels and the time will be returned. Otherwise all of them are returned.freq – The block will loop at this frequency.
Multiplex
- class crappy.blocks.multiplex.Multiplex(*args, **kwargs)[source]
This block takes data from upstream blocks as input and interpolates it to output all labels in a common time basis.
It is useful for synchronizing data acquired from different sensors, e.g. to plot a real-time stress-strain curve. This block is however quite resource-consuming, so it is preferable to perform interpolation in post-processing if real-time is not needed.
Note
This block doesn’t truly output data in real-time as it needs to wait for data from all the upstream blocks before performing the interpolation. So it should only be used with care when it is an input of a decision-making block. This is especially true when the upstream blocks have very different sample rates.
- __init__(time_label: str = 't(s)', freq: float = 200, verbose: bool = False) None [source]
Sets the args and initializes the parent class.
- Parameters
time_label – The label carrying the time information.
freq – The sample rate for the interpolation, and the target looping frequency for the block. If this value is set too high and your machine cannot keep up, the block will most likely lag.
verbose – If
True
, prints information about the looping frequency of the block.
PID
- class crappy.blocks.pid.PID(*args, **kwargs)[source]
A PID corrector.
A PID will continuously adjust its output based on the target value and the actual measured value, to try to actually reach the target.
- __init__(kp: float, ki: float = 0, kd: float = 0, freq: float = 500, out_max: float = inf, out_min: float = - inf, target_label: str = 'cmd', input_label: str = 'V', time_label: str = 't(s)', labels: Optional[list] = None, reverse: bool = False, i_limit: Union[float, tuple] = 1, send_terms: bool = False) None [source]
Sets the args and initializes the parent class.
- Parameters
kp (
float
) – P gain.ki (
float
) – I gain.kd (
float
) – D gain.freq (
float
, optional) – The block will loop at this frequency.out_max (
float
, optional) – A value the output can never be superior to.out_min (
float
, optional) – A value the output can never be inferior to.target_label (
str
, optional) – The label of the setpoint.input_label (
str
, optional) – The reading of the actual value to be compared with the setpoint.time_label (
str
, optional) – The label of the time.labels (
list
, optional) – The labels of the output of the block. It must contain twostr
: the time label and the actual output.reverse (
bool
, optional) – To reverse the retro-action.i_limit (
tuple
, optional) –To avoid over-integration. If given as a
tuple
of two values, they will be the boundaries for the I term. If given as a singlefloat
the boundaries will be:i_limit * out_min, i_limit * out_max
send_terms (
bool
, optional) – To get the weight of each term in the output value. It will add['p_term', 'i_term', 'd_term']
to the labels. This is particularly useful to tweak the gains.
Reader
Recorder
- class crappy.blocks.recorder.Recorder(*args, **kwargs)[source]
Will save the incoming data to a file (default .csv).
Important
Can only take ONE input, i.e. save labels from only one block. If you want multiple readings in a single file use the Multiplex block.
- __init__(filename: str, delay: float = 2, labels: Union[str, list] = 't(s)') None [source]
Sets the args and initializes the parent class.
- Parameters
filename (
str
) – Path and name of the output file. If the folders do not exist, they will be created. If the file already exists, the actual file will be named with a trailing number to avoid overriding it.delay (
float
, optional) – Delay between each write in seconds.labels (
list
, optional) – What labels to save. Can be either astr
to save all labels but this one first, or alist
to save only these labels.
Sink
UController
- class crappy.blocks.ucontroller.UController(*args, **kwargs)[source]
Block for interfacing over serial with an external device, written mostly for communication with microcontrollers.
It can send labeled commands to the device, and/or receive labeled data from it. This block is meant to be used along with the MicroController.py MicroPython template located in the tool folder of Crappy, even though it is not mandatory. A given syntax needs to be followed for any data to be exchanged.
- __init__(labels: Optional[list] = None, cmd_labels: Optional[list] = None, init_output: Optional[dict] = None, post_process: Optional[dict] = None, t_device: bool = False, port: str = '/dev/ttyUSB0', baudrate: int = 115200, verbose: bool = False, freq: float = 100) None [source]
Checks the validity of the arguments.
- Parameters
labels (
list
, optional) – The list of the labels to get from the device. Only these labels should be given as argument to thesend_to_pc()
method in the MicroPython script. If this argument is notNone
, then the``init_output`` argument should be given as well. No more than 9 labels should be given.cmd_labels (
list
, optional) – The list of the command labels that will be sent to the device upon reception from an upstream block. The variables in the MicroPython script should have these exact names. No more than 9 cmd_labels should be given.init_output (
dict
, optional) – If thelabels
argument is notNone
, the values to output to downstream blocks for each label as long as no value has been received from the device. An initial output value must be given for each label.post_process (
dict
, optional) – Optionally allows applying a function to the data of a label before transmitting it to downstream blocks. It is possible to give functions for only part of the labels.t_device (
bool
, optional) – ItTrue
, the timestamp returned under the label ‘t(s)’ is the one of the device, not the one of Crappy. It may reduce the maximum achievable sample rate, as more bytes have to be transmitted, but it is also far more precise.port (
str
, optional) – The serial port to open for communicating with the device. In Windows, they are usually called COMx, whereas in Linux and Mac they’re called /dev/ttyxxxx.baudrate (
int
, optional) – The baudrate for serial communication. It depends on the capabilities of the device.verbose (
bool
, optional) – IfTrue
, prints debugging information.freq (
float
, optional) – The looping frequency of the block.
- loop() None [source]
First sends the commands from upstream blocks to the device, then reads the data from the device and sends it to the downstream blocks.
Important
The precision of the commands sent to the device is limited to 3 digits after the decimal point, to limit the traffic on the bus. Adapt the range of the command values consequently.
Note
Commands are sent as text, because some boards cannot read bytes from the stdin buffer in MicroPython. Data is however received on the PC from the device as bytes.
- prepare() None [source]
Opens the serial port, and sends a ‘go’ message to the device.
Also shares with the device two tables associating each cmd_label and label with an integer. This allows reducing the traffic on the serial bus.
Note
The commands are sent as text because some boards cannot read bytes from the stdin buffer in MicroPython.
VideoExtenso
- class crappy.blocks.videoExtenso.Video_extenso(*args, **kwargs)[source]
Measures the deformation from video by tracking dots on the sample.
This requires the user to select the ROI to make the spot detection. Once done, it will return the deformation (in %) along X and Y axis. Optionally, it can save images.
It also returns a
list
of :obj`tuple`, which are the coordinates (in pixel) of the barycenter of the spots.The initial length is reset when receiving data from a parent block.
- __init__(camera: str, save_folder: Optional[str] = None, verbose: bool = False, labels: Optional[list] = None, fps_label: bool = False, img_name: str = '{self.loops:06d}_{t-self.t0:.6f}', ext: str = 'tiff', save_period: int = 1, save_backend: Optional[str] = None, transform: Optional[Callable] = None, input_label: Optional[str] = None, config: bool = False, show_image: bool = False, wait_l0: bool = False, end: bool = True, white_spots: bool = False, update_thresh: bool = False, num_spots: Union[str, int] = 'auto', safe_mode: bool = False, border: int = 5, min_area: float = 150, blur: float = 5, **kwargs) None [source]
Sets the args and initializes the camera.
- Parameters
camera (
str
) – The name of the camera to control. See Cameras for an exhaustive list of available ones.save_folder (
str
, optional) – The directory to save images to. If it doesn’t exist it will be created. IfNone
the images won’t be saved.verbose (
bool
, optional) – IfTrue
, the block will print the number of loops/s.labels (
list
, optional) – Names of the labels for the output.fps_label (
str
, optional) – If set,self.max_fps
will be set to the value received by the block with this label.img_name (
str
, optional) – Template for the name of the image to save. It is evaluated as an f-string.ext (
str
, optional) – Extension of the image. Make sure it is supported by the saving backend.save_period (
int
, optional) – Will save only one in x images.save_backend (
str
, optional) – Module to use to save the images. The supported backends are:sitk
(SimpleITK),cv2
(OpenCV) andpil
(Pillow). IfNone
, will trysitk
and thencv2
if not successful.transform (
function
, optional) – Function to be applied on the image before sending. It will not be applied on the saved images.input_label (
str
, optional) – If specified, the image will not be read from a camera object but from this label.config (
bool
, optional) – Show the popup for config ?show_image –
wait_l0 (
bool
, optional) – If set toTrue
, the block sends only zeros until the initial length is reset by receiving data from an input.end (
bool
, optional) – IfTrue
, the block will stop the Crappy program when the spots are lost, else it will just stop sending data.white_spots – Set to
True
if the spots are lighter than the surroundings, else set toFalse
.update_thresh – Should the threshold be updated in each round ? If so there are lower chances to lose the spots but there will be more noise in the measurement.
num_spots –
The number of spots to detect. Helps for spot detection and allows to force detection of a given number of spots (“auto” works fine most of the time). Can be set to:
"auto", 2, 3, 4
safe_mode – If set to
False
, it will try hard to catch the spots when losing them. Could result in incoherent values without crash. Set toTrue
when security is a concern.border – The number of pixels that will be added to the limits of the boundingbox.
min_area – Filters regions with an area smaller than this value among the selected regions.
blur – Median blur to be added to the image to smooth out irregularities and make detection more reliable.
**kwargs – Any additional specific argument to pass to the camera.