# Simulation and testing

sick_canopen_simu implements a software simulation of MLS and OLS devices for test purposes. This simulation generates synthetical can frames from an input xml-file,
and verifies the measurement messages published by the sick_line_guidance driver. By sending specified can frames, the complete processing chain of the ros driver can be verified
by comparing the actual measurement messages with the expected results. In addition, error messages and error handling can be tested, which otherwise can be challenging.

Please note, that sick_canopen_simu does not implement or simulate the behavior of the MLS or OLS hardware. It just sends specified can frames and checks the measurement messages
from the sick_line_guidance driver after entering the operational state. The purpose of sick_canopen_simu is driver verification and testing, not a fully functional simulation of
can devices.

## Usage

To test the sick_line_guidance driver with simulated can frames, four ros nodes have to be started: 
- sick_line_guidance_ros2can_node to send ros messages of type can::Frame to the can driver, which sends the frames to the can bus,
- sick_line_guidance_can2ros_node to receive can frames and to publish them as ros messages of type can::Frame,
- sick_canopen_simu to read the simulation data from file, to convert them to can::Frame messages and to verify the resulting sick_line_guidance messages from the driver,
- sick_line_guidance_node, i.e. the sick_line_guidance driver.

Example for simulation and test of the OLS20 driver:
```bash
# Start can2ros converter
roslaunch -v sick_line_guidance sick_line_guidance_can2ros_node.launch &
sleep 5
# Start ros2can converter
roslaunch -v sick_line_guidance sick_line_guidance_ros2can_node.launch &
sleep 5
# Start OLS20 simulation
roslaunch -v --screen sick_line_guidance sick_canopen_simu.launch device:=OLS20 &
sleep 5
# Start OLS driver incl. canopen_chain_node, sick_line_guidance_node and sick_line_guidance_cloud_publisher
roslaunch -v --screen sick_line_guidance sick_line_guidance.launch yaml:=sick_line_guidance_ols20.yaml
```

The same example works for MLS, too, with slightly different arguments (`device:=MLS` and `yaml:=sick_line_guidance_mls.yaml`):
```bash
# Start can2ros converter
roslaunch -v sick_line_guidance sick_line_guidance_can2ros_node.launch &
sleep 5
# Start ros2can converter
roslaunch -v sick_line_guidance sick_line_guidance_ros2can_node.launch &
sleep 5
# Start MLS simulation
roslaunch -v --screen sick_line_guidance sick_canopen_simu.launch device:=MLS &
sleep 5
# Start MLS driver incl. canopen_chain_node, sick_line_guidance_node and sick_line_guidance_cloud_publisher
roslaunch -v --screen sick_line_guidance sick_line_guidance.launch yaml:=sick_line_guidance_mls.yaml
```

To simulate and test the OLS10 driver, just use the parameter `device:=OLS10` and `yaml:=sick_line_guidance_ols10.yaml`.

If the verification of measurement messages failed, an error message is displayed. 

To run an automated unittest of both the MLS, OLS10 and OLS20 driver, script `runsimu.bash` in folder `sick_line_guidance/test/scripts` is provided: 
```bash
cd catkin_ws/src/sick_line_guidance/test/scripts
./runsimu.bash
```

## Configuration

Settings and testcases for the simulation are specified in file `sick_line_guidance/test/cfg/sick_canopen_simu_cfg.xml`. To modify the current unittest
or to append further testcases, open this file in editor, save it and install the new configuration by 
```bash
cd catkin_ws
catkin_make install
source ./install/setup.bash
```

Configuration file sick_canopen_simu_cfg.xml has three sections:

1. **sick_canopen_simu/SDO_config** : A lookup table for SDO response from SDO get request. 
    Whenever the ros driver sends a SDO request, the simulation responds with a SDO request from this table.
 
    Example:
    ```bash
    <SDO_config>    
    <sdo request="0x4018100400000000" response="0x4318100411AE2201" /> <!-- 1018sub4: Serial number -->
    <sdo request="0x4018200000000000" response="0x4F18200000000000" /> <!-- 2018: OLS dev_status -->
    </SDO_config>    
    ```
    The simulation will send a SDO response 4318100411AE2201 when receiving SDO request 4018100400000000 (serial number, object 1018sub4).
    SDO response 4F18200000000000 will be sent after receiving a SDO request 4018200000000000 (OLS device status, object 2018).
    Note: SDO responses of PDO mapped objects are modified, whenever a PDO is generated by the simulation.

2. **sick_canopen_simu/OLS20/PDO_config** : A list of sensor states transmitted by PDOs to simulate an OLS20 device. 
    This list specifies the measurement data transmitted by PDOs (lcp1, lcp2, lcp3, width1, width2, width3, status, barcode, barcode center, line quality and line intensities).
    Each measurement is transmitted 25 times with a rate of 50 hertz (PDOs in 20 milliseconds intervall, configurable in the launch file sick_canopen_simu.launch)
    before switching to the next sensor state. All measurements are repeated in an endless loop while the simulation is running.
    
    Example:
    ```bash
    <OLS20>
    <PDO_config>
    <pdo lcp1="0.000" lcp2="0.002"  lcp3="0.000"  width1="0.000" width2="0.012" width3="0.000" status="0x02" barcode="0x00"       devstatus="0x00" error="0x00" barcodecenter="0.000" linequality="0" lineintensity1="0" lineintensity2="0" lineintensity3="0" frame_id="ols_simulation_frame"/>
    <pdo lcp1="0.010" lcp2="-0.020" lcp3="-0.030" width1="0.031" width2="0.032" width3="0.033" status="0xC7" barcode="0x12345678" devstatus="0x00" error="0x00" barcodecenter="0.050" linequality="7" lineintensity1="3" lineintensity2="9" lineintensity3="8" frame_id="ols_simulation_frame"/>
    </PDO_config>
    </OLS20>
    ```
    The simulation will convert the specified sensor states and transmit PDO1 and PDO2 every 20 milliseconds.

3. **sick_canopen_simu/OLS10/PDO_config** : A list of sensor states transmitted by PDOs to simulate an OLS10 device.
   This list is identical to OLS20, except that barcode center, line quality and line intensities are not supported by OLS10 devices and therefor have to be set to 0. 

    Example:
    ```bash
    <OLS10>
    <PDO_config>
    <pdo lcp1="0.000" lcp2="0.002"  lcp3="0.000"  width1="0.000" width2="0.012" width3="0.000" status="0x02" barcode="0x00"       devstatus="0x00" error="0x00" barcodecenter="0.000" linequality="0" lineintensity1="0" lineintensity2="0" lineintensity3="0" frame_id="ols_simulation_frame"/>
    <pdo lcp1="0.010" lcp2="-0.020" lcp3="-0.030" width1="0.031" width2="0.032" width3="0.033" status="0xC7" barcode="0x12345678" devstatus="0x00" error="0x00" barcodecenter="0.000" linequality="0" lineintensity1="0" lineintensity2="0" lineintensity3="0" frame_id="ols_simulation_frame"/>
    </PDO_config>
    </OLS10>
    ```

4. **sick_canopen_simu/MLS/PDO_config** : A list of sensor states transmitted by PDOs to simulate a MLS device. 
    This list specifies the measurement data transmitted by PDOs (lcp1, lcp2, lcp3, status and #lcp).
    Each measurement is transmitted 5 times with a rate of 50 hertz (PDOs in 20 milliseconds intervall, configurable in the launch file sick_canopen_simu.launch)
    before switching to the next sensor state. All measurements are repeated in an endless loop while the simulation is running.
    
    Example:
    ```bash
    <MLS>
    <PDO_config>
    <pdo lcp1="0.000"  lcp2="0.002"  lcp3="0.000"  status="0x01" lcp="0x02" error="0x00" frame_id="mls_simulation_frame"/>
    <pdo lcp1="-0.005" lcp2="-0.006" lcp3="-0.007" status="0x41" lcp="0x57" error="0x00" frame_id="mls_simulation_frame"/>
    </PDO_config>
    </MLS>
    ```
    The simulation will convert the specified sensor states and transmit PDO1 every 20 milliseconds.
