Watchdog

HIL.watchdog_set_analog_expiration_state(channels, num_channels, voltages)

Sets the state that the analog outputs will be set to if the watchdog expires. Most cards do not allow this state to be configured. The expiration states must be set prior to starting the watchdog timer using watchdog_start. The Quanser Q8-series cards may be configured to reset the analog outputs to 0V. In this case, the digital outputs must also be configured to go tristate. If no expiration states are configured for the Q8-series, then the analog and digital outputs will not be reconfigured when the watchdog expires.

Parameters
  • channels (array_like) – An array containing the numbers of the analog output channels for which the expiration state should be set. Channel numbers are zero-based. Thus, channel 0 is the first channel, channel 1 the second channel, etc.

  • num_channels (int) – The number of channels specified in the channels array.

  • voltages (array_like) – An array containing the analog voltages to which to set the corresponding channel in the channels array upon watchdog expiration. This array must be the same size as the channels array.

Raises

HILError – On non-zero return code. A suitable error message may be retrieved using get_error_message.

Examples

Configure the first three analog outputs to go to 0V upon watchdog expiration.

Using array:

>>> from array as array
>>> from quanser.hardware import HIL
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   channels = array('I', [0, 1, 2])
>>>   num_channels = len(channels)
>>>   voltages = array('d', [0.0, 0.0, 0.0])
>>>   card.watchdog_set_analog_expiration_state(channels, num_channels, voltages)
>>>   # ...
...
>>> finally:
>>>   card.close()

Using numpy:

>>> import numpy as np
>>> from quanser.hardware import HIL
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   channels = np.array([0, 1, 2], dtype=np.uint32)
>>>   num_channels = len(channels)
>>>   voltages = np.array([0.0, 0.0, 0.0], dtype=np.float64)
>>>   card.watchdog_set_analog_expiration_state(channels, num_channels, voltages)
>>>   # ...
...
>>> finally:
>>>   card.close()
HIL.watchdog_set_pwm_expiration_state(channels, num_channels, duty_cycles)

Sets the state that the PWM outputs will be set to if the watchdog expires. Most cards do not allow this state to be configured. The expiration states must be set prior to starting the watchdog timer using watchdog_start. Currently, there are no cards which allow this state to be configured.

Parameters
  • channels (array_like) – An array containing the numbers of the PWM output channels for which the expiration state should be set. Channel numbers are zero-based. Thus, channel 0 is the first channel, channel 1 the second channel, etc.

  • num_channels (int) – The number of channels specified in the channels array.

  • duty_cycles (array_like) – An array of doubles in which each element contains the PWM duty cycle, frequency or period to which to set the corresponding channel in the channels array upon watchdog expiration. The interpretation of this parameter depends upon the PWM mode set using the set_pwm_mode function. This array must be the same size as the channels array.

Raises

HILError – On non-zero return code. A suitable error message may be retrieved using get_error_message.

Examples

Configure the first two PWM outputs to go to 0V upon watchdog expiration.

Using array:

>>> from array as array
>>> from quanser.hardware import HIL
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   channels = array('I', [0, 1])
>>>   num_channels = len(channels)
>>>   duty_cycles = array('d', [0.0, 0.0])
>>>   card.watchdog_set_pwm_expiration_state(channels, num_channels, duty_cycles)
>>>   # ...
...
>>> finally:
>>>   card.close()

Using numpy:

>>> import numpy as np
>>> from quanser.hardware import HIL
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   channels = np.array([0, 1], dtype=np.uint32)
>>>   num_channels = len(channels)
>>>   duty_cycles = np.array([0.0, 0.0], dtype=np.float64)
>>>   card.watchdog_set_pwm_expiration_state(channels, num_channels, duty_cycles)
>>>   # ...
...
>>> finally:
>>>   card.close()
HIL.watchdog_set_digital_expiration_state(channels, num_channels, states)

Sets the state that the digital outputs will be set to if the watchdog expires. Most cards do not allow this state to be configured. The expiration states must be set prior to starting the watchdog timer using watchdog_start. Valid output states are: DigitalState.LOW = Set the digital output low (ground). DigitalState.HIGH = Set the digital output high (Vcc). DigitalState.TRISTATE = Set the digital output tristate. DigitalState.NO_CHANGE = Do not change the expiration state of this digital output.

The Q8-series cards may be configured to reset the digital outputs to tri-state. In this case, the analog outputs must also be configured to go to 0V. If no expiration states are configured for the Q8-series, then the analog and digital outputs will not be reconfigured when the watchdog expires.

Parameters
  • channels (array_like) – An array containing the numbers of the digital output channels for which the expiration state should be set. Channel numbers are zero-based. Thus, channel 0 is the first channel, channel 1 the second channel, etc.

  • num_channels (int) – The number of channels specified in the channels array.

  • states (array_like) – An array of DigitalState constants in which each element contains the digital state to which to set the corresponding channel in the channels array upon watchdog expiration. This array must be the same size as the channels array.

Raises

HILError – On non-zero return code. A suitable error message may be retrieved using get_error_message.

Warning

Many cards allow the digital I/O lines to be programmed as inputs or outputs. The digital I/O lines are configured as inputs or outputs using the set_digital_directions function. All the channels which will be used as digital outputs must be configured as outputs using this function. Failure to configure the digital I/O may result in the watchdog_set_digital_expiration_state function failing to write those outputs when the watchdog expires.

Examples

Configure the first three digital outputs to go tristate upon watchdog expiration.

Using array:

>>> from array as array
>>> from quanser.hardware import HIL, DigitalState
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   channels = array('I', [0, 1, 2])
>>>   num_channels = len(channels)
>>>   states = array('i', [DigitalState.TRISTATE, DigitalState.TRISTATE, DigitalState.TRISTATE])
>>>   card.watchdog_set_digital_expiration_state(channels, num_channels, states)
>>>   # ...
...
>>> finally:
>>>   card.close()

Using numpy:

>>> import numpy as np
>>> from quanser.hardware import HIL, DigitalState
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   channels = np.array([0, 1, 2], dtype=np.uint32)
>>>   num_channels = len(channels)
>>>   states = np.array([DigitalState.TRISTATE, DigitalState.TRISTATE, DigitalState.TRISTATE], dtype=np.int32)
>>>   card.watchdog_set_digital_expiration_state(channels, num_channels, states)
>>>   # ...
...
>>> finally:
>>>   card.close()
HIL.watchdog_set_other_expiration_state(channels, num_channels, states)

Sets the state that the other outputs will be set to if the watchdog expires. The expiration states must be set prior to starting the watchdog timer using watchdog_start. Currently there are no cards which allow this state to be configured.

Parameters
  • channels (array_like) – An array containing the numbers of the other output channels for which the expiration state should be set. Channel numbers are zero-based. Thus, channel 0 is the first channel, channel 1 the second channel, etc.

  • num_channels (int) – The number of channels specified in the channels array.

  • states (array_like) – An array of doubles in which each element contains the other value to which to set the corresponding channel in the channels array upon watchdog expiration. This array must be the same size as the channels array.

Raises

HILError – On non-zero return code. A suitable error message may be retrieved using get_error_message.

Examples

Configure the first two other outputs to go to 0 upon watchdog expiration.

Using array:

>>> from array as array
>>> from quanser.hardware import HIL
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   channels = array('I', [0, 1])
>>>   num_channels = len(channels)
>>>   values = array('d', [0.0] * num_channels)
>>>   card.watchdog_set_other_expiration_state(channels, num_channels, values)
>>>   # ...
...
>>> finally:
>>>   card.close()

Using numpy:

>>> import numpy as np
>>> from quanser.hardware import HIL
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   channels = np.array([0, 1], dtype=np.uint32)
>>>   num_channels = len(channels)
>>>   values = np.zeros(num_channels, dtype=np.float64)
>>>   card.watchdog_set_other_expiration_state(channels, num_channels, values)
>>>   # ...
...
>>> finally:
>>>   card.close()
HIL.watchdog_start(timeout)

Starts the watchdog timer with the given timeout interval. It should only be called after the expiration states have been configured using the watchdog_set_xxxx_expiration_state functions. Once the watchdog timer has been started, it must be reloaded each time before it expires using the watchdog_reload function.

Parameters

timeout (double) – The expiration timeout interval in seconds.

Raises

HILError – On non-zero return code. A suitable error message may be retrieved using get_error_message.

Examples

Configure a watchdog timer that will expire every 0.1 seconds and reset the analog outputs to 0V and the digital outputs to tristate upon expiration. Also create a task for performing real-time control that reads four encoder channels every millisecond. The watchdog is reloaded every sampling instant.

Using array:

>>> from array import array
>>> from quanser.hardware import HIL, Clock, DigitalState
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   frequency = 1000.0
>>>   samples = 5000
>>>   samples_in_buffer = int(frequency)
>>>   samples_to_read = 1
>>>   timeout = 100 / frequency
>>>   num_analog_channels = 4
>>>   num_encoder_channels = 4
>>>   num_digital_channels = 16
>>>   analog_channels = array('I', [x for x in range(num_analog_channels)])
>>>   encoder_channels = array('I', [x for x in range(num_encoder_channels)])
>>>   digital_channels = array('I', [x for x in range(num_digital_channels)])
>>>   voltages = array('d', [0.0] * num_analog_channels])
>>>   states = array('i', [DigitalState.TRISTATE] * num_digital_channels)
>>>   counts = array('i', [0] * num_encoder_channels)
>>>   card.watchdog_set_analog_expiration_state(analog_channels, num_analog_channels, voltages)
>>>   card.watchdog_set_digital_expiration_state(digital_channels, num_digital_channels, states)
>>>   task = card.task_create_encoder_reader(samples_in_buffer, encoder_channels, num_encoder_channels)
>>>   card.watchdog_start(timeout)
>>>   card.task_start(task, Clock.SYSTEM_CLOCK_1, frequency, samples)
>>>   for index in range(samples):
>>>     card.task_read_encoder(task, samples_to_read, counts)  # Returns every millisecond with next sample
>>>     card.watchdog_reload()  # Reload watchdog before using counts for control
>>>     # Do control calculations and output motor torques
...
>>>   card.task_stop()
>>>   card.task_delete()
>>>   card.watchdog_stop()
>>> finally:
>>>   card.close()

Using numpy:

>>> import numpy as np
>>> from quanser.hardware import HIL, Clock, DigitalState
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   frequency = 1000.0
>>>   samples = 5000
>>>   samples_in_buffer = int(frequency)
>>>   samples_to_read = 1
>>>   timeout = 100 / frequency
>>>   num_analog_channels = 4
>>>   num_encoder_channels = 4
>>>   num_digital_channels = 16
>>>   analog_channels = np.array([x for x in range(num_analog_channels)], dtype=np.uint32)
>>>   encoder_channels = np.array([x for x in range(num_encoder_channels)], dtype=np.uint32)
>>>   digital_channels = np.array([x for x in range(num_digital_channels)], dtype=np.uint32)
>>>   voltages = np.array([0.0] * num_analog_channels], dtype=np.float64)
>>>   states = np.array([DigitalState.TRISTATE] * num_digital_channels, dtype=np.int32)
>>>   counts = np.zeros(num_encoder_channels, dtype=np.int32)
>>>   card.watchdog_set_analog_expiration_state(analog_channels, num_analog_channels, voltages)
>>>   card.watchdog_set_digital_expiration_state(digital_channels, num_digital_channels, states)
>>>   task = card.task_create_encoder_reader(samples_in_buffer, encoder_channels, num_encoder_channels)
>>>   card.watchdog_start(timeout)
>>>   card.task_start(task, Clock.SYSTEM_CLOCK_1, frequency, samples)
>>>   for index in range(samples):
>>>     card.task_read_encoder(task, samples_to_read, counts)  # Returns every millisecond with next sample
>>>     card.watchdog_reload()  # Reload watchdog before using counts for control
>>>     # Do control calculations and output motor torques
...
>>>   card.task_stop()
>>>   card.task_delete()
>>>   card.watchdog_stop()
>>> finally:
>>>   card.close()
HIL.watchdog_reload()

Reloads the watchdog timer. It is typically called to reload the watchdog timer before it expires at the top of the control loop.

Returns

Returns True if the watchdog timer was reloaded prior to expiration. Returns False if the watchdog timer had expired before being reloaded.

Return type

int

Raises

HILError – On non-zero return code. A suitable error message may be retrieved using get_error_message.

Examples

Configure a watchdog timer that will expire every 0.1 seconds and reset the analog outputs to 0V and the digital outputs to tristate upon expiration. Also create a task for performing real-time control that reads four encoder channels every millisecond. The watchdog is reloaded every sampling instant.

Using array:

>>> from array import array
>>> from quanser.hardware import HIL, Clock, DigitalState
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   frequency = 1000.0
>>>   samples = 5000
>>>   samples_in_buffer = int(frequency)
>>>   samples_to_read = 1
>>>   timeout = 100 / frequency
>>>   num_analog_channels = 4
>>>   num_encoder_channels = 4
>>>   num_digital_channels = 16
>>>   analog_channels = array('I', [x for x in range(num_analog_channels)])
>>>   encoder_channels = array('I', [x for x in range(num_encoder_channels)])
>>>   digital_channels = array('I', [x for x in range(num_digital_channels)])
>>>   voltages = array('d', [0.0] * num_analog_channels])
>>>   states = array('i', [DigitalState.TRISTATE] * num_digital_channels)
>>>   counts = array('i', [0] * num_encoder_channels)
>>>   card.watchdog_set_analog_expiration_state(analog_channels, num_analog_channels, voltages)
>>>   card.watchdog_set_digital_expiration_state(digital_channels, num_digital_channels, states)
>>>   task = card.task_create_encoder_reader(samples_in_buffer, encoder_channels, num_encoder_channels)
>>>   card.watchdog_start(timeout)
>>>   card.task_start(task, Clock.SYSTEM_CLOCK_1, frequency, samples)
>>>   for index in range(samples):
>>>     card.task_read_encoder(task, samples_to_read, counts)  # Returns every millisecond with next sample
>>>     card.watchdog_reload()  # Reload watchdog before using counts for control
>>>     # Do control calculations and output motor torques
...
>>>   card.task_stop()
>>>   card.task_delete()
>>>   card.watchdog_stop()
>>> finally:
>>>   card.close()

Using numpy:

>>> import numpy as np
>>> from quanser.hardware import HIL, Clock, DigitalState
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   frequency = 1000.0
>>>   samples = 5000
>>>   samples_in_buffer = int(frequency)
>>>   samples_to_read = 1
>>>   timeout = 100 / frequency
>>>   num_analog_channels = 4
>>>   num_encoder_channels = 4
>>>   num_digital_channels = 16
>>>   analog_channels = np.array([x for x in range(num_analog_channels)], dtype=np.uint32)
>>>   encoder_channels = np.array([x for x in range(num_encoder_channels)], dtype=np.uint32)
>>>   digital_channels = np.array([x for x in range(num_digital_channels)], dtype=np.uint32)
>>>   voltages = np.array([0.0] * num_analog_channels], dtype=np.float64)
>>>   states = np.array([DigitalState.TRISTATE] * num_digital_channels, dtype=np.int32)
>>>   counts = np.zeros(num_encoder_channels, dtype=np.int32)
>>>   card.watchdog_set_analog_expiration_state(analog_channels, num_analog_channels, voltages)
>>>   card.watchdog_set_digital_expiration_state(digital_channels, num_digital_channels, states)
>>>   task = card.task_create_encoder_reader(samples_in_buffer, encoder_channels, num_encoder_channels)
>>>   card.watchdog_start(timeout)
>>>   card.task_start(task, Clock.SYSTEM_CLOCK_1, frequency, samples)
>>>   for index in range(samples):
>>>     card.task_read_encoder(task, samples_to_read, counts)  # Returns every millisecond with next sample
>>>     card.watchdog_reload()  # Reload watchdog before using counts for control
>>>     # Do control calculations and output motor torques
...
>>>   card.task_stop()
>>>   card.task_delete()
>>>   card.watchdog_stop()
>>> finally:
>>>   card.close()
HIL.watchdog_is_expired()

Indicates whether the watchdog has expired. It is not typically required because the watchdog_reload function’s return value also indicates whether the watchdog has expired.

Returns

True if the watchdog has expired; False otherwise.

Return type

int

Raises

HILError – On non-zero return code. A suitable error message may be retrieved using get_error_message.

Example

>>> import time
>>> from quanser.hardware import HIL
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   timeout = 0.2
>>>   card.watchdog_start(timeout)
>>>   time.sleep(0.5)
>>>   is_watchdog_expired = card.watchdog_is_expired()
>>>   # ...
...
>>> finally:
>>>   card.close()
HIL.watchdog_clear()

Clears the watchdog state after expiration. When the watchdog timer expires, it prevents further access to the hardware after setting the outputs to the configured expiration states. In order to clear this “protected” state and allow access to the hardware again, the watchdog_clear function must be called. This function estores the hardware to its state prior to the watchdog timer expiring, if possible.

For example, for the Q8-series cards it reprograms the digital directions and analog modes to their original values since these are reset by the watchdog expiration (if the analog and digital output expiration states have been configured).

Raises

HILError – On non-zero return code. A suitable error message may be retrieved using get_error_message.

Example

If the watchdog expires before reload, clear the watchdog state so that we can continue to control the hardware.

>>> import time
>>> from quanser.hardware import HIL
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   timeout = 0.1
>>>   card.watchdog_start(timeout)
>>>   time.sleep(0.2)
>>>   if not card.watchdog_reload():
>>>     card.watchdog_clear()
...
>>>   # ...
...
>>> finally:
>>>   card.close()
HIL.watchdog_stop()

Stops the watchdog timer. The watchdog timer will no longer expire so the watchdog_reload function need no longer be called. Stopping the watchdog timer does not clear the watchdog state if the watchdog has already expired. Use the watchdog_clear function for this purpose.

Raises

HILError – On non-zero return code. A suitable error message may be retrieved using get_error_message.

Example

>>> import time
>>> from quanser.hardware import HIL
>>> card = HIL("q8_usb", "0")
>>> try:
>>>   timeout = 0.2
>>>   card.watchdog_start(timeout)
>>>   for i in range(10):
...       time.sleep(0.1)
...       # ...
...
>>>   card.watchdog_stop()
>>> finally:
>>>   card.close()