{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "911f65de-cee5-4218-b508-5ab1063fdc3a",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-05-12 at 14:39:29 | INFO | Loading started.\n",
      "2025-05-12 at 14:39:29 | WARNING | Cannot write log file to snapshots.\n",
      "2025-05-12 at 14:39:29 | WARNING | [Errno 13] Permission denied: '/sf/cristallina/applications/beamline/snapshots/slic_logs/cristallina.log'\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/gfa/.mounts/sf_cristallina/applications/slic/cristallina\n",
      "\u001b]0;⊚slic\u0007could not set up DBusNotify: org.freedesktop.DBus.Error.NotSupported: Using X11 for dbus-daemon autolaunch was disabled at compile time, set your DBUS_SESSION_BUS_ADDRESS instead\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-05-12 at 14:39:35 | WARNING | No transmission value reported from SARFE10-OATT053\n",
      "2025-05-12 at 14:39:35 | WARNING | No transmission value reported from SAROP31-OATA150\n",
      "2025-05-12 at 14:39:36 | INFO | Using undulator (Aramis) offset to PSSS energy of 0 eV.\n",
      "2025-05-12 at 14:39:36 | INFO | Photon energy offsets: PSSS -8 eV , DCCM -12 eV, undulator -16 eV.\n",
      "2025-05-12 at 14:39:36 | WARNING | Error: Could not connect to dilution fridge. name 'Dilution' is not defined\n",
      "2025-05-12 at 14:39:36 | INFO | Connected to stand server\n",
      "2025-05-12 at 14:39:36 | WARNING | Cannot write log file to pgroup p22478.\n",
      "2025-05-12 at 14:39:36 | INFO | Using CristallinaQ setup for detectors.\n",
      "2025-05-12 at 14:39:36 | INFO | Running at cristallina with pgroup p22478. Experiment type: Q.\n",
      "2025-05-12 at 14:39:36 | INFO | Loading finished.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "SAT functions\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "sys.path.append('/sf/cristallina/applications/slic/cristallina/crq_exp/')\n",
    "from tqdm.notebook import tqdm\n",
    "%cd /sf/cristallina/applications/slic/cristallina\n",
    "%run /sf/cristallina/applications/slic/cristallina/cristallina.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "0e264fea-8070-4173-bd1b-2e86ea783386",
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "import os\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import smaract.smarpod as smarpod\n",
    "from smaract.smarpod import Pose as Pose"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "564f383e-a516-4160-b446-0bae514e62dd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "api version = 1.9.20\n",
      "lib version = 1.11.4\n",
      "device opened successfully\n",
      "referencing...\n",
      "movement status = 1 (1)\n",
      "movement status = 0 (0)\n",
      "pose = 9.53363734703935e-10,-4.3032376366873044e-10,-0.0016776778132903925,-9.549834512512486e-07,-3.8592949236139845e-06,7.816448044732403\n"
     ]
    }
   ],
   "source": [
    "def check_lib_compatibility():\n",
    "    \"\"\"\n",
    "    checks that the major version numbers of the Python API and the\n",
    "    loaded shared library are the same to avoid errors due to \n",
    "    incompatibilites.\n",
    "    raises a RuntimeError if the major version numbers are different.\n",
    "    \"\"\"\n",
    "    vapi = smarpod.api_version\n",
    "    vlib = smarpod.GetDLLVersion()\n",
    "    if vapi[0] != vlib[0]:\n",
    "        raise RuntimeError(\"incompatible python api and library version\")    \n",
    "\n",
    "def print_info():\n",
    "    vapi = smarpod.api_version\n",
    "    print(\"api version = %s.%s.%s\" % (vapi[0], vapi[1], vapi[2]))\n",
    "    vlib = smarpod.GetDLLVersion()\n",
    "    print(\"lib version = %s.%s.%s\" % (vlib[0], vlib[1], vlib[2]))\n",
    "\n",
    "def print_controllers():\n",
    "    syslist = smarpod.FindSystems().splitlines()\n",
    "    for sys in syslist:\n",
    "        print(\"controllers found:\\n%s\\n\" % sys)    \n",
    "\n",
    "def pose_to_str(pose):\n",
    "    return \"%s,%s,%s,%s,%s,%s\" %  (\n",
    "        pose.positionX, pose.positionY, pose.positionZ,\n",
    "        pose.rotationX, pose.rotationY, pose.rotationZ)\n",
    "\n",
    "def pose_print(pose):\n",
    "    p = pose_to_str(pose)\n",
    "    print(f'X={pose.positionX:.3e}\\nY={pose.positionY:.3e}\\nZ={pose.positionZ:.3e}\\nRX={pose.rotationX:.3e}\\nRY={pose.rotationY:.3e}\\nRZ={pose.rotationZ:.3e}')\n",
    "          \n",
    "def check_pose_list(h,list):\n",
    "    \"\"\"\n",
    "    returns True if all poses in list are reachable\n",
    "    \"\"\"\n",
    "    for pose in list:\n",
    "        if not smarpod.IsPoseReachable(h,pose):\n",
    "            return False\n",
    "    return True\n",
    "\n",
    "def move_sequence(h,seq):\n",
    "    \"\"\"\n",
    "    moves to each pose in the list seq\n",
    "    \"\"\"\n",
    "    for pose in seq:\n",
    "        print(\"moving to %s\" % pose_to_str(pose))\n",
    "        smarpod.Move(h,pose,0,True)\n",
    "\n",
    "\n",
    "h = None    # SmarPod device handle\n",
    "try:\n",
    "    check_lib_compatibility()\n",
    "    print_info()\n",
    "\n",
    "    # change model to the model code of your SmarPod model code before\n",
    "    # starting the program\n",
    "    model = 10068\n",
    "\n",
    "\n",
    "    # uncomment the following line to show available controllers\n",
    "    #print_controllers()\n",
    "    \n",
    "    # change the locator of your positioner controller: if it is connected\n",
    "    # over USB, \"usb:ix:0\" should work. If if it connected over ethernet,\n",
    "    # use the network locator format and replace the ip address by the one\n",
    "    # of your controller. (for MCS 1 controllers append the port number\n",
    "    # :5000, for MCS 2 controllers, when specifying the locator with an IPv4 \n",
    "    # address, no port should be appended. alternatively, for MCS 2 the\n",
    "    # serial number can be used in the locator)\n",
    "    locator = 'network:MCS2-00002749'\n",
    "    #locator = \"usb:id:123456789\"               # MCS 1\n",
    "    #locator = \"network:198.168.1.200:5000\"     # MCS 1\n",
    "    #locator = \"network:ip:198.168.1.200\"       # MCS 2\n",
    "    #locator = \"network:sn:MCS2-000001234\"      # MCS 2\n",
    "\n",
    "    # set to True to perform a calibration of the positioner sensors\n",
    "    do_calibrate = False\n",
    "    # the sensor power mode to set\n",
    "    sensor_mode = smarpod.SensorPowerMode.ENABLED\n",
    "\n",
    "    # enable z-safe ref method to prefer z-negative direction\n",
    "    # (this will fail with a FEATURE_UNAVAILABLE error if the SmarPod model \n",
    "    #  doesn't support the selected method)\n",
    "    ref_zsafe = False\n",
    "    # perform a referencing even if SmarPod is already the referenced state\n",
    "    force_referencing = False\n",
    "\n",
    "    \n",
    "    # open the connection to the SmarPod device.\n",
    "    # on success, a handle is returned, else an execption is thrown\n",
    "    # if Open raises an exception with ErrorCode.SYSTEM_CONFIGURATION\n",
    "    # the model code and the controller configuration don't match.\n",
    "    h = smarpod.Open(model, locator)\n",
    "    print(\"device opened successfully\")\n",
    "\n",
    "    # set the frequency used for referencing and calibration\n",
    "    smarpod.Set_ui(h, smarpod.Property.FREF_AND_CAL_FREQUENCY, 8000)\n",
    "\n",
    "    # if do_calibrate is True, perform calibration\n",
    "    if do_calibrate:\n",
    "        print(\"calibrating...\")\n",
    "        smarpod.Calibrate(h)\n",
    "\n",
    "    # if not referenced, perform referencing\n",
    "    do_referencing = force_referencing or not smarpod.IsReferenced(h)\n",
    "    if do_referencing:\n",
    "        # set referencing method and parameters\n",
    "        if (ref_zsafe):\n",
    "            smarpod.Set_ui(h, smarpod.Property.FREF_METHOD, smarpod.FrefMethod.ZSAFE)\n",
    "            smarpod.Set_ui(h, smarpod.Property.FREF_ZDIRECTION, smarpod.Direction.NEGATIVE)\n",
    "        else:\n",
    "            smarpod.Set_ui(h, smarpod.Property.FREF_METHOD, smarpod.DEFAULT)\n",
    "        print(\"referencing...\")\n",
    "        smarpod.FindReferenceMarks(h)\n",
    "\n",
    "    smarpod.SetSensorMode(h, sensor_mode)\n",
    "\n",
    "    mstat = smarpod.GetMoveStatus(h)\n",
    "    print(\"movement status = %s (%s)\" % (smarpod.MoveStatus(mstat), mstat))\n",
    "\n",
    "    smarpod.Stop(h)\n",
    "\n",
    "    mstat = smarpod.GetMoveStatus(h)\n",
    "    print(\"movement status = %s (%s)\" % (smarpod.MoveStatus(mstat), mstat))\n",
    "\n",
    "\n",
    "    # move sequence of poses\n",
    "\n",
    "    # set speed and maximum closed-loop piezo frequency\n",
    "    smarpod.SetSpeed(h, 1, 3e-3)\n",
    "    smarpod.SetMaxFrequency(h, 18500)\n",
    "\n",
    "    # pivot point should move with the top plate: set to RELATIVE mode\n",
    "    smarpod.Set_ui(h, smarpod.Property.PIVOT_MODE, smarpod.PivotMode.RELATIVE)\n",
    "    # set pivot point\n",
    "    smarpod.SetPivot(h,[0,0,20e-3])\n",
    "\n",
    "    pHome = Pose(0, 0, 0, 0, 0, 0)\n",
    "    pSequence = [\n",
    "            pHome,\n",
    "            Pose(0, 0, 0.002, 0, 0, 0),\n",
    "            Pose(0, 0, -0.002, 0, 0, 0),\n",
    "            Pose(-0.002, 0, 0, 0, 0, 0),\n",
    "            Pose(-0.002, -0.002, 0, 0, 0, 0),\n",
    "            Pose(0.002, 0.002, 0, 0, 0, 0),\n",
    "            Pose(0, 0, 0, 0, 0, -5),\n",
    "            Pose(0, 0, 0, -0.02, 0, 5),\n",
    "            pHome\n",
    "            ]\n",
    "\n",
    "    if not check_pose_list(h,pSequence):\n",
    "        raise Exception(\"not all poses in sequence are reachable\")\n",
    "\n",
    "    # if all poses are reachable, move the sequence of poses\n",
    "    #move_sequence(h,pSequence)\n",
    "\n",
    "    # query current pose (should be close to pHome)\n",
    "    pose = smarpod.GetPose(h)\n",
    "    print(\"pose = %s\" % pose_to_str(pose))\n",
    "\n",
    "except smarpod.Error as err:\n",
    "    print(\"SMARPOD ERROR: %s -> %s (%s) \" % (err.func, smarpod.ErrorCode(err.code), err.code))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "228d8308-11d5-4af7-bac7-250e02d81e82",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X=-4.226e-10\n",
      "Y=2.440e-10\n",
      "Z=1.155e-09\n",
      "RX=9.547e-07\n",
      "RY=1.654e-06\n",
      "RZ=-5.730e-06\n"
     ]
    }
   ],
   "source": [
    "smarpod.Move(h,Pose(0, 0, 0, 0, 0, 0),100,True)\n",
    "pose = smarpod.GetPose(h)\n",
    "pose_print(pose)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "7ed3d2c9-f918-4725-9dda-191e8bb17884",
   "metadata": {},
   "outputs": [],
   "source": [
    "def pose_to_str(pose):\n",
    "    return \"%s,%s,%s,%s,%s,%s\" %  (\n",
    "        pose.positionX, pose.positionY, pose.positionZ,\n",
    "        pose.rotationX, pose.rotationY, pose.rotationZ)\n",
    "\n",
    "def pose_to_array(pose):\n",
    "    return np.asarray([pose.positionX, pose.positionY, pose.positionZ,\n",
    "        pose.rotationX, pose.rotationY, pose.rotationZ])\n",
    "\n",
    "def array_to_pose(arr):\n",
    "    arr = np.asarray(arr)\n",
    "    shape = len(arr.shape)\n",
    "    assert shape <3, KeyError('Your array needs to be 2D max')\n",
    "    if shape == 1: \n",
    "        return Pose(*arr)\n",
    "    else:\n",
    "        poses = []\n",
    "        for i in range(arr.shape[0]):\n",
    "            poses.append(Pose(*arr[i,:]))\n",
    "        return poses\n",
    "\n",
    "def make_positions(base_array, index,new_values):\n",
    "    result = np.tile(base_array, (len(new_values),1)).astype('float64')\n",
    "    result[:,index] = new_values\n",
    "    return result\n",
    "\n",
    "def convert_results_to_pandas(readbacks,times,timestrings):\n",
    "    d = pd.DataFrame({'Time':timestrings,\n",
    "                      'X (m)':readbacks[:,0],\n",
    "                      'Y (m)':readbacks[:,1],\n",
    "                      'Z (m)':readbacks[:,2],\n",
    "                      'RX (deg)':readbacks[:,3],\n",
    "                      'RY (deg)':readbacks[:,4],\n",
    "                      'RZ (deg)':readbacks[:,5],\n",
    "                      'Epoch time':times\n",
    "                    })\n",
    "    return d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "164d4bf4-5eac-4681-904f-e3e8f4d44b7b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def move_around_current_pose(pose,axis_index,movement_array,hold_time=1000,folder=None,filename=None,press_to_continue=True):\n",
    "    assert (type(axis_index) == int) & (axis_index>=0) & (axis_index<6), KeyError('Axis index must be an int between 0 and 5 (e.g. RX=3)')\n",
    "    pose_beg = pose_to_array(pose)\n",
    "    positions = make_positions(pose_beg, axis_index, movement_array)\n",
    "    poses = array_to_pose(positions) \n",
    "    readbacks,times,timestrings = [], [],[]\n",
    "    for i,pos in enumerate(poses):\n",
    "        print(f'Step {i}: Go to position {pose_to_str(pos)}')\n",
    "        if press_to_continue:\n",
    "            input('Press any key to continue')\n",
    "        smarpod.Move(h,pos,hold_time,True)\n",
    "        readbacks.append(pose_to_array( smarpod.GetPose(h) ))\n",
    "        times.append(time.time())\n",
    "        timestrings.append(time.strftime('%Y-%m-%d %H:%M:%S'))\n",
    "    results = convert_results_to_pandas(np.asarray(readbacks),times,timestrings)\n",
    "    if folder:\n",
    "        if filename == None:\n",
    "            filename = f'{time.strftime(\"%Y%m%d_%H%M%S\")}_axis={axis_index}.csv'\n",
    "        else:\n",
    "            filename=filename+'.csv'\n",
    "        filepath=os.path.join(folder,filename)\n",
    "        results.to_csv(filepath)\n",
    "    return results\n",
    "        \n",
    "#res = move_around_current_pose(smarpod.GetPose(h),5,[-5,0,5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "b2e7239e-ae18-4f04-b3d0-15d6251bda66",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #000080; text-decoration-color: #000080\">╭─ daq.acquire = &lt;bound method SFAcquisition.acquire of SF DAQ (status: idle, last run: None) BrokerAPI @ http://─╮</span>\n",
       "<span style=\"color: #000080; text-decoration-color: #000080\">│</span> <span style=\"color: #00ffff; text-decoration-color: #00ffff; font-style: italic\">def </span><span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">SFAcquisition.acquire</span><span style=\"font-weight: bold\">(</span>filename, <span style=\"color: #808000; text-decoration-color: #808000\">data_base_dir</span>=<span style=\"color: #800080; text-decoration-color: #800080; font-style: italic\">None</span>, <span style=\"color: #808000; text-decoration-color: #808000\">detectors</span>=<span style=\"color: #800080; text-decoration-color: #800080; font-style: italic\">None</span>, <span style=\"color: #808000; text-decoration-color: #808000\">channels</span>=<span style=\"color: #800080; text-decoration-color: #800080; font-style: italic\">None</span>, <span style=\"color: #808000; text-decoration-color: #808000\">pvs</span>=<span style=\"color: #800080; text-decoration-color: #800080; font-style: italic\">None</span>,                <span style=\"color: #000080; text-decoration-color: #000080\">│</span>\n",
       "<span style=\"color: #000080; text-decoration-color: #000080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000\">scan_info</span>=<span style=\"color: #800080; text-decoration-color: #800080; font-style: italic\">None</span>, <span style=\"color: #808000; text-decoration-color: #808000\">n_pulses</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">100</span>, <span style=\"color: #808000; text-decoration-color: #808000\">n_repeat</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>, <span style=\"color: #808000; text-decoration-color: #808000\">is_scan_step</span>=<span style=\"color: #ff0000; text-decoration-color: #ff0000; font-style: italic\">False</span>, <span style=\"color: #808000; text-decoration-color: #808000\">wait</span>=<span style=\"color: #00ff00; text-decoration-color: #00ff00; font-style: italic\">True</span>, **kwargs<span style=\"font-weight: bold\">)</span>:                             <span style=\"color: #000080; text-decoration-color: #000080\">│</span>\n",
       "<span style=\"color: #000080; text-decoration-color: #000080\">│</span>                                                                                                                 <span style=\"color: #000080; text-decoration-color: #000080\">│</span>\n",
       "<span style=\"color: #000080; text-decoration-color: #000080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">27</span><span style=\"font-style: italic\"> attribute(s) not shown.</span> Run <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">inspect</span><span style=\"font-weight: bold\">(</span>inspect<span style=\"font-weight: bold\">)</span> for options.                                                    <span style=\"color: #000080; text-decoration-color: #000080\">│</span>\n",
       "<span style=\"color: #000080; text-decoration-color: #000080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[34m╭─\u001b[0m\u001b[34m daq.acquire = <bound method SFAcquisition.acquire of SF DAQ (status: idle, last run: None) BrokerAPI @ http://\u001b[0m\u001b[34m─╮\u001b[0m\n",
       "\u001b[34m│\u001b[0m \u001b[3;96mdef \u001b[0m\u001b[1;31mSFAcquisition.acquire\u001b[0m\u001b[1m(\u001b[0mfilename, \u001b[33mdata_base_dir\u001b[0m=\u001b[3;35mNone\u001b[0m, \u001b[33mdetectors\u001b[0m=\u001b[3;35mNone\u001b[0m, \u001b[33mchannels\u001b[0m=\u001b[3;35mNone\u001b[0m, \u001b[33mpvs\u001b[0m=\u001b[3;35mNone\u001b[0m,                \u001b[34m│\u001b[0m\n",
       "\u001b[34m│\u001b[0m \u001b[33mscan_info\u001b[0m=\u001b[3;35mNone\u001b[0m, \u001b[33mn_pulses\u001b[0m=\u001b[1;36m100\u001b[0m, \u001b[33mn_repeat\u001b[0m=\u001b[1;36m1\u001b[0m, \u001b[33mis_scan_step\u001b[0m=\u001b[3;91mFalse\u001b[0m, \u001b[33mwait\u001b[0m=\u001b[3;92mTrue\u001b[0m, **kwargs\u001b[1m)\u001b[0m:                             \u001b[34m│\u001b[0m\n",
       "\u001b[34m│\u001b[0m                                                                                                                 \u001b[34m│\u001b[0m\n",
       "\u001b[34m│\u001b[0m \u001b[1;36m27\u001b[0m\u001b[3m attribute(s) not shown.\u001b[0m Run \u001b[1;35minspect\u001b[0m\u001b[1m(\u001b[0minspect\u001b[1m)\u001b[0m for options.                                                    \u001b[34m│\u001b[0m\n",
       "\u001b[34m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "daq.acquire?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "c5a5a484-2130-45a9-8a75-bf558238d71b",
   "metadata": {},
   "outputs": [],
   "source": [
    "pose = smarpod.GetPose(h)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "14e64a15-f7d8-4fa3-b234-55e16d8e6da8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
      ],
      "text/plain": []
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "\n",
       "\u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m-2.74212563e-09\u001b[0m, \u001b[1;36m-3.44389924e-09\u001b[0m,  \u001b[1;36m4.59956670e-08\u001b[0m,\n",
       "        \u001b[1;36m-2.65212072e-05\u001b[0m,  \u001b[1;36m1.69357078e-06\u001b[0m, \u001b[1;36m-1.00000000e+00\u001b[0m\u001b[1m]\u001b[0m,\n",
       "       \u001b[1m[\u001b[0m\u001b[1;36m-2.74212563e-09\u001b[0m, \u001b[1;36m-3.44389924e-09\u001b[0m,  \u001b[1;36m4.59956670e-08\u001b[0m,\n",
       "        \u001b[1;36m-2.65212072e-05\u001b[0m,  \u001b[1;36m1.69357078e-06\u001b[0m,  \u001b[1;36m0.00000000e+00\u001b[0m\u001b[1m]\u001b[0m,\n",
       "       \u001b[1m[\u001b[0m\u001b[1;36m-2.74212563e-09\u001b[0m, \u001b[1;36m-3.44389924e-09\u001b[0m,  \u001b[1;36m4.59956670e-08\u001b[0m,\n",
       "        \u001b[1;36m-2.65212072e-05\u001b[0m,  \u001b[1;36m1.69357078e-06\u001b[0m,  \u001b[1;36m1.00000000e+00\u001b[0m\u001b[1m]\u001b[0m\u001b[1m]\u001b[0m\u001b[1m)\u001b[0m"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "make_positions(pose_to_array(pose), 5, [-1,0,1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "bf5fec3c-1680-4505-afcc-1af088636c29",
   "metadata": {},
   "outputs": [],
   "source": [
    "def hexapod_rocking_curve(positions,scan_name,settle_time=1,n_pulses=100,folder=os.getcwd(),filename=None):\n",
    "    readbacks,times,timestrings = [], [],[]\n",
    "    poses = array_to_pose(positions)\n",
    "    \n",
    "    for i,pos in enumerate(poses):\n",
    "        if i==0:\n",
    "            is_scan_step=False\n",
    "        else:\n",
    "            is_scan_step=True\n",
    "\n",
    "        smarpod.Move(h,pos,1000,True)\n",
    "        time.sleep(settle_time)\n",
    "\n",
    "        # Record hexapod positions\n",
    "        readbacks.append(pose_to_array( smarpod.GetPose(h) ))\n",
    "        times.append(time.time())\n",
    "        timestrings.append(time.strftime('%Y-%m-%d %H:%M:%S'))\n",
    "\n",
    "        # Record the data\n",
    "        daq.acquire(scan_name,n_pulses=n_pulses,is_scan_step=is_scan_step)\n",
    "\n",
    "    # Save encoder readbacks readbacks\n",
    "    results = convert_results_to_pandas(np.asarray(readbacks),times,timestrings)\n",
    "    if filename == None:\n",
    "        filename = f'{time.strftime(\"%Y%m%d_%H%M%S\")}_axis={axis_index}.csv'\n",
    "    else:\n",
    "        filename=filename+'.csv'\n",
    "    filepath=os.path.join(folder,filename)\n",
    "    results.to_csv(filepath)\n",
    "    return results\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0aaf3507-518f-4529-8483-418ba1ea5688",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:it-smarpod]",
   "language": "python",
   "name": "conda-env-it-smarpod-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
