# NI counter read task

> Read frequency, edge counts, pulse widths, and encoder positions from NI counters into channels.

An NI counter read task reads the counter inputs of NI devices into channels. A counter measures digital pulses: their frequency, their count, their width, or the position and speed of an encoder. For example, it can record the speed of a flow meter on `ctr0` of a USB-6343.

Before you start, you need [configured devices](https://docs.synnaxlabs.com/reference/hardware/ni/configure-device).

## Counters and timing

Each channel reads one counter, set by its **Port**: port 0 is `ctr0`. The pulses come in on a PFI terminal. Set **Input terminal** to choose the terminal, or leave it empty to use the default terminal of the counter. The device manual lists the counters and their terminals.

The Driver reads the counters on the computer clock, at the **Sample rate**. See [timing](https://docs.synnaxlabs.com/reference/hardware/tasks#timing).

## Create an NI counter read task

[Enterprise](https://docs.synnaxlabs.com/reference/get-started/editions "Needs Synnax Enterprise")

**Console**

1. In the devices toolbar, right-click a device and select **Create counter read task**.
2. Set **Sample rate** and **Stream rate**.
3. Click **Add channel**. In **Source**, select the **Device** and the **Port**.
4. In **Signal**, select the **Channel type**, then set its fields. See the [channel reference](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#channel-reference).
5. Click (**Start**).

The Console creates the channels. For a device with the identifier `dev1`, counter 0 gives `dev1_ctr_0`, with the index channel `dev1_ctr_time`.

[](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/hardware/ni/counter-read-task-dark.mp4#t=0.001)

**Python**

Python does not create channels. Create them first.

```python
import synnax as sy
from synnax import ni

dev = client.devices.retrieve(key="<device key>")
time = client.channels.create(
    name="dev1_ctr_time", is_index=True, data_type=sy.DataType.TIMESTAMP
)
flow = client.channels.create(
    name="flow_meter_hz", index=time.key, data_type=sy.DataType.FLOAT64
)

task = ni.CounterReadTask(
    name="Flow meter",
    device=dev.key,
    sample_rate=100,
    stream_rate=10,
    channels=[
        ni.CIFrequencyChannel(port=0, min_val=1, max_val=1000, channel=flow.key)
    ],
)
client.tasks.configure(task)
task.start()
```

Python creates the task on the embedded Driver of the Core. For a device on another Driver, use the Console or TypeScript. If you open the task in the Console and click **Start**, the Console replaces your channels with its own.

**TypeScript**

TypeScript does not create channels. Create them first, as in the Python example.

```typescript
import { ni } from "@synnaxlabs/client";

const dev = await client.devices.retrieve({ key: "<device key>" });
const task = await client.tasks.create({
  name: "Flow meter",
  rack: dev.rack,
  type: "ni_counter_read",
  config: ni.counterReadConfigZ.parse({
    sampleRate: 100,
    streamRate: 10,
    channels: [
      {
        type: "ci_frequency",
        device: dev.key,
        port: 0,
        minVal: 1,
        maxVal: 1000,
        channel: flow.key,
      },
    ],
  }),
});
await task.start();
```

## Tare channels

Tare sets the current value of a channel to zero. The task must be running.

1. In the channel list, click **Tare** on a channel. To tare several channels, select them, right-click, and select **Tare**.
2. The values of those channels start from zero.

## Task options

| Console label | Python field           | Default | Notes                                                                                               |
| ------------- | ---------------------- | ------- | --------------------------------------------------------------------------------------------------- |
| Sample rate   | `sample_rate`          | 10 Hz   | Up to 1,000,000 Hz in the Console.                                                                  |
| Stream rate   | `stream_rate`          | 5 Hz    | Up to 20,000 Hz. See [read tasks](https://docs.synnaxlabs.com/reference/hardware/tasks#read-tasks). |
| Data saving   | `data_saving_disabled` | On      | See [data saving](https://docs.synnaxlabs.com/reference/hardware/tasks#data-saving).                |
| Auto start    | `auto_start`           | Off     | Starts the task each time the Driver starts.                                                        |

## Channel reference

Every channel has a `channel`, the Synnax channel that records the value, a `device`, the key of the device (**Device**), and a `port`, the counter number (**Port**). In Python, a channel with no `device` uses the `device` of the task.

Each table shows the Console label of a setting, with its Python field under it. The **Notes** column lists the values that code uses. The Console shows the same values in plain words. Every type except edge count also has **Custom scaling**.

**Pulse**

**Frequency**

#### [Frequency](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#ci_frequency)

Python `CIFrequencyChannel`TypeScript `ci_frequency`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__counter__input__channels_1gad7f76a3c13cd1acceb5015cbb57c5743.html)

Measures the frequency of a digital signal.

| Setting                          | Default      | Notes                                                              |
| -------------------------------- | ------------ | ------------------------------------------------------------------ |
| Range `min_val`, `max_val`       | `2` to `100` | In **Units**.                                                      |
| Starting edge `edge`             | `Rising`     | `Rising`, `Falling`.                                               |
| Units `units`                    | `Hz`         | `Hz`, `Ticks`.                                                     |
| Input terminal `terminal`        |              | `PFI0` to `PFI15`. Empty uses the default terminal of the counter. |
| Measurement method `meas_method` | `DynamicAvg` | `LowFreq1Ctr`, `HighFreq2Ctr`, `LargeRng2Ctr`, `DynamicAvg`.       |
| Measurement time (s) `meas_time` | `0.000006`   | In seconds. Shows for `HighFreq2Ctr`.                              |
| Divisor `divisor`                | `4`          | Shows for `LargeRng2Ctr`.                                          |

**Edge count**

#### [Edge count](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#ci_edge_count)

Python `CIEdgeCountChannel`TypeScript `ci_edge_count`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__counter__input__channels_1ga898d4d3101b616a681bc31199ae37d5f.html)

Counts the edges of a digital signal.

| Setting                           | Default   | Notes                                                              |
| --------------------------------- | --------- | ------------------------------------------------------------------ |
| Active edge `active_edge`         | `Rising`  | `Rising`, `Falling`.                                               |
| Count direction `count_direction` | `CountUp` | `CountUp`, `CountDown`, `ExternallyControlled`.                    |
| Input terminal `terminal`         |           | `PFI0` to `PFI15`. Empty uses the default terminal of the counter. |
| Initial count `initial_count`     | `0`       | The count when the task starts.                                    |

**Period**

#### [Period](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#ci_period)

Python `CIPeriodChannel`TypeScript `ci_period`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__counter__input__channels_1gafff33171661e94431afbd5a0abf4f73e.html)

Measures the period of a digital signal.

| Setting                          | Default             | Notes                                                              |
| -------------------------------- | ------------------- | ------------------------------------------------------------------ |
| Range `min_val`, `max_val`       | `0.000001` to `0.1` | In **Units**.                                                      |
| Starting edge `starting_edge`    | `Rising`            | `Rising`, `Falling`.                                               |
| Units `units`                    | `Seconds`           | `Seconds`, `Ticks`.                                                |
| Input terminal `terminal`        |                     | `PFI0` to `PFI15`. Empty uses the default terminal of the counter. |
| Measurement method `meas_method` | `DynamicAvg`        | `LowFreq1Ctr`, `HighFreq2Ctr`, `LargeRng2Ctr`, `DynamicAvg`.       |
| Measurement time (s) `meas_time` | `0.001`             | In seconds. Shows for `HighFreq2Ctr`.                              |
| Divisor `divisor`                | `4`                 | Shows for `LargeRng2Ctr`.                                          |

**Pulse width**

#### [Pulse width](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#ci_pulse_width)

Python `CIPulseWidthChannel`TypeScript `ci_pulse_width`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__counter__input__channels_1gab7c2c214f995c0b0a065940d739b3168.html)

Measures the width of a pulse.

| Setting                       | Default             | Notes                                                              |
| ----------------------------- | ------------------- | ------------------------------------------------------------------ |
| Range `min_val`, `max_val`    | `0.000001` to `0.1` | In **Scaled units**.                                               |
| Starting edge `starting_edge` | `Rising`            | `Rising`, `Falling`.                                               |
| Scaled units `units`          | `Seconds`           | `Seconds`, `Ticks`.                                                |
| Input terminal `terminal`     |                     | `PFI0` to `PFI15`. Empty uses the default terminal of the counter. |

**Semi period**

#### [Semi period](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#ci_semi_period)

Python `CISemiPeriodChannel`TypeScript `ci_semi_period`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__counter__input__channels_1ga7ee9e61ab68edc4c6c72e9bc347a623f.html)

Measures the time between each edge of a digital signal and the next edge.

| Setting                    | Default             | Notes                                                              |
| -------------------------- | ------------------- | ------------------------------------------------------------------ |
| Range `min_val`, `max_val` | `0.000001` to `0.1` | In **Scaled units**.                                               |
| Scaled units `units`       | `Seconds`           | `Seconds`, `Ticks`.                                                |
| `terminal`                 |                     | `PFI0` to `PFI15`. Empty uses the default terminal of the counter. |

**Two edge separation**

#### [Two edge separation](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#ci_two_edge_sep)

Python `CITwoEdgeSepChannel`TypeScript `ci_two_edge_sep`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__counter__input__channels_1ga48a4f962e8752504edea1a0de6e39c74.html)

Measures the time from an edge on one input to an edge on a second input.

| Setting                    | Default           | Notes                             |
| -------------------------- | ----------------- | --------------------------------- |
| Range `min_val`, `max_val` | `0.000001` to `1` | In **Scaled units**.              |
| Scaled units `units`       | `Seconds`         | `Seconds`, `Ticks`.               |
| Edge 1 `first_edge`        | `Rising`          | `Rising`, `Falling`.              |
| Edge 2 `second_edge`       | `Falling`         | `Rising`, `Falling`.              |
| `first_terminal`           |                   | The terminal of the first input.  |
| `second_terminal`          |                   | The terminal of the second input. |

**Duty cycle**

#### [Duty cycle](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#ci_duty_cycle)

Python `CIDutyCycleChannel`TypeScript `ci_duty_cycle`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__counter__input__channels_1ga038bacad83c2aa098da70bf6ce810c10.html)

Measures the duty cycle of a digital signal.

| Setting                    | Default        | Notes                                                              |
| -------------------------- | -------------- | ------------------------------------------------------------------ |
| Range `min_val`, `max_val` | `2` to `10000` | The frequency of the signal, in hertz.                             |
| Active edge `active_edge`  | `Rising`       | `Rising`, `Falling`.                                               |
| Input terminal `terminal`  |                | `PFI0` to `PFI15`. Empty uses the default terminal of the counter. |

**Encoder**

**Position linear**

#### [Position linear](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#ci_position_linear)

Python `CIPositionLinearChannel`TypeScript `ci_position_linear`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__counter__input__channels__position_1ga90a24201a424fd7f4a436f45c726c618.html)

Measures linear position from an encoder.

| Setting                           | Default      | Notes                                               |
| --------------------------------- | ------------ | --------------------------------------------------- |
| Initial position `initial_pos`    | `0`          | The position when the task starts.                  |
| Distance / pulse `dist_per_pulse` | `0.000001`   | The distance for each encoder pulse.                |
| Units `units`                     | `Meters`     | `Meters`, `Inches`, `Ticks`.                        |
| Input terminal A `terminal_a`     |              | The terminal of the A signal.                       |
| Input terminal B `terminal_b`     |              | The terminal of the B signal.                       |
| Decoding type `decoding_type`     | `X4`         | `X1`, `X2`, `X4`, `TwoPulse`.                       |
| Z index enable `z_index_enabled`  | `false`      | Resets the position at each Z index pulse.          |
| Z index value `z_index_val`       | `0`          | The position at a Z index pulse.                    |
| Z index phase `z_index_phase`     | `AHighBHigh` | `AHighBHigh`, `AHighBLow`, `ALowBHigh`, `ALowBLow`. |
| Input terminal Z `terminal_z`     |              | The terminal of the Z index signal.                 |

**Position angular**

#### [Position angular](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#ci_position_angular)

Python `CIPositionAngularChannel`TypeScript `ci_position_angular`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__counter__input__channels__position_1ga942ca714baeb63c64fc0136bf61f3c6b.html)

Measures angular position from an encoder.

| Setting                          | Default      | Notes                                               |
| -------------------------------- | ------------ | --------------------------------------------------- |
| Pulses / rev `pulses_per_rev`    | `24`         | Encoder pulses for each revolution.                 |
| Initial angle `initial_angle`    | `0`          | The angle when the task starts.                     |
| Units `units`                    | `Degrees`    | `Degrees`, `Radians`, `Ticks`.                      |
| Input terminal A `terminal_a`    |              | The terminal of the A signal.                       |
| Input terminal B `terminal_b`    |              | The terminal of the B signal.                       |
| Decoding type `decoding_type`    | `X4`         | `X1`, `X2`, `X4`, `TwoPulse`.                       |
| Z index enable `z_index_enabled` | `false`      | Resets the angle at each Z index pulse.             |
| Z index value `z_index_val`      | `0`          | The angle at a Z index pulse.                       |
| Z index phase `z_index_phase`    | `AHighBHigh` | `AHighBHigh`, `AHighBLow`, `ALowBHigh`, `ALowBLow`. |
| Input terminal Z `terminal_z`    |              | The terminal of the Z index signal.                 |

**Velocity linear**

#### [Velocity linear](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#ci_velocity_linear)

Python `CIVelocityLinearChannel`TypeScript `ci_velocity_linear`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__counter__input__channels_1gaffd68d2994c51dfd10ec8d61f723983f.html)

Measures linear velocity from an encoder.

| Setting                           | Default    | Notes                                |
| --------------------------------- | ---------- | ------------------------------------ |
| Range `min_val`, `max_val`        | `0` to `1` | In **Scaled units**.                 |
| Scaled units `units`              | `m/s`      | `m/s`, `in/s`.                       |
| Distance / pulse `dist_per_pulse` | `0.001`    | The distance for each encoder pulse. |
| Decoding type `decoding_type`     | `X4`       | `X1`, `X2`, `X4`, `TwoPulse`.        |
| Input terminal A `terminal_a`     |            | The terminal of the A signal.        |
| Input terminal B `terminal_b`     |            | The terminal of the B signal.        |

**Velocity angular**

#### [Velocity angular](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#ci_velocity_angular)

Python `CIVelocityAngularChannel`TypeScript `ci_velocity_angular`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__counter__input__channels_1ga6bf192a1dff614bfb0055bc94149c860.html)

Measures angular velocity from an encoder.

| Setting                       | Default    | Notes                               |
| ----------------------------- | ---------- | ----------------------------------- |
| Range `min_val`, `max_val`    | `0` to `1` | In **Scaled units**.                |
| Scaled units `units`          | `RPM`      | `RPM`, `Radians/s`, `Degrees/s`.    |
| Pulses / rev `pulses_per_rev` | `24`       | Encoder pulses for each revolution. |
| Decoding type `decoding_type` | `X4`       | `X1`, `X2`, `X4`, `TwoPulse`.       |
| Input terminal A `terminal_a` |            | The terminal of the A signal.       |
| Input terminal B `terminal_b` |            | The terminal of the B signal.       |

### Custom scaling

Channels with **Custom scaling** convert the raw value before the Driver writes it. In the Console, the options are in the **Scale** section of the channel. In code, set `custom_scale` to one of these scales:

| Console option | Python class      | Fields                                                                                                                         |
| -------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| None           | `NoneScale`       | No scaling. This is the default.                                                                                               |
| Linear         | `LinearScale`     | **Slope** (`slope`, 1) and **Y-intercept** (`y_intercept`, 0).                                                                 |
| Map            | `MapScale`        | **Pre-scaled min** and **max** to **Scaled min** and **max** (`pre_scaled_min`, `pre_scaled_max`, `scaled_min`, `scaled_max`). |
| Polynomial     | `PolynomialScale` | **Forward coefficients** (`forward_coeffs`) and **Reverse coefficients** (`reverse_coeffs`), from c0 up.                       |
| Table          | `TableScale`      | **Pre-scaled** and **Scaled** pairs (`pre_scaled_vals`, `scaled_vals`). A CSV file can fill them.                              |

Every scale except **None** also has **Prescaled units** (`pre_scaled_units`, `Volts`) and **Scaled units** (`scaled_units`).

## Troubleshooting

* [Counter port ... has already been used on another channel on the same device](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#counter-port-has-already-been-used-on-another-channel-on-the-sam)

  * Cause

    Two channels use the same counter of one device.

  * Fix

    Change the port of one of them.

* [No device provided for channel ...](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#no-device-provided-for-channel)

  * Cause

    A Python channel has no `device`, and the task has no `device` either.

  * Fix

    Set one of them.

* [Cannot create task with channels from multiple racks](https://docs.synnaxlabs.com/reference/hardware/ni/counter-read-task#cannot-create-task-with-channels-from-multiple-racks)

  * Cause

    The channels use devices on two Drivers.

  * Fix

    Create one task for each Driver.

For other problems, see [Configure an NI device](https://docs.synnaxlabs.com/reference/hardware/ni/configure-device#troubleshooting) and [Troubleshoot hardware](https://docs.synnaxlabs.com/reference/hardware/troubleshooting).
