diff --git a/.gitignore b/.gitignore index d660b3ade6bb036d44fd6f4b723765a414a1d6a3..411f65872b6b5acccde4445192ad665579f627b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ -data/*.csv +data/* **/.ipynb_notebooks/** data.zip __pycache__ Ohmpi_4elec_mqtt.py +ohmpy/* +logs/* +sequence.txt diff --git a/PCB_file_measurement card/MUX_board/ohmPi_MUX_64elec_I2C.fzz b/PCB_file_measurement card/MUX_board/ohmPi_MUX_64elec_I2C.fzz index a2d174561a8c37c5df39a0ac62f066b296a4f9d7..77b1393dff6b82da6756942eb24d07f8699c36a0 100644 Binary files a/PCB_file_measurement card/MUX_board/ohmPi_MUX_64elec_I2C.fzz and b/PCB_file_measurement card/MUX_board/ohmPi_MUX_64elec_I2C.fzz differ diff --git a/PCB_file_measurement card/measurement_board/card_measure_raspberry_v4.00.fzz b/PCB_file_measurement card/measurement_board/card_measure_raspberry_v4.00.fzz index 4c4d071e6820c512a41066eb2d120b7555c725e0..2e5921d27311266d393b40c8db449bafa7329b45 100644 Binary files a/PCB_file_measurement card/measurement_board/card_measure_raspberry_v4.00.fzz and b/PCB_file_measurement card/measurement_board/card_measure_raspberry_v4.00.fzz differ diff --git a/config.py b/config.py index 355d61bf4a54b164f4c55f39d0ebeda409f516a8..b8e3ed001595884a4920f94c5e33604bb1eed7db 100644 --- a/config.py +++ b/config.py @@ -12,7 +12,8 @@ OHMPI_CONFIG = { 'integer': 2, # Max value 10 # TODO: Explain what this is... 'version': 2, 'max_elec': 64, - 'board_address': {'A': 0x76, 'B': 0x71, 'M': 0x74, 'N': 0x70} # def. {'A': 0x76, 'B': 0x71, 'M': 0x74, 'N': 0x70} + 'board_address': {'A': 0x70, 'B': 0x71, 'M': 0x72, 'N': 0x73} # def. {'A': 0x76, 'B': 0x71, 'M': 0x74, 'N': 0x70} + #'board_address': {'A': 0x76, 'B': 0x71, 'M': 0x74, 'N': 0x70} # def. {'A': 0x76, 'B': 0x71, 'M': 0x74, 'N': 0x70} } # Execution logging configuration @@ -48,7 +49,7 @@ SOH_LOGGING_CONFIG = { # MQTT logging configuration parameters MQTT_LOGGING_CONFIG = { - 'hostname': 'ohmpy.umons.ac.be', + 'hostname': 'raspberrypi.local', 'port': 1883, 'qos': 0, 'retain': False, diff --git a/doc/source/Ohmpi.rst b/doc/source/Ohmpi.rst index de48bb0c56121c3092c25e70b04192c0fbd4e3a4..ab41c4e2d16fe5e3a1acdf22f2c945a7292fc899 100644 --- a/doc/source/Ohmpi.rst +++ b/doc/source/Ohmpi.rst @@ -48,6 +48,12 @@ OhmPi project **Introduction :** ------------------- +.. warning:: + **Ohmpi is a participative project open to all, it requires skills in electronics and to respect the safety rules. Ohmpi must be assembled in a professional context and by people competent in electronics. The Ohmpi team cannot be held responsible for any material or human damage which would be associated with the use or the assembly of OHMPI. The Ohmpi team cannot be held responsible if the equipment does not work after assembly.** + + + + | This documentation presents the development of a low-cost, open hardware \ diff --git a/doc/source/Ohmpi_V2_00/V2_00_step_01.rst b/doc/source/Ohmpi_V2_00/V2_00_step_01.rst index a2a882a8b11ac8cbd04a857c1271b961eb099b18..eee25a76d76b17e5bc391d22798c0b3b71a6e19d 100644 --- a/doc/source/Ohmpi_V2_00/V2_00_step_01.rst +++ b/doc/source/Ohmpi_V2_00/V2_00_step_01.rst @@ -1,6 +1,10 @@ **STEP n°1** : Raspberry Pi configuration ******************************************* +.. warning:: + **Ohmpi is a participative project open to all, it requires skills in electronics and to respect the safety rules. Ohmpi must be assembled in a professional context and by people competent in electronics. The Ohmpi team cannot be held responsible for any material or human damage which would be associated with the use or the assembly of OHMPI. The Ohmpi team cannot be held responsible if the equipment does not work after assembly.** + + **PART A:** OS installation ============================= diff --git a/doc/source/Ohmpi_V2_00/V2_00_step_02.rst b/doc/source/Ohmpi_V2_00/V2_00_step_02.rst index 42a0ad45f3fd40b560ff9f91cb7823cc4779e266..cbbb1daac53e11f97254da3f558aff20f43340db 100644 --- a/doc/source/Ohmpi_V2_00/V2_00_step_02.rst +++ b/doc/source/Ohmpi_V2_00/V2_00_step_02.rst @@ -2,6 +2,10 @@ **STEP n°2**: Measurement board **************************************************** +.. warning:: + **Ohmpi is a participative project open to all, it requires skills in electronics and to respect the safety rules. Ohmpi must be assembled in a professional context and by people competent in electronics. The Ohmpi team cannot be held responsible for any material or human damage which would be associated with the use or the assembly of OHMPI. The Ohmpi team cannot be held responsible if the equipment does not work after assembly.** + + **PART A** Assembly of measurement board ====================================================== diff --git a/doc/source/Ohmpi_V2_00/V2_00_step_03.rst b/doc/source/Ohmpi_V2_00/V2_00_step_03.rst index 19bf57fc1b5b1118ae0eb56b6aa38ee5a3e7c8ef..352276d8e697ac2f7d5b471abb95d5f21ca9357c 100644 --- a/doc/source/Ohmpi_V2_00/V2_00_step_03.rst +++ b/doc/source/Ohmpi_V2_00/V2_00_step_03.rst @@ -1,4 +1,10 @@ + +.. warning:: + **Ohmpi is a participative project open to all, it requires skills in electronics and to respect the safety rules. Ohmpi must be assembled in a professional context and by people competent in electronics. The Ohmpi team cannot be held responsible for any material or human damage which would be associated with the use or the assembly of OHMPI. The Ohmpi team cannot be held responsible if the equipment does not work after assembly.** + + + **STEP n°3:** MUX board **************************************************** The multiplexing of the channels is a mechanical multiplexing based on OMRON's manufacturing relays (G5LE-1-VD 12 VDC). Each relay is combined with diff --git a/doc/source/Ohmpi_V2_00/V2_00_step_04.rst b/doc/source/Ohmpi_V2_00/V2_00_step_04.rst index 1c9fe0def7258a7a68e55be683e78d35f023a522..eea88949b5f9b548cb0c7460c8291e3eee26d689 100644 --- a/doc/source/Ohmpi_V2_00/V2_00_step_04.rst +++ b/doc/source/Ohmpi_V2_00/V2_00_step_04.rst @@ -1,4 +1,12 @@ +.. warning:: + **Ohmpi is a participative project open to all, it requires skills in electronics and to respect the safety rules. Ohmpi must be assembled in a professional context and by people competent in electronics. The Ohmpi team cannot be held responsible for any material or human damage which would be associated with the use or the assembly of OHMPI. The Ohmpi team cannot be held responsible if the equipment does not work after assembly.** + + + + + + **STEP n°4:** assemble Ohmpi **************************************************** @@ -17,11 +25,437 @@ +--------+------------------------------------------------------------+ | | .. image:: step_n_4/step_4_2.jpg | - | 1 +------------------------------------------------------------+ + | 2 +------------------------------------------------------------+ | |Crimp the ribbon cable on the corresponding idc connector | | |with a suitable clamp. Pay attention to the direction of the| | |cables. Unbalanced IDC connector. The ribbon cable must be | | |perpendicular to the connector. | +--------+------------------------------------------------------------+ +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_3.jpg | + | 3 +------------------------------------------------------------+ + | |Example of IDC connector mounting. The wires should run as | + | |perpendicular as possible to the IDC connector. | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_4.jpg | + | 4 +------------------------------------------------------------+ + | |Same for a 6 wires ribbon cable of 1 m length. | + | | | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_5.jpg | + | 5 +------------------------------------------------------------+ + | |Cut the ribbon cable flush with the IDC connector. | + | | | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_6.jpg | + | 6 +------------------------------------------------------------+ + | |Position 9 spacers above the MUX board, and 9 spacers below.| + | | | + + +------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_7.jpg | + | +------------------------------------------------------------+ + | |Profile view for mounting the spacers above and below. | + | | | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_8.jpg | + | 7 +------------------------------------------------------------+ + | |Cut a 50 cm long wire of any color (here yellow). Strip and | + | |tin each end of the wire. Install the wire "A" on the screw | + | |terminal of MUX board « A ». | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_9.jpg | + | 8 +------------------------------------------------------------+ + | |Cut a red wire and a black wire of 50 cm length. Strip, tin | + | |and position the wires on the left screw terminal as shown | + | |in the picture: i)Red wire 12 V, ii) Black wire GND | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_10.jpg | + | 9 +------------------------------------------------------------+ + | |Mount the 4 ribbon cables (16-wires each) with IDC | + | |connectors. A small noise is often heard when the IDC | + | |connector is clipped in place. | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_11.jpg | + | 10+------------------------------------------------------------+ + | |Mount the ribbon cables with 6-wires with the corresponding | + | |IDC connectors | + | | | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_12.jpg | + | 11+------------------------------------------------------------+ + | |Cut a red wire and a black wire of 10 cm length. Strip and | + | |tin the wires at the ends. Mount the red wire on the 12V | + | |input and the black wire on the GND input on the right screw| + | |terminal. | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_13.jpg | + | 12+------------------------------------------------------------+ + | |Mount and fix the second MUX board "B" on the first with | + | |the help of 9 spacers. | + | | | + | | | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_14.jpg | + | 13+------------------------------------------------------------+ + | |Cut, strip and tin a red wire and a black wire of 10 cm | + | |length. Mount the wires on the left screw terminal. | + | |Red wire 12V input, black wire GND input. | + | |Connect the red and black wires from board A to the right | + | |screw terminal of board B. Red wire 12V input. Black wire | + | |GND input. | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_15.jpg | + | 14+------------------------------------------------------------+ + | |Crimp a 16 wires IDC connector on the ribbon cable at about | + | |15 cm from the previous connector. Please, pay attention to | + | |the direction of the cable before the crimp procedure. | + | |Mount the ribbon cable on the IDC connector on the board. | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_16.jpg | + | 15+------------------------------------------------------------+ + | |Repeat the operation for the other 3 ribbon cables. | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_17.jpg | + | 16+------------------------------------------------------------+ + | |Repeat the operation for the 6 wires ribbon cable. | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_18.jpg | + | 17+------------------------------------------------------------+ + | |Cut a 50 cm long wire "here purple" (Color not relevant but | + | |to be defined). Strip and tin the wire at its ends. Position| + | |the wire on the input B of the screw terminal of the | + | |multiplexing board B. | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_19.jpg | + | 18+------------------------------------------------------------+ + | |Repeat all these operations for the third MUX board | + | |called "M". | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_20.jpg | + | 19+------------------------------------------------------------+ + | |Repeat the operations for the fourth MUX Boards. Attention, | + | |it is necessary to position 5 different spacers (here nylon | + | |screw hex spacers) in between the “M†board and the “N†MUX | + | |Board (as shown on the photograph). Refer to the following | + | |photographs for more details on the assembly of the spacers.| + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_21.jpg | + | 20+------------------------------------------------------------+ + | |When mounting the 4th MUX board ("N"), screws can be placed | + | |on the nylon spacers to fix the boards together. Note that | + | |the other spacers could be used for this purpose. | + | |Connect ribbon cables (16 wires) from board 3 to board 4 as | + | |previously described. Connect the red wire (12V) of MUX | + | |board "M" to the 12V terminal of the right screw terminal | + | |of MUX Board "N". Connect the black wire (GND) of MUX board | + | |“M†to the GND screw terminal on MUX board “Nâ€. | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_22.jpg | + | 21+------------------------------------------------------------+ + | |Cut a red wire and a black wire of one meter length. Place | + | |the red wire on terminal “12V†and the black wire on | + | |terminal “GND†of the left screw terminal. Tie the wires | + | |together. | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_23.jpg | + | 22+------------------------------------------------------------+ + | |Tie the A, B, M and N wires together | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_24.jpg | + | 23+------------------------------------------------------------+ + | |Cut a PVC plate with the following minimum dimensions : | + | |200 mm * 150 mm * 5 mm | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_25.jpg | + | 24+------------------------------------------------------------+ + | |Drill the plate to mount it on the remaining metal spacers. | + | |Do not tighten the assembly. | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_26.jpg | + | 25+------------------------------------------------------------+ + | |Position the Raspberry Pi (RPI) board on the plate so that | + | |you can access the USB ports. Mark the holes of the RPI | + | |board on the plate for mounting. | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_27.jpg | + | 26+------------------------------------------------------------+ + | |Add spacers on the PVC plate. | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_28.jpg | + | 27+------------------------------------------------------------+ + | |Attach the PVC plate to the metal spacers with washers | + | |and nuts. | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_29.jpg | + | 28+------------------------------------------------------------+ + | |Position and fix the RPI card on the spacers | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_30.jpg | + | 29+------------------------------------------------------------+ + | |Add spacers on the RPI board. The red (12V) and black (GND) | + | |wires coming out of the "M" MUX board must pass under | + | |the RPI board. | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_31.jpg | + | 30+------------------------------------------------------------+ + | |Place the measurement board on the RPI GPIO outputs and on | + | |the pre-positioned spacers. Note that LEDs are present on | + | |this measurement board with an associated resistance simply | + | |for testing purposes (do not consider this temporary | + | |modification of the board). Same for the orange wire present| + | |on the board. | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_32.jpg | + | 31+------------------------------------------------------------+ + | |Connect the wires " A " (here yellow), " B " (here purple), | + | |" M " (here brown) and " N " (here blue) on the | + | |corresponding terminal blocks on the measurement board. | + | |Connect the 6 wires ribbon cable on the measurement board | + | |by passing under the PVC plate.Connect the red and black | + | |wires to the 12 V and GND terminal block. | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_33.jpg | + | 32+------------------------------------------------------------+ + | |Top view of the assembly. Add clips to secure the wires | + | |together. | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_34.jpg | + | 33+------------------------------------------------------------+ + | |Second view. | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_35.jpg | + | 34+------------------------------------------------------------+ + | |Zoom in on the connection of the M and N wires. | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_36.jpg | + | 35+------------------------------------------------------------+ + | |Zoom in on the connection of the A and B wires. | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_37.jpg | + | 36+------------------------------------------------------------+ + | |Zoom in on the connection of the « 12V » and « GND » wires. | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_38.jpg | + | 37+------------------------------------------------------------+ + | |Fixing the measurement board on the spacers present on the | + | |RPI board. | + +--------+------------------------------------------------------------+ + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_39.jpg | + | 38+------------------------------------------------------------+ + | |Place the SD card containing the OS and the pre-installed | + | |programs. Connect a mouse and a keyboard to the USB inputs | + | |of the RPI board. Connect a monitor to the HDMI output of | + | |the RPI board. | + +--------+------------------------------------------------------------+ + + +.. table:: + :align: center + + +--------+------------------------------------------------------------+ + | | .. image:: step_n_4/step_4_40.jpg | + | 39+------------------------------------------------------------+ + | |Connect the red and black cables of board A to a 12V battery| + | |or other laboratory power supply delivering a 12V-DC | + | |voltage. | + | |Enjoy 😊 | + +--------+------------------------------------------------------------+ + + \ No newline at end of file diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_21.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step4_21.jpg deleted file mode 100644 index d8295583f5393324d85337a6b06f8609b5771fd5..0000000000000000000000000000000000000000 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_21.jpg and /dev/null differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step_4_1.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_1.jpg index 927a0dc6aea9997e8650b5c2b758389e9e60cc89..e4eb3687f78063a906547807b5868f565fa37187 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step_4_1.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_1.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_10.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_10.jpg similarity index 80% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_10.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_10.jpg index b4b7d05de6d7441e26f486a4d99ca26bddb4857d..1ebd190225f88a94121a361570b05de2924d8205 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_10.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_10.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_11.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_11.jpg similarity index 80% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_11.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_11.jpg index 764cb4307f10a59306f394f2650b5053c2ad026b..d9dba19839c5b0228f36ccf795638217de1165d9 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_11.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_11.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_12.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_12.jpg similarity index 84% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_12.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_12.jpg index b10ec828fe7e5e00adab98cce14102887077593a..211b5e3dcf92702da580d3aad7bd18ce344196e1 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_12.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_12.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_13.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_13.jpg similarity index 87% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_13.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_13.jpg index ad9f3491c02f3a6b559450acfa7dafe6b783ebed..2439d6e3fdddbe8aec6da51025e339ec7cdf1547 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_13.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_13.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_14.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_14.jpg similarity index 85% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_14.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_14.jpg index 288cb40e0e482877c91b9741d7397f693dbc6105..b4a64f230604d055107b351fbb83235089d2db03 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_14.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_14.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_15.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_15.jpg similarity index 85% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_15.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_15.jpg index 18961ef1fdb2ef9ad14420a7222e2c5e0ce3e947..1d1fd20da45556675bb871f1e4e40fa48c6b6695 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_15.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_15.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_16.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_16.jpg similarity index 86% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_16.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_16.jpg index 245e0c5a24ed3605761396bffef42180c6d22ebe..b15f4667969dc68a6274568ea7ea1c9c65600f31 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_16.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_16.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_17.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_17.jpg similarity index 78% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_17.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_17.jpg index da33cd86273158357c678f9624e47fff2bdb1d4c..f4fe61e241a5194afb644f311c32f6194750e501 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_17.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_17.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_18.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_18.jpg similarity index 85% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_18.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_18.jpg index d9701d1f3f014865eebf78976c9a4d6d9875d41d..5245c98331705ec8cb38d69ae0619d680bf2248c 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_18.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_18.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_19.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_19.jpg similarity index 86% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_19.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_19.jpg index 9ac1bcd784712e967118127a6895e1ebe0daaab9..d665462c5e478a8c79c2bb14f88c6472692e8206 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_19.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_19.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step_4_2.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_2.jpg index 78107714608a83c73852e3d538cefe05c4022d41..68ed786249bdc49e1a3b2b145749bac64ed4cc77 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step_4_2.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_2.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_20.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_20.jpg similarity index 87% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_20.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_20.jpg index b2f5757311952ccd19a4a5f11814df7fa7370973..26e5f5388a347f3bb21578914fbe6cbca9d3d9fe 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_20.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_20.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step_4_21.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_21.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3971defc2d0f8ac88219e0b3ea1bbe80a511b9de Binary files /dev/null and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_21.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_22.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_22.jpg similarity index 85% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_22.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_22.jpg index e717af1c91a9724e747bf4d7f596b98cdb728a4d..b6f5cc44cdacfcc963d37de5ae076b4df89a3f74 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_22.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_22.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_23.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_23.jpg similarity index 77% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_23.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_23.jpg index 5fa8abc5577255c8c127acd085771370c1143d33..0c8fc43d07c7ce06a98065c45e5c112b0659d79b 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_23.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_23.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_24.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_24.jpg similarity index 80% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_24.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_24.jpg index 60f3d6fa2580df2a684d9810b37868667f98b0d4..ab0229896a8da7d88cb20340df18a1072b5468b1 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_24.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_24.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_25.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_25.jpg similarity index 84% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_25.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_25.jpg index 777370fc5a1c06ffcc8f8347b67fd2ee1e774430..98462528479b7186f1073ca7726dc71406b96b5c 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_25.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_25.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_26.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_26.jpg similarity index 84% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_26.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_26.jpg index fb42273e79469f396f1334a4dbba60f42f48ae16..ec6602090c69e11fbd41e9c7d09d33e262b1dade 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_26.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_26.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_27.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_27.jpg similarity index 84% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_27.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_27.jpg index 646c2248e47199432021818115ab7324797240a0..46170e10d01b6f59cc2fb8fdf95f82414b024d87 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_27.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_27.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_28.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_28.jpg similarity index 85% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_28.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_28.jpg index 3f657aa764a4ab337be0f031b35815e98379c77a..b7f40ea765a80267e48e94d9e3a26f88cabde203 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_28.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_28.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_29.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_29.jpg similarity index 85% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_29.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_29.jpg index 9e740b778a10bccf362fb93a4534c2a8f106b571..68ae66d0b8e9e3c62eef8ac97145979792ea6b10 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_29.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_29.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_3.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_3.jpg similarity index 81% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_3.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_3.jpg index f06d962add5387698f9aa381e0b42df8c50c5038..3664f0d1d546302a20bdc34f523419dcb2e45079 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_3.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_3.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_30.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_30.jpg similarity index 85% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_30.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_30.jpg index 370b6263b8085e87ee46e96357c19dee51631bae..927caa9dd631ace1d7ecc981507d409c9031258c 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_30.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_30.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_31.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_31.jpg similarity index 84% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_31.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_31.jpg index fca4f058b822d927ec736f8d483c8fd896167e11..4ec168254878a1fdc9c9a978b7c5021c8336a1be 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_31.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_31.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_32.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_32.jpg similarity index 86% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_32.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_32.jpg index d30bc8b95bf03acd358ed8cdb418a037acbe3569..205c2a7b2b26178b7d46165f600beeabbb5f8ef6 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_32.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_32.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_33.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_33.jpg similarity index 79% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_33.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_33.jpg index 3581d9e0d88619fc4870217961f451862eb70457..6c1c25833af94797ff75ebc861c515a965e48479 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_33.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_33.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_34.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_34.jpg similarity index 79% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_34.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_34.jpg index ffe4b9b305230598f6ee348c035bc51db195ea88..75b311b7d17450714f92d250d39dc8f56c97ed7f 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_34.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_34.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_35.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_35.jpg similarity index 85% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_35.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_35.jpg index b6fe7d7551877a79d640f4389c0a04ebab389eee..92b72080b3b33509cbeedb8e869b830e8cb4499e 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_35.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_35.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_36.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_36.jpg similarity index 85% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_36.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_36.jpg index 1282fd99287351e2620051741d1c7c4b79506681..9edcb7ee706acefba05780060bbd5e727daf7582 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_36.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_36.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_37.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_37.jpg similarity index 84% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_37.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_37.jpg index 9fa84020762012c3affc8ee2341ce15c376d762c..7ad7b6cfb1a8b29c7bc80484219129ff012bc307 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_37.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_37.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_38.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_38.jpg similarity index 77% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_38.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_38.jpg index ec5094da54ea33507a862252c428e2436b0f871b..03f5aa63de94d7d34934d67098a402f88004acb3 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_38.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_38.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_39.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_39.jpg similarity index 76% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_39.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_39.jpg index 4445d75d4b6ef50b8f3cd211eaac58737945dbfb..5c0e0bdd41d73bbf60c62f7b3c7ded8b56a1cdd1 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_39.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_39.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_4.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_4.jpg similarity index 83% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_4.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_4.jpg index fec1eec8a3d4b28d96178630d22aabbae2f2b0c8..8dd3c4f5f5dbbba64547a2eeaacab68cad1745f5 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_4.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_4.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_40.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_40.jpg similarity index 77% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_40.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_40.jpg index bb0d1d9038f0831ae338d8f6c5ff05a333c30c58..3fcb1ceff92b0a418d02977478ef825517df0318 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_40.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_40.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_5.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_5.jpg similarity index 77% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_5.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_5.jpg index c8adc480f92fc0e81098087afc58bc6500eee77b..7a31399772303ebb337885892b0cd40ede1a414c 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_5.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_5.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_6.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_6.jpg similarity index 89% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_6.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_6.jpg index 22e03c78dc6575568ad515de4237d34a2db1e40e..c0fd38f7a29da56317ecbe0ebd921bb877e73e89 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_6.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_6.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_7.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_7.jpg similarity index 79% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_7.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_7.jpg index bc1d74e734d1fb7019e7b85789a063b20e085ba1..ff776456e020bef31c26beda5d0c50134522b9d9 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_7.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_7.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_8.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_8.jpg similarity index 89% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_8.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_8.jpg index 32cf9243bdeebdbd96868e3158f7f98dfddfdec1..3601fdfac7ccbc5d515471f8508af3e8301d4f66 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_8.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_8.jpg differ diff --git a/doc/source/Ohmpi_V2_00/step_n_4/step4_9.jpg b/doc/source/Ohmpi_V2_00/step_n_4/step_4_9.jpg similarity index 89% rename from doc/source/Ohmpi_V2_00/step_n_4/step4_9.jpg rename to doc/source/Ohmpi_V2_00/step_n_4/step_4_9.jpg index 5a9df2157763df64592019d7fef2a89cfb71f038..02d3fa23825550f2ea55d6b99087b3937b9eea3f 100644 Binary files a/doc/source/Ohmpi_V2_00/step_n_4/step4_9.jpg and b/doc/source/Ohmpi_V2_00/step_n_4/step_4_9.jpg differ diff --git a/doc/source/V1_01.rst b/doc/source/V1_01.rst index f1610bfd3c48cce409df560574f596e77a84ab28..4b1a56cf81d053c1aee9999d16280cac9891ff5c 100644 --- a/doc/source/V1_01.rst +++ b/doc/source/V1_01.rst @@ -7,6 +7,9 @@ OhmPi V 1.01 (limited to 32 electrodes) However, we have corrected the bugs that existed on this version and explained the missing mounting points in detail below. We invite you to refer to this document to assemble Ohmpi V1.01. +.. warning:: + **Ohmpi is a participative project open to all, it requires skills in electronics and to respect the safety rules. Ohmpi must be assembled in a professional context and by people competent in electronics. The Ohmpi team cannot be held responsible for any material or human damage which would be associated with the use or the assembly of OHMPI. The Ohmpi team cannot be held responsible if the equipment does not work after assembly.** + diff --git a/doc/source/V1_02.rst b/doc/source/V1_02.rst index ff4c42ece839b61930eb862d4e9f47edfec01d83..d35e3e5fce308b943aa491277241b171b600d0cb 100644 --- a/doc/source/V1_02.rst +++ b/doc/source/V1_02.rst @@ -2,6 +2,12 @@ OhmPi V 1.02 (limited to 32 electrodes) ***************************************** + +.. warning:: + **Ohmpi is a participative project open to all, it requires skills in electronics and to respect the safety rules. Ohmpi must be assembled in a professional context and by people competent in electronics. The Ohmpi team cannot be held responsible for any material or human damage which would be associated with the use or the assembly of OHMPI. The Ohmpi team cannot be held responsible if the equipment does not work after assembly.** + + + .. note:: In this version, we have improved the electronic measurement board. To upgrade from version 1.01 to 1.02, you just have to replace the measurement board by the new one proposed here. diff --git a/doc/source/V2_00.rst b/doc/source/V2_00.rst index 8dbaefaac435bc9d93f354fc9e69894fb37fc261..907cb3aba651c8e6e3e682904fa5114e21e310bd 100644 --- a/doc/source/V2_00.rst +++ b/doc/source/V2_00.rst @@ -2,12 +2,10 @@ OhmPi V 2.00 (64 electrodes and 12V) ******************************************** -.. figure:: Under-Construction.png - :width: 500px - :align: center - :height: 250px - :alt: Ohmpi 2 - :figclass: align-center +.. warning:: + **Ohmpi is a participative project open to all, it requires skills in electronics and to respect the safety rules. Ohmpi must be assembled in a professional context and by people competent in electronics. The Ohmpi team cannot be held responsible for any material or human damage which would be associated with the use or the assembly of OHMPI. The Ohmpi team cannot be held responsible if the equipment does not work after assembly.** + + .. figure:: image_ohmpi_2.jpg :width: 400px diff --git a/doc/source/api.rst b/doc/source/api.rst index c1157b20f6f7090299118d1b70501ae0202d961a..c5c9a92aca74518508821f8a32c77fe20aa3f902 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -1,9 +1,9 @@ -API reference -============= -.. toctree:: - :maxdepth: 2 - :caption: Contents: -.. automodule:: Ohmpi - :members: - - +API reference +============= +.. toctree:: + :maxdepth: 2 + :caption: Contents: +.. automodule:: ohmpi + :members: + + diff --git a/env.sh b/env.sh old mode 100644 new mode 100755 index e79f68dfd58fdfd2e7d0a984708ef57c33471693..7f8f33f924942ce32cff08982c81987785e28184 --- a/env.sh +++ b/env.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash sudo apt-get install -y libatlas-base-dev python3 -m venv ohmpy source ohmpy/bin/activate || exit 1 # NOTE: Added || exit to avoid installing requirements in system python diff --git a/index.html b/index.html index 0207a38f5c4978460192d6331f14d2da250f1781..423e5591797f17d7fd9895a803029bce00cddc1d 100644 --- a/index.html +++ b/index.html @@ -1,427 +1,549 @@ -<!DOCTYPE html> -<html> -<head> - <meta charset="utf8"/> - <title>OhmPi Acquisition Board</title> - <link rel="shortcut icon" type="image/jpg" href="logo_ohmpi.jpg"/> - - <!-- dependencies (need to be local as no internet in AP mode)--> - <script src="js/plotly-basic-2.8.3.min.js"></script> - <script src="js/jquery-3.4.1.min.js"></script> - <link type="text/css" href="css/bootstrap.min.css" rel="stylesheet"> - <!-- <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> --> - <!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous"> --> - <!-- <script src="js/danfojs/bundle.min.js"></script> --> -</head> -<body> - <div class='container'> - <h1>OhmPi Acquisition Board</h1> - <!-- nb stacks, on-time --> - <button id="setConfigBtn" type="button" class="btn btn-secondary" data-toggle="modal" data-target="#exampleModal">Settings</button> - <button id='startBtn' type="button" class="btn btn-primary">Start</button> - <button id='stopBtn' type="button" class="btn btn-warning">Stop</button> - <!-- upload button for csv which display the table ABMN --> - <button id="removeDataBtn" type="button" class="btn btn-danger">Clear data</button> - <button id="getDataBtn" type="button" class="btn btn-info">Get data</button> - <div class="form-check"> - <input id="dataRetrievalCheck" class="form-check-input" type="checkbox" value=""> - <label class="form-check-label" for="dataRetrievalCheck"> - Automatically get data every 1 second - </label> - </div> - <div id='output'>Status: idle</div> - <select id='surveySelect' class='custom-select'> - </select> - <div id="gd"></div> - <div class="mb3 row"> - <label for="quadSelect">Quadrupole:</label> - <div class="col-sm-10"> - <select id='quadSelect' class='custom-select'></select> - </div> - </div> - <button id="addTraceBtn" type="button" class="btn btn-info">Add trace</button> - <button id="removeTracesBtn" type="button" class="btn btn-info">Remove all traces</button> - <div id="ts"></div> - <button id="downloadBtn" type="button" class="btn btn-primary">Download data</button> - <!-- <button id="invertBtn" type="button" class="btn btn-primary">Invert</button> --> - <a id="download"></a> - - <!-- Modal for configuration --> - <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> - <div class="modal-dialog" role="document"> - <div class="modal-content"> - <div class="modal-header"> - <h5 class="modal-title" id="exampleModalLabel">OhmPi configuration</h5> - <button type="button" class="close" data-dismiss="modal" aria-label="Close"> - <span aria-hidden="true">×</span> - </button> - </div> - <div class="modal-body"> - <form> - <div class="form-group row"> - <label for="nbElectrodes" class="col-sm-2 col-form-label">Nb electrodes</label> - <div class="col-sm-10"> - <input type="number" class="form-control-number" id="nbElectrodes" value="64"> - </div> - </div> - <div class="form-group row"> - <label for="injectionDuration" class="col-sm-2 col-form-label">Injection duration [s]</label> - <div class="col-sm-10"> - <input type="number" class="form-control-number" id="injectionDuration" value="0.2"> - </div> - </div> - <div class="form-group row"> - <label for="nbMeasurements" class="col-sm-2 col-form-label">Nb Measurements</label> - <div class="col-sm-10"> - <input type="number" class="form-control-number" id="nbMeasurements" value="1"> - </div> - </div> - <div class="form-group row"> - <label for="sequenceDelay" class="col-sm-2 col-form-label">Sequence delay [s]</label> - <div class="col-sm-10"> - <input type="number" class="form-control-number" id="sequenceDelay" value="100"> - </div> - </div> - <div class="form-group row"> - <label for="nbStack" class="col-sm-2 col-form-label">Nb stack</label> - <div class="col-sm-10"> - <input type="number" class="form-control-number" id="nbStack" value="1"> - </div> - </div> - </form> - </div> - <div class="modal-footer"> - <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> - <button id="saveConfigBtn" type="button" data-dismiss="modal" class="btn btn-primary">Save</button> - </div> - </div> - </div> - </div> - - <footer>v0.2.0</footer> - </div> - - <script type="text/javascript"> - //let serverUrl = 'http://10.3.141.1:8080' - let serverUrl = 'http://0.0.0.0:8080' - //let serverUrl = 'http://localhost:8080' - let output = document.getElementById('output') - let data = {} // hold data of all surveys - let interv = null // hold interval for automatic data retrieval - let quads = [] // available quadrupoles for time-series figure - let squads = [] // selected quadrupoles for time-series figure - - // useful functions - function sendCommand(query, callback=null) { - // dic in the form: {'command': X, ...} as JSON - if (callback == null) { - function callback(x) { - console.log('default callback:', x) - } - } - let xhr = new XMLHttpRequest(); - xhr.onreadystatechange = function() { - if (this.readyState == 4) { - if (xhr.status == 200) { - callback(JSON.parse(xhr.response)) - } - } - } - xhr.open('POST', serverUrl) - xhr.setRequestHeader('Content-Type', 'application/json') - xhr.send(query) - } - - // start button - function startBtnFunc() { - sendCommand('{"command": "start"}', function(x) { - console.log(x['status']) - if (x['status'] == 'running') { - output.innerHTML = 'Status: measuring...' - } - }) - } - let startBtn = document.getElementById('startBtn') - startBtn.addEventListener('click', startBtnFunc) - - // stop button - function stopBtnFunc() { - sendCommand('{"command": "stop"}', function(x) { - output.innerHTML = 'Status: ' + x['status'] - clearInterval(interv) - getData() - }) - } - let stopBtn = document.getElementById('stopBtn') - stopBtn.addEventListener('click', stopBtnFunc) - - // set configuration - function saveConfigBtnFunc() { - // collect values from modal - let formVals = {} - for (let field of ['nbElectrodes', 'injectionDuration', - 'nbMeasurements', 'sequenceDelay', 'nbStack']) { - formVals[field] = document.getElementById(field).value - } - console.log(formVals) - - sendCommand(JSON.stringify({ - 'command': 'setConfig', - 'config': formVals - }), function(x) { - console.log('setconfig:', x) - }) - } - let saveConfigBtn = document.getElementById('saveConfigBtn') - saveConfigBtn.addEventListener('click', saveConfigBtnFunc) - - // make pseudo plot - var trace = { - x: [], - y: [], - mode: 'markers', - marker: { - size: 40, - color: [], - colorbar: { - title: 'App. res. [Ohm.m]' - } - } - } - let layout = { - title: 'Pseudo-section', - yaxis: { - title: 'Pseudo-depth', - autorange: 'reversed' - }, - xaxis: { - title: 'X' - } - - } - Plotly.newPlot('gd', [trace], layout) - - // make time-series plot - let tdata = [] - let layout2 = { - title: 'Time series', - yaxis: { - title: 'App. res. [Ohm.m]' - }, - xaxis: { - title: 'Sampling time' - } - } - Plotly.newPlot('ts', tdata, layout2) - - // add trace to time-series plot - function addTraceBtnFunc() { - let val = document.getElementById('quadSelect').value - squads.push(val.split(', ')) - tdata.push({ - x: [], - y: [], - name: val, - type: 'scatter' - }) - Plotly.newPlot('ts', tdata, layout2) - getData() - } - let addTraceBtn = document.getElementById('addTraceBtn') - addTraceBtn.addEventListener('click', addTraceBtnFunc) - - // remove all traces from time-series plot - function removeTracesBtnFunc() { - squads = [] - tdata = [] - Plotly.newPlot('ts', tdata, layout2) - } - let removeTracesBtn = document.getElementById('removeTracesBtn') - removeTracesBtn.addEventListener('click', removeTracesBtnFunc) - - // getData - function getData() { - sendCommand(JSON.stringify({ - 'command': 'getData', - 'surveyNames': Object.keys(data).slice(0, -1) - // last survey is often partial so we download it again - }), function(ddic) { - // update status - output.innerHTML = 'Status: ' + ddic['status'] - - // update data dic with new data - data = { // destructuring assignment (magic! :o) - ...data, - ...ddic['data'] // value from second dic are preferred - } - - // dropdown with number of surveys and +++ - let surveyNames = Object.keys(data).sort() - - // callback function to draw the plot - function surveySelectFunc(el) { - let surveyName = el['target'].value - let df = data[surveyName] - if (df != undefined) { - let a = df['a'] - let b = df['b'] - let m = df['m'] - let n = df['n'] - // let's assume electrodes are 1 m distance - // compute pseudo-depth (assume no topo) - let xpos = [] - let ypos = [] - for (let i = 0; i < a.length; i++) { - let ab = (a[i] + b[i])/2 - let mn = (m[i] + n[i])/2 - let dist = Math.abs(ab - mn) - xpos.push(Math.min(ab, mn) + dist/2) - ypos.push(Math.sqrt(2)/2*dist) - } - // update the trace and redraw the figure - trace['x'] = xpos - trace['y'] = ypos - trace['marker']['color'] = df['rho'] - Plotly.redraw('gd') - } - } - - let surveySelect = document.getElementById('surveySelect') - - // remove listener as we will replace the choices - surveySelect.removeEventListener('change', surveySelectFunc) - surveySelect.innerHTML = '' // clearing all child nodes - - // add choices again - for (let surveyName of surveyNames) { - let option = document.createElement('option') - option.innerText = surveyName - option.value = surveyName - surveySelect.appendChild(option) - } - - // listener again - surveySelect.addEventListener('change', surveySelectFunc) - - // plot last one by default - surveySelect.value = surveyNames[surveyNames.length - 1] - - // call the function directly - // (as programmatically changing the value does not trigger the event) - surveySelectFunc({'target': surveySelect}) - - // update list of quadrupoles if any - if (quads.length == 0) { - console.log('updating list of quadrupoles') - let df = data[surveyNames[0]] - let quadSelect = document.getElementById('quadSelect') - quadSelect.innerHTML = '' - for (let i = 0; i < df['a'].length; i++) { - quad = [df['a'][i], df['b'][i], df['m'][i], df['n'][i]] - quads.push(quad) - let option = document.createElement('option') - option.value = quad.join(', ') - option.innerText = quad.join(', ') - quadSelect.appendChild(option) - } - console.log('quads=', quads) - } - - // update time-series figure - if (squads.length > 0) { - - // transform all surveyNames to datetime - let xt = [] - for (surveyName of surveyNames) { - let a = surveyName.split('_').slice(-1)[0] - xt.push(a.slice(0, 4) + '-' - + a.slice(4, 6) + '-' - + a.slice(6, 8) + ' ' - + a.slice(9, 11) + ':' - + a.slice(11, 13) + ':' - + a.slice(13, 15)) - } - //console.log(xt) - - // create one new trace per selected quadrupole - for (let k = 0; k < squads.length; k++) { - squad = squads[k] - let x = [] - let y = [] - for (let i = 0; i < surveyNames.length; i++) { - df = data[surveyNames[i]] - for (let j = 0; j < df['a'].length; j++) { - if (df['a'][j] == squad[0] - && df['b'][j] == squad[1] - && df['m'][j] == squad[2] - && df['n'][j] == squad[3]) { - y.push(df['rho'][j]) - x.push(xt[i]) - break - } - } - } - - // update trace dictionary - tdata[k]['x'] = x - tdata[k]['y'] = y - } - //console.log(tdata) - Plotly.redraw('ts') - } - }) - } - let getDataBtn = document.getElementById('getDataBtn') - getDataBtn.addEventListener('click', getData) - - // checkbox interaction for data download - function dataRetrievalCheckFunc(x) { - if (x['target'].checked == true) { - interv = setInterval(getData, 1000) // every 5s - } else { - clearInterval(interv) - } - } - let dataRetrievalCheck = document.getElementById('dataRetrievalCheck') - dataRetrievalCheck.addEventListener('change', dataRetrievalCheckFunc) - - // remove data - function removeDataBtnFunc() { - sendCommand('{"command": "removeData"}',function(x) { - data = {} - output.innerHTML = 'Status: ' + x['status'] + ' (all data cleared)' - console.log('all data removed') - }) - } - let removeDataBtn = document.getElementById('removeDataBtn') - removeDataBtn.addEventListener('click', removeDataBtnFunc) - - // invert data - // function invertBtnFunc() { - // sendCommand('{"command": "invert"}', function(x) { - // console.log('inversion results', x) - // }) - // } - // let invertBtn = document.getElementById('invertBtn') - // invertBtn.addEventListener('click', invertBtnFunc) - - // download data - function downloadBtnFunc() { - sendCommand('{"command": "download"}', function(x) { - let dwl = document.getElementById('download') - dwl.setAttribute('href', serverUrl + '/data.zip') - dwl.setAttribute('download', 'data.zip') - dwl.click() - }) - } - let downloadBtn = document.getElementById('downloadBtn') - downloadBtn.addEventListener('click', downloadBtnFunc) - - - </script> - - <!-- Boostrap scripts (at the end of the page for faster loading time)--> - <script src="js/bootstrap.bundle.min.js"></script> - <!-- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js" integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf" crossorigin="anonymous"></script> --> -</body> -</html> +<!DOCTYPE html> +<html> +<head> + <meta charset="utf8"/> + <title>OhmPi Acquisition Board</title> + <link rel="shortcut icon" type="image/jpg" href="logo_ohmpi.jpg"/> + + <!-- dependencies (need to be local as no internet in AP mode)--> + <script src="js/plotly-basic-2.8.3.min.js"></script> + <script src="js/jquery-3.4.1.min.js"></script> + <link type="text/css" href="css/bootstrap.min.css" rel="stylesheet"> + <!-- <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> --> + <!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous"> --> + <!-- <script src="js/danfojs/bundle.min.js"></script> --> +</head> +<body> + <div class='container'> + <h1>OhmPi Acquisition Board</h1> + <!-- nb stacks, on-time --> + <button id="setConfigBtn" type="button" class="btn btn-secondary" data-toggle="modal" data-target="#exampleModal">Settings</button> + <button id='startBtn' type="button" class="btn btn-primary">Start</button> + <button id='stopBtn' type="button" class="btn btn-warning">Stop</button> + <!-- upload button for csv which display the table ABMN --> + <button id="removeDataBtn" type="button" class="btn btn-danger">Clear data</button> + <button id="getDataBtn" type="button" class="btn btn-info">Get data</button> + <div class="form-check"> + <input id="dataRetrievalCheck" class="form-check-input" type="checkbox" value=""> + <label class="form-check-label" for="dataRetrievalCheck"> + Automaticaly get data every 1 second + </label> + </div> + <div id='output'>Status: idle</div> + + <!-- Pseudo section --> + <select id='surveySelect' class='custom-select'> + </select> + <input id="cmin" type="number" value="0"/> + <input id="cmax" type="number" value="150"/> + <button id="capplyBtn" type="button" class="btn btn-info">Apply</button> + <div id="gd"></div> + <div class="mb3 row"> + <label for="quadSelect">Quadrupole:</label> + <div class="col-sm-10"> + <select id='quadSelect' class='custom-select'></select> + </div> + </div> + + <!-- trace figure --> + <button id="addTraceBtn" type="button" class="btn btn-info">Add trace</button> + <button id="removeTracesBtn" type="button" class="btn btn-info">Remove all traces</button> + <div id="ts"></div> + + <!-- RS check --> + <button id="rsBtn" type="button" class="btn btn-info">Check contact resistance</button> + <button id="rsClearBtn" type="button" class="btn btn-info">Clear plot</button> + <div id="rs"></div> + + <!-- Additional buttons --> + <button id="downloadBtn" type="button" class="btn btn-primary">Download data</button> + <!-- <button id="invertBtn" type="button" class="btn btn-primary">Invert</button> --> + <a id="download"></a> + + <!-- Modal for configuration --> + <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h5 class="modal-title" id="exampleModalLabel">OhmPi configuration</h5> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"> + <span aria-hidden="true">×</span> + </button> + </div> + <div class="modal-body"> + <form> + <div class="form-group row"> + <label for="nbElectrodes" class="col-sm-2 col-form-label">Nb electrodes</label> + <div class="col-sm-10"> + <input type="number" class="form-control-number" id="nbElectrodes" value="64"> + </div> + </div> + <div class="form-group row"> + <label for="injectionDuration" class="col-sm-2 col-form-label">Injection duration [s]</label> + <div class="col-sm-10"> + <input type="number" class="form-control-number" id="injectionDuration" value="0.2"> + </div> + </div> + <div class="form-group row"> + <label for="nbMeasurements" class="col-sm-2 col-form-label">Nb Measurements</label> + <div class="col-sm-10"> + <input type="number" class="form-control-number" id="nbMeasurements" value="1"> + </div> + </div> + <div class="form-group row"> + <label for="sequenceDelay" class="col-sm-2 col-form-label">Sequence delay [s]</label> + <div class="col-sm-10"> + <input type="number" class="form-control-number" id="sequenceDelay" value="100"> + </div> + </div> + <div class="form-group row"> + <label for="nbStack" class="col-sm-2 col-form-label">Nb stack</label> + <div class="col-sm-10"> + <input type="number" class="form-control-number" id="nbStack" value="1"> + </div> + </div> + <div class="form-group row"> + <label for="sequence" class="col-sm-2 col-form-label">Sequence</label> + <div class="col-sm-10"> + <input type="file" class="form-control" id="sequence"> + </div> + </div> + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> + <button id="saveConfigBtn" type="button" data-dismiss="modal" class="btn btn-primary">Save</button> + </div> + </div> + </div> + </div> + <button id="restartBtn" type="button" class="btn btn-danger">Restart</button> + <button id="shutdownBtn" type="button" class="btn btn-danger">Shutdown</button> + <footer>v0.2.0</footer> + </div> + + <script type="text/javascript"> + //let serverUrl = 'http://10.3.141.1:8080' + //let serverUrl = 'http://0.0.0.0:8080' + //let serverUrl = 'http://localhost:8080' + let serverUrl = 'http://' + window.location.host + console.log('serverUrl =', serverUrl) + let output = document.getElementById('output') + let data = {} // hold data of all surveys + let interv = null // hold interval for automatic data retrieval + let quads = [] // available quadrupoles for time-serie figure + let squads = [] // selected quadrupoles for time-serie figure + + // useful functions + function sendCommand(query, callback=null) { + // dic in the form: {'command': X, ...} as JSON + if (callback == null) { + function callback(x) { + console.log('default callback:', x) + } + } + let xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function() { + if (this.readyState == 4) { + if (xhr.status == 200) { + callback(JSON.parse(xhr.response)) + } + } + } + xhr.open('POST', serverUrl) + xhr.setRequestHeader('Content-Type', 'application/json') + xhr.send(query) + } + + // start button + function startBtnFunc() { + sendCommand('{"command": "start"}', function(x) { + console.log(x['status']) + if (x['status'] == 'running') { + output.innerHTML = 'Status: measuring...' + } + }) + } + let startBtn = document.getElementById('startBtn') + startBtn.addEventListener('click', startBtnFunc) + + // stop button + function stopBtnFunc() { + sendCommand('{"command": "stop"}', function(x) { + output.innerHTML = 'Status: ' + x['status'] + clearInterval(interv) + getData() + }) + } + let stopBtn = document.getElementById('stopBtn') + stopBtn.addEventListener('click', stopBtnFunc) + + // set configuration + function saveConfigBtnFunc() { + // collect values from modal + let formVals = {} + for (let field of ['nbElectrodes', 'injectionDuration', + 'nbMeasurements', 'sequenceDelay', 'nbStack']) { + formVals[field] = document.getElementById(field).value + } + console.log(formVals) + + // define callback to send settigs to Pi + function configCallback() { + sendCommand(JSON.stringify({ + 'command': 'setConfig', + 'config': formVals + }), function(x) { + console.log('setconfig:', x) + }) + } + + // deal with the potential file containing the sequence + // https://stackoverflow.com/questions/19038919/is-it-possible-to-upload-a-text-file-to-input-in-html-js + if (!window.FileReader) { + alert('Your browser is not supported'); + return false; + } + let input = document.getElementById('sequence') + if (input.files.length) { + const reader = new FileReader() + reader.readAsText(input.files[0]) + reader.addEventListener('load', () => { + formVals['sequence'] = reader.result + console.log('file==', reader.result) + configCallback() + }, false) + } else { + console.log('no sequence uploaded') + formVals['sequence'] = '' + configCallback() + } + + + } + let saveConfigBtn = document.getElementById('saveConfigBtn') + saveConfigBtn.addEventListener('click', saveConfigBtnFunc) + + // make pseudo plot + var trace = { + x: [], + y: [], + mode: 'markers', + marker: { + size: 40, + color: [], + colorbar: { + title: 'App. res. [Ohm.m]', + cmin: 0, + cmax: 100, + } + } + } + let layout = { + title: 'Pseudo-section', + yaxis: { + title: 'Pseudo-depth', + autorange: 'reversed' + }, + xaxis: { + title: 'X' + } + + } + Plotly.newPlot('gd', [trace], layout) + + // make time-serie plot + let tdata = [] + let layout2 = { + title: 'Time-serie', + yaxis: { + title: 'App. res. [Ohm.m]' + }, + xaxis: { + title: 'Sampling time' + } + } + Plotly.newPlot('ts', tdata, layout2) + + // add trace to time-serie plot + function addTraceBtnFunc() { + let val = document.getElementById('quadSelect').value + squads.push(val.split(', ')) + tdata.push({ + x: [], + y: [], + name: val, + type: 'scatter' + }) + Plotly.newPlot('ts', tdata, layout2) + getData() + } + let addTraceBtn = document.getElementById('addTraceBtn') + addTraceBtn.addEventListener('click', addTraceBtnFunc) + + // remove all traces from time-serie plot + function removeTracesBtnFunc() { + squads = [] + tdata = [] + Plotly.newPlot('ts', tdata, layout2) + } + let removeTracesBtn = document.getElementById('removeTracesBtn') + removeTracesBtn.addEventListener('click', removeTracesBtnFunc) + + // callback function to draw the plot + function surveySelectFunc(el) { + let surveyName = el['target'].value + let df = data[surveyName] + if (df != undefined) { + let a = df['a'] + let b = df['b'] + let m = df['m'] + let n = df['n'] + // let's assume electrodes are 1 m distance + // compute pseudo-depth (assume no topo) + // compute app res (assumping flat, line survey) + let xpos = [] + let ypos = [] + let app = [] + for (let i = 0; i < a.length; i++) { + let ab = (a[i] + b[i])/2 + let mn = (m[i] + n[i])/2 + let dist = Math.abs(ab - mn) + xpos.push(Math.min(ab, mn) + dist/2) + ypos.push(Math.sqrt(2)/2*dist) + let am = Math.abs(a[i] - m[i]) + let bm = Math.abs(b[i] - m[i]) + let an = Math.abs(a[i] - n[i]) + let bn = Math.abs(a[i] - n[i]) + let K = (2*Math.PI)/((1/am)-(1/an)-(1/an)+(1/bn)) + app.push(df['rho'][i]*-K) + } + console.log(app) + // update the trace and redraw the figure + trace['x'] = xpos + trace['y'] = ypos + trace['marker']['color'] = app + trace['marker']['cmax'] = document.getElementById('cmax').value + trace['marker']['cmin'] = document.getElementById('cmin').value + Plotly.redraw('gd') + } + } + let surveySelect = document.getElementById('surveySelect') + + // bar chart for contact resistance + let rsdata = [] + let rslayout = { + title: 'Contact resistances', + yaxis: { + title: 'Resistance [kOhm]' + }, + xaxis: { + title: 'Consecutive electrodes' + } + } + Plotly.newPlot('rs', rsdata, rslayout) + + // run RS check + function rsBtnFunc() { + sendCommand('{"command": "rsCheck"}', function (res) { + // update the bar plot + rsdata.push({ + x: res['data']['AB'], + y: res['data']['res'], + name: 'RS', + type: 'bar' + }) + Plotly.redraw('rs') + }) + } + let rsBtn = document.getElementById('rsBtn') + rsBtn.addEventListener('click', rsBtnFunc) + + // clear RS graph + function rsClearBtnFunc() { + rsdata = [] + Plotly.newPlot('rs', rsdata, rslayout) + } + let rsClearBtn = document.getElementById('rsClearBtn') + rsClearBtn.addEventListener('click', rsClearBtnFunc) + + // getData + function getData() { + sendCommand(JSON.stringify({ + 'command': 'getData', + 'surveyNames': Object.keys(data).slice(0, -1) + // last survey is often partial so we download it again + }), function(ddic) { + // update status + output.innerHTML = 'Status: ' + ddic['status'] + + // update data dic with new data + data = { // destructuring assignement (magic! :o) + ...data, + ...ddic['data'] // value from second dic are preferred + } + + // dropdown with number of surveys and +++ + let surveyNames = Object.keys(data).sort() + + // remove listener as we will replace the choices + surveySelect.removeEventListener('change', surveySelectFunc) + surveySelect.innerHTML = '' // clearing all child nodes + + // add choices again + for (let surveyName of surveyNames) { + let option = document.createElement('option') + option.innerText = surveyName + option.value = surveyName + surveySelect.appendChild(option) + } + + // listener again + surveySelect.addEventListener('change', surveySelectFunc) + + // plot last one by default + surveySelect.value = surveyNames[surveyNames.length - 1] + + // call the function directly + // (as progammatically chaging the value does not trigger the event) + surveySelectFunc({'target': surveySelect}) + + // update list of quadrupoles if any + if (quads.length == 0) { + console.log('updating list of quadrupoles') + let df = data[surveyNames[0]] + let quadSelect = document.getElementById('quadSelect') + quadSelect.innerHTML = '' + for (let i = 0; i < df['a'].length; i++) { + quad = [df['a'][i], df['b'][i], df['m'][i], df['n'][i]] + quads.push(quad) + let option = document.createElement('option') + option.value = quad.join(', ') + option.innerText = quad.join(', ') + quadSelect.appendChild(option) + } + console.log('quads=', quads) + } + + // update time-serie figure + if (squads.length > 0) { + + // transform all surveyNames to datetime + let xt = [] + for (surveyName of surveyNames) { + let a = surveyName.split('_').slice(-1)[0] + xt.push(a.slice(0, 4) + '-' + + a.slice(4, 6) + '-' + + a.slice(6, 8) + ' ' + + a.slice(9, 11) + ':' + + a.slice(11, 13) + ':' + + a.slice(13, 15)) + } + //console.log(xt) + + // create one new trace per selected quadrupole + for (let k = 0; k < squads.length; k++) { + squad = squads[k] + let x = [] + let y = [] + for (let i = 0; i < surveyNames.length; i++) { + df = data[surveyNames[i]] + for (let j = 0; j < df['a'].length; j++) { + if (df['a'][j] == squad[0] + && df['b'][j] == squad[1] + && df['m'][j] == squad[2] + && df['n'][j] == squad[3]) { + y.push(df['rho'][j]) + x.push(xt[i]) + break + } + } + } + + // update trace dictionnary + tdata[k]['x'] = x + tdata[k]['y'] = y + } + //console.log(tdata) + Plotly.redraw('ts') + } + }) + } + let getDataBtn = document.getElementById('getDataBtn') + getDataBtn.addEventListener('click', getData) + + // apply new colorscale + let capplyBtn = document.getElementById('capplyBtn') + capplyBtn.addEventListener('click', function() { + surveySelectFunc({'target': surveySelect}) + }) + + // checkbox interaction for data download + function dataRetrievalCheckFunc(x) { + if (x['target'].checked == true) { + interv = setInterval(getData, 1000) // every 5s + } else { + clearInterval(interv) + } + } + let dataRetrievalCheck = document.getElementById('dataRetrievalCheck') + dataRetrievalCheck.addEventListener('change', dataRetrievalCheckFunc) + + // remove data + function removeDataBtnFunc() { + sendCommand('{"command": "removeData"}',function(x) { + data = {} + output.innerHTML = 'Status: ' + x['status'] + ' (all data cleared)' + console.log('all data removed') + }) + } + let removeDataBtn = document.getElementById('removeDataBtn') + removeDataBtn.addEventListener('click', removeDataBtnFunc) + + // shutdown Pi + function shutdownBtnFunc() { + sendCommand('{"command": "shutdown"}', function(x) { + console.log('shuting down...') + }) + } + let shutdownBtn = document.getElementById('shutdownBtn') + shutdownBtn.addEventListener('click', shutdownBtnFunc) + + // restart Pi + function restartBtnFunc() { + sendCommand('{"command": "restart"}', function(x) { + console.log('rebooting...') + }) + } + let restartBtn = document.getElementById('restartBtn') + restartBtn.addEventListener('click', restartBtnFunc) + + // invert data + // function invertBtnFunc() { + // sendCommand('{"command": "invert"}', function(x) { + // console.log('inversion results', x) + // }) + // } + // let invertBtn = document.getElementById('invertBtn') + // invertBtn.addEventListener('click', invertBtnFunc) + + // download data + function downloadBtnFunc() { + sendCommand('{"command": "download"}', function(x) { + let dwl = document.getElementById('download') + dwl.setAttribute('href', serverUrl + '/data.zip') + dwl.setAttribute('download', 'data.zip') + dwl.click() + }) + } + let downloadBtn = document.getElementById('downloadBtn') + downloadBtn.addEventListener('click', downloadBtnFunc) + + + </script> + + <!-- Boostrap scripts (at the end of the page for faster loading time)--> + <script src="js/bootstrap.bundle.min.js"></script> + <!-- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js" integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf" crossorigin="anonymous"></script> --> +</body> +</html> diff --git a/install_local_mqtt_broker.sh b/install_local_mqtt_broker.sh old mode 100644 new mode 100755 diff --git a/ohmpi.py b/ohmpi.py index 90efae8c30537fd6bdd2ade0c40530a0988306e2..cbbb3fcd3fe3e3326a9a241fcf6c451ce3a1e63d 100644 --- a/ohmpi.py +++ b/ohmpi.py @@ -120,7 +120,7 @@ class OhmPi(object): - injection_duration (in seconds) - nbr_meas (total number of times the sequence will be run) - sequence_delay (delay in second between each sequence run) - - stack (number of stack for each quadrupole measurement) + - nb_stack (number of stack for each quadrupole measurement) - export_path (path where to export the data, timestamp will be added to filename) Parameters @@ -379,7 +379,7 @@ class OhmPi(object): # TODO here we can add the current_injected or voltage_injected in mA or mV # check arguments if nb_stack is None: - nb_stack = self.pardict['stack'] + nb_stack = self.pardict['nb_stack'] if injection_duration is None: injection_duration = self.pardict['injection_duration'] @@ -414,8 +414,7 @@ class OhmPi(object): gain_voltage = self.gain_auto(AnalogIn(self.ads_voltage, ads.P0, ads.P1)) pin0.value = False pin1.value = False - print(gain_current) - print(gain_voltage) + print('gain current: {:.3f}, gain voltage: {:.3f}'.format(gain_current, gain_voltage)) self.ads_current = ads.ADS1115(self.i2c, gain=gain_current, data_rate=860, address=0x48) self.ads_voltage = ads.ADS1115(self.i2c, gain=gain_voltage, data_rate=860, address=0x49) @@ -469,20 +468,20 @@ class OhmPi(object): # create a dictionary and compute averaged values from all stacks d = { - "time": [datetime.now().isoformat()], + "time": datetime.now().isoformat(), "A": quad[0], "B": quad[1], "M": quad[2], "N": quad[3], "inj time [ms]": (end_delay - start_delay) * 1000, - "Vmn [mV]": [(sum_vmn / (3 + 2 * nb_stack - 1))], - "I [mA]": [(injection_current / (3 + 2 * nb_stack - 1))], - "R [ohm]": [(sum_vmn / (3 + 2 * nb_stack - 1) / (injection_current / (3 + 2 * nb_stack - 1)))], - "Ps [mV]": [(sum_ps / (3 + 2 * nb_stack - 1))], - "nbStack": [nb_stack], - "CPU temp [degC]": [CPUTemperature().temperature], - "Time [s]": [(-start_time + time.time())], - "Nb samples [-]": [self.nb_samples] + "Vmn [mV]": (sum_vmn / (3 + 2 * nb_stack - 1)), + "I [mA]": (injection_current / (3 + 2 * nb_stack - 1)), + "R [ohm]": (sum_vmn / (3 + 2 * nb_stack - 1) / (injection_current / (3 + 2 * nb_stack - 1))), + "Ps [mV]": (sum_ps / (3 + 2 * nb_stack - 1)), + "nbStack": nb_stack, + "CPU temp [degC]": CPUTemperature().temperature, + "Time [s]": (-start_time + time.time()), + "Nb samples [-]": self.nb_samples } # round number to two decimal for nicer string output @@ -504,18 +503,45 @@ class OhmPi(object): """ Check contact resistance. """ # create custom sequence where MN == AB - nelec = self.sequence.max() # number of elec used in the sequence + # we only check the electrodes which are in the sequence (not all might be connected) + elec = np.sort(np.unique(self.sequence.flatten())) # assumed order quads = np.vstack([ - np.arange(nelec - 1) + 1, - np.arange(nelec - 1) + 2, - np.arange(nelec - 1) + 1, - np.arange(nelec - 1) + 2 + elec[:-1], + elec[1:], + elec[:-1], + elec[1:], ]).T + + # create filename to store RS + export_path_rs = self.pardict['export_path'].replace('.csv', '') \ + + '_' + datetime.now().strftime('%Y%m%dT%H%M%S') + '_rs.csv' + # perform RS check + self.run = True + self.status = 'running' + + # make sure all mux are off to start with + self.reset_mux() + + # measure all quad of the RS sequence for i in range(0, quads.shape[0]): quad = quads[i, :] # quadrupole - self.reset_mux() - self.switch_mux_on(quad) + + # NOTE (GB): I'd use the self.run_measurement() for all this middle part so we an make use of autogain and so ... + # call the switch_mux function to switch to the right electrodes + #self.switch_mux_on(quad) + + # run a measurement + #current_measurement = self.run_measurement(quad, 1, 0.25) + + # switch mux off + #self.switch_mux_off(quad) + + # save data and print in a text file + #self.append_and_save(export_path_rs, current_measurement) + + + # current injection pin0 = self.mcp.get_pin(0) pin0.direction = Direction.OUTPUT pin1 = self.mcp.get_pin(1) @@ -523,40 +549,51 @@ class OhmPi(object): pin0.value = False pin1.value = False - print(quad) # call the switch_mux function to switch to the right electrodes + self.switch_mux_on(quad) self.ads_current = ads.ADS1115(self.i2c, gain=2 / 3, data_rate=860, address=0x48) # ADS1115 for voltage measurement (MN) self.ads_voltage = ads.ADS1115(self.i2c, gain=2 / 3, data_rate=860, address=0x49) - pin1.value = True + pin1.value = True # inject from pin1 to pin0 pin0.value = False time.sleep(0.2) + + # measure current and voltage current = AnalogIn(self.ads_current, ads.P0).voltage / (50 * self.r_shunt) voltage = -AnalogIn(self.ads_voltage, ads.P0, ads.P1).voltage * 2.5 resistance = voltage / current - # print(B) - # print(A) - print(abs(round(resistance / 1000, 1)), "kOhm") + + # compute resistance measured (= contact resistance) + resist = abs(resistance / 1000) + msg = 'Contact resistance {:s}: {:.3f} kOhm'.format( + str(quad), resist) + print(msg) + self.exec_logger.debug(msg) + + + # if contact resistance = 0 -> we have a short circuit!! + if resist < 1e-5: + msg = '!!!SHORT CIRCUIT!!! {:s}: {:.3f} kOhm'.format( + str(quad), resist) + self.exec_logger.warning(msg) + print(msg) + + # save data and print in a text file + self.append_and_save(export_path_rs, { + 'A': quad[0], + 'B': quad[1], + 'RS [kOhm]': resist, + }) + + # close mux path and put pin back to GND self.switch_mux_off(quad) pin0.value = False pin1.value = False + + self.reset_mux() + self.status = 'idle' + self.run = False - # # create backup TODO not good - # export_path = self.pardict['export_path'] - # sequence = self.sequence.copy() - # - # # assign new value - # self.pardict['export_path'] = export_path.replace('.csv', '_rs.csv') - # self.sequence = quads - # print(self.sequence) - # - # # run the RS check - # self.log_exec('RS check (check contact resistance)', level='debug') - # self.measure() - # - # # restore - # self.pardict['export_path'] = export_path - # self.sequence = sequence # # # TODO if interrupted, we would need to restore the values # # TODO or we offer the possiblity in 'run_measurement' to have rs_check each time? @@ -620,7 +657,7 @@ class OhmPi(object): # run a measurement if self.on_pi: - current_measurement = self.run_measurement(quad, self.pardict["stack"], + current_measurement = self.run_measurement(quad, self.pardict["nb_stack"], self.pardict["injection_duration"]) else: # for testing, generate random data current_measurement = { @@ -682,7 +719,7 @@ if on_pi: # and emit a warning otherwise if not arm64_imports: print(colored(f'Warning: Required packages are missing.\n' - f'Please run . env.sh at command prompt to update your virtual environment\n', 'yellow')) + f'Please run ./env.sh at command prompt to update your virtual environment\n', 'yellow')) else: print(colored(f'Not running on the Raspberry Pi platform.\nFor simulation purposes only...', 'yellow')) diff --git a/ohmpi_param.json b/ohmpi_param.json index 7071487a858d80f5fa2bec82abde9eec12c3a328..c2c68558a80f39841ea5d17858a2900ca4f9d454 100644 --- a/ohmpi_param.json +++ b/ohmpi_param.json @@ -3,6 +3,6 @@ "injection_duration":0.2, "nbr_meas": 100, "sequence_delay": 1, - "stack": 1, + "nb_stack": 1, "export_path": "data/measurement.csv" } diff --git a/run.sh b/run.sh old mode 100644 new mode 100755 index 61eb5c72bd2127c03a2529bde5a92e34b49bdc98..76b58dca433be66edff7bd1c39cb4323939ede9a --- a/run.sh +++ b/run.sh @@ -1,2 +1,2 @@ source ./ohmpy/bin/activate -python3 webserver.py +python webserver.py diff --git a/runOnStart.sh b/runOnStart.sh new file mode 100755 index 0000000000000000000000000000000000000000..801ecbaa9986b26597ce0e4facb98326cf3e5225 --- /dev/null +++ b/runOnStart.sh @@ -0,0 +1,2 @@ +echo "# start OhmPi web interface" >> $HOME/.bashrc +echo "(cd $HOME/OhmPi; ./run.sh)" >> $HOME/.bashrc diff --git a/webserver.py b/webserver.py index f2f85f596ab86e90f2676ec87167a7a4eaedef02..8171a5a93a08b45a3b265488e4c334778d0cc98b 100644 --- a/webserver.py +++ b/webserver.py @@ -1,99 +1,123 @@ -from http.server import SimpleHTTPRequestHandler, HTTPServer -# import time -import os -import json -from ohmpi import OhmPi -# import threading -import pandas as pd -import shutil - -hostName = 'localhost' -serverPort = 8080 - -# https://gist.github.com/MichaelCurrie/19394abc19abd0de4473b595c0e37a3a - -with open('ohmpi_param.json') as json_file: - pardict = json.load(json_file) - -ohmpi = OhmPi(pardict) - - -class MyServer(SimpleHTTPRequestHandler): - # because we use SimpleHTTPRequestHandler, we do not need to implement - # the do_GET() method (if we use the BaseHTTPRequestHandler, we would need to) - - # def do_GET(self): - # # normal get for wepages (not so secure!) - # print(self.command) - # print(self.headers) - # print(self.request) - # self.send_response(200) - # self.send_header("Content-type", "text/html") - # self.end_headers() - # with open(os.path.join('.', self.path[1:]), 'r') as f: - # self.wfile.write(bytes(f.read(), "utf-8")) - - def do_POST(self): - # global ohmpiThread, status, run - - dic = json.loads(self.rfile.read(int(self.headers['Content-Length']))) - rdic = {} - if dic['command'] == 'start': - ohmpi.measure() - elif dic['command'] == 'stop': - ohmpi.stop() - elif dic['command'] == 'getData': - # get all .csv file in data folder - fnames = os.listdir('data/') - ddic = {} - for fname in fnames: - if fname.replace('.csv', '') not in dic['surveyNames'] and fname != 'readme.txt': - df = pd.read_csv('data/' + fname) - ddic[fname.replace('.csv', '')] = { - 'a': df['A'].tolist(), - 'b': df['B'].tolist(), - 'm': df['M'].tolist(), - 'n': df['N'].tolist(), - 'rho': df['R [ohm]'].tolist(), - } - rdic['data'] = ddic - elif dic['command'] == 'removeData': - shutil.rmtree('data') - os.mkdir('data') - elif dic['command'] == 'setConfig': - ohmpi.stop() - cdic = dic['config'] - ohmpi.pardict['nb_electrodes'] = int(cdic['nbElectrodes']) - ohmpi.pardict['injection_duration'] = float(cdic['injectionDuration']) - ohmpi.pardict['nbr_meas'] = int(cdic['nbMeasurements']) - ohmpi.pardict['stack'] = int(cdic['nbStack']) - ohmpi.pardict['sequence_delay'] = int(cdic['sequenceDelay']) - print('setConfig', ohmpi.pardict) - elif dic['command'] == 'invert': - pass - elif dic['command'] == 'getResults': - pass - elif dic['command'] == 'download': - shutil.make_archive('data', 'zip', 'data') - else: - # command not found - rdic['response'] = 'command not found' - - rdic['status'] = ohmpi.status - self.send_response(200) - self.send_header('Content-Type', 'text/json') - self.end_headers() - self.wfile.write(bytes(json.dumps(rdic), 'utf8')) - - -if __name__ == "__main__": - webServer = HTTPServer((hostName, serverPort), MyServer) - print("Server started http://%s:%s" % (hostName, serverPort)) - - try: - webServer.serve_forever() - except KeyboardInterrupt: - pass - - webServer.server_close() - print("Server stopped.") +from http.server import SimpleHTTPRequestHandler, HTTPServer +import time +import os +import json +from ohmpi import OhmPi +import threading +import pandas as pd +import shutil + +hostName = "raspberrypi.local" # works for AP-STA +#hostName = "192.168.50.1" # fixed IP in AP-STA mode +#hostName = "0.0.0.0" # for AP mode (not AP-STA) +serverPort = 8080 + +# https://gist.github.com/MichaelCurrie/19394abc19abd0de4473b595c0e37a3a + +with open('ohmpi_param.json') as json_file: + pardict = json.load(json_file) + +ohmpi = OhmPi(pardict, sequence='breadboard.txt') +#ohmpi = OhmPi(pardict, sequence='dd16s0no8.txt') + + +class MyServer(SimpleHTTPRequestHandler): + # because we use SimpleHTTPRequestHandler, we do not need to implement + # the do_GET() method (if we use the BaseHTTPRequestHandler, we would need to) + + # def do_GET(self): + # # normal get for wepages (not so secure!) + # print(self.command) + # print(self.headers) + # print(self.request) + # self.send_response(200) + # self.send_header("Content-type", "text/html") + # self.end_headers() + # with open(os.path.join('.', self.path[1:]), 'r') as f: + # self.wfile.write(bytes(f.read(), "utf-8")) + + def do_POST(self): + global ohmpiThread, status, run + dic = json.loads(self.rfile.read(int(self.headers['Content-Length']))) + rdic = {} + if dic['command'] == 'start': + ohmpi.measure() + elif dic['command'] == 'stop': + ohmpi.stop() + elif dic['command'] == 'getData': + # get all .csv file in data folder + fnames = [fname for fname in os.listdir('data/') if fname[-4:] == '.csv'] + ddic = {} + for fname in fnames: + if (fname.replace('.csv', '') not in dic['surveyNames'] + and fname != 'readme.txt' + and '_rs' not in fname): + df = pd.read_csv('data/' + fname) + ddic[fname.replace('.csv', '')] = { + 'a': df['A'].tolist(), + 'b': df['B'].tolist(), + 'm': df['M'].tolist(), + 'n': df['N'].tolist(), + 'rho': df['R [ohm]'].tolist(), + } + rdic['data'] = ddic + elif dic['command'] == 'removeData': + shutil.rmtree('data') + os.mkdir('data') + elif dic['command'] == 'setConfig': + ohmpi.stop() + cdic = dic['config'] + ohmpi.pardict['nb_electrodes'] = int(cdic['nbElectrodes']) + ohmpi.pardict['injection_duration'] = float(cdic['injectionDuration']) + ohmpi.pardict['nbr_meas'] = int(cdic['nbMeasurements']) + ohmpi.pardict['nb_stack'] = int(cdic['nbStack']) + ohmpi.pardict['sequence_delay'] = int(cdic['sequenceDelay']) + if cdic['sequence'] != '': + with open('sequence.txt', 'w') as f: + f.write(cdic['sequence']) + ohmpi.read_quad('sequence.txt') + print('new sequence set.') + print('setConfig', ohmpi.pardict) + elif dic['command'] == 'invert': + pass + elif dic['command'] == 'getResults': + pass + elif dic['command'] == 'rsCheck': + ohmpi.rs_check() + fnames = sorted([fname for fname in os.listdir('data/') if fname[-7:] == '_rs.csv']) + df = pd.read_csv('data/' + fnames[-1]) + ddic = { + 'AB': (df['A'].astype('str') + '-' + df['B'].astype(str)).tolist(), + 'res': df['RS [kOhm]'].tolist() + } + rdic['data'] = ddic + elif dic['command'] == 'download': + shutil.make_archive('data', 'zip', 'data') + elif dic['command'] == 'shutdown': + print('shutting down...') + os.system('shutdown now -h') + elif dic['command'] == 'restart': + print('shutting down...') + os.system('reboot') + else: + # command not found + rdic['response'] = 'command not found' + + rdic['status'] = ohmpi.status + self.send_response(200) + self.send_header('Content-Type', 'text/json') + self.end_headers() + self.wfile.write(bytes(json.dumps(rdic), 'utf8')) + + +if __name__ == "__main__": + webServer = HTTPServer((hostName, serverPort), MyServer) + print("Server started http://%s:%s" % (hostName, serverPort)) + + try: + webServer.serve_forever() + except KeyboardInterrupt: + pass + + webServer.server_close() + print("Server stopped.")