├── .gitignore ├── 3dprinting ├── LickometerHolder │ ├── Readme.md │ ├── operant_chamber_spout_holder_plate.scad │ ├── operant_chamber_spout_holder_plate.stl │ ├── rat.spout.holder.plate.stl │ ├── rat.water.holder.plate.FCStd │ ├── rat.water.spout.e-phyis.faceplate.fcstd │ ├── rat.water.spout.holder.tilted.fcstd │ ├── ratSpoutHolderPlate.scad │ ├── water.spout.holder.ephyis.face.plate.stl │ └── waterbottleholder.tiltedbottom.stl ├── Readme.md ├── ball │ ├── ball.scad │ ├── ball_hi_res.stl │ └── ball_lo_res.stl ├── brainMatrix │ ├── Readme.md │ ├── brainMatrix.scad │ ├── brainMatrix_assembled.stl │ ├── brainMatrix_base.stl │ ├── brainMatrix_cutter.stl │ └── brainMatrix_slider.stl ├── mouseBoxDivider │ ├── MoueBoxInsertPart1.fcstd │ ├── MouseBoxInsertPart2.fcstd │ ├── Readme.md │ ├── mouseBoxDividerPart1.stl │ └── mouseBoxDividerPart2.stl ├── mouseNosePokeInRatBox │ ├── Readme.md │ ├── mouseNosePokeForRat.stl │ └── nosepokeAdapt.fcstd ├── mouseRestraint │ └── mouseRestraint.scad ├── mouse_eartag │ ├── mouse_eartag.scad │ └── mouse_eartag.stl ├── operantChamberTopCover │ ├── Readme.md │ ├── rat.operant.chamber.center.cover.fcstd │ └── rat.operant.chamber.center.cover.stl ├── poopScoop │ ├── RatPoopScoop.fcstd │ ├── Readme.md │ └── ratPoopScoop.stl ├── raspberrypi_camer_case │ ├── rpi_camera_mount.scad │ └── rpi_camera_mount.stl ├── ratButton │ ├── Readme.md │ ├── ratButton.scad │ ├── ratButton.scad_original │ └── ratButton.stl ├── rat_eartag │ ├── rat_eartag.scad │ └── rat_eartag.stl └── steps4ElevatedPlusMaze │ ├── plusmaze_openfield_corner_fasterner.scad │ └── plusmazeboots.scad ├── README.md ├── RFID ├── Adafruit_CharLCD.py ├── RDM630-Spec.pdf ├── Rdm6300UART.py ├── Rdm6300_USB.py ├── Readme.md ├── Untitled.scad ├── connections.txt ├── install.sh ├── rfidReaderCase.scad ├── rfidReaderCase.stl ├── rfidReaderFront.stl ├── rfidReaderTop.stl ├── rfidReaderTopCover.stl ├── rfidscanner.py ├── rfidscanner.service └── settingUpUART.readme ├── RFID_eInk_Reader ├── Readme.md ├── a_rfid.py ├── rfid_reader_eink.py ├── rfid_reader_eink.scad ├── rfid_reader_eink.stl ├── rfid_reader_eink_box.stl └── rfid_reader_eink_cover.stl ├── RPI.PinLables.pdf ├── envSensors ├── 3D_design_frame │ ├── envSensorBoard.scad │ └── envSensorBoard.stl ├── Adafruit_I2C.py ├── HTU21DF.py ├── Readme.md ├── SampleData.tab ├── TSL2561.py ├── bmp.py ├── checklux.py ├── env_logger.cron.py ├── images │ ├── envSensor1.jpg │ ├── envSensor2.jpg │ ├── envSensor3.jpg │ ├── envSensor4.jpg │ └── envSensor5.jpg └── setup_scripts │ ├── setup.sh │ ├── setup_auto_log_copy.sh │ └── setup_ds1307.sh ├── extinction ├── ExtinctionBoxWiring.ods ├── Readme.md ├── cuelights.py ├── extinction.py ├── extinctionCase.scad ├── extinctionCase.stl ├── extinctionCaseCover.stl ├── extinctionCueLightBox.stl ├── extinctionCueLightPlate.stl └── extinctionLEDBox.scad ├── infrared ├── MiceTunnels │ ├── DuralLayerPCBForIRDetections.jpg │ ├── OneWayDoorClosed.jpg │ ├── OneWayDoorOpen.jpg │ └── SixTunnelsForMiceWithOneWayDoors.jpg ├── board │ ├── ir.GBL │ ├── ir.GBO │ ├── ir.GBS │ ├── ir.GTL │ ├── ir.GTS │ ├── ir.TXT │ ├── ir.b## │ ├── ir.b#1 │ ├── ir.b#4 │ ├── ir.b#5 │ ├── ir.b#6 │ ├── ir.brd │ ├── ir.dri │ ├── ir.dru │ ├── ir.gpi │ ├── ir.pdf │ └── ir.sch ├── gpio.ir.py └── parts_list.txt ├── motion ├── Readme.md ├── motion.py ├── motionSensorCaseOP.stl ├── motionSensorCaseOPCover.stl └── motionSensorCaseOperantChamber.scad ├── openscad ├── project.scad └── pump_design │ ├── design.scad │ ├── endPiece.scad │ └── middlePieceModified.scad ├── operantLeverPressing ├── 1video.h264 ├── 2video.h264 ├── Readme.md ├── bmp183.py ├── bmp183.pyc ├── data.txt ├── htu21d.py ├── htu21d.pyc ├── leverRecord.py ├── measure.py ├── operant.py ├── scratch │ ├── sensor-test.py │ ├── start-scratch-program.py │ ├── test.sb │ └── test1.py ├── sensor.py ├── temperature and humidity │ ├── HTU21DF.py │ ├── HTU21DF.pyc │ └── HTU21DF_Logger.py ├── temperature.csv ├── templogs │ └── temperature.csv └── weather_to_statsd.py ├── operantLicking ├── Assembly.md ├── PartsList.md ├── Readme.md ├── images │ ├── LCD1.jpg │ ├── LCD2.jpg │ ├── LCD_connections.jpg │ ├── RFID_antenna.jpg │ ├── RFID_antenna2.jpg │ ├── RFID_antenna3.jpg │ ├── RFID_board1.jpg │ ├── RFID_board2.jpg │ ├── Rpi_pins.jpg │ ├── SwitchBoardBack2.jpg │ ├── assembled.jpg │ ├── cuelight.jpg │ ├── cuelight2.jpg │ ├── frame0.jpg │ ├── inRatCage.jpg │ ├── microUSB.jpg │ ├── motion_sensor.jpg │ ├── rfid2.jpg │ ├── spout.jpg │ ├── stepMotorBoardBack.jpg │ ├── stepMotorShaft.jpg │ ├── stepMotorWires.jpg │ ├── switchBoardBack.jpg │ ├── switchBoardFront.jpg │ ├── syringCarrier.jpg │ ├── syringEnd.jpg │ ├── syringPumbAssembled.jpg │ ├── syrngeLoaded.jpg │ ├── threadedRod.jpg │ ├── voltageConverter.jpg │ └── wires.jpg ├── openscad │ ├── alcoholSelfAdminFrame.scad │ ├── alcoholSelfAdminFrame_Bottom.stl │ ├── alcoholSelfAdminFrame_Cover.stl │ ├── alcoholSelfAdminFrame_Top.stl │ ├── alcoholSelfAdmin_RFIDDoor.stl │ ├── alcoholSelfAdmin_RFIDFrame.stl │ ├── alcoholSelfAdmin_SpoutHolder.stl │ ├── alcoholSelfAdmin_cueLightFastner.stl │ ├── alcoholSelfAdmin_stepMotorFastner.stl │ ├── bearings.scad │ ├── fasteners.scad │ ├── pump_assembly.scad │ ├── stepmotor_fastner.scad │ └── steppers.scad ├── python │ ├── blinkenlights.py │ ├── datalogger.py │ ├── main.py │ ├── motion.py │ ├── motor2.py │ ├── pumpcontrol.py │ ├── pumpinterface.py │ ├── pumpmove.py │ └── touchsensor.py ├── scripts │ └── rpi3.sh └── wiring_tables.ods ├── operantSensationSeeking ├── README.md ├── blink.py ├── errorled.py ├── freecad │ ├── Readme.md │ ├── rfid.annt.lid.stl │ ├── rfid.annte.stl │ ├── roof.stl │ ├── touchOSSwithBattery.stl │ └── touchoss.Battery.fcstd ├── motion.py ├── ossByTouch.py ├── ossHabituation.py └── touchled.py ├── ratremor ├── Readme.md ├── ratremor_prototype.jpg └── tremor.py ├── rtc ├── hwclock.sh └── remove_fake_hwclock.sh ├── socialDrinking ├── openscad │ ├── rfid_water_spout_cboard_cover.stl │ ├── rfid_waterspout.scad │ ├── rfid_waterspout_complete.stl │ ├── rfid_waterspout_entire_unit.stl │ ├── rfid_waterspout_front_panel.stl │ ├── rfid_waterspout_holder.stl │ └── rfid_waterspout_ring_cover.stl ├── python │ ├── Pies │ │ └── Oxycodone │ │ │ └── Oxy_Box1_S1_dkfasl_dfkas;jf.csv │ ├── PigpioStepperMotor.py │ ├── PumpTest.py │ ├── __pycache__ │ │ ├── PigpioStepperMotor.cpython-35.pyc │ │ ├── datalogger.cpython-35.pyc │ │ ├── ids.cpython-35.pyc │ │ ├── mover_subproc.cpython-35.pyc │ │ └── pump_move.cpython-35.pyc │ ├── blinkenlights.py │ ├── datalogger.py │ ├── deviceid │ ├── err.txt │ ├── ids.py │ ├── log.err │ ├── main.py │ ├── mover_subproc.py │ ├── operant.py │ ├── pump_move.py │ ├── pumpmove.py │ ├── ratids │ ├── sessionid │ ├── timers.py │ ├── touchsensor.py │ └── turnoff_light.py └── utility_script │ ├── check_empty_program.sh │ ├── printEmptySyringeInfo.sh │ ├── test.csv │ └── update_and_reboot.sh ├── tailTimer ├── config.py ├── readme.md ├── runtailtimer.sh ├── tailTimer.jpg ├── tailTimerCase.scad └── tailwithdrawal.py ├── touchscreen ├── circle.png ├── star.png └── touchscreen.py └── wifi-network ├── cronsync.sh ├── deviceinfo.sh ├── interfaces ├── killhtpd.sh ├── rsync.sh ├── wlan0down.sh └── wpa_supplicant.conf /.gitignore: -------------------------------------------------------------------------------- 1 | .pyc 2 | .stl 3 | __pycache__/ -------------------------------------------------------------------------------- /3dprinting/LickometerHolder/Readme.md: -------------------------------------------------------------------------------- 1 | # Water spout holder for operant chambers 2 | 3 | The tilted bottom one prevents extra liquid causing short circuits. The tall one allows rats with head stages to access the spout. These fits in the standard operant chambers for rats. 4 | 5 | -------------------------------------------------------------------------------- /3dprinting/LickometerHolder/operant_chamber_spout_holder_plate.scad: -------------------------------------------------------------------------------- 1 | difference(){ 2 | cube([77,88,2]); 3 | translate([13.5,10,-1])cube([50,50,4]); 4 | translate([38.5,72, 0]) screw(); 5 | translate([8.5, 40,0]) screw(); 6 | translate([68.5,40,0]) screw(); 7 | } 8 | 9 | 10 | module screw(){ 11 | cylinder(r1=3.8, r2=2, h=2); 12 | } 13 | -------------------------------------------------------------------------------- /3dprinting/LickometerHolder/rat.spout.holder.plate.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/LickometerHolder/rat.spout.holder.plate.stl -------------------------------------------------------------------------------- /3dprinting/LickometerHolder/rat.water.holder.plate.FCStd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/LickometerHolder/rat.water.holder.plate.FCStd -------------------------------------------------------------------------------- /3dprinting/LickometerHolder/rat.water.spout.e-phyis.faceplate.fcstd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/LickometerHolder/rat.water.spout.e-phyis.faceplate.fcstd -------------------------------------------------------------------------------- /3dprinting/LickometerHolder/rat.water.spout.holder.tilted.fcstd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/LickometerHolder/rat.water.spout.holder.tilted.fcstd -------------------------------------------------------------------------------- /3dprinting/LickometerHolder/ratSpoutHolderPlate.scad: -------------------------------------------------------------------------------- 1 | $fn=100; 2 | difference(){ 3 | 4 | cube([77,82,1.8]); // plate per se 5 | translate([13,21,-1]) cube([50,50,3]); // open in the middle 6 | translate([77/2,10,-1]) cylinder(r1=1.8, r2=3, h=3); // screw 7 | translate([8.5,42.5,-1]) cylinder(r1=1.8, r2=3, h=3); // screw 8 | translate([68.5,42.5,-1]) cylinder(r1=1.8, r2=3,h=3); // screw 9 | 10 | } 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /3dprinting/LickometerHolder/water.spout.holder.ephyis.face.plate.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/LickometerHolder/water.spout.holder.ephyis.face.plate.stl -------------------------------------------------------------------------------- /3dprinting/LickometerHolder/waterbottleholder.tiltedbottom.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/LickometerHolder/waterbottleholder.tiltedbottom.stl -------------------------------------------------------------------------------- /3dprinting/Readme.md: -------------------------------------------------------------------------------- 1 | Design files for 3D printing 2 | ============================== 3 | 4 | The frames or cases used for the various devices are located in the devices folder. Here are some misc. objects that we use in the lab. Older files were designed using using FreeCAD. Newer files were designed uing Openscad. You can click on the .stl file and view a 3D rendering of the design using Github's built-in viewer. 5 | 6 | 7 | -------------------------------------------------------------------------------- /3dprinting/ball/ball.scad: -------------------------------------------------------------------------------- 1 | $fn=40; 2 | $fn=13; 3 | module bar(){ 4 | difference(){ 5 | cylinder(r1=14, r2=8, h=106, center=true); 6 | cylinder(r1=12, r2=6, h=104, center=true); 7 | } 8 | } 9 | 10 | difference (){ 11 | radius=50; 12 | union(){ 13 | sphere(r=radius); 14 | bar(); 15 | rotate([90,0,0]) bar(); 16 | rotate([0,90,0]) bar(); 17 | } 18 | sphere(r=radius-2); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /3dprinting/brainMatrix/Readme.md: -------------------------------------------------------------------------------- 1 | # Brain slicer 2 | 3 | ## Assembly 4 | See brainMatrix_assembled.stl. The other three stl files are for printing. 5 | 6 | ## Procedure 7 | A fresh rat brain is placed in the cutter. Single edge blades are then lowered into the guide slots of the cutter to cut the brain at 1 mm intervals. The slider is then moved out, allowing the cutter to be lowered into the base. The side bars of the base catch the blades and allow the brain sections to be removed one at a time. 8 | 9 | 10 | -------------------------------------------------------------------------------- /3dprinting/brainMatrix/brainMatrix.scad: -------------------------------------------------------------------------------- 1 | $fn=100; 2 | module slider(){ 3 | difference(){ 4 | translate([0,-8,9])cube([28,28,14], center=true); 5 | translate([0,-6,9]) cube ([14,28,15], center=true); 6 | } 7 | } 8 | 9 | module cutter(){ 10 | difference(){ 11 | cube ([26,26,14], center=true); // outside 12 | translate([0,4,0]) cube ([14,26,15], center=true); // inside 13 | for (i = [3:6]) { 14 | translate([0,i,1]) cube ([30,0.4,14], center=true); // knife cuts 15 | } 16 | } 17 | } 18 | 19 | module base(){ 20 | cube ([38,40,4], center=true); 21 | translate([0,6,9]) cube ([13,28,17], center=true); 22 | translate([-19,0,2])side(); 23 | translate([15,0,2])side(); 24 | } 25 | 26 | module side(){ 27 | // translate([16,13,13]) cube([4,2,h], center=true); 28 | // translate([-16,13,13]) cube([4,2,h], center=true); 29 | translate([0,-2,0]) cube([4,9,h]); 30 | h=14; 31 | translate([0,5,h]) cube([4,2,h]); 32 | translate([0,-2,h]) cube([4,2,h]); 33 | } 34 | 35 | 36 | color("yellow") translate([0,5,0]) slider(); // 37 | translate([0,-2,23]) cutter(); 38 | 39 | color("grey") base(); 40 | 41 | -------------------------------------------------------------------------------- /3dprinting/brainMatrix/brainMatrix_slider.stl: -------------------------------------------------------------------------------- 1 | solid OpenSCAD_Model 2 | facet normal -1 0 0 3 | outer loop 4 | vertex -14 -17 2 5 | vertex -14 11 16 6 | vertex -14 11 2 7 | endloop 8 | endfacet 9 | facet normal -1 -0 0 10 | outer loop 11 | vertex -14 11 16 12 | vertex -14 -17 2 13 | vertex -14 -17 16 14 | endloop 15 | endfacet 16 | facet normal 0 0 1 17 | outer loop 18 | vertex -7 11 16 19 | vertex -14 11 16 20 | vertex -7 -15 16 21 | endloop 22 | endfacet 23 | facet normal 0 0 1 24 | outer loop 25 | vertex 7 -15 16 26 | vertex 14 11 16 27 | vertex 7 11 16 28 | endloop 29 | endfacet 30 | facet normal 0 0 1 31 | outer loop 32 | vertex 14 11 16 33 | vertex 7 -15 16 34 | vertex 14 -17 16 35 | endloop 36 | endfacet 37 | facet normal -0 0 1 38 | outer loop 39 | vertex -7 -15 16 40 | vertex 14 -17 16 41 | vertex 7 -15 16 42 | endloop 43 | endfacet 44 | facet normal 0 0 1 45 | outer loop 46 | vertex -7 -15 16 47 | vertex -14 -17 16 48 | vertex 14 -17 16 49 | endloop 50 | endfacet 51 | facet normal 0 0 1 52 | outer loop 53 | vertex -14 -17 16 54 | vertex -7 -15 16 55 | vertex -14 11 16 56 | endloop 57 | endfacet 58 | facet normal 1 -0 0 59 | outer loop 60 | vertex 14 -17 16 61 | vertex 14 11 2 62 | vertex 14 11 16 63 | endloop 64 | endfacet 65 | facet normal 1 0 0 66 | outer loop 67 | vertex 14 11 2 68 | vertex 14 -17 16 69 | vertex 14 -17 2 70 | endloop 71 | endfacet 72 | facet normal 0 0 -1 73 | outer loop 74 | vertex 14 -17 2 75 | vertex 7 -15 2 76 | vertex 14 11 2 77 | endloop 78 | endfacet 79 | facet normal 0 0 -1 80 | outer loop 81 | vertex 14 -17 2 82 | vertex -7 -15 2 83 | vertex 7 -15 2 84 | endloop 85 | endfacet 86 | facet normal 0 0 -1 87 | outer loop 88 | vertex -14 -17 2 89 | vertex -7 -15 2 90 | vertex 14 -17 2 91 | endloop 92 | endfacet 93 | facet normal 0 0 -1 94 | outer loop 95 | vertex -14 11 2 96 | vertex -7 -15 2 97 | vertex -14 -17 2 98 | endloop 99 | endfacet 100 | facet normal 0 0 -1 101 | outer loop 102 | vertex -7 -15 2 103 | vertex -14 11 2 104 | vertex -7 11 2 105 | endloop 106 | endfacet 107 | facet normal -0 0 -1 108 | outer loop 109 | vertex 14 11 2 110 | vertex 7 -15 2 111 | vertex 7 11 2 112 | endloop 113 | endfacet 114 | facet normal 0 -1 0 115 | outer loop 116 | vertex -14 -17 2 117 | vertex 14 -17 16 118 | vertex -14 -17 16 119 | endloop 120 | endfacet 121 | facet normal 0 -1 -0 122 | outer loop 123 | vertex 14 -17 16 124 | vertex -14 -17 2 125 | vertex 14 -17 2 126 | endloop 127 | endfacet 128 | facet normal 0 1 -0 129 | outer loop 130 | vertex 14 11 2 131 | vertex 7 11 16 132 | vertex 14 11 16 133 | endloop 134 | endfacet 135 | facet normal 0 1 0 136 | outer loop 137 | vertex 7 11 16 138 | vertex 14 11 2 139 | vertex 7 11 2 140 | endloop 141 | endfacet 142 | facet normal 0 1 -0 143 | outer loop 144 | vertex -7 11 2 145 | vertex -14 11 16 146 | vertex -7 11 16 147 | endloop 148 | endfacet 149 | facet normal 0 1 0 150 | outer loop 151 | vertex -14 11 16 152 | vertex -7 11 2 153 | vertex -14 11 2 154 | endloop 155 | endfacet 156 | facet normal 1 -0 0 157 | outer loop 158 | vertex -7 -15 16 159 | vertex -7 11 2 160 | vertex -7 11 16 161 | endloop 162 | endfacet 163 | facet normal 1 0 0 164 | outer loop 165 | vertex -7 11 2 166 | vertex -7 -15 16 167 | vertex -7 -15 2 168 | endloop 169 | endfacet 170 | facet normal -1 0 0 171 | outer loop 172 | vertex 7 -15 2 173 | vertex 7 11 16 174 | vertex 7 11 2 175 | endloop 176 | endfacet 177 | facet normal -1 -0 0 178 | outer loop 179 | vertex 7 11 16 180 | vertex 7 -15 2 181 | vertex 7 -15 16 182 | endloop 183 | endfacet 184 | facet normal 0 1 -0 185 | outer loop 186 | vertex 7 -15 2 187 | vertex -7 -15 16 188 | vertex 7 -15 16 189 | endloop 190 | endfacet 191 | facet normal 0 1 0 192 | outer loop 193 | vertex -7 -15 16 194 | vertex 7 -15 2 195 | vertex -7 -15 2 196 | endloop 197 | endfacet 198 | endsolid OpenSCAD_Model 199 | -------------------------------------------------------------------------------- /3dprinting/mouseBoxDivider/MoueBoxInsertPart1.fcstd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/mouseBoxDivider/MoueBoxInsertPart1.fcstd -------------------------------------------------------------------------------- /3dprinting/mouseBoxDivider/MouseBoxInsertPart2.fcstd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/mouseBoxDivider/MouseBoxInsertPart2.fcstd -------------------------------------------------------------------------------- /3dprinting/mouseBoxDivider/Readme.md: -------------------------------------------------------------------------------- 1 | These two part fit together to divide a mouse box into three parts. This allows three mice to be put in the same box after surgery. So they can still have social interaction and not bite each other's wound. 2 | -------------------------------------------------------------------------------- /3dprinting/mouseBoxDivider/mouseBoxDividerPart1.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/mouseBoxDivider/mouseBoxDividerPart1.stl -------------------------------------------------------------------------------- /3dprinting/mouseBoxDivider/mouseBoxDividerPart2.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/mouseBoxDivider/mouseBoxDividerPart2.stl -------------------------------------------------------------------------------- /3dprinting/mouseNosePokeInRatBox/Readme.md: -------------------------------------------------------------------------------- 1 | This adapter allows us to install a nose poke sensor designed for mouse operant chambers in rat operant chambers. 2 | -------------------------------------------------------------------------------- /3dprinting/mouseNosePokeInRatBox/mouseNosePokeForRat.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/mouseNosePokeInRatBox/mouseNosePokeForRat.stl -------------------------------------------------------------------------------- /3dprinting/mouseNosePokeInRatBox/nosepokeAdapt.fcstd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/mouseNosePokeInRatBox/nosepokeAdapt.fcstd -------------------------------------------------------------------------------- /3dprinting/mouseRestraint/mouseRestraint.scad: -------------------------------------------------------------------------------- 1 | $fn=100; 2 | !rotate([180,0,180]) translate([0,0,-55]) color("blue") cover(); 3 | innerR=15; 4 | difference(){ 5 | cylinder(r=18, h=110, center=true); 6 | cylinder(r=innerR, h=111, center=true); 7 | ventHole(); 8 | translate([0,0,25]) ventHole(); 9 | translate([0,0,-25]) ventHole(); 10 | translate([-15,0,-20])cube([10,3,80], center=true ); // later cut 11 | translate([0,-15,-20])cube([8,10,80], center=true ); // top cut head end 12 | translate([0,-13,63])cube([4,10,30], center=true ); // top cut tail end 13 | translate([-4,-14,50]) rotate([90,225,0]) slit(); // tail end screw slit 14 | slit2(); 15 | translate([0,0,12]) slit2(); 16 | translate([0,0,-12]) slit2(); 17 | translate([0,0,-24]) slit2(); 18 | translate([0,0,-36]) slit2(); 19 | translate([0,0,-48]) slit2(); 20 | 21 | } 22 | 23 | module ventHole() { 24 | rotate([0,90,0])translate([0,0,20]) cylinder (r=3, h=40, center=true); 25 | } 26 | 27 | module slit2() { 28 | translate([-13,3,0])rotate([0,90,0]) slit(); 29 | } 30 | 31 | module slit(){ 32 | cylinder(r=1.9, h=10, center=true); 33 | rotate([0,0,135]) translate([0,2,0]) cube([4,4,10], center=true); 34 | } 35 | 36 | module cover(){ 37 | h2=8; 38 | difference(){ 39 | union(){ 40 | translate([0,0,h2/2]) cylinder(r=innerR-.7, h=h2, center=true); 41 | cylinder(r=17, h=2, center=true); 42 | } 43 | translate([0,-1,0]) rotate([0,0,90]) cylinder(r=3.2, h=25, center=true); 44 | translate([0,14,0]) cube([6.4,30,17], center=true ); // verticl cut 45 | rotate([90,0,0]) translate([0,5,0]) cylinder(r=2.1,h=20); //screw small =1.8, large=2.1 46 | //translate([0,-9,0]) cube ([6,3,9], center=true) ; //hex nut 47 | } 48 | } 49 | 50 | 51 | //translate([0,0,-50]) color("red") nosecone(); 52 | module nosecone() { 53 | difference (){ 54 | cylinder(r=innerR-0.5, h=38); 55 | translate([0,0,-.1])cylinder(r2=innerR-1, r1=5, h=39); 56 | rotate([90,0,-90]) translate([0,3,4]) cylinder(r=2.1,h=18); //screw 57 | translate([0,-7,26])cube([8,16,25], center=true ); // top cut head end 58 | } 59 | } 60 | 61 | 62 | //!cover2(); // models the original cover 63 | module cover2(){ 64 | difference(){ 65 | union(){ 66 | difference(){ 67 | cylinder(r=18.5, h=2, center=true); 68 | translate([0,-15,0])cube([40,20,2], center=true); 69 | } 70 | h2=7; translate([0,0,h2/2-1]) cylinder(r=15, h=h2, center=true); 71 | 72 | } 73 | translate([0,10,0]) rotate([0,0,90]) cylinder(r=4, h=25, center=true); 74 | translate([0,14,0]) cube([8,10,17], center=true ); // verticl cut 75 | rotate([90,0,0]) translate([0,3,6]) cylinder(r=1.4,h=10); //screw 76 | rotate([0,90,0]) translate([-6,-6,0]) cylinder(r=4,h=50, center=true); // horizontal groove 77 | translate([0,4,4])cube([40,25,4], center=true); 78 | } 79 | } 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /3dprinting/mouse_eartag/mouse_eartag.scad: -------------------------------------------------------------------------------- 1 | $fn=60; 2 | 3 | difference(){ 4 | cylinder(r=3.9, h=0.8); // top above the base 5 | cylinder(r=0.62, h=30, center=true); // was .42 center hole 6 | } 7 | 8 | #difference(){ 9 | cylinder(r=3.9, h=3); 10 | cylinder(r=3.1, h=3); 11 | translate([-4,1,.5])cube([8,8,4]); 12 | } 13 | -------------------------------------------------------------------------------- /3dprinting/operantChamberTopCover/Readme.md: -------------------------------------------------------------------------------- 1 | A cover for the top center hole of rat operant chamber to allow a spring to go through and prevent the rat from escaping. 2 | 3 | -------------------------------------------------------------------------------- /3dprinting/operantChamberTopCover/rat.operant.chamber.center.cover.fcstd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/operantChamberTopCover/rat.operant.chamber.center.cover.fcstd -------------------------------------------------------------------------------- /3dprinting/operantChamberTopCover/rat.operant.chamber.center.cover.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/operantChamberTopCover/rat.operant.chamber.center.cover.stl -------------------------------------------------------------------------------- /3dprinting/poopScoop/RatPoopScoop.fcstd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/poopScoop/RatPoopScoop.fcstd -------------------------------------------------------------------------------- /3dprinting/poopScoop/Readme.md: -------------------------------------------------------------------------------- 1 | Well, the name says it all. 2 | -------------------------------------------------------------------------------- /3dprinting/poopScoop/ratPoopScoop.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/3dprinting/poopScoop/ratPoopScoop.stl -------------------------------------------------------------------------------- /3dprinting/raspberrypi_camer_case/rpi_camera_mount.scad: -------------------------------------------------------------------------------- 1 | // original design by devzero, published Oct 19, 2013 2 | // https://www.thingiverse.com/thing:168581 3 | // modified by Hao Chen Oct 11 2017 4 | 5 | board_width=25.5; 6 | board_height=23; 7 | board_thick=4.75; 8 | cable_width=18; 9 | cable_thick=1; 10 | side_cover=7.5; 11 | camera_hole_width=10; 12 | camera_hole_height=5.5; 13 | screw_hole_r=2.65; 14 | padding=2.5; 15 | d=0.001; 16 | mount_offset=2*padding+board_width; 17 | mount_thickness=8; 18 | 19 | 20 | //camera holder 21 | difference(){ 22 | cube([board_thick+2*padding, board_width+2*padding, board_height+2*padding]); 23 | //main compartment 24 | translate([padding, padding, padding]) cube([board_thick, board_width, board_height+padding+d]); 25 | //front camera slot 26 | translate([board_thick+padding-d, padding+side_cover, padding+camera_hole_height]) cube([padding+2*d, camera_hole_width, board_height+padding-camera_hole_height+d]); 27 | //hole for cable in the bottom 28 | translate([padding+2,padding+(board_width-cable_width)/2,0]) cube([cable_thick, cable_width+2*d, padding+2*d]); 29 | } 30 | 31 | //handle 32 | 33 | translate([7.8,10,-40])cube([2,10, 40]); 34 | 35 | -------------------------------------------------------------------------------- /3dprinting/ratButton/Readme.md: -------------------------------------------------------------------------------- 1 | # Rat 'button' for jugular catheter 2 | This is an improved version of the implant for jugular catheter originally described in our Front Behav Neurosci paper . 3 | The 'mesh' like base makes it much more stable than the previous version. 4 | -------------------------------------------------------------------------------- /3dprinting/ratButton/ratButton.scad: -------------------------------------------------------------------------------- 1 | $fn=60; 2 | 3 | module button(){ 4 | difference() { 5 | //cylinder(r=10, h=.6) ; // medium thickness 6 | cylinder(r=10, h=.4) ; // think thickness 7 | // #translate([0,0,0]) cylinder(r1=8, r2=7, h=0.5) ; // base 8 | 9 | 10 | for (a=[1:8]){ 11 | rotate([0,0,a*45])translate([5,5,0]) #cylinder(r=1, h=2, center=true); // hole 12 | 13 | } 14 | } 15 | } 16 | 17 | 18 | 19 | module groove(){ 20 | z=1; 21 | w=1.2; 22 | cube([80,w,z], center=true); 23 | for (a=[1:3]){ 24 | translate([0,-a*3,0]) cube([80,w,z], center=true); 25 | translate([0,a*3,0]) cube([80,w,z], center=true); 26 | } 27 | } 28 | 29 | 30 | module base(){ 31 | difference() { 32 | union(){ 33 | cylinder(r=10, h=1) ; // base 34 | translate([0,0,1]) cylinder(r1=10, r2=7, h=0.5) ; // base 35 | } 36 | translate([0,0,0]) 37 | union(){ 38 | cylinder(r1=3, r2=0.68, h=1); //bottom cone 39 | scale([0.5,1,0.5]) rotate([0,0,45]) cube([20,16,0.7]); 40 | groove(); 41 | rotate([0,0,90]) translate([0,0,1.5]) groove(); 42 | x=4.5; 43 | y=4.5; 44 | r=1; 45 | for (a=[0:8]){ 46 | rotate([0,0,45*a])translate([x,-y,0]) cylinder(r=1.5, h=12, center=true); // hole 47 | rotate([0,0,45*a])translate([-x,y,0]) cylinder(r=1.5, h=12, center=true); // hole 48 | } 49 | } 50 | } 51 | 52 | } 53 | 54 | difference(){ 55 | union(){ 56 | //scale([1,1,1]) 57 | base(); 58 | translate([0,0,0.3])cylinder(r=2.8, h=12) ; // stem above the base 59 | //#translate([0,0,0.5])cylinder(r2=4, r1=6.1, h=1) ; // Qin's suggestion 60 | translate([0,0,6])cylinder(r=5, h=9); // top above the base 61 | translate([0,0,4])cylinder(r2=5, r1=3, h=2); // top above the base 62 | 63 | } 64 | translate([0,0,8])cylinder(r=1.55, r2=1.65, h=7); // spring connector, i.e. center cone 65 | 66 | cylinder(r=0.66, h=30, center=true); // center hole 67 | } 68 | -------------------------------------------------------------------------------- /3dprinting/ratButton/ratButton.scad_original: -------------------------------------------------------------------------------- 1 | $fn=100; 2 | 3 | module groove(){ 4 | x=4; 5 | y=4; 6 | translate([-x,y,0]) cylinder(r=1, h=10, center=true); // hole 7 | translate([x,-y,0]) cylinder(r=1, h=10, center=true); // hole 8 | z=1; 9 | w=1.2; 10 | cube([80,w,z], center=true); 11 | translate([0,-3,0]) cube([80,w,z], center=true); 12 | translate([0,3,0]) cube([80,w,z], center=true); 13 | translate([0,-6,0]) cube([80,w,z], center=true); 14 | translate([0,-9, 0]) cube([80,w,z], center=true); 15 | translate([0,6,0]) cube([80,w,z], center=true); 16 | translate([0,9, 0]) cube([80,w,z], center=true); 17 | } 18 | 19 | module button(){ 20 | difference() { 21 | union(){ 22 | cylinder(r=1.95, h=18) ; // stem 23 | cylinder(r=8, h=1) ; // base 24 | translate([0,0,1]) cylinder(r1=8, r2=7, h=0.5) ; // base 25 | cylinder(r=1.4, h=21) ; // spring connector 26 | translate([0,0,21]) cylinder(r1=1.4, r2=1, h=1.5); // tip 27 | } 28 | translate([0,0,-0.01]) 29 | union(){ 30 | cylinder(r1=3, r2=0.68, h=1); //bottom cone 31 | scale([0.5,1,1]) rotate([0,0,45]) cube([20,10,0.7]); 32 | groove(); 33 | rotate([0,0,90]) translate([0,0,1.4]) groove(); 34 | rotate([0,0,-45])translate([4,4,1]) cylinder(r=1, h=2, center=true); // hole 35 | rotate([0,0,-225])translate([4,4,1]) cylinder(r=1, h=2, center=true); // hole 36 | } 37 | } 38 | 39 | } 40 | 41 | module suture(){ 42 | difference(){ 43 | hull(){ 44 | translate([0,2,3.1]) rotate([0,90,0]) cylinder(r0=1,h=2, center=true); 45 | translate([0,4.5,3.1]) rotate([0,90,0]) cylinder(r0=1,h=2, center=true); 46 | translate([-1,2,0.7])cube([2,3.4,3], cente=true); 47 | } 48 | translate([-3,2,0.7])cube([5,2.3,2.1], cente=true); 49 | } 50 | 51 | } 52 | 53 | 54 | difference(){ 55 | union(){ 56 | button(); 57 | suture(); 58 | rotate([0,0,180]) suture(); 59 | translate([0,0,1]) cylinder(r=2.5, h=7) ; // larger stem above the base 60 | } 61 | cylinder(r=0.68, h=30); // center hole 62 | } 63 | -------------------------------------------------------------------------------- /3dprinting/rat_eartag/rat_eartag.scad: -------------------------------------------------------------------------------- 1 | $fn=50; 2 | 3 | module inside_ear(){ 4 | scale([0.8,0.8,1.1]) 5 | difference(){ 6 | sphere(r=4.5); 7 | sphere(r=3.7); 8 | cylinder(h=10,r=1.4, center=true); 9 | } 10 | difference(){ 11 | translate([0,0,-0.5])cylinder(h=0.5, r=3.6,center=false); 12 | translate([1,0,0])cube([4,8,3], center=true); 13 | } 14 | } 15 | 16 | module back_of_ear(){ 17 | difference(){ 18 | union(){ 19 | scale([1,1,0.9])sphere(r=4.5); 20 | translate([0,0,4])cylinder(r=3.2,h=3, center=true); 21 | } 22 | sphere(r=3.5); 23 | cylinder(h=13,r=1.4, center=true); 24 | translate([0,0,5.4]) cube([1.30,7,4], center=true); // top cut 25 | } 26 | //} 27 | // translate([1.2,0,4.7])rotate([90,0,0])difference(){ // notch 28 | // cylinder(h=1,r=0.8, center=true); 29 | // translate([0,-1,0]) cube([2,2,4], center=true); 30 | } 31 | 32 | 33 | difference(){ 34 | union(){ 35 | back_of_ear(); 36 | translate([12,0,0]) inside_ear(); 37 | } 38 | translate([0,0,-5]) cube([40,9,9], center=true); 39 | } 40 | 41 | -------------------------------------------------------------------------------- /3dprinting/steps4ElevatedPlusMaze/plusmaze_openfield_corner_fasterner.scad: -------------------------------------------------------------------------------- 1 | 2 | $fn=40; 3 | 4 | totalW=100; 5 | totalH=100; 6 | 7 | 8 | difference(){ 9 | cube([totalW, totalW, totalH]); 10 | cube([totalW*0.70, totalW*0.70, totalH*1.2]); 11 | } 12 | -------------------------------------------------------------------------------- /3dprinting/steps4ElevatedPlusMaze/plusmazeboots.scad: -------------------------------------------------------------------------------- 1 | // this boot further increases the height of the plus maze so that it can be placed in the openfield and not worry about the open arm is close to the wall of the open field. 2 | 3 | $fn=100; 4 | 5 | module hollow(w1, w2,h){ 6 | difference(){ 7 | cube([w1, w1, h], center=true); 8 | cube([w2, w2, h], center=true); 9 | } 10 | 11 | } 12 | 13 | 14 | module space(w, h){ 15 | w1=10; 16 | gap=20; 17 | for (i = [1:6]) { 18 | translate([gap*i,0,0]) cube([w1,w,h]); 19 | } 20 | } 21 | 22 | 23 | difference(){ 24 | hollow(152,142,100); 25 | translate([0,0,50]) cube([142, 142, 20], center=true); 26 | difference(){ 27 | cylinder (r=110, h=100, center=true); 28 | cylinder(r=104, h=100,center=true, $fs=0.2); 29 | } 30 | // reduce the printing time 31 | translate([-75, 140/2, -40]) space(10,80); 32 | rotate([0,0,90])translate([-75, 140/2, -40]) space(10,80); 33 | rotate([0,0,180])translate([-75, 140/2, -40]) space(10,80); 34 | rotate([0,0,270])translate([-75, 140/2, -40]) space(10,80); 35 | translate([0,0,-50])rotate([90,0,90]) scale([1,0.1,1]) cylinder(r=55, h=160, center=true); 36 | translate([0,0,-50])rotate([90,0,180])scale([1,0.1,1]) cylinder(r=55, h=160, center=true); 37 | 38 | } 39 | 40 | difference(){ 41 | translate([0,0,-3.2]) rotate([0,0,45]) hollow(107,100,100-6.4); 42 | // further reduce print time 43 | translate([0,0,-50])rotate([90,0,45]) cylinder(r=45, h=120, center=true); 44 | translate([0,0,-50])rotate([90,0,135]) cylinder(r=45, h=120, center=true); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenBehavior 2 | 3 | This project aims to establish a computing platform for rodent behavior research using the Raspberry Pi computer. We are building devices for conducting operant conditioning, as well as some infrared sensor based assays. We also designed an environmental sensor set that records the temperature, humidity, air pressure, ambient light, noise level, etc. 4 | 5 | These projects are in various stages of development. The following are the most mature projects. 6 | 7 | ## Operant Licking 8 | This project develops a home cage device for operant licking (fixed ratio, various ratio, or progressive ratio schedules). Detailed description of this project is published in a [PeerJ article]( https://peerj.com/articles/2981/) 9 | 10 | 11 | ## EnvSensors 12 | 13 | This device collects four environmental variables and we have several of them running in the lab. This device is also described in our [PeerJ article](https://peerj.com/articles/2981/) 14 | 15 | ## RFID 16 | 17 | This project develops a standalone RFID reader for the EM4100 implantable glass chips. We use this daily in the lab. 18 | 19 | ## Extinction 20 | 21 | This device is used to run extinction experiments as described by [Wang et al. (2014)](www.ncbi.nlm.nih.gov/PubMed/25532105) 22 | 23 | 24 | ## Motion 25 | 26 | This project adds a motion sensor to standard operant chambers. 27 | 28 | -------------------------------------------------------------------------------- /RFID/RDM630-Spec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/RFID/RDM630-Spec.pdf -------------------------------------------------------------------------------- /RFID/Rdm6300UART.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | ''' 4 | code originally obtained from raspberry pi forum: 5 | http://www.raspberrypi.org/forums/viewtopic.php?t=59025&p=501603 6 | ''' 7 | 8 | import serial 9 | import sys 10 | import time 11 | from operator import xor 12 | # UART 13 | ID = "" 14 | Zeichen = 0 15 | Checksumme = 0 16 | Tag = 0 17 | # Flags 18 | Startflag = "\x02" 19 | Endflag = "\x03" 20 | # UART oeffnen 21 | UART = serial.Serial("/dev/ttyAMA0", 9600) 22 | UART.close(); 23 | UART.open() 24 | while True: 25 | # Variablen loeschen 26 | Checksumme = 0 27 | Checksumme_Tag = 0 28 | ID = "" 29 | # Zeichen einlesen 30 | Zeichen = UART.read() 31 | # Uebertragungsstart signalisiert worden? 32 | if Zeichen == Startflag: 33 | # ID zusammen setzen 34 | for Counter in range(13): 35 | Zeichen = UART.read() 36 | ID = ID + str(Zeichen) 37 | # Endflag aus dem String loeschen 38 | ID = ID.replace(Endflag, "" ) # Checksumme berechnen 39 | for I in range(0, 9, 2): 40 | Checksumme = Checksumme ^ (((int(ID[I], 16)) << 4) + int(ID[I+1], 16)) 41 | Checksumme = hex(Checksumme) 42 | # Tag herausfiltern 43 | Tag = ((int(ID[1], 16)) << 8) + ((int(ID[2], 16)) << 4) + ((int(ID[3], 16)) << 0) 44 | Tag = hex(Tag) 45 | # Ausgabe der Daten 46 | print "------------------------------------------" 47 | print "Datensatz: ", ID 48 | print "Tag: ", Tag 49 | print "ID: ", ID[4:10], " - ", int(ID[4:10], 16) 50 | print "Checksumme: ", Checksumme 51 | print "------------------------------------------" 52 | -------------------------------------------------------------------------------- /RFID/Rdm6300_USB.py: -------------------------------------------------------------------------------- 1 | import time 2 | import serial 3 | import RPi.GPIO as gpio 4 | from operator import xor 5 | 6 | ### This is the USB version 7 | ### The RDM6300 is connected to a CP2102 serial to USB breakout board 8 | ### http://forum.arduino.cc/index.php?topic=138611.0 9 | ### http://www.amazon.com/gp/product/B009T2ZR6W 10 | ### modified from code written by Ivan Amies. 11 | 12 | 13 | # Flags ## DO NOT CHANGE #### 14 | ############################# 15 | Startflag = "\x02" 16 | Endflag = "\x03" 17 | ############################# 18 | 19 | # initial settings for the uart device. Change as necessary, or read in as desired.# 20 | baud_rate = 9600 21 | time_out = 0.05 22 | ### 23 | 24 | def initialize_uart(path_to_sensor) : 25 | uart = serial.Serial(path_to_sensor, baud_rate, timeout = time_out) 26 | uart.close() 27 | uart.open() 28 | uart.flushInput() 29 | uart.flushOutput() 30 | print(path_to_sensor + " initiated") 31 | return uart; 32 | 33 | def readrfid(uart): 34 | while True: 35 | Zeichen = 0 36 | Tag = 0 37 | ID = "" 38 | Zeichen = uart.read() 39 | if Zeichen == Startflag: 40 | for Counter in range(13): 41 | Zeichen = uart.read() 42 | ID = ID + str(Zeichen) 43 | ID = ID.replace(Endflag, "" ) 44 | print "RFID detected: "+ ID 45 | 46 | usb = "/dev/ttyUSB0" 47 | uart = initialize_uart(usb) 48 | readrfid(uart) 49 | 50 | 51 | -------------------------------------------------------------------------------- /RFID/Readme.md: -------------------------------------------------------------------------------- 1 | # Standalone RFID Reader 2 | 3 | This is a simple device that connects an RDM 6300 RFID reader board to the RPi. The ID of the glass tags is shown on the LCD. 4 | 5 | -------------------------------------------------------------------------------- /RFID/Untitled.scad: -------------------------------------------------------------------------------- 1 | module rfid_antenna_housing(){ 2 | difference(){ 3 | cube([53,43,7], center=true); // rfid antenna outside; 4 | translate([3,0,0]) cube([56,37,3.6], center=true); // rfid antenna groove; 5 | cube([39,31,30], center=true); //rfid antenna loop inside 6 | } 7 | } 8 | 9 | rfid_antenna_housing(); -------------------------------------------------------------------------------- /RFID/connections.txt: -------------------------------------------------------------------------------- 1 | RDM 6300 connections 2 | ------------------- 3 | The antenna can be connected in either direction 4 | connect the Tx on the RPi (i.e. pin 8) to Rx on the board (i.e. PIN 2) 5 | connect the Rx on the RPi (i.e. pin 10) to Tx on the board (i.e. PIN 1) 6 | connect the ground on the RPi (i.e. pin 6) to the ground on the board (i.e. Pin 4) 7 | connect the 5V on the RPi (i.e. pin 2) to the power in on the board (i.e. Pin 5) 8 | 9 | LCD connections 10 | -------------- 11 | RS -> Pin 03 / GPIO 02 12 | EN -> Pin 05 / GPIO 03 13 | D7 -> Pin 07 / GPIO 04 14 | D6 -> Pin 11 / GPIO 17 15 | D5 -> Pin 13 / GPIO 27 16 | D4 -> Pin 15 / GPIO 22 17 | 18 | -------------------------------------------------------------------------------- /RFID/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Clone the openbehavior repository to the home directory of user 'pi' and 4 | # then run this script with root permissions to install RFID scanner 5 | 6 | if [ ! -d "/home/pi/Pies" ]; then 7 | mkdir "/home/pi/Pies" 8 | chown pi:users "/home/pi/Pies" 9 | fi 10 | 11 | if [ ! -d "/home/pi/Pies/RFIDReader" ]; then 12 | mkdir "/home/pi/Pies/RFIDReader" 13 | chown pi:users "/home/pi/Pies/RFIDReader" 14 | fi 15 | 16 | cp /home/pi/openbehavior/RFID/rfidscanner.service /etc/systemd/system/rfidscanner.service 17 | systemctl enable rfidscanner.service 18 | 19 | -------------------------------------------------------------------------------- /RFID/rfidReaderCase.scad: -------------------------------------------------------------------------------- 1 | $fn=100; 2 | 3 | module mounting_m25(innR=1.6, h=4){ // screw 4 | difference(){ 5 | color("orange") cylinder(r=3.8, h); 6 | cylinder(r=innR, h=10); 7 | } 8 | } 9 | 10 | module mounting_pi(){ 11 | translate([-58/2,-49/2,0]) mounting_m25(); 12 | translate([58/2,-49/2,0]) mounting_m25(); 13 | translate([-58/2,49/2,0]) mounting_m25(); 14 | translate([58/2,49/2,0]) mounting_m25(); 15 | translate([-10,0,0]) cube([85,56,0.1], center=true); 16 | } 17 | 18 | module rfid_antenna_housing(){ 19 | difference(){ 20 | cube([53,40,10], center=true); // rfid antenna outside; 21 | translate([0,-6,0]) cube([47,46,5], center=true); // rfid antenna groove; 22 | cube([36,25,18], center=true); //rfid antenna loop inside 23 | } 24 | } 25 | 26 | module lcdPanel(){ 27 | w=75; 28 | l=31; 29 | difference(){ 30 | union(){ 31 | translate([w/2, l/2,0])cylinder(r=3.6, h=10); 32 | translate([w/2, -l/2,0])cylinder(r=3.6, h=10); 33 | translate([-w/2, -l/2,0])cylinder(r=3.6, h=10); 34 | translate([-w/2, l/2,0])cylinder(r=3.6, h=10); 35 | 36 | } 37 | union (){ 38 | translate([w/2, l/2,0])cylinder(r=1.6, h=11); 39 | translate([w/2, -l/2,0])cylinder(r=1.6, h=11); 40 | translate([-w/2, -l/2,0])cylinder(r=1.6, h=11); 41 | translate([-w/2, l/2,0])cylinder(r=1.6, h=11); 42 | } 43 | } 44 | 45 | } 46 | 47 | module baseboard(){ 48 | difference(){ 49 | color("grey") translate([0,-96,-3]) cube([90, 152, 4], center=true); // base board 50 | translate([40,-105,-2])cube([3.0, 11.5,5], center=true); // rfid board connection via the pins; 51 | translate([0,-6,0]) cube([47,46,5], center=true); // rfid antenna groove; 52 | } 53 | } 54 | module sidewall(){ 55 | color("blue") cube([2,100,30], center=true); 56 | translate([3,46.5,8]) difference( ) { cube([7,7,14], center=true); cylinder(r=1.9, h=43);} 57 | translate([3,-46.5,8]) difference( ) { cube([7,7,14], center=true); cylinder(r=1.9, h=43);} 58 | } 59 | 60 | 61 | module topCoverMounting() { 62 | mx=41; 63 | my=-73.3; 64 | my2=-166.6; 65 | color("blue") translate([mx,my,0]) cylinder(r=1.8,h=40); 66 | color("blue") translate([-mx,my,0]) cylinder(r=1.8,h=40); 67 | color("blue") translate([-mx,my2,0])cylinder(r=1.8,h=40); 68 | color("blue") translate([mx,my2,0]) cylinder(r=1.8,h=40); 69 | } 70 | 71 | module topCover(){ 72 | difference(){ 73 | translate([0,-120,30]) cube([90, 104, 3], center=true); 74 | topCoverMounting(); 75 | } 76 | } 77 | 78 | module lcd(){ // model: HD44780 79 | translate([0,-44, 13.1]) cube([69+1, 24+1, 8.4], center=true); 80 | translate([0,-44, 13.1-3.7]) cube([80.6, 36, 1], center=true); 81 | } 82 | 83 | module screws_frontCover(){ 84 | r0=1.6; 85 | h0=25; 86 | // in the base 87 | translate([40,-67,-20]) cylinder(r=r0, h0); 88 | translate([-40,-67,-20]) cylinder(r=r0, h0); 89 | // on the side 90 | h1=10; 91 | translate([41,-67,20]) rotate([90,0,0]) cylinder(r=r0, h1); 92 | translate([-41,-67,20]) rotate([90,0,0]) cylinder(r=r0, h1); 93 | } 94 | 95 | module frontCover (){ 96 | difference() { 97 | union(){ 98 | translate([-45,-70,-1]) color("pink") cube([2,50,16]); 99 | translate([45-2,-70,-1]) color("pink") cube([2,50,16]); 100 | translate([-45,-22,-1]) color("pink") cube([90, 2,16]); 101 | translate([-45,-70,15]) color("blue") cube([90, 50,2]); 102 | translate([-45,-70,13]) cube ([90,2,15]); 103 | translate([-40,-67,6]) cube([6,6,14],center=true); // for screws 104 | translate([40,-67,6]) cube([6,6,14],center=true); // for screws 105 | } 106 | lcd(); 107 | translate([-27,-69,10]) cylinder(r=5,h=6); // brightness adjust 108 | screws_frontCover(); 109 | } 110 | } 111 | 112 | union(){ 113 | // lcd(); 114 | difference() { 115 | union(){ 116 | rfid_antenna_housing(); 117 | translate([0,-43,-1]) lcdPanel(); 118 | translate([-13,-143+8,-1.0]) rotate([0,0,-90]) mounting_pi(); // pi // rpi 119 | bx=44; 120 | by=-120; 121 | baseboard(); 122 | translate([bx,by,13]) rotate([0,0,180]) sidewall(); 123 | translate([-bx,by,13]) sidewall(); 124 | } 125 | screws_frontCover(); 126 | } 127 | difference(){ 128 | translate([0,-171,13]) cube([90,2,30], center=true);// backwall 129 | translate([-13,-170,3]) cube([20,10, 5], center=true); // sdcard slot 130 | translate([35,-170, 28]) rotate([90,0,0]) cylinder(r=2.5, h=20); 131 | } 132 | } 133 | topCover(); 134 | frontCover(); 135 | 136 | 137 | -------------------------------------------------------------------------------- /RFID/rfidscanner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import serial 4 | import sys 5 | import time 6 | import datetime 7 | import operator 8 | import Adafruit_CharLCD 9 | 10 | # CONSTANTS 11 | # path to data file 12 | 13 | idfile=open("/home/pi/deviceid") 14 | device=idfile.read() 15 | device=device.strip() 16 | today=datetime.date.today() 17 | td=str(today)+"\n" 18 | year=datetime.date.today().year 19 | month=datetime.date.today().month 20 | datafile="/home/pi/Pies/RFIDReader/"+device+"_"+str(year)+"-"+str(month)+".log" 21 | # flags 22 | startflag = "\x02" 23 | endflag = "\x03" 24 | 25 | def printIDtoLCD(lcd, idstring): 26 | lcd.clear() 27 | lcd.message(td) 28 | lcd.message("Tag Found!\n") 29 | time.sleep(.5) 30 | lcd.clear() 31 | lcd.message(idstring) 32 | 33 | def main(): 34 | # UART data 35 | idstring = "" 36 | chardata = 0 37 | 38 | # initialize the LCD 39 | lcd = Adafruit_CharLCD.Adafruit_CharLCD() 40 | lcd.begin(16,1) 41 | lcd.clear() 42 | lcd.message("a posse ad esse\n") 43 | lcd.message(td) 44 | time.sleep(2) 45 | 46 | # open the reader through UART 47 | UART = serial.Serial("/dev/ttyAMA0", 9600) 48 | UART.close() 49 | UART.open() 50 | 51 | # Instruct the user that the scanner is ready to read 52 | lcd.clear() 53 | lcd.message("Ready to scan!") 54 | 55 | # time of scan 56 | firstsaw={} 57 | # Main program loop 58 | while True: 59 | time.sleep(0.25) 60 | # zero out the variables 61 | tag = 0 62 | idstring = "" 63 | # read in a character 64 | chardata = UART.read() 65 | # Is it the start flag? 66 | if chardata == startflag: 67 | # concatenate id together 68 | for i in range(12): 69 | chardata = UART.read() 70 | idstring = idstring + str(chardata) 71 | if idstring not in firstsaw: 72 | firstsaw[idstring]=time.time() 73 | lapsed=int((time.time()-firstsaw[idstring])/60) 74 | msg=idstring + "\n"+ "Seen "+ str(lapsed) + " m ago" 75 | printIDtoLCD(lcd, msg) 76 | with open(datafile, "a") as f: 77 | f.write(time.strftime("%Y-%m-%d\t%H:%M:%S\t") + idstring + "\n") 78 | f.close() 79 | UART.flushInput() 80 | 81 | main() 82 | -------------------------------------------------------------------------------- /RFID/rfidscanner.service: -------------------------------------------------------------------------------- 1 | # systemd unit for starting RFID scanner on boot 2 | [Unit] 3 | Description=RFIDscanner 4 | 5 | [Service] 6 | Type=simple 7 | ExecStart=/home/pi/openbehavior/RFID/rfidscanner.py 8 | ExecStop=/usr/bin/pkill rfidscanner.py 9 | 10 | [Install] 11 | WantedBy=getty.target 12 | DefaultInstance=tty1 13 | -------------------------------------------------------------------------------- /RFID/settingUpUART.readme: -------------------------------------------------------------------------------- 1 | For Raspbian Jessie: 2 | run the following two commands 3 | 4 | sudo systemctl stop serial-getty@ttyAMA0.service 5 | sudo systemctl disable serial-getty@ttyAMA0.service 6 | 7 | then disable the login shell: 8 | 9 | sudo raspi-config 10 | 11 | select 9 for advanced options. 12 | select A8 for Serial to disable login shell. 13 | 14 | then reboot. 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /RFID_eInk_Reader/Readme.md: -------------------------------------------------------------------------------- 1 | # This is a RFID reader with an eInk hat display 2 | 3 | ## 2.7 inch e-paper hat 4 | * From [WaveShare.com](https://www.waveshare.com/2.7inch-e-Paper-HAT.htm) 5 | * User manual in [PDF](https://www.waveshare.com/w/upload/3/31/2.7inch_e-paper_hat_user_manual_en.pdf) 6 | 7 | ## RFID USB reader 8 | * https://www.amazon.com/Reader-LANMU-125khz-Contactless-Proximity/dp/B07B7H6CQ2 9 | 10 | ## Software 11 | * Library https://github.com/waveshare/e-Paper/tree/master/2.7inch_e-paper_code/RaspberryPi/ 12 | * Steps not described in the user manual 13 | * enable SPI interface in the PI ```sudo raspi-config``` 14 | * For the python demo code from waveshare, make sure the font is present in your system. 15 | * To run the python code automatically after boot, do the following 16 | * change the boot into command line and enable auto login with user pi by running ```sudo raspi-config``` 17 | * add the python program to the end of the .bashrc file for user pi 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /RFID_eInk_Reader/a_rfid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding:utf-8 -*- 3 | 4 | #import epd2in7 5 | import time 6 | #from PIL import Image,ImageDraw,ImageFont 7 | import os 8 | 9 | 10 | #epd = epd2in7.EPD() 11 | #epd.init() 12 | #epd.Clear(0xFF) 13 | 14 | def show(text): 15 | # Himage = Image.new('1', (epd2in7.EPD_HEIGHT, epd2in7.EPD_WIDTH), 255) # 255: clear the frame 16 | # draw = ImageDraw.Draw(Himage) 17 | # font32 = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',32) 18 | # draw.text((10, 0), text, font = font32, fill = 0) 19 | # epd.display(epd.getbuffer(Himage)) 20 | print(text) 21 | 22 | print("Ready to scan") 23 | line="" 24 | cnt=0 25 | while True: 26 | if (cnt == 5 ): 27 | cnt=0 28 | line="" 29 | cnt=cnt+1 30 | rfid=input("Waiting for RFID") 31 | #rfid=hex(int(rfid)).upper() 32 | l=len(rfid) 33 | line=line + rfid[2:l-4] + "." + rfid[-4:] + "\n" 34 | print(line) 35 | time.sleep(.5) 36 | 37 | -------------------------------------------------------------------------------- /RFID_eInk_Reader/rfid_reader_eink.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding:utf-8 -*- 3 | 4 | import epd2in7 5 | import time 6 | from PIL import Image,ImageDraw,ImageFont 7 | import os 8 | 9 | 10 | epd = epd2in7.EPD() 11 | epd.init() 12 | epd.Clear(0xFF) 13 | 14 | def show(text): 15 | Himage = Image.new('1', (epd2in7.EPD_HEIGHT, epd2in7.EPD_WIDTH), 255) # 255: clear the frame 16 | draw = ImageDraw.Draw(Himage) 17 | font32 = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',32) 18 | draw.text((10, 0), text, font = font32, fill = 0) 19 | epd.display(epd.getbuffer(Himage)) 20 | 21 | show("Ready to scan") 22 | line="" 23 | cnt=0 24 | while True: 25 | if (cnt == 5 ): 26 | cnt=0 27 | line="" 28 | cnt=cnt+1 29 | rfid=input("Waiting for RFID") 30 | rfid=rfid.upper() 31 | l=len(rfid) 32 | line=line + rfid[0:l-4] + "." + rfid[-4:] + "\n" 33 | show(line) 34 | time.sleep(.5) 35 | 36 | epd.sleep() 37 | -------------------------------------------------------------------------------- /RFID_eInk_Reader/rfid_reader_eink.scad: -------------------------------------------------------------------------------- 1 | $fn=100; 2 | 3 | module mounting_m25(innR=1.6, h=4){ // screw 4 | difference(){ 5 | color("orange") cylinder(r=3.8, h); 6 | cylinder(r=innR, h=10); 7 | } 8 | } 9 | 10 | module mounting_pi(){ 11 | translate([-58/2,-49/2,0]) mounting_m25(); 12 | translate([58/2,-49/2,0]) mounting_m25(); 13 | translate([-58/2,49/2,0]) mounting_m25(); 14 | translate([58/2,49/2,0]) mounting_m25(); 15 | translate([-10,0,0]) cube([85,56,0.1], center=true); 16 | } 17 | 18 | 19 | 20 | module baseboard(){ 21 | color("grey")cube([70, 93, 3], center=true); // base board 22 | } 23 | module sidewall(){ // include the top cover mounting holes 24 | color("blue") cube([2,93,27], center=true); 25 | translate([3, 43,10]) difference( ) { cylinder(r=3.5, h=5, center=true); cylinder(r=1.6, h=43);} 26 | translate([3,-43,10]) difference( ) { cylinder(r=3.5, h=5, center=true); cylinder(r=1.6, h=43);} 27 | } 28 | 29 | 30 | module topCoverMounting() { 31 | mx=31; 32 | my=-31.5; 33 | my2=54.5; 34 | color("blue") translate([mx,my,0]) cylinder(r=1.9,h=40); 35 | color("blue") translate([-mx,my,0]) cylinder(r=1.9,h=40); 36 | color("blue") translate([-mx,my2,0])cylinder(r=1.9,h=40); 37 | color("blue") translate([mx,my2,0]) cylinder(r=1.9,h=40); 38 | } 39 | 40 | module epaper(){ 41 | translate([-18,-24,0]) cube([40, 60, 30]); 42 | } 43 | 44 | module header(){ 45 | translate([-30,-26,25.5]) cube([10,60,2]); 46 | } 47 | 48 | module topCover(){ 49 | difference(){ 50 | color("green")translate([0,11.5,27]) cube([70, 93, 3], center=true); 51 | topCoverMounting(); 52 | epaper(); 53 | header(); 54 | } 55 | } 56 | 57 | module case(){ 58 | union(){ 59 | difference() { 60 | union(){ 61 | rotate([0,0,-90]) translate([0,0,1])mounting_pi(); // pi // rpi 62 | translate([0,11.5,1]) baseboard(); 63 | bx=34; 64 | by=11.5; 65 | translate([bx,by,13]) rotate([0,0,180]) sidewall(); 66 | translate([-bx,by,13]) sidewall(); 67 | } 68 | translate([30,-30, 4]) cube([10, 15, 9]); // power plug 69 | } 70 | difference(){ // short end 71 | translate([0,-34,13]) cube([70,2,27], center=true);// backwall 72 | translate([0,-34,4]) cube([20,10, 6], center=true); // sdcard slot 73 | translate([-18,-34,6]) rotate([90,0,0]) cylinder(r=3,h=5, center=true); // view port for LEDs 74 | 75 | } 76 | difference(){ // USB end 77 | translate([0,57,13]) cube([70,2,27], center=true);// backwall 78 | translate([-10,56,18]) cube([35,20,25], center=true); // USB 79 | } 80 | } 81 | } 82 | 83 | module rfidholder(){ 84 | difference() { 85 | cube ([74, 80, 17],center=true); //outside 86 | cube ([66, 130,40],center=true); // middle 87 | translate([0,0,-2])cube ([70, 100,13],center=true); //inner most 88 | } 89 | } 90 | 91 | 92 | //case(); 93 | 94 | topCover(); 95 | //translate([0,10,34])rfidholder(); 96 | 97 | -------------------------------------------------------------------------------- /RFID_eInk_Reader/rfid_reader_eink_cover.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/RFID_eInk_Reader/rfid_reader_eink_cover.stl -------------------------------------------------------------------------------- /RPI.PinLables.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/RPI.PinLables.pdf -------------------------------------------------------------------------------- /envSensors/3D_design_frame/envSensorBoard.scad: -------------------------------------------------------------------------------- 1 | $fn=60; 2 | 3 | translate([-4,0,0]) pi(); 4 | translate([-65,-100,0]) base(); 5 | translate([-60,-65,0]) color("red") devboard(); 6 | translate([-2,-35,0]) rtc(); 7 | translate([13,-94,0]) humidity(); 8 | color("green") translate([-22,-94,0]) lux(); 9 | color("cyan") translate([-56,-94,0]) barometer(); 10 | 11 | module barometer(){ 12 | m25(innR=1.1); 13 | translate([12,0,0]) m25(innR=1.1); 14 | } 15 | 16 | module humidity(){ 17 | m25(innR=1.1); 18 | translate([11,0,0]) m25(innR=1.1); 19 | } 20 | 21 | module lux(){ 22 | m25(innR=1.1); 23 | translate([13.5,0,0]) m25(innR=1.1); 24 | } 25 | 26 | 27 | module devboard() { 28 | translate([4,4,0]) m25(); 29 | translate([44,4,0]) m25(); 30 | translate([4,26,0]) m25(); 31 | translate([44,26,0]) m25(); 32 | } 33 | 34 | module rtc(){ 35 | m25(innR=1.3); 36 | difference(){ 37 | union(){ 38 | translate([22.5,0,0]) cylinder(r=3.8, h=7); 39 | translate([24.5,0,0]) cylinder(r=3.8, h=7) ; 40 | } 41 | translate([22.5,0,0]) cylinder(r=1.2, h=10); 42 | translate([24.5,0,0]) cylinder(r=1.2, h=10); 43 | } 44 | } 45 | 46 | 47 | module m25(innR=1.6, h=7){ // screw 48 | difference(){ 49 | color("orange") cylinder(r=3.8, h); 50 | cylinder(r=innR, h=10); 51 | } 52 | } 53 | 54 | module pi(){ 55 | translate([-58/2,-49/2,0]) m25(); 56 | translate([58/2,-49/2,0]) m25(); 57 | translate([-58/2,49/2,0]) m25(); 58 | translate([58/2,49/2,0]) m25(); 59 | // translate([-10,0,0]) cube([85,56,0.1], center=true); 60 | } 61 | 62 | module base(){ 63 | color("grey") cube([100,130,2]); 64 | } 65 | 66 | 67 | -------------------------------------------------------------------------------- /envSensors/HTU21DF.py: -------------------------------------------------------------------------------- 1 | # Raspberry Pi Driver for Adafruit HTU21D-F 2 | # Go buy one at https://www.adafruit.com/products/1899 3 | # written by D. Alex Gray dalexgray@mac.com 4 | # Thanks to egutting at the adafruit.com forums 5 | # Thanks to Joan on the raspberrypi.org forums 6 | # This requires the pigpio library 7 | # Get pigpio at http://abyz.co.uk/rpi/pigpio/index.html 8 | # 9 | # Copyright (c) 2014 D. Alex Gray 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | # 17 | # The above copyright notice and this permission notice shall be included in 18 | # all copies or substantial portions of the Software. 19 | # 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | # THE SOFTWARE. 27 | import time 28 | import pigpio 29 | import math 30 | 31 | pi = pigpio.pi() 32 | 33 | # HTU21D-F Address 34 | addr = 0x40 35 | 36 | # i2c bus, if you have a Raspberry Pi Rev A, change this to 0 37 | bus = 1 38 | 39 | # HTU21D-F Commands 40 | rdtemp = 0xE3 41 | rdhumi = 0xE5 42 | wtreg = 0xE6 43 | rdreg = 0xE7 44 | reset = 0xFE 45 | 46 | def htu_reset(): 47 | handle = pi.i2c_open(bus, addr) # open i2c bus 48 | pi.i2c_write_byte(handle, reset) # send reset command 49 | pi.i2c_close(handle) # close i2c bus 50 | time.sleep(0.2) # reset takes 15ms so let's give it some time 51 | 52 | def read_temperature(): 53 | handle = pi.i2c_open(bus, addr) # open i2c bus 54 | pi.i2c_write_byte(handle, rdtemp) # send read temp command 55 | time.sleep(0.055) # readings take up to 50ms, lets give it some time 56 | (count, byteArray) = pi.i2c_read_device(handle, 3) # vacuum up those bytes 57 | pi.i2c_close(handle) # close the i2c bus 58 | t1 = byteArray[0] # most significant byte msb 59 | t2 = byteArray[1] # least significant byte lsb 60 | temp_reading = (t1 * 256) + t2 # combine both bytes into one big integer 61 | temp_reading = math.fabs(temp_reading) # I'm an idiot and can't figure out any other way to make it a float 62 | temperature = ((temp_reading / 65536) * 175.72 ) - 46.85 # formula from datasheet 63 | return temperature 64 | 65 | def read_humidity(): 66 | handle = pi.i2c_open(bus, addr) # open i2c bus 67 | pi.i2c_write_byte(handle, rdhumi) # send read humi command 68 | time.sleep(0.055) # readings take up to 50ms, lets give it some time 69 | (count, byteArray) = pi.i2c_read_device(handle, 3) # vacuum up those bytes 70 | pi.i2c_close(handle) # close the i2c bus 71 | h1 = byteArray[0] # most significant byte msb 72 | h2 = byteArray[1] # least significant byte lsb 73 | humi_reading = (h1 * 256) + h2 # combine both bytes into one big integer 74 | humi_reading = math.fabs(humi_reading) # I'm an idiot and can't figure out any other way to make it a float 75 | uncomp_humidity = ((humi_reading / 65536) * 125 ) - 6 # formula from datasheet 76 | # to get the compensated humidity we need to read the temperature 77 | temperature = read_temperature() 78 | humidity = ((25 - temperature) * -0.15) + uncomp_humidity 79 | return humidity 80 | 81 | if __name__ == "__main__": 82 | while 1: 83 | temp=read_temperature() 84 | humd=read_humidity() 85 | print (temp, humd) 86 | time.sleep(2) 87 | -------------------------------------------------------------------------------- /envSensors/Readme.md: -------------------------------------------------------------------------------- 1 | # Using the Raspberry Pi single board computer to monitor the lab environment 2 | 3 | The sensor we use include the HTU21DF for humidity, TSL2561 for light, and BMP180 for barometric pressure. Both the HTU21DF and BMP180 have a temperature sensor. So we take the average readout of the two. These sensors are all connected to the Raspberry Pi via I2C. We also use a I2C real-time clock (DS1307 from either Adafruit or JBtek. JBtek is cheaper but some of the units we got were not reliable) to ensure the accuracy of the time. 4 | 5 | The location of the device is identified in a file named deviceid located at /home/pi/. The ID stored in this file is used to name the data file. This ID is also entered in the data file. This allows the same program to be deployed at multiple locations. The python logger program is run once every 10 min via cron. 6 | 7 | We use this device to monitor the environment of animal housing rooms where the light cycle is reversed. The logger program writes the lux level during the night to a file called lux.csv. The checklux.py program, also ran via a cron job, checks the lux level during the day and flashes an LED to alert the technician if lights are off during the night. 8 | 9 | ## Parts list 10 | 11 | Raspberry Pi 2B or 3 [Element 14] (https://www.element14.com/community/community/raspberry-pi) 12 | 13 | TSL2561 Lux Sensor [Adafruit] (https://www.adafruit.com/products/439) 14 | 15 | BMP180 Pressure Sensor [Adafruit] (https://www.adafruit.com/products/1603) 16 | 17 | HTU21D-F Humidity Sensor [Adafruit] (https://www.adafruit.com/products/1899) 18 | 19 | SB4 Snappable PC BreadBoard [Amazon] (https://www.amazon.com/gp/product/B00PX52C7Q) 20 | 21 | 1P-1P female to Female Jump Wire [Amazon] (https://www.amazon.com/gp/product/B00R96X8JS) 22 | 23 | Edimax USB WiFi module, not needed if use RPi 3B [Amazon] (https://www.amazon.com/Edimax-EW-7811Un-150Mbps-Raspberry-Supports/dp/B003MTTJOY/) 24 | 25 | ## Assembly 26 | 27 | ### Add wires to the sensors 28 | 29 | Cut the jumper wire in half. Solder four wires to each sensor (and RTC). We use black (or grey) for ground, red (or orange) for 5V, blue for SCL, and green for SDA. ![](./images/envSensor1.jpg) 30 | 31 | 32 | ### Prepare the breadboard 33 | Drill four holes at the corners. Solder four rows of pin heads (five pins each) to the snappable breadboard. 34 | We use the two side rows for the GND and 5V. Use the middle two rows for SDA and SCL. 35 | ![](./images/envSensor2.jpg). 36 | 37 | Make sure pins on the same head are all connected at the back. (You can solder a short segment of wire to two middle pin heads to connect them). 38 | ![](./images/envSensor5.jpg). 39 | 40 | ### Connect the wires 41 | 42 | Connect the sensors and the real-time clock to the pins. 43 | ![](./images/envSensor3.jpg) 44 | 45 | Use one additional sets of four wires to connect the last set of pins to the GND, 5V, SCL, and SDA pins on the RPi. 46 | 47 | ### Final step 48 | 49 | Screw the parts to the 3D printed base. 50 | ![](./images/envSensor4.jpg) 51 | 52 | ## Software 53 | 54 | Clone the repository 55 | ``` 56 | cd /home/pi/ 57 | git clone https://github.com/chen42/openbehavior.git 58 | ``` 59 | 60 | Enable the realtime clock by following these [instructions](https://learn.adafruit.com/adding-a-real-time-clock-to-raspberry-pi/overview) 61 | 62 | Edit the /etc/rc.local file to include the following lines (needed by the RTC and HTU21D-F sensor library) 63 | 64 | ``` 65 | echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device 66 | pigpiod & 67 | ``` 68 | 69 | Run the following command to edit cron 70 | 71 | ``` 72 | sudo crontab -e 73 | ``` 74 | 75 | Add the following line will run the EnvSensor script once every 20 min. 76 | 77 | ``` 78 | */20 * * * python /home/pi/openbehavior/envSensors/env_logger.cron.py 79 | ``` 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /envSensors/SampleData.tab: -------------------------------------------------------------------------------- 1 | 2015-09-23 14:50:03 HSRatsIVSARoom 20.0444042969 65.3711937256 100982 0.0 2 | 2015-09-23 15:00:03 HSRatsIVSARoom 20.1265795898 66.8091518555 100982 0.0 3 | 2015-09-23 15:10:03 HSRatsIVSARoom 20.1319421387 66.8794251709 100977 0.0 4 | 5 | -------------------------------------------------------------------------------- /envSensors/bmp.py: -------------------------------------------------------------------------------- 1 | 2 | import time 3 | import Adafruit_BMP.BMP085 as BMP085 4 | 5 | 6 | barometer = BMP085.BMP085(mode=BMP085.BMP085_ULTRAHIGHRES) 7 | while 1: 8 | pressure=barometer.read_pressure() 9 | temp=barometer.read_temperature() 10 | print (str(temp), str(pressure)) 11 | time.sleep(2) 12 | 13 | -------------------------------------------------------------------------------- /envSensors/checklux.py: -------------------------------------------------------------------------------- 1 | # Abigail Salinero, a summer student, contributed this code. 2 | 3 | import RPi.GPIO as GPIO 4 | import time 5 | 6 | pin=11 7 | GPIO.setmode(GPIO.BOARD) 8 | GPIO.setup(pin, GPIO.OUT) 9 | 10 | 11 | def blink(pin): 12 | GPIO.output(pin,GPIO.HIGH) 13 | time.sleep(.2) 14 | GPIO.output(pin,GPIO.LOW) 15 | time.sleep(.2) 16 | return 17 | 18 | 19 | sum = 0 20 | count = 0 21 | threshold = 5 22 | with open('/home/pi/lux.csv') as f: 23 | for line in f: 24 | sum += float(line) 25 | count = count + 1 26 | avg = sum/count 27 | print avg 28 | while avg <= threshold: 29 | blink(pin) 30 | -------------------------------------------------------------------------------- /envSensors/env_logger.cron.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Author: Ethan Willis, Hao Chen 3 | Description: This program will log temperature, humidity, and barometric pressure 4 | and luminosity to a log file with a given frequency. 5 | This is scheduled to run via cron jobs. An LED connected to GPIO pin 8 is turned on when the script is ran 6 | 7 | 8 | ''' 9 | 10 | import time 11 | from time import strftime 12 | import datetime 13 | import sys 14 | import RPi.GPIO as gpio 15 | 16 | ## moved this block here to turn off the LED when program starts 17 | led=8 18 | gpio.setmode(gpio.BOARD) 19 | gpio.setup(led, gpio.OUT) 20 | gpio.output(led,False) 21 | 22 | import HTU21DF 23 | import TSL2561 24 | import Adafruit_BMP.BMP085 as BMP085 25 | 26 | ''' 27 | Writes data to the logfile located at the location specified 28 | by the filename variable. 29 | ''' 30 | def write_to_log(filename, data): 31 | with open(filename, "a") as logfile: 32 | datastring = str(data[0]) + "\t" + location + "\t" + str(data[1]) + "\t" + str(data[2]) + "\t" + str(data[3]) + "\t" + str(data[4])+"\n" 33 | logfile.write(datastring) 34 | print datastring 35 | 36 | def write_lux(filename, data): 37 | with open(filename, "a") as luxfile: 38 | datastring= str(data)+"\n" 39 | luxfile.write(datastring) 40 | 41 | def readLux(): 42 | LightSensor = TSL2561.Adafruit_TSL2561() 43 | LightSensor.enableAutoGain(True) 44 | count=0 45 | luxTotal=0 46 | while True: 47 | if (count <=100): 48 | luxTotal=LightSensor.calculateLux() + luxTotal 49 | count+=1 50 | else: 51 | lux=round(luxTotal/100) 52 | break 53 | return lux 54 | 55 | def prog(filename): 56 | err=0 57 | try: 58 | print ("Reading humidity") 59 | HTU21DF.htu_reset 60 | humidity=HTU21DF.read_humidity() 61 | temp1=HTU21DF.read_temperature() 62 | time.sleep(5) 63 | except: 64 | print ("Failed") 65 | humidity="NA" 66 | temp1=0 67 | err=1 68 | try: 69 | print ("Reading the barometer") 70 | barometer = BMP085.BMP085(mode=BMP085.BMP085_ULTRAHIGHRES) 71 | pressure=barometer.read_pressure() 72 | temp2=barometer.read_temperature() 73 | time.sleep(5) 74 | except: 75 | print ("Failed") 76 | pressure="NA" 77 | temp2=0 78 | err=1 79 | if (temp1==0 or temp2==0): 80 | temp=temp1+temp2 81 | else: 82 | temp=(temp1+temp2)/2 83 | try: 84 | print ("Reading Lux level") 85 | lux=readLux() 86 | time.sleep(5) 87 | except: 88 | print ("Failed") 89 | lux="" 90 | err=1 91 | datetime=strftime("%Y-%m-%d\t%H:%M:%S") 92 | data=[datetime,temp,humidity,pressure,lux] 93 | # savenewdataentry 94 | write_to_log(filename,data) 95 | hour=strftime("%H") 96 | if int(hour) < 7: 97 | write_lux("/home/pi/lux.csv",lux) 98 | return err 99 | 100 | 101 | idfile=open("/home/pi/deviceid") 102 | location=idfile.read().strip() 103 | year=datetime.date.today().year 104 | month=datetime.date.today().month 105 | filename="/home/pi/Pies/Env/Env"+location+str(year)+"-"+str(month)+".log" 106 | err=prog(filename) 107 | if err==0: 108 | gpio.output(led,True) 109 | else: 110 | gpio.output(led,False) 111 | 112 | -------------------------------------------------------------------------------- /envSensors/images/envSensor1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/envSensors/images/envSensor1.jpg -------------------------------------------------------------------------------- /envSensors/images/envSensor2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/envSensors/images/envSensor2.jpg -------------------------------------------------------------------------------- /envSensors/images/envSensor3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/envSensors/images/envSensor3.jpg -------------------------------------------------------------------------------- /envSensors/images/envSensor4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/envSensors/images/envSensor4.jpg -------------------------------------------------------------------------------- /envSensors/images/envSensor5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/envSensors/images/envSensor5.jpg -------------------------------------------------------------------------------- /envSensors/setup_scripts/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ## NOTE: pigpoid can be found here: wget abyz.co.uk/rpi/pigpio/pigpio.zip 4 | ## need to install the following: 5 | ## enable I2C: https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup/configuring-i2c 6 | ## install Adafruit library for the MCP9808 https://learn.adafruit.com/mcp9808-temperature-sensor-python-library/software 7 | 8 | ## The following commands need to be run before the env log file 9 | 10 | sudo chmod 666 /sys/module/i2c_bcm2708/parameters/combined 11 | sudo echo -n 1 > /sys/module/i2c_bcm2708/parameters/combined 12 | sudo pigpiod 13 | 14 | ## Setup our DS1307 Clock 15 | ./setup_ds1307.sh 16 | -------------------------------------------------------------------------------- /envSensors/setup_scripts/setup_auto_log_copy.sh: -------------------------------------------------------------------------------- 1 | # create usb UDEV rules for running script when USB drive is plugged in. 2 | sudo echo 'SUBSYSTEMS=="usb", KERNEL=="sd[a-h]", SYMLINK+="usbkey", RUN+="/home/pi/autocopylogs.sh" SUBSYSTEMS=="usb",KERNEL=="sd[a-h]",ACTION=="remove", RUN+="/home/pi/autocopylogs.sh"' > /etc/udev/rules.d/999-env-autologging.rules 3 | sudo echo 'SUBSYSTEMS=="usb", KERNEL=="sd[a-h]1", SYMLINK+="usbkey", RUN+="/home/pi/autocopylogs.sh" SUBSYSTEMS=="usb",KERNEL=="sd[a-h]1",ACTION=="remove", RUN+="/home/pi/autocopylogs.sh"' >> /etc/udev/rules.d/999-env-autologging.rules 4 | 5 | 6 | # create shell script for copying files to usb drive from /home/pi/ 7 | OUTPUTDIR=/home/pi/autocopylogs.sh 8 | LOGFILESRC=/home/pi/behaviorRoomEnv.log 9 | LOGFILEDEST=/mnt/usblog/behaviorRoomEnv.log 10 | sudo echo '#!/bin/sh' > $OUTPUTDIR 11 | sudo echo 'ACTION=$(expr "ACTION" : "\([a-zA-Z]\+\).*")' >> $OUTPUTDIR 12 | sudo echo 'if [ "$ACTION" = "add" ]' >> $OUTPUTDIR 13 | sudo echo 'then' >> $OUTPUTDIR 14 | sudo echo ' mount /mnt/usb' >> $OUTPUTDIR 15 | sudo echo " # Copy log files to /mnt/usb/" >> $OUTPUTDIR 16 | sudo echo " cp $LOGFILESRC $LOGFILEDEST" >> $OUTPUTDIR 17 | sudo echo " # Blink RPi LED" >> $OUTPUTDIR 18 | sudo echo " # Turn off Default SD Card blinking mechanisms" >> $OUTPUTDIR 19 | sudo echo " echo none > /sys/class/leds/led0/trigger" >> $OUTPUTDIR 20 | sudo echo " echo 1 > /sys/class/leds/led0/brightness" >> $OUTPUTDIR 21 | sudo echo " sleep 1" >> $OUTPUTDIR 22 | sudo echo " echo 0 > /sys/class/leds/led0/brightness" >> $OUTPUTDIR 23 | sudo echo " sleep 1" >> $OUTPUTDIR 24 | sudo echo " echo 1 > /sys/class/leds/led0/brightness" >> $OUTPUTDIR 25 | sudo echo " sleep 2" >> $OUTPUTDIR 26 | sudo echo " echo 0 > /sys/class/leds/led0/brightness" >> $OUTPUTDIR 27 | sudo echo " sleep 2" >> $OUTPUTDIR 28 | sudo echo " echo 1 > /sys/class/leds/led0/brightness" >> $OUTPUTDIR 29 | sudo echo " sleep 1" >> $OUTPUTDIR 30 | sudo echo " echo 0 > /sys/class/leds/led0/brightness" >> $OUTPUTDIR 31 | sudo echo " sleep 1" >> $OUTPUTDIR 32 | sudo echo " echo 1 > /sys/class/leds/led0/brightness" >> $OUTPUTDIR 33 | sudo echo " sleep 1" >> $OUTPUTDIR 34 | sudo echo " echo 0 > /sys/class/leds/led0/brightness" >> $OUTPUTDIR 35 | sudo echo " sleep 1" >> $OUTPUTDIR 36 | sudo echo " echo 1 > /sys/class/leds/led0/brightness" >> $OUTPUTDIR 37 | sudo echo " sleep 1" >> $OUTPUTDIR 38 | sudo echo " # Turn back on normal SD card trigger for LED " >> $OUTPUTDIR 39 | sudo echo " echo mmc0 > /sys/class/leds/led0/trigger" >> $OUTPUTDIR 40 | sudo echo 'else' >> $OUTPUTDIR 41 | sudo echo ' umount /mnt/usb' >> $OUTPUTDIR 42 | sudo echo 'fi' >> $OUTPUTDIR 43 | 44 | 45 | # Create directory for mounting usb drive 46 | sudo mkdir /mnt/usblog 47 | 48 | # Add entry into fstab to automount usb devices to /mnt/usblog 49 | # TODO: Make this smarter and make it so that only one such entry exists in our fstab 50 | echo "/dev/usbkey /mnt/usblog vfat ro,noauto,user,exec 0 0" >> /etc/fstab 51 | -------------------------------------------------------------------------------- /envSensors/setup_scripts/setup_ds1307.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ## This script is meant to be run once in order to setup a connected ds1307 adafruit RTC module. 4 | 5 | # Step 1: Add the RTC-DS1307 to our list of modules 6 | echo "rtc-ds1307" >> /etc/modules 7 | 8 | # Step 2: Create our ds-1307 as a device on Raspberry Pi boot 9 | # TODO: Make sure that this gets echoed before the exit 0 command in rc.local 10 | echo "echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device" >> /etc/rc.local 11 | echo "sudo hwclock -s" >> /etc/rc.local 12 | -------------------------------------------------------------------------------- /extinction/ExtinctionBoxWiring.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/extinction/ExtinctionBoxWiring.ods -------------------------------------------------------------------------------- /extinction/Readme.md: -------------------------------------------------------------------------------- 1 | # Using a Raspberry Pi to run extinction sessions 2 | 3 | We have several old operant chamber where the electronics are starting to fail. This project uses a RPi to record the number of licks on two spouts. There is also a constantly flashing visual cue during the session. We now use these to run the contextual extinction sessions as described in our earlier papers by Wang et al. (2014) and by Wang et al. (2014) .  4 | 5 | The *extinctionCase* holds the RPi. The *extinctionCueLightPlate* holds the cue light for one side. The *extinctionCueLightBox* is inserted into the *extinctionCase* and holds the other set of cue lights. The *extinctionCaseCover* has an opening for an LCD, which displays session info and data. 6 | 7 | The device is running either from a 5V DC microusb power supply or using a large 5V cell phone backup battery. 8 | -------------------------------------------------------------------------------- /extinction/cuelights.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import RPi.GPIO as gpio 4 | import time 5 | 6 | # BEGIN CONSTANT DEFINITIONS 7 | LED1 = int(33) 8 | LED2 = int(29) 9 | duration=int(1) 10 | 11 | # setup GPIO 12 | gpio.setwarnings(False) 13 | gpio.setmode(gpio.BOARD) 14 | gpio.setup(LED1, gpio.OUT) 15 | gpio.setup(LED2, gpio.OUT) 16 | 17 | start=time.time() 18 | 19 | while ( time.time()-start < 3600 ): 20 | gpio.output(LED1, gpio.HIGH) 21 | gpio.output(LED2, gpio.HIGH) 22 | time.sleep(duration) 23 | gpio.output(LED1, gpio.LOW) 24 | gpio.output(LED2, gpio.LOW) 25 | time.sleep(duration) 26 | 27 | -------------------------------------------------------------------------------- /extinction/extinction.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import RPi.GPIO as gpio 4 | import time 5 | import os 6 | import sys 7 | import Adafruit_MPR121.MPR121 as MPR121 8 | import Adafruit_CharLCD as LCD 9 | 10 | def initLCD(): 11 | # Raspberry Pi pin configuration: 12 | lcd_rs = 25 13 | lcd_en = 24 14 | lcd_d4 = 23 15 | lcd_d5 = 17 16 | lcd_d6 = 21 17 | lcd_d7 = 22 18 | lcd_backlight = 4 19 | # Define LCD column and row size for 16x2 LCD. 20 | lcd_columns = 16 21 | lcd_rows = 2 22 | # Initialize the LCD using the pins above. 23 | lcd = LCD.Adafruit_CharLCD(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7, lcd_columns, lcd_rows, lcd_backlight) 24 | lcd.clear() 25 | sysTime= time.strftime("%H:%M:%S", time.localtime()) 26 | lcd.message("Hurry up, Wifi!\n" + deviceid + "Sess."+ sessionid) 27 | return lcd 28 | 29 | def initTouch(): 30 | cap = MPR121.MPR121() 31 | if not cap.begin(): 32 | print ("Error initializing MPR121. Check your wiring!") 33 | lcd.clean() 34 | lcd.message("Touch Sensor \nConnection Error") 35 | sys.exit(1) 36 | print ("Touch Sensor Started\n") 37 | return cap 38 | 39 | def updatelcd(active, inactive, seconds): 40 | minutes=str(int(seconds/60)) 41 | lcd.clear() 42 | lcd.message("A:" + str(active) + " I:" + str(inactive) + "\n" + "Min:" + str(minutes) + " "+ deviceid[3:] + "S" +sessionid ) 43 | 44 | def recordLicks(sessionLength): 45 | active=0 46 | inactive=0 47 | start=time.time() 48 | updateTime=start 49 | print ("session started\n") 50 | while time.time() - start < sessionLength: 51 | time.sleep(0.07) # sets time resolution 52 | lapsed = time.time() - start 53 | if cap.is_touched(1): 54 | active+=1 55 | updatelcd(active, inactive, lapsed) 56 | updateTime=time.time() 57 | print(active, inactive, lapsed) 58 | with open(lickDataFile,"a") as f: 59 | f.write(str(deviceid) + "\t" + "ratID\t"+today +"\t" + startTime + "\t" + "active\t" + str(lapsed) + "\n") 60 | f.close() 61 | elif cap.is_touched(0): 62 | inactive+=1 63 | lapsed=time.time()-start 64 | updatelcd(active, inactive, lapsed) 65 | updateTime=time.time() 66 | print (active, inactive, lapsed) 67 | with open(lickDataFile,"a") as f: 68 | f.write(str(deviceid) + "\t" + "ratID\t"+today +"\t" + startTime + "\t" + "inactive\t" + str(lapsed) + "\n") 69 | f.close() 70 | if time.time() - updateTime > 60 : # update LCD every 60 sec 71 | updatelcd(active, inactive, lapsed) 72 | updateTime=time.time() 73 | # finishing the data files 74 | updatelcd(active, inactive, lapsed) 75 | print (active, inactive, lapsed) 76 | 77 | if __name__ == '__main__': 78 | idfile=open('/home/pi/deviceid') 79 | deviceid=idfile.read() 80 | deviceid=deviceid.strip() 81 | with open ("/home/pi/sessionid", "r+") as f: 82 | sessionid=f.read() 83 | sessionid=sessionid.strip() 84 | nextSession=int(sessionid)+1 85 | f.seek(0) 86 | f.write(str(nextSession)) 87 | f.close() 88 | lcd=initLCD() 89 | time.sleep(1) 90 | os.system("bash /home/pi/openbehavior/wifi-network/deviceinfo.sh") 91 | os.system("bash /home/pi/openbehavior/wifi-network/wlan0down.sh") 92 | os.system("python /home/pi/openbehavior/extinction/cuelights.py &") 93 | today= time.strftime("%Y-%m-%d", time.localtime()) 94 | startTime= time.strftime("%H:%M:%S", time.localtime()) 95 | lcd.clear() 96 | lcd.message("Session started\n" + startTime) 97 | cap=initTouch() 98 | currentTime=today + "_" + startTime 99 | lickDataFile="/home/pi/Pies/Extinction/" + deviceid + "S"+ sessionid + "_" + today + ".csv" 100 | with open(lickDataFile,"a") as f: 101 | f.write("#Session Started on " + currentTime + "\n") 102 | f.write("device\tRatID\tDate\tStartTime\tSpout\tlapsed\n") 103 | f.close() 104 | recordLicks(3600) # session length in seconds 105 | with open(lickDataFile,"a") as f: 106 | f.write("#Session Ended on " +time.strftime("%Y-%m-%d\t%H:%M:%S\t", time.localtime())+"\n") 107 | f.close() 108 | os.system('/home/pi/openbehavior/wifi-network/rsync.sh &') 109 | 110 | -------------------------------------------------------------------------------- /extinction/extinctionCase.scad: -------------------------------------------------------------------------------- 1 | $fn=100; 2 | 3 | module mounting_m25(innR=1.6, h=10){ // screw 4 | difference(){ 5 | color("orange") cylinder(r=3.8, h); 6 | cylinder(r=innR, h=10); 7 | } 8 | } 9 | 10 | module mounting_pi(){ 11 | translate([-58/2,-49/2,0]) mounting_m25(h=5); 12 | translate([58/2,-49/2,0]) mounting_m25(h=5); 13 | translate([-58/2,49/2,0]) mounting_m25(h=5); 14 | translate([58/2,49/2,0]) mounting_m25(h=5); 15 | translate([-10,0,0]) cube([85,56,0.1], center=true); // pi 16 | } 17 | 18 | 19 | module mounting(){ 20 | cube([14,12,3],center=true); 21 | } 22 | 23 | module col2nd(){ 24 | difference(){ 25 | cube([6,6,12], center=true); 26 | screw(); 27 | } 28 | } 29 | 30 | 31 | module lcd(){ // model: HD44780 32 | translate([0,0, 13.1]) cube([71.5, 25, 8.4], center=true); 33 | //translate([0,0, 13.1-3.7]) cube([80.6, 36, 0.1], center=true); // base plate 34 | } 35 | 36 | 37 | module cover(){ 38 | difference() { 39 | union(){ 40 | cube([x0,y0,3], center=true); 41 | translate([14,2,0])rotate([0,0,90]) lcd_mounting(); 42 | } 43 | rotate([0,0,180]) translate([0,0,-20]) color("blue") screw4(); 44 | # translate([13,2,15]) rotate([0,180,90])lcd(); 45 | } 46 | } 47 | 48 | 49 | module col(){ 50 | cube([8,8,12],center=true); 51 | } 52 | 53 | module col4(){ 54 | zz=15; 55 | translate([x0/2-4, y0/2-9, zz]) col(); 56 | translate([-x0/2+5, y0/2-9, zz]) col(); 57 | translate([x0/2-5, -y0/2+5, zz]) col(); 58 | translate([-x0/2+5, -y0/2+5, zz]) col(); 59 | } 60 | 61 | module screw() { 62 | translate([0,0,-10]) cylinder(r=1.6, h=20); 63 | } 64 | 65 | module screw4(){ 66 | zz=15; 67 | translate([x0/2-5, y0/2-9, zz]) screw(); 68 | translate([-x0/2+5, y0/2-9, zz]) screw(); 69 | translate([x0/2-5, -y0/2+5, zz]) screw(); 70 | translate([-x0/2+5, -y0/2+5, zz]) screw(); 71 | } 72 | 73 | x0=76; 74 | y0=104; 75 | z0=42; 76 | 77 | module case(){ 78 | difference(){ 79 | cube([x0, y0, z0], center=true); // outside 80 | translate([0,0,4]) cube([x0-4, y0-4, z0+5], center=true); // inside 81 | translate([0,y0/2,1]) cube([56, 8, 41], center=true); 82 | translate([0,-40,21]) rotate([90,0,0]) cylinder(r=3,h=30); // cables 83 | translate([-4,-53,-z0/2+5]) cube([20,10, 5], center=true); // sdcard slot 84 | translate([-25,-44,14]) rotate([90,0,0]) cylinder (r=1.5, h=20); // touch sensor 85 | # translate([3,-44,14]) rotate([90,0,0]) cylinder (r=1.5, h=20); // touch sensor 86 | translate([30,21,8]) cube ([10,10,13]); // potential meter for lcd 87 | translate([30,-45,-16])cube([20,14,8]); //powercord 88 | translate([-40, -45, -16]) cube([5,2,20]); // peak slit for the Pi LEDs, 89 | translate([-40, -49, -16]) cube([5,2,20]); // peak slit for the Pi LEDs, 90 | } 91 | translate([-4,-17,-z0/2+1]) rotate([0, 0, -90]) mounting_pi(); 92 | // translate([-25,-47,14]) rotate([90,0,0]) mounting_touch(); 93 | difference(){ 94 | col4(); 95 | screw4(); 96 | } 97 | } 98 | 99 | 100 | 101 | module lcd_mounting(){ 102 | w=75; 103 | l=31; 104 | difference(){ 105 | union(){ 106 | translate([w/2, l/2,0])cylinder(r=3.4, h=7); 107 | translate([w/2, -l/2,0])cylinder(r=3.4, h=7); 108 | translate([-w/2, -l/2,0])cylinder(r=3.4, h=7); 109 | translate([-w/2, l/2,0])cylinder(r=3.4, h=7); 110 | 111 | } 112 | union (){ 113 | translate([w/2, l/2,0])cylinder(r=1.2, h=11); 114 | translate([w/2, -l/2,0])cylinder(r=1.2, h=11); 115 | translate([-w/2, -l/2,0])cylinder(r=1.2, h=11); 116 | translate([-w/2, l/2,0])cylinder(r=1.2, h=11); 117 | } 118 | } 119 | 120 | } 121 | 122 | module mounting_touch(){ 123 | mounting_m25(innR=1.2, h=4); 124 | translate([28,0,0]) mounting_m25(innR=1.5, h=4); 125 | } 126 | 127 | //case(); 128 | translate([0,0,25]) rotate([0,180,180]) cover(); 129 | -------------------------------------------------------------------------------- /extinction/extinctionLEDBox.scad: -------------------------------------------------------------------------------- 1 | $fn=100; 2 | 3 | module LEDBoxPos() { 4 | translate([0,-2/2,0]) cube([63.4, 2,40], center=true) ; //backplate 5 | translate([0,-2/2-4.5,0]) cube([63.4, 2,40], center=true) ;//bbackplate 6 | translate([0,-25,0]) cube([77.4, 2,40], center=true); //faceplete 7 | translate([0,-25/2,0]) cube([55.4,25,40], center=true); // outside 8 | } 9 | 10 | module LEDBoxNeg() { 11 | translate([0,-25/2+2, 0]) cube([52, 26, 35.5], center=true); // inside 12 | } 13 | 14 | module drillholes() {//all four screw holes for LED board 15 | translate([4,3,0]) hollow(); 16 | translate([44,3,0]) hollow(); 17 | translate([4,26,0]) hollow(); 18 | translate([44,26,0]) hollow(); 19 | } 20 | 21 | module hollow() { //the screw holes 22 | cylinder(9.1,1.5,1.5); 23 | } 24 | 25 | module cols4LED(){ //all four inside columns 26 | translate([4,3,2.23]) column(); 27 | translate([44,3,2.23]) column(); 28 | translate([4,26,2.23]) column(); 29 | translate([44,26,2.23]) column(); 30 | } 31 | 32 | module column(){ 33 | cylinder(r=4,6); 34 | } //the inside column 35 | 36 | module led() { // hole for the LED lights 37 | cube([22,10,6],center=true); 38 | } 39 | 40 | module CueLightBox() { 41 | difference() { 42 | LEDBoxPos(); 43 | difference() { 44 | LEDBoxNeg(); 45 | rotate([90,0,0]) translate([-24,-15,17]) cols4LED(); 46 | } 47 | rotate([90,0,0]) translate([-24,-15,14]) drillholes(); 48 | translate([0,-25,12.5]) led(); 49 | } 50 | } 51 | 52 | module CueLightPanel() { 53 | difference(){ 54 | union(){ 55 | translate([0,-25,0]) cube([77.4, 2,40], center=true); //faceplete 56 | rotate([90,0,0]) translate([-24,-15,17]) cols4LED(); 57 | } 58 | rotate([90,0,0]) translate([-24,-15,16]) drillholes(); 59 | translate([0,-25,12.5]) led(); 60 | } 61 | } 62 | //translate([0,48,1]) rotate([0,0,180] ) CueLightBox(); 63 | translate([0,48,1]) rotate([0,0,180] ) CueLightPanel(); 64 | 65 | -------------------------------------------------------------------------------- /infrared/MiceTunnels/DuralLayerPCBForIRDetections.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/infrared/MiceTunnels/DuralLayerPCBForIRDetections.jpg -------------------------------------------------------------------------------- /infrared/MiceTunnels/OneWayDoorClosed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/infrared/MiceTunnels/OneWayDoorClosed.jpg -------------------------------------------------------------------------------- /infrared/MiceTunnels/OneWayDoorOpen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/infrared/MiceTunnels/OneWayDoorOpen.jpg -------------------------------------------------------------------------------- /infrared/MiceTunnels/SixTunnelsForMiceWithOneWayDoors.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/infrared/MiceTunnels/SixTunnelsForMiceWithOneWayDoors.jpg -------------------------------------------------------------------------------- /infrared/board/ir.GBO: -------------------------------------------------------------------------------- 1 | G75* 2 | %MOIN*% 3 | %OFA0B0*% 4 | %FSLAX24Y24*% 5 | %IPPOS*% 6 | %LPD*% 7 | %AMOC8* 8 | 5,1,8,0,0,1.08239X$1,22.5* 9 | % 10 | M02* 11 | -------------------------------------------------------------------------------- /infrared/board/ir.GBS: -------------------------------------------------------------------------------- 1 | G75* 2 | %MOIN*% 3 | %OFA0B0*% 4 | %FSLAX24Y24*% 5 | %IPPOS*% 6 | %LPD*% 7 | %AMOC8* 8 | 5,1,8,0,0,1.08239X$1,22.5* 9 | % 10 | %ADD10C,0.0820*% 11 | %ADD11C,0.1360*% 12 | %ADD12OC8,0.0680*% 13 | D10* 14 | X011100Y004600D03* 15 | X014100Y004600D03* 16 | X017100Y009600D03* 17 | X013850Y012100D03* 18 | X012850Y012100D03* 19 | X011850Y012100D03* 20 | X011350Y013100D03* 21 | X012350Y013100D03* 22 | X013350Y013100D03* 23 | X017100Y012600D03* 24 | X020850Y013100D03* 25 | X021850Y013100D03* 26 | X022850Y013100D03* 27 | X022350Y012100D03* 28 | X021350Y012100D03* 29 | X023350Y012100D03* 30 | X026600Y012600D03* 31 | X026600Y009600D03* 32 | X030850Y012100D03* 33 | X031850Y012100D03* 34 | X032850Y012100D03* 35 | X032350Y013100D03* 36 | X031350Y013100D03* 37 | X030350Y013100D03* 38 | X030100Y017100D03* 39 | X033100Y017100D03* 40 | X036100Y012600D03* 41 | X036100Y009600D03* 42 | X033100Y004600D03* 43 | X030100Y004600D03* 44 | X023600Y004600D03* 45 | X020600Y004600D03* 46 | X020600Y017100D03* 47 | X023600Y017100D03* 48 | X026600Y021600D03* 49 | X026600Y024600D03* 50 | X023350Y024600D03* 51 | X022350Y024600D03* 52 | X021350Y024600D03* 53 | X020850Y025600D03* 54 | X021850Y025600D03* 55 | X022850Y025600D03* 56 | X017100Y024600D03* 57 | X013850Y024600D03* 58 | X012850Y024600D03* 59 | X011850Y024600D03* 60 | X011350Y025600D03* 61 | X012350Y025600D03* 62 | X013350Y025600D03* 63 | X017100Y021600D03* 64 | X014100Y017100D03* 65 | X011100Y017100D03* 66 | X030350Y025600D03* 67 | X031350Y025600D03* 68 | X032350Y025600D03* 69 | X031850Y024600D03* 70 | X030850Y024600D03* 71 | X032850Y024600D03* 72 | X036100Y024600D03* 73 | X036100Y021600D03* 74 | D11* 75 | X033600Y022100D03* 76 | X029600Y022100D03* 77 | X024100Y022100D03* 78 | X020100Y022100D03* 79 | X014600Y022100D03* 80 | X010600Y022100D03* 81 | X010600Y009600D03* 82 | X014600Y009600D03* 83 | X020100Y009600D03* 84 | X024100Y009600D03* 85 | X029600Y009600D03* 86 | X033600Y009600D03* 87 | D12* 88 | X003100Y006600D03* 89 | X003100Y007600D03* 90 | X004100Y007600D03* 91 | X004100Y006600D03* 92 | X004100Y008600D03* 93 | X004100Y009600D03* 94 | X004100Y010600D03* 95 | X004100Y011600D03* 96 | X004100Y012600D03* 97 | X004100Y013600D03* 98 | X003100Y013600D03* 99 | X003100Y012600D03* 100 | X003100Y011600D03* 101 | X003100Y010600D03* 102 | X003100Y009600D03* 103 | X003100Y008600D03* 104 | X003100Y014600D03* 105 | X003100Y015600D03* 106 | X003100Y016600D03* 107 | X003100Y017600D03* 108 | X003100Y018600D03* 109 | X003100Y019600D03* 110 | X003100Y020600D03* 111 | X004100Y020600D03* 112 | X004100Y019600D03* 113 | X004100Y018600D03* 114 | X004100Y017600D03* 115 | X004100Y016600D03* 116 | X004100Y015600D03* 117 | X004100Y014600D03* 118 | X004100Y021600D03* 119 | X004100Y022600D03* 120 | X004100Y023600D03* 121 | X004100Y024600D03* 122 | X004100Y025600D03* 123 | X003100Y025600D03* 124 | X003100Y024600D03* 125 | X003100Y023600D03* 126 | X003100Y022600D03* 127 | X003100Y021600D03* 128 | M02* 129 | -------------------------------------------------------------------------------- /infrared/board/ir.GTS: -------------------------------------------------------------------------------- 1 | G75* 2 | %MOIN*% 3 | %OFA0B0*% 4 | %FSLAX24Y24*% 5 | %IPPOS*% 6 | %LPD*% 7 | %AMOC8* 8 | 5,1,8,0,0,1.08239X$1,22.5* 9 | % 10 | %ADD10C,0.0820*% 11 | %ADD11C,0.1360*% 12 | %ADD12OC8,0.0680*% 13 | D10* 14 | X011100Y004600D03* 15 | X014100Y004600D03* 16 | X017100Y009600D03* 17 | X013850Y012100D03* 18 | X012850Y012100D03* 19 | X011850Y012100D03* 20 | X011350Y013100D03* 21 | X012350Y013100D03* 22 | X013350Y013100D03* 23 | X017100Y012600D03* 24 | X020850Y013100D03* 25 | X021850Y013100D03* 26 | X022850Y013100D03* 27 | X022350Y012100D03* 28 | X021350Y012100D03* 29 | X023350Y012100D03* 30 | X026600Y012600D03* 31 | X026600Y009600D03* 32 | X030850Y012100D03* 33 | X031850Y012100D03* 34 | X032850Y012100D03* 35 | X032350Y013100D03* 36 | X031350Y013100D03* 37 | X030350Y013100D03* 38 | X030100Y017100D03* 39 | X033100Y017100D03* 40 | X036100Y012600D03* 41 | X036100Y009600D03* 42 | X033100Y004600D03* 43 | X030100Y004600D03* 44 | X023600Y004600D03* 45 | X020600Y004600D03* 46 | X020600Y017100D03* 47 | X023600Y017100D03* 48 | X026600Y021600D03* 49 | X026600Y024600D03* 50 | X023350Y024600D03* 51 | X022350Y024600D03* 52 | X021350Y024600D03* 53 | X020850Y025600D03* 54 | X021850Y025600D03* 55 | X022850Y025600D03* 56 | X017100Y024600D03* 57 | X013850Y024600D03* 58 | X012850Y024600D03* 59 | X011850Y024600D03* 60 | X011350Y025600D03* 61 | X012350Y025600D03* 62 | X013350Y025600D03* 63 | X017100Y021600D03* 64 | X014100Y017100D03* 65 | X011100Y017100D03* 66 | X030350Y025600D03* 67 | X031350Y025600D03* 68 | X032350Y025600D03* 69 | X031850Y024600D03* 70 | X030850Y024600D03* 71 | X032850Y024600D03* 72 | X036100Y024600D03* 73 | X036100Y021600D03* 74 | D11* 75 | X033600Y022100D03* 76 | X029600Y022100D03* 77 | X024100Y022100D03* 78 | X020100Y022100D03* 79 | X014600Y022100D03* 80 | X010600Y022100D03* 81 | X010600Y009600D03* 82 | X014600Y009600D03* 83 | X020100Y009600D03* 84 | X024100Y009600D03* 85 | X029600Y009600D03* 86 | X033600Y009600D03* 87 | D12* 88 | X003100Y006600D03* 89 | X003100Y007600D03* 90 | X004100Y007600D03* 91 | X004100Y006600D03* 92 | X004100Y008600D03* 93 | X004100Y009600D03* 94 | X004100Y010600D03* 95 | X004100Y011600D03* 96 | X004100Y012600D03* 97 | X004100Y013600D03* 98 | X003100Y013600D03* 99 | X003100Y012600D03* 100 | X003100Y011600D03* 101 | X003100Y010600D03* 102 | X003100Y009600D03* 103 | X003100Y008600D03* 104 | X003100Y014600D03* 105 | X003100Y015600D03* 106 | X003100Y016600D03* 107 | X003100Y017600D03* 108 | X003100Y018600D03* 109 | X003100Y019600D03* 110 | X003100Y020600D03* 111 | X004100Y020600D03* 112 | X004100Y019600D03* 113 | X004100Y018600D03* 114 | X004100Y017600D03* 115 | X004100Y016600D03* 116 | X004100Y015600D03* 117 | X004100Y014600D03* 118 | X004100Y021600D03* 119 | X004100Y022600D03* 120 | X004100Y023600D03* 121 | X004100Y024600D03* 122 | X004100Y025600D03* 123 | X003100Y025600D03* 124 | X003100Y024600D03* 125 | X003100Y023600D03* 126 | X003100Y022600D03* 127 | X003100Y021600D03* 128 | M02* 129 | -------------------------------------------------------------------------------- /infrared/board/ir.TXT: -------------------------------------------------------------------------------- 1 | % 2 | M48 3 | M72 4 | T01C0.0354 5 | T02C0.0400 6 | T03C0.1280 7 | % 8 | T01 9 | X11100Y4600 10 | X14100Y4600 11 | X17100Y9600 12 | X17100Y12600 13 | X14100Y17100 14 | X11100Y17100 15 | X17100Y21600 16 | X17100Y24600 17 | X20600Y17100 18 | X23600Y17100 19 | X26600Y12600 20 | X26600Y9600 21 | X23600Y4600 22 | X20600Y4600 23 | X30100Y4600 24 | X33100Y4600 25 | X36100Y9600 26 | X36100Y12600 27 | X33100Y17100 28 | X30100Y17100 29 | X26600Y21600 30 | X26600Y24600 31 | X36100Y24600 32 | X36100Y21600 33 | T02 34 | X3100Y6600 35 | X3100Y7600 36 | X4100Y7600 37 | X4100Y6600 38 | X4100Y8600 39 | X4100Y9600 40 | X4100Y10600 41 | X4100Y11600 42 | X4100Y12600 43 | X4100Y13600 44 | X3100Y13600 45 | X3100Y12600 46 | X3100Y11600 47 | X3100Y10600 48 | X3100Y9600 49 | X3100Y8600 50 | X3100Y14600 51 | X3100Y15600 52 | X3100Y16600 53 | X3100Y17600 54 | X3100Y18600 55 | X3100Y19600 56 | X3100Y20600 57 | X4100Y20600 58 | X4100Y19600 59 | X4100Y18600 60 | X4100Y17600 61 | X4100Y16600 62 | X4100Y15600 63 | X4100Y14600 64 | X11350Y13100 65 | X12350Y13100 66 | X13350Y13100 67 | X12850Y12100 68 | X11850Y12100 69 | X13850Y12100 70 | X20850Y13100 71 | X21850Y13100 72 | X22850Y13100 73 | X22350Y12100 74 | X21350Y12100 75 | X23350Y12100 76 | X30350Y13100 77 | X31350Y13100 78 | X32350Y13100 79 | X31850Y12100 80 | X30850Y12100 81 | X32850Y12100 82 | X32850Y24600 83 | X31850Y24600 84 | X30850Y24600 85 | X30350Y25600 86 | X31350Y25600 87 | X32350Y25600 88 | X23350Y24600 89 | X22350Y24600 90 | X21350Y24600 91 | X20850Y25600 92 | X21850Y25600 93 | X22850Y25600 94 | X13850Y24600 95 | X12850Y24600 96 | X11850Y24600 97 | X11350Y25600 98 | X12350Y25600 99 | X13350Y25600 100 | X4100Y25600 101 | X4100Y24600 102 | X4100Y23600 103 | X4100Y22600 104 | X4100Y21600 105 | X3100Y21600 106 | X3100Y22600 107 | X3100Y23600 108 | X3100Y24600 109 | X3100Y25600 110 | T03 111 | X10600Y22100 112 | X14600Y22100 113 | X20100Y22100 114 | X24100Y22100 115 | X29600Y22100 116 | X33600Y22100 117 | X33600Y9600 118 | X29600Y9600 119 | X24100Y9600 120 | X20100Y9600 121 | X14600Y9600 122 | X10600Y9600 123 | M30 124 | -------------------------------------------------------------------------------- /infrared/board/ir.dri: -------------------------------------------------------------------------------- 1 | Generated by EAGLE CAM Processor 7.1.0 2 | 3 | Drill Station Info File: /Users/paper_ziggurat/Documents/eagle/IR/ir.dri 4 | 5 | Date : 9/25/14 3:31 PM 6 | Drills : generated 7 | Device : Excellon drill station 8 | 9 | Parameter settings: 10 | 11 | Tolerance Drill + : 0.00 % 12 | Tolerance Drill - : 0.00 % 13 | Rotate : no 14 | Mirror : no 15 | Optimize : yes 16 | Auto fit : yes 17 | OffsetX : 0inch 18 | OffsetY : 0inch 19 | Layers : Drills Holes 20 | 21 | Drill File Info: 22 | 23 | Data Mode : Absolute 24 | Units : 1/10000 Inch 25 | 26 | Drills used: 27 | 28 | Code Size used 29 | 30 | T01 0.0354inch 24 31 | T02 0.0400inch 76 32 | T03 0.1280inch 12 33 | 34 | Total number of drills: 112 35 | 36 | Plotfiles: 37 | 38 | /Users/paper_ziggurat/Documents/eagle/IR/ir.TXT 39 | -------------------------------------------------------------------------------- /infrared/board/ir.dru: -------------------------------------------------------------------------------- 1 | description[de] = EAGLE Design Rules\n

\nDie Standard-Design-Rules sind so gewählt, dass sie für \ndie meisten Anwendungen passen. Sollte ihre Platine \nbesondere Anforderungen haben, treffen Sie die erforderlichen\nEinstellungen hier und speichern die Design Rules unter \neinem neuen Namen ab. 2 | description[en] = EAGLE Design Rules\n

\nThe default Design Rules have been set to cover\na wide range of applications. Your particular design\nmay have different requirements, so please make the\nnecessary adjustments and save your customized\ndesign rules under a new name. 3 | layerSetup = (1*16) 4 | mtCopper = 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 5 | mtIsolate = 1.5mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 6 | mdWireWire = 8mil 7 | mdWirePad = 8mil 8 | mdWireVia = 8mil 9 | mdPadPad = 8mil 10 | mdPadVia = 8mil 11 | mdViaVia = 8mil 12 | mdSmdPad = 8mil 13 | mdSmdVia = 8mil 14 | mdSmdSmd = 8mil 15 | mdViaViaSameLayer = 8mil 16 | mnLayersViaInSmd = 2 17 | mdCopperDimension = 40mil 18 | mdDrill = 8mil 19 | mdSmdStop = 0mil 20 | msWidth = 10mil 21 | msDrill = 24mil 22 | msMicroVia = 9.99mm 23 | msBlindViaRatio = 0.500000 24 | rvPadTop = 0.250000 25 | rvPadInner = 0.250000 26 | rvPadBottom = 0.250000 27 | rvViaOuter = 0.250000 28 | rvViaInner = 0.250000 29 | rvMicroViaOuter = 0.250000 30 | rvMicroViaInner = 0.250000 31 | rlMinPadTop = 10mil 32 | rlMaxPadTop = 20mil 33 | rlMinPadInner = 10mil 34 | rlMaxPadInner = 20mil 35 | rlMinPadBottom = 10mil 36 | rlMaxPadBottom = 20mil 37 | rlMinViaOuter = 8mil 38 | rlMaxViaOuter = 20mil 39 | rlMinViaInner = 8mil 40 | rlMaxViaInner = 20mil 41 | rlMinMicroViaOuter = 4mil 42 | rlMaxMicroViaOuter = 20mil 43 | rlMinMicroViaInner = 4mil 44 | rlMaxMicroViaInner = 20mil 45 | psTop = -1 46 | psBottom = -1 47 | psFirst = -1 48 | psElongationLong = 100 49 | psElongationOffset = 100 50 | mvStopFrame = 1.000000 51 | mvCreamFrame = 0.000000 52 | mlMinStopFrame = 4mil 53 | mlMaxStopFrame = 4mil 54 | mlMinCreamFrame = 0mil 55 | mlMaxCreamFrame = 0mil 56 | mlViaStopLimit = 0mil 57 | srRoundness = 0.000000 58 | srMinRoundness = 0mil 59 | srMaxRoundness = 0mil 60 | slThermalIsolate = 10mil 61 | slThermalsForVias = 0 62 | dpMaxLengthDifference = 10mm 63 | dpGapFactor = 2.500000 64 | checkGrid = 0 65 | checkAngle = 0 66 | checkFont = 1 67 | checkRestrict = 1 68 | useDiameter = 13 69 | maxErrors = 50 70 | -------------------------------------------------------------------------------- /infrared/board/ir.gpi: -------------------------------------------------------------------------------- 1 | Generated by EAGLE CAM Processor 7.1.0 2 | 3 | Photoplotter Info File: /Users/paper_ziggurat/Documents/eagle/IR/ir.gpi 4 | 5 | Date : 9/25/14 3:31 PM 6 | Plotfile : /Users/paper_ziggurat/Documents/eagle/IR/ir.GBS 7 | Apertures : generated: 8 | Device : Gerber RS-274-X photoplotter, coordinate format 2.4 inch 9 | 10 | Parameter settings: 11 | 12 | Emulate Apertures : no 13 | Tolerance Draw + : 0.00 % 14 | Tolerance Draw - : 0.00 % 15 | Tolerance Flash + : 0.00 % 16 | Tolerance Flash - : 0.00 % 17 | Rotate : no 18 | Mirror : no 19 | Optimize : yes 20 | Auto fit : yes 21 | OffsetX : 0inch 22 | OffsetY : 0inch 23 | 24 | Plotfile Info: 25 | 26 | Coordinate Format : 2.4 27 | Coordinate Units : Inch 28 | Data Mode : Absolute 29 | Zero Suppression : None 30 | End Of Block : * 31 | 32 | Apertures used: 33 | 34 | Code Shape Size used 35 | 36 | D10 round 0.0820inch 60 37 | D11 round 0.1360inch 12 38 | D12 octagon 0.0680inch 40 39 | 40 | -------------------------------------------------------------------------------- /infrared/board/ir.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/infrared/board/ir.pdf -------------------------------------------------------------------------------- /infrared/gpio.ir.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import RPi.GPIO as GPIO 4 | from time import strftime 5 | import time 6 | import os 7 | import grp 8 | import pwd 9 | #from collections import defaultdict 10 | 11 | GPIO.setwarnings(False) 12 | GPIO.setmode(GPIO.BOARD) 13 | 14 | pinCount = input("Enter number of pins in use by IR sensors: ") 15 | channels = [] 16 | pin_alloc = 0 17 | 18 | #get pins to be used from command line 19 | while pin_alloc < pinCount: 20 | pin = input("Enter GPIO pin number: ") 21 | if pin in range (1,27) and not pin in [1, 2, 4, 6, 9, 14, 17, 20, 25]: 22 | channels.append(pin) 23 | pin_alloc += 1 24 | else: 25 | print "Invalid GPIO pin number (power pins are included)" 26 | 27 | #initialize counts 28 | for c in channels: 29 | print str(c) 30 | GPIO.setup(c, GPIO.IN, pull_up_down = GPIO.PUD_UP) 31 | 32 | fo = open("/home/pi/data/ir_log.txt", "a") 33 | uid = pwd.getpwnam("pi").pw_uid 34 | gid = grp.getgrnam("pi").gr_gid 35 | path = "/home/pi/data/ir_log.txt" 36 | os.chown(path, uid, gid) 37 | 38 | def intervalCounting(channel): 39 | fo = open("/home/pi/data/ir_log.txt", "a") 40 | currentTime = strftime("%Y-%m-%d\t%H:%M:%S") 41 | if GPIO.input(channel): 42 | fo.write(str(currentTime) + "\tchannel " + str(channel) + "\tblocked\n") 43 | print currentTime + "\tchannel " + str(channel) + "\tblocked\n" 44 | else: 45 | fo.write(currentTime + "\tchannel " + str(channel) + "\topen\n") 46 | print currentTime + "\tchannel " + str(channel) + "\topen\n" 47 | return 48 | 49 | for c in channels: 50 | GPIO.add_event_detect(c, GPIO.RISING, callback = intervalCounting, bouncetime = 0) 51 | 52 | try: 53 | while True: 54 | time.sleep(50) 55 | 56 | except KeyboardInterrupt: 57 | GPIO.cleanup() 58 | 59 | GPIO.cleanup() 60 | -------------------------------------------------------------------------------- /infrared/parts_list.txt: -------------------------------------------------------------------------------- 1 | items from sparkfun. 2 | 3 | Infrared Emitter & Detector Set: 4 | SEN-00241 5 | 6 | Emitter: 7 | LTE-302 8 | 9 | Detector: 10 | LTR-301 11 | 12 | -------------------------------------------------------------------------------- /motion/Readme.md: -------------------------------------------------------------------------------- 1 | #Adding motion sensors to operant conditioning chambers 2 | 3 | ## Description 4 | This project adds a motion sensor to the commercial MedPC operant chambers. The motion sensor is controlled by a RPi. The RPi is powered by the 28V power source available in the operant chamber (via a step down converter). The RPi is turned on and off via MedPC programs. The data are stored in the SD card of the Pi. Each operant chamber use one Pi. All the Pi computers are connected by a WiFi network and data are transferred to a remote server via sftp. 5 | 6 | ## Parts list 7 | 8 | Molex connector for 28V. Mfg P/N: 03-06-2032 [Mouser] ( http://www.mouser.com/ProductDetail/Molex/03-06-2032/?qs=%2fha2pyFadugvI%2fznVBilJA6N4bQxmqBpdBoCzb%2f9bbY%3d) 9 | 10 | Molex pin. Mfg P/N: 02-06-2103 [Mouser] (http://www.mouser.com/ProductDetail/Molex/02-06-2103/?qs=%2fha2pyFaduhC0HER4S2%2flGJ0%2fQN3qzJ5F27g%252bKWL4TY%3d) 11 | 12 | Motion sensor. [Amazon] (http://www.amazon.com/gp/product/B00FDPO9B8) 13 | 14 | EdiMax WiFi USB. [Amazon] (http://www.amazon.com/gp/product/B003MTTJOY) 15 | 16 | Step-down LM2596 power converter. [eBay] (http://www.ebay.com/itm/161476280982) 17 | 18 | ## Notes 19 | 20 | Two step down DC-DC converters are used. One is set to 5 V to power the RPi. This is always on. The other one is set to 3.3 V. This is only on when the output port in the MedPC is activated. This then controls the on and off of the motion.py program. 21 | 22 | -------------------------------------------------------------------------------- /motion/motion.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import RPi.GPIO as gpio 4 | import time 5 | import os 6 | import sys 7 | 8 | pirPin=12 9 | offPin=16 10 | motionLed=40 11 | gpio.setwarnings(False) 12 | gpio.setmode(gpio.BOARD) 13 | gpio.setup(pirPin, gpio.IN, pull_up_down=gpio.PUD_DOWN) 14 | gpio.setup(offPin, gpio.IN, pull_up_down=gpio.PUD_DOWN) 15 | gpio.setup(motionLed, gpio.OUT) 16 | 17 | while(True): 18 | if not gpio.input(offPin): 19 | os.system("/home/pi/openbehavior/wifi-network/killhtpd.sh &") # kills htpd in 30 sec 20 | os.system("/home/pi/openbehavior/wifi-network/deviceinfo.sh") # try to connect to wifi but only wait for max 20 sec. 21 | os.system("sudo ifconfig wlan0 down") # disconnect from the internet 22 | boxid=open("/home/pi/deviceid").read().strip() 23 | # session id 24 | with open ("/home/pi/sessionid", "r+") as f: 25 | storedSessionID=f.read().strip() 26 | sessionID=int(storedSessionID)+1 27 | f.seek(0) 28 | f.write(str(sessionID)) 29 | f.close() 30 | startTime=time.strftime("%Y-%m-%d_%H:%M:%S", time.localtime()) 31 | motionDataFile='/home/pi/Pies/OCMotion/'+ boxid + "_s" + str(sessionID) + "_" + startTime + ".csv" 32 | with open(motionDataFile,"a") as f: 33 | f.write("#Session started at " + startTime +"\n") 34 | f.write("seconds\n") 35 | f.close() 36 | print ("session starts at " + startTime) 37 | cnt=0 38 | start=time.time() 39 | 40 | while gpio.input(offPin)==0: 41 | # time.sleep(0.1) # time resolution of motion data 42 | if gpio.input(pirPin): 43 | cnt=cnt+1 44 | # print ("motion cnt " + str(cnt)) 45 | with open(motionDataFile,"a") as f: 46 | lapsed=time.time()-start 47 | f.write(str(lapsed) +"\n") 48 | f.close() 49 | gpio.output(motionLed, True) 50 | time.sleep(0.2) 51 | gpio.output(motionLed, False) 52 | time.sleep(0.2) 53 | # print "session ended\n" 54 | with open(motionDataFile,"a") as f: 55 | f.write("#Session ended\t" + boxid + "\tsession"+ str(sessionid)+ "\t"+ time.strftime("%Y-%m-%d\t%H:%M:%S", time.localtime()) + "\t" + str(cnt)+"\n") 56 | f.close() 57 | os.system("sudo ifconfig wlan0 up") 58 | os.system("/home/pi/openbehavior/wifi-network/rsync.sh &") 59 | else: 60 | time.sleep(1) 61 | gpio.output(motionLed, True) 62 | #print "pin 16 has no signal\n" 63 | 64 | -------------------------------------------------------------------------------- /motion/motionSensorCaseOperantChamber.scad: -------------------------------------------------------------------------------- 1 | $fn=100; 2 | 3 | module mounting_m25(innR=1.6, h=10){ // screw 4 | difference(){ 5 | color("orange") cylinder(r=3.8, h); 6 | cylinder(r=innR, h=10); 7 | } 8 | } 9 | 10 | module mounting_pi(){ 11 | translate([-58/2,-49/2,0]) mounting_m25(); 12 | translate([58/2,-49/2,0]) mounting_m25(); 13 | translate([-58/2,49/2,0]) mounting_m25(); 14 | translate([58/2,49/2,0]) mounting_m25(); 15 | translate([-10,0,0]) cube([85,56,0.1], center=true); 16 | } 17 | 18 | module volhouse () { /* voltage converter*/ 19 | difference(){ 20 | cube([22,27,12],center=true); 21 | cube([18,23,12.1],center=true); 22 | } 23 | } 24 | module mounting(){ 25 | cube([14,12,3],center=true); 26 | } 27 | 28 | module col2nd(){ 29 | difference(){ 30 | cube([6,6,12], center=true); 31 | screw(); 32 | } 33 | } 34 | module cover(){ 35 | difference() { 36 | cube([x0,y0,3], center=true); 37 | rotate([0,0,180]) translate([0,0,-20]) color("blue") screw4(); 38 | } 39 | y=-20; 40 | x=16; 41 | z=4.5; 42 | translate([x,y,z]) volhouse(); 43 | translate([-x,y,z]) volhouse(); 44 | translate([x+13,y, z]) col2nd(); 45 | translate([-x-13,y, z]) col2nd(); 46 | } 47 | 48 | 49 | module col(){ 50 | cube([8,8,12],center=true); 51 | } 52 | module col4(){ 53 | zz=15; 54 | translate([x0/2-4, y0/2-9, zz]) col(); 55 | translate([-x0/2+5, y0/2-9, zz]) col(); 56 | translate([x0/2-5, -y0/2+5, zz]) col(); 57 | translate([-x0/2+5, -y0/2+5, zz]) col(); 58 | 59 | } 60 | 61 | module screw() { 62 | translate([0,0,-10]) cylinder(r=1.6, h=20); 63 | } 64 | 65 | 66 | module screw4(){ 67 | zz=15; 68 | translate([x0/2-5, y0/2-9, zz]) screw(); 69 | translate([-x0/2+5, y0/2-9, zz]) screw(); 70 | translate([x0/2-5, -y0/2+5, zz]) screw(); 71 | translate([-x0/2+5, -y0/2+5, zz]) screw(); 72 | } 73 | 74 | x0=76; 75 | y0=104; 76 | z0=42; 77 | 78 | 79 | module case(){ 80 | difference(){ 81 | cube([x0, y0, z0], center=true); // outside 82 | translate([0,0,4]) cube([x0-4, y0-4, z0+5], center=true); // inside 83 | translate([0,y0/2,1]) cube([56, 8, 41], center=true); 84 | translate([0,-40,21]) rotate([90,0,0]) cylinder(r=3,h=30); // power cords 85 | translate([-4,-53,-z0/2+10]) cube([20,10, 5], center=true); // sdcard slot 86 | } 87 | translate([-4,-17,-z0/2+1]) rotate([0, 0, -90]) mounting_pi(); 88 | difference(){ 89 | col4(); 90 | screw4(); 91 | } 92 | } 93 | 94 | module volcover(){ 95 | sx=29; 96 | sy=-20; 97 | sz=10; 98 | difference(){ 99 | translate([0, sy,sz]) cube([64,8,2],center=true); 100 | translate([sx, sy,sz])screw(); 101 | translate([-sx, sy,sz])screw(); 102 | } 103 | } 104 | 105 | module motionBoxPos() { 106 | translate([0,-2/2,0]) cube([63.4, 2,40], center=true) ; //backplate 107 | translate([0,-2/2-4.5,0]) cube([63.4, 2,40], center=true) ;//bbackplate 108 | translate([0,-25,0]) cube([77.4, 2,40], center=true); //faceplete 109 | translate([0,-25/2,0]) cube([55.4,25,40], center=true); // outside 110 | } 111 | 112 | module motionBoxNeg() { 113 | translate([0,-25/2+2, 0]) cube([51.4, 26, 31], center=true); // inside 114 | translate([14.5,0,0]) rotate([90,0,0]) cylinder(r=1, h=25); // motion sensor mounting screw 115 | translate([-14.5, 0,0]) rotate([90,0,0]) cylinder(r=1, h=25); // motion sensor mounting screw 116 | rotate([90,0,0]) cylinder(r=4.5, h=30); // motion sensor proper 117 | translate([0,-25,0])rotate([90,0,0]) cylinder(r1=4.5, r2=14,h=3); // motion sensor proper 118 | } 119 | 120 | module motionBoardBox(){ 121 | difference() { 122 | motionBoxPos(); 123 | motionBoxNeg(); 124 | } 125 | } 126 | 127 | //case(); 128 | //translate([0,48,1]) rotate([0,0,180] ) motionBoardBox(); 129 | //translate([0,0,25]) rotate([0,180,180]) cover(); 130 | color("yellow") volcover(); 131 | 132 | -------------------------------------------------------------------------------- /openscad/pump_design/middlePieceModified.scad: -------------------------------------------------------------------------------- 1 | pumpHolderWidth=50.25; 2 | pumpHolderHeight=36;//38.26; 3 | pumpHolderThickness=10.20; 4 | 5 | 6 | semiCircleDiameter=19; //16.36; 7 | semiCircleRadius=semiCircleDiameter/2; 8 | 9 | semiCircleHeight=26.54; 10 | semiCircleThickness=7.23; 11 | 12 | recBlockHeight=13.63; 13 | recBlockWidth=8.25; 14 | 15 | offsetThickness=2.03; 16 | 17 | 18 | 19 | sideScrewRadius=1.75; 20 | sideScrewHeight=4; 21 | sideScrewOffsetRatio=0.38; 22 | 23 | rotate([90,0,0]) scale([0.94,1,1]) translate([0,0,0]) difference(){ 24 | minkowski(){ 25 | 26 | difference(){ 27 | difference(){ 28 | difference(){ 29 | cube([pumpHolderWidth,pumpHolderThickness,pumpHolderHeight],center=true); 30 | 31 | translate([0,(pumpHolderThickness/2)-(semiCircleThickness/2)+.001,(pumpHolderHeight/2) - (semiCircleHeight/2) + .5]) color("red") union(){ 32 | rotate([90,0,0]) cylinder(h=pumpHolderThickness+5,r=semiCircleRadius, center=true); 33 | 34 | color("blue") translate([0,0,(semiCircleHeight/2)/2]) cube([semiCircleDiameter,pumpHolderThickness+5,semiCircleHeight/2 +.1],center=true); 35 | } 36 | } 37 | 38 | union(){ 39 | color("red") translate([(pumpHolderWidth/2)-(recBlockWidth/2),0,-(pumpHolderHeight/2)+(recBlockHeight/2)]) cube([recBlockWidth,pumpHolderThickness,recBlockHeight],center=true); 40 | 41 | color("red") translate([-((pumpHolderWidth/2)-(recBlockWidth/2)),0,-(pumpHolderHeight/2)+(recBlockHeight/2)]) cube([recBlockWidth,pumpHolderThickness,recBlockHeight],center=true); 42 | } 43 | 44 | } 45 | 46 | translate([0,(pumpHolderThickness/2)-(offsetThickness/2),(pumpHolderHeight-recBlockHeight)/2 - ((pumpHolderHeight/2) - recBlockHeight)]) color("black") cube([pumpHolderWidth-3,offsetThickness,pumpHolderHeight-recBlockHeight],center=true); 47 | 48 | } 49 | 50 | 51 | cylinder(1,center=true,$fn=50); 52 | 53 | } 54 | union(){ 55 | screwZAxisoffSet=2.15; 56 | color("red") translate([pumpHolderWidth/2 - (recBlockWidth/2) - (sideScrewHeight/2)-3.1,0,(pumpHolderHeight/2) + 1/2 -(pumpHolderHeight-recBlockHeight) - (sideScrewOffsetRatio*recBlockHeight) - screwZAxisoffSet]) rotate([0,90,0]) cylinder(h=sideScrewHeight,r=sideScrewRadius,$fn=50,center=true); 57 | 58 | color("red") translate([-(pumpHolderWidth/2 - (recBlockWidth/2) - (sideScrewHeight/2)-3.1 ),0,(pumpHolderHeight/2) + 1/2 -(pumpHolderHeight-recBlockHeight) - (sideScrewOffsetRatio*recBlockHeight) - screwZAxisoffSet]) rotate([0,90,0]) cylinder(h=sideScrewHeight,r=sideScrewRadius,$fn=50,center=true); 59 | } 60 | } 61 | 62 | 63 | 64 | // 65 | ////pumpHolderWidth 66 | ////recBlockWidth/2 + (sideScrewHeight/2) 67 | //color("red") translate([pumpHolderWidth/2 - (recBlockWidth/2) - (sideScrewHeight/2)-3.1,0,(pumpHolderHeight/2) + 1/2 -(pumpHolderHeight-recBlockHeight) - (sideScrewOffsetRatio*recBlockHeight)]) rotate([0,90,0]) cylinder(h=sideScrewHeight,r=sideScrewRadius,$fn=50,center=true); 68 | // 69 | //color("red") translate([-(pumpHolderWidth/2 - (recBlockWidth/2) - (sideScrewHeight/2)-3.1 ),0,(pumpHolderHeight/2) + 1/2 -(pumpHolderHeight-recBlockHeight) - (sideScrewOffsetRatio*recBlockHeight)]) rotate([0,90,0]) cylinder(h=sideScrewHeight,r=sideScrewRadius,$fn=50,center=true); 70 | ////cube([60,1,1],center=true); 71 | // 72 | // 73 | //color("blue") translate([0,0,recBlockHeight/2]) cube([recBlockWidth, pumpHolderThickness,recBlockHeight],center=true); 74 | //minkowski(){ 75 | // translate([0,0,recBlockHeight/2]) cube([recBlockWidth, pumpHolderThickness,recBlockHeight],center=true); 76 | // cylinder(.00000000001,center=true,$fn=50); 77 | //} 78 | 79 | 80 | 81 | //----------------------------------------- 82 | 83 | //translate([0,(pumpHolderThickness/2)-(offsetThickness/2),(pumpHolderHeight-recBlockHeight)/2 - ((pumpHolderHeight/2) - recBlockHeight)]) color("black") cube([pumpHolderWidth-3,offsetThickness,pumpHolderHeight-recBlockHeight],center=true); 84 | 85 | // 86 | //difference(){ 87 | // %cube([pumpHolderWidth,pumpHolderThickness,pumpHolderHeight],center=true); 88 | // 89 | // translate([0,(pumpHolderThickness/2)-(semiCircleThickness/2)+.001,(pumpHolderHeight/2) - (semiCircleHeight/2)]) color("red") union(){ 90 | // rotate([90,0,0]) cylinder(h=pumpHolderThickness+5,r=semiCircleRadius, center=true); 91 | // 92 | // color("red") translate([0,0,(semiCircleHeight/2)/2]) cube([semiCircleDiameter,pumpHolderThickness+5,semiCircleHeight/2 +.1],center=true); 93 | // } 94 | //} -------------------------------------------------------------------------------- /operantLeverPressing/1video.h264: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLeverPressing/1video.h264 -------------------------------------------------------------------------------- /operantLeverPressing/2video.h264: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLeverPressing/2video.h264 -------------------------------------------------------------------------------- /operantLeverPressing/Readme.md: -------------------------------------------------------------------------------- 1 | #Operant Lever Pressing 2 | 3 | This is one of the earliest attempts we had. It uses a RPi to monitor two levers (i.e. switches). The output is a dry food pellet deliverying device. 4 | -------------------------------------------------------------------------------- /operantLeverPressing/bmp183.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLeverPressing/bmp183.pyc -------------------------------------------------------------------------------- /operantLeverPressing/htu21d.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLeverPressing/htu21d.pyc -------------------------------------------------------------------------------- /operantLeverPressing/leverRecord.py: -------------------------------------------------------------------------------- 1 | import RPi.GPIO as GPIO 2 | import time 3 | from time import gmtime, strftime 4 | import sys 5 | 6 | # the pin numbers where the two levers ar connected 7 | l1=8 8 | l2=10 9 | 10 | def init(): 11 | GPIO.setmode(GPIO.BOARD) 12 | GPIO.setwarnings(False) 13 | GPIO.setup(l1, GPIO.IN) #for lever 1 14 | GPIO.setup(l2, GPIO.IN) #for lever 2 15 | 16 | def main(argv): 17 | c1=0 # counter for number of presses on lever 1 18 | c2=0 # counter for number of presses on lever 2 19 | t1, animalID = argv.split(":") 20 | t = float(t1) 21 | totalT = time.time() + t - .5 #it should end a bit early than our main program 22 | while True: 23 | input1= GPIO.input(l1) 24 | input2= GPIO.input(l2) 25 | if(input1==0): # i.e. lever is pressed 26 | curTime = strftime("%Y-%m-%d %H:%M:%S", gmtime()) 27 | c1+=1 28 | data = open('data.csv', 'a') 29 | data.write(animalID + "," + str(curTime) + ",Lever 1\n") 30 | data.close() 31 | time.sleep(.200) # debouncing 32 | if(input2==0): 33 | c2+=1 34 | curTime = strftime("%Y-%m-%d %H:%M:%S", gmtime()) 35 | data = open('data.csv', 'a') 36 | data.write(animalID + "," + str(curTime) + ",Lever 2\n") 37 | time.sleep(.200) 38 | if(time.time()>totalT): 39 | print(c1,":",c2) 40 | break 41 | 42 | 43 | if __name__ == "__main__": 44 | init() 45 | main(sys.argv[1]) 46 | -------------------------------------------------------------------------------- /operantLeverPressing/measure.py: -------------------------------------------------------------------------------- 1 | ''' 2 | bmp183 - Adafruit BMP183 SPI interface for Raspberry Pi 3 | Copyright (C) 2014 Przemo Firszt @ https://github.com/PrzemoF/bmp183 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | ''' 18 | 19 | from bmp183 import bmp183 20 | 21 | bmp = bmp183() 22 | bmp.measure_pressure() 23 | print "Temperature: ", bmp.temperature, "deg C" 24 | print "Pressure: ", bmp.pressure/100.0, " hPa" 25 | quit() 26 | 27 | #TODO: Log temp/pressure to data file 28 | -------------------------------------------------------------------------------- /operantLeverPressing/scratch/sensor-test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import scratch 3 | 4 | s = scratch.Scratch() 5 | 6 | message = s.receive() 7 | 8 | #print(type(message)) 9 | #print(message) 10 | 11 | sensor="measure temp and humidity" 12 | 13 | for key, value in message.iteritems(): 14 | print(value) 15 | if sensor in value: 16 | os.system("sudo python3 /home/pi/OpenB/htu21d.py") # this is hardcoded. Need to change. 17 | -------------------------------------------------------------------------------- /operantLeverPressing/scratch/start-scratch-program.py: -------------------------------------------------------------------------------- 1 | import scratch 2 | s = scratch.Scratch() 3 | 4 | # to make a broadcast to scratch 5 | s.broadcast("start") 6 | 7 | -------------------------------------------------------------------------------- /operantLeverPressing/scratch/test.sb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLeverPressing/scratch/test.sb -------------------------------------------------------------------------------- /operantLeverPressing/scratch/test1.py: -------------------------------------------------------------------------------- 1 | # this code is taken from: https://code.google.com/p/py-scratch/ 2 | # The py scratch module needs to be installed for this to work (can be downloaded from the above link) 3 | 4 | import scratch 5 | s = scratch.Scratch() 6 | 7 | # to make a broadcast to scratch 8 | s.broadcast("start") 9 | 10 | # to receive an update from scratch 11 | message = s.receive() 12 | # blocks until an update is received 13 | # message returned as  {'broadcast': [], 'sensor-update': {'scratchvar': '64'}} 14 | #                  or  {'broadcast': ['from scratch'], 'sensor-update': {}} 15 | # where scratchvar is the name of a variable in scratch 16 | # and 'from scratch' is the name of a scratch broadcast 17 | 18 | # send sensor updates to scratch 19 | data = {} 20 | data['pyvar'] = 123 21 | for data['pycounter'] in range(60): 22 | s.sensorupdate(data) 23 | -------------------------------------------------------------------------------- /operantLeverPressing/sensor.py: -------------------------------------------------------------------------------- 1 | #from htu21d import HTU21D ## this is only for the I2C board from adafruit 2 | import time 3 | from time import gmtime, strftime 4 | import sys 5 | from bmp183 import bmp183 6 | 7 | #htu21d = HTU21D() 8 | #htu21d.reset() 9 | bmp = bmp183() 10 | def main(argv): 11 | logs = open('temperature.csv', 'a') 12 | logs.write("AnimalID\tTime\tTemp (C)\tHumidity \tbmp Temp \tbmp Pressure\n") 13 | logs.close() 14 | 15 | animalID = str(argv) 16 | while True: 17 | logs = open('temperature.csv', 'a') 18 | logs.write(animalID) 19 | logs.write(" ") 20 | curTime = strftime("%Y-%m-%d %H:%M:%S", gmtime()) 21 | # temperature = "{:.2f}".format(htu21d.get_temp()) 22 | temperature = -1 23 | # humidity = "{:.2f}".format(htu21d.get_rel_humidity()) 24 | humidity = -1 25 | logs.write(str(curTime)) 26 | logs.write("\t") 27 | logs.write(str(temperature)) 28 | logs.write("\t") 29 | logs.write(str(humidity)) 30 | logs.write("\t") 31 | logs.write(str(bmp.temperature)) 32 | logs.write("\t") 33 | logs.write(str(bmp.pressure)) 34 | logs.close() 35 | time.sleep(120) 36 | 37 | if __name__ == "__main__": 38 | main(sys.argv[1]) 39 | 40 | -------------------------------------------------------------------------------- /operantLeverPressing/temperature and humidity/HTU21DF.py: -------------------------------------------------------------------------------- 1 | # Raspberry Pi Driver for Adafruit HTU21D-F 2 | # Go buy one at https://www.adafruit.com/products/1899 3 | # written by D. Alex Gray dalexgray@mac.com 4 | # Thanks to egutting at the adafruit.com forums 5 | # Thanks to Joan on the raspberrypi.org forums 6 | # This requires the pigpio library 7 | # Get pigpio at http://abyz.co.uk/rpi/pigpio/index.html 8 | # 9 | # Copyright (c) 2014 D. Alex Gray 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | # 17 | # The above copyright notice and this permission notice shall be included in 18 | # all copies or substantial portions of the Software. 19 | # 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | # THE SOFTWARE. 27 | import time 28 | import pigpio 29 | import math 30 | 31 | pi = pigpio.pi() 32 | 33 | # HTU21D-F Address 34 | addr = 0x40 35 | 36 | # i2c bus, if you have a Raspberry Pi Rev A, change this to 0 37 | bus = 1 38 | 39 | # HTU21D-F Commands 40 | rdtemp = 0xE3 41 | rdhumi = 0xE5 42 | wtreg = 0xE6 43 | rdreg = 0xE7 44 | reset = 0xFE 45 | 46 | def htu_reset(): 47 | handle = pi.i2c_open(bus, addr) # open i2c bus 48 | pi.i2c_write_byte(handle, reset) # send reset command 49 | pi.i2c_close(handle) # close i2c bus 50 | time.sleep(0.2) # reset takes 15ms so let's give it some time 51 | 52 | def read_temperature(): 53 | handle = pi.i2c_open(bus, addr) # open i2c bus 54 | pi.i2c_write_byte(handle, rdtemp) # send read temp command 55 | time.sleep(0.055) # readings take up to 50ms, lets give it some time 56 | (count, byteArray) = pi.i2c_read_device(handle, 3) # vacuum up those bytes 57 | pi.i2c_close(handle) # close the i2c bus 58 | t1 = byteArray[0] # most significant byte msb 59 | t2 = byteArray[1] # least significant byte lsb 60 | temp_reading = (t1 * 256) + t2 # combine both bytes into one big integer 61 | temp_reading = math.fabs(temp_reading) # I'm an idiot and can't figure out any other way to make it a float 62 | temperature = ((temp_reading / 65536) * 175.72 ) - 46.85 # formula from datasheet 63 | return temperature 64 | 65 | def read_humidity(): 66 | handle = pi.i2c_open(bus, addr) # open i2c bus 67 | pi.i2c_write_byte(handle, rdhumi) # send read humi command 68 | time.sleep(0.055) # readings take up to 50ms, lets give it some time 69 | (count, byteArray) = pi.i2c_read_device(handle, 3) # vacuum up those bytes 70 | pi.i2c_close(handle) # close the i2c bus 71 | h1 = byteArray[0] # most significant byte msb 72 | h2 = byteArray[1] # least significant byte lsb 73 | humi_reading = (h1 * 256) + h2 # combine both bytes into one big integer 74 | humi_reading = math.fabs(humi_reading) # I'm an idiot and can't figure out any other way to make it a float 75 | uncomp_humidity = ((humi_reading / 65536) * 125 ) - 6 # formula from datasheet 76 | # to get the compensated humidity we need to read the temperature 77 | temperature = read_temperature() 78 | humidity = ((25 - temperature) * -0.15) + uncomp_humidity 79 | return humidity 80 | -------------------------------------------------------------------------------- /operantLeverPressing/temperature and humidity/HTU21DF.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLeverPressing/temperature and humidity/HTU21DF.pyc -------------------------------------------------------------------------------- /operantLeverPressing/temperature and humidity/HTU21DF_Logger.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Author: Ethan Willis 3 | Description: This program will log temperature and humidity 4 | to a log file with a given frequency. 5 | 6 | The log will have the following structure per entry. 7 | "date\ttime\ttemperature\thumidity\n" 8 | 9 | Usage: 10 | python HTU21DF_Logger.py 11 | ''' 12 | import time 13 | import datetime 14 | import HTU21DF 15 | import sys 16 | 17 | ''' 18 | Writes data to the logfile located at the location specified 19 | by the filename variable. 20 | ''' 21 | def write_to_log(filename, data): 22 | with open(filename, "a") as logfile: 23 | datastring = str(data[0]) + "\t" + str(data[1]) + "\t" + str(data[2]) + "\t" + str(data[3]) + "\n" 24 | logfile.write(datastring) 25 | print datastring 26 | 27 | ''' 28 | Collects temperature and humidity data on the time period 29 | specified by the sleeptime variable. 30 | ''' 31 | def prog(filename="/home/pi/data/htu21df.log", sleeptime=3600): 32 | while True: 33 | # reset sensor and collect data for next log entry. 34 | HTU21DF.htu_reset 35 | temperature = HTU21DF.read_temperature() 36 | humidity = HTU21DF.read_humidity() 37 | cur_date = datetime.date.today() 38 | cur_time = time.time() 39 | data = [cur_date, cur_time, temperature, humidity] 40 | 41 | # save new data entry 42 | write_to_log(filename, data) 43 | 44 | # sleep until ready to collect next measurements. 45 | time.sleep(sleeptime) 46 | 47 | prog() 48 | -------------------------------------------------------------------------------- /operantLeverPressing/temperature.csv: -------------------------------------------------------------------------------- 1 | AnimalID Time Temp (C) Humidity bmp Temp bmp Pressure 2 | 1 2014-10-08 18:13:17 -1 -1 23.9 100570 -------------------------------------------------------------------------------- /operantLeverPressing/templogs/temperature.csv: -------------------------------------------------------------------------------- 1 | AnimalID Time Temp (C) Humidity 2 | 1 2014-10-07 21:15:01 AnimalID Time Temp (C) Humidity 3 | 1 2014-10-07 21:18:45 12 12 4 | AnimalID Time Temp (C) Humidity 5 | 8 2014-10-07 21:29:35 12 12 6 | AnimalID Time Temp (C) Humidity 7 | 12 2014-10-07 21:36:15 -1 -1 8 | AnimalID Time Temp (C) Humidity 9 | 12 2014-10-07 21:38:02 -1 -1 10 | AnimalID Time Temp (C) Humidity 11 | 1 2014-10-07 21:38:19 -1 -1 12 | AnimalID Time Temp (C) Humidity 13 | 13 2014-10-08 17:53:22 -1 -1 14 | AnimalID Time Temp (C) Humidity 15 | 1 2014-10-08 17:54:14 -1 -1 16 | 23.6100587 -------------------------------------------------------------------------------- /operantLeverPressing/weather_to_statsd.py: -------------------------------------------------------------------------------- 1 | import time 2 | import math 3 | 4 | from htu21d import HTU21D 5 | 6 | 7 | def calc_dew_pt(temp_c, rel_hum): 8 | A, B, C = 8.1332, 1762.39, 235.66 9 | 10 | pp_amb = 10 ** (A - (B / (temp_c + C))) 11 | return -(C + (B / (math.log10(rel_hum * pp_amb / 100) - A ))), pp_amb 12 | 13 | 14 | if __name__ == '__main__': 15 | sensor = HTU21D() 16 | sensor.reset() 17 | temp = sensor.get_temp() 18 | hum = sensor.get_rel_humidity() 19 | print(time.time(), temp , hum) 20 | 21 | temp_f = temp * 9/5 + 32 22 | dew_pt, pp_amb = calc_dew_pt(temp, hum) 23 | 24 | import statsd 25 | from local_settings import STATSD_HOST, STATSD_PORT, STATSD_PREFIX 26 | client = statsd.StatsClient(STATSD_HOST, STATSD_PORT, prefix=STATSD_PREFIX) 27 | 28 | with client.pipeline() as pipe: 29 | pipe.gauge('deg_f', 0) 30 | pipe.gauge('deg_c', 0) 31 | pipe.gauge('rel_hum', 0) 32 | pipe.gauge('pp_ambient', 0) 33 | pipe.gauge('dew_pt', 0) 34 | 35 | pipe.gauge('deg_f', round(temp_f, 2)) 36 | pipe.gauge('deg_c', round(temp, 2)) 37 | pipe.gauge('rel_hum', round(hum, 2)) 38 | pipe.gauge('pp_ambient', round(pp_amb, 2)) 39 | pipe.gauge('dew_pt', round(dew_pt, 2)) 40 | 41 | -------------------------------------------------------------------------------- /operantLicking/PartsList.md: -------------------------------------------------------------------------------- 1 | 2 | # Parts list 3 | 4 | Qty 1 for most parts, unless otherwise stated. 5 | 6 | Most parts can be purchased from Amazon or Ebay by searching the model number. 7 | 8 | ## Operant Licking Device 9 | 10 | Raspberry Pi Model 2B or newer [Element 14](https://www.element14.com/community/community/raspberry-pi). 11 | 12 | Edimax WiFi USB connector Model: EW-7811Un N150 USB 2.0 (not needed for Raspberry Pi 3 or newer). 13 | 14 | DS1307 realtime clock with dual I2C connections (Model: AT24C32 IIC) 15 | 16 | 12V AC-DC converter (2 Amp) [Amazon](https://www.amazon.com/gp/product/B00PJZQDDO/). 17 | 18 | DC-DC step down module adjustable to 5V (Model: LM2596s ASIN: B00W94HW8S) 19 | 20 | Touch sensor (Model: MPR121, 12 channel) [Adafruit](https://www.adafruit.com/products/1982). 21 | 22 | Motion sensor (Model: HC-SR501) 23 | 24 | RFID reader (Model: RDM 6300) [Amazon](https://www.amazon.com/gp/product/B00KBN01VY/). 25 | 26 | RFID glass tags and injection syringe (EM4100 encoding) [AliExpress](https://www.aliexpress.com/item/RFID-glass-4x20-application-logistics-patrol-asset-identification-management-security-frequency-125KHZ/931328784.html). 27 | 28 | LCD 16 x 2 characters (Model HD44780) 29 | 30 | 10K ohm potentiometer (if the LCD does not come with one) [Amazon](https://www.amazon.com/gp/product/B00OK9DEL4). 31 | 32 | 5 mm LED (white, for cue light). 33 | 34 | 3 mm LED (Assorted colors, for signals). 35 | 36 | 100 om resister Qty: 3. 37 | 38 | Omal (TM) 2 x 40 pcs 20 cm 1P-1P female to female bread jump wire (or other brands). 39 | 40 | Stainless steel flux, such as [Amazon](https://www.amazon.com/gp/product/B001HWE9A2) 41 | 42 | Solid core Hook-up Wire 22 AWG [Sparkfun](https://www.sparkfun.com/products/11367) 43 | 44 | ### Syringe Pump 45 | 46 | LM6UU linear ball bearing bushing Qty: 2 per pump [Amazon](https://www.amazon.com/gp/product/B00NQ2DPV0). 47 | 48 | 625Z single shielded deep groove ball bearing [Amazon](https://www.amazon.com/gp/product/B008ASXTZM/). 49 | 50 | NEMA 11 step motor [Pololu](https://www.pololu.com/product/1205). 51 | 52 | Elegoo Step motor controller with heat sink (Model: A4988) [Amazon](https://www.amazon.com/gp/product/B01GJJGRF2). 53 | 54 | 18-8 Stainless stell threaded Rod M5-0.8 thread [Amazon](https://www.amazon.com/gp/product/B00G3R7J1W/). 55 | 56 | CND motor shaft coupler 5mm to 5mm [Amazon](https://www.amazon.com/gp/product/B00DCAISM2). 57 | 58 | Steel Rod 6mm Diameter [Amazon](https://www.amazon.com/gp/product/B0050RMVLE). 59 | 60 | -------------------------------------------------------------------------------- /operantLicking/Readme.md: -------------------------------------------------------------------------------- 1 | # Operant Licking 2 | 3 | This device uses a RPi to record the licking events on two spouts. It then drives a syring pump to deliver a fixed amount of liquid to the spout, based on the reinforcement schedule in effect (fixed, variable, or progressive ratio). 4 | 5 | ![](images/syrngeLoaded.jpg) 6 | 7 | ## [Parts list](PartsList.md) 8 | 9 | ## [Assembly instruction](Assembly.md) 10 | 11 | Detailed description is published in this [PeerJ Article](https://peerj.com/articles/2981/) 12 | 13 | A video of rat licking for sucrose under a VR10 schedule is available [here](https://youtu.be/l3SEo6oAtPM) 14 | -------------------------------------------------------------------------------- /operantLicking/images/LCD1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/LCD1.jpg -------------------------------------------------------------------------------- /operantLicking/images/LCD2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/LCD2.jpg -------------------------------------------------------------------------------- /operantLicking/images/LCD_connections.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/LCD_connections.jpg -------------------------------------------------------------------------------- /operantLicking/images/RFID_antenna.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/RFID_antenna.jpg -------------------------------------------------------------------------------- /operantLicking/images/RFID_antenna2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/RFID_antenna2.jpg -------------------------------------------------------------------------------- /operantLicking/images/RFID_antenna3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/RFID_antenna3.jpg -------------------------------------------------------------------------------- /operantLicking/images/RFID_board1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/RFID_board1.jpg -------------------------------------------------------------------------------- /operantLicking/images/RFID_board2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/RFID_board2.jpg -------------------------------------------------------------------------------- /operantLicking/images/Rpi_pins.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/Rpi_pins.jpg -------------------------------------------------------------------------------- /operantLicking/images/SwitchBoardBack2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/SwitchBoardBack2.jpg -------------------------------------------------------------------------------- /operantLicking/images/assembled.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/assembled.jpg -------------------------------------------------------------------------------- /operantLicking/images/cuelight.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/cuelight.jpg -------------------------------------------------------------------------------- /operantLicking/images/cuelight2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/cuelight2.jpg -------------------------------------------------------------------------------- /operantLicking/images/frame0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/frame0.jpg -------------------------------------------------------------------------------- /operantLicking/images/inRatCage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/inRatCage.jpg -------------------------------------------------------------------------------- /operantLicking/images/microUSB.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/microUSB.jpg -------------------------------------------------------------------------------- /operantLicking/images/motion_sensor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/motion_sensor.jpg -------------------------------------------------------------------------------- /operantLicking/images/rfid2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/rfid2.jpg -------------------------------------------------------------------------------- /operantLicking/images/spout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/spout.jpg -------------------------------------------------------------------------------- /operantLicking/images/stepMotorBoardBack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/stepMotorBoardBack.jpg -------------------------------------------------------------------------------- /operantLicking/images/stepMotorShaft.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/stepMotorShaft.jpg -------------------------------------------------------------------------------- /operantLicking/images/stepMotorWires.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/stepMotorWires.jpg -------------------------------------------------------------------------------- /operantLicking/images/switchBoardBack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/switchBoardBack.jpg -------------------------------------------------------------------------------- /operantLicking/images/switchBoardFront.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/switchBoardFront.jpg -------------------------------------------------------------------------------- /operantLicking/images/syringCarrier.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/syringCarrier.jpg -------------------------------------------------------------------------------- /operantLicking/images/syringEnd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/syringEnd.jpg -------------------------------------------------------------------------------- /operantLicking/images/syringPumbAssembled.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/syringPumbAssembled.jpg -------------------------------------------------------------------------------- /operantLicking/images/syrngeLoaded.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/syrngeLoaded.jpg -------------------------------------------------------------------------------- /operantLicking/images/threadedRod.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/threadedRod.jpg -------------------------------------------------------------------------------- /operantLicking/images/voltageConverter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/voltageConverter.jpg -------------------------------------------------------------------------------- /operantLicking/images/wires.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/images/wires.jpg -------------------------------------------------------------------------------- /operantLicking/openscad/bearings.scad: -------------------------------------------------------------------------------- 1 | 2 | 3 | // 608 bearing 4 | od_608 = 22.5; 5 | id_608 = 8.4; 6 | h_608 = 7; 7 | bearing_608 = [od_608, id_608, h_608]; 8 | 9 | // 624 bearing 10 | od_624 = 13; 11 | id_624 = 4.4; 12 | h_624 = 5; 13 | bearing_624 = [od_624, id_624, h_624]; 14 | 15 | // 625 bearing 16 | od_625 = 16.4; 17 | id_625 = 5.4; 18 | h_625 = 5; 19 | bearing_625 = [od_625, id_625, h_625]; 20 | 21 | 22 | // lm8uu bearing dims 23 | od_lm8uu = 15.2; // measured 15 24 | id_lm8uu = 8; // should be 8 or so 25 | l_lm8uu = 24.5; // measured 24 26 | bearing_lm8uu = [od_lm8uu, id_lm8uu, l_lm8uu]; 27 | 28 | // lm6uu bearing dims 29 | //od_lm6uu = 12.8; // measured 12 30 | od_lm6uu = 13.4; 31 | id_lm6uu = 6; 32 | l_lm6uu = 19; 33 | bearing_lm6uu = [od_lm6uu, id_lm6uu, l_lm6uu]; 34 | 35 | module bearing(type=608) { 36 | if (type==608) 37 | difference() { 38 | cylinder(r=od_608/2, h=h_608); 39 | 40 | translate([0, 0, -1]) 41 | cylinder(r=id_608/2, h=h_608+2); 42 | } 43 | 44 | if (type==624) 45 | difference() { 46 | cylinder(r=od_624/2, h=h_624); 47 | 48 | translate([0, 0, -1]) 49 | cylinder(r=id_624/2, h=h_624+2); 50 | } 51 | } 52 | 53 | module lm8uu(opening = 0) { 54 | if (opening == 1) 55 | difference() { 56 | cylinder(r = od_lm8uu / 2, h = l_lm8uu); 57 | 58 | translate([0, 0, -1]) 59 | cylinder(r = id_lm8uu / 2, h = l_lm8uu + 2); 60 | } 61 | else 62 | cylinder(r = od_lm8uu / 2, h = l_lm8uu); 63 | } 64 | -------------------------------------------------------------------------------- /operantLicking/openscad/fasteners.scad: -------------------------------------------------------------------------------- 1 | d_M2_screw = 2.3; 2 | d_M2_screw_head = 4; 3 | h_M2_screw_head = 2; 4 | 5 | d_M2_5_screw = 3.1; // 0.5 add't for clearance 6 | d_M2_5_screw_head = 5; // 0.5 add't for clearance 7 | d_M2_5_washer = 6; 8 | d_M2_5_nut = 5.8; // added some clearance 9 | h_M2_5_nut = 2.0; 10 | d_M2_5_cap = 5.5; 11 | h_M2_5_cap = 2.5; 12 | h_M2_5_washer = 0.45; 13 | 14 | d_M3_screw = 3.5; // measured 2.9 15 | d_M3_screw_head = 6.2; // measured 5.5 16 | d_M3_washer = 6.9; // measured 6.7 17 | d_M3_nut = 6.2; 18 | h_M3_nut = 2.7; // measured 2.35 19 | d_M3_cap = 6.0; 20 | h_M3_cap = 3; 21 | h_M3_washer = 0.5; 22 | 23 | d_M4_screw = 4.3; 24 | d_M4_cap = 7.4; // measured 12 25 | h_M4_cap = 4; 26 | d_M4_nut = 8.7; 27 | h_M4_nut = 3.5; // measured 3.1 28 | h_M4_locknut = 5; 29 | d_M4_washer = 9; // measured 8.75 30 | h_M4_washer = 0.75; 31 | 32 | d_M5_screw = 5.3; 33 | d_M5_nut = 9.3; 34 | h_M5_nut = 4.2; // measured 4.0 35 | 36 | d_M6_screw = 6.5; 37 | d_M6_nut = 11.8; 38 | h_M6_nut = 5.5; 39 | 40 | d_M8_screw = 8.4; 41 | d_M8_nut = 15; 42 | h_M8_nut = 6.35; 43 | d_M8_washer= 16; 44 | h_M8_washer = 1.5; 45 | -------------------------------------------------------------------------------- /operantLicking/openscad/stepmotor_fastner.scad: -------------------------------------------------------------------------------- 1 | $fn=40; 2 | module step_motor_fastener (){ 3 | difference(){ 4 | cube([13, 9, 3],center=true); 5 | translate([4,0,-3]) cylinder(r=1.7, h=8); 6 | } 7 | } 8 | 9 | step_motor_fastener() ; 10 | 11 | -------------------------------------------------------------------------------- /operantLicking/openscad/steppers.scad: -------------------------------------------------------------------------------- 1 | include 2 | 3 | function r_mounts(cc_mounts) = 4 | pow(pow(cc_mounts, 2) / 2, 0.5); 5 | 6 | l_NEMA11 = 28.2; // length of one side 7 | d_NEMA11_collar = 22; // diameter of collar 8 | d_NEMA11_shaft = 4.5; // diameter of shaft 9 | cc_NEMA11_mount = 23; // c-c distance for mount holes 10 | d_NEMA11_mount_screw = d_M2_5_screw; 11 | NEMA11 = [l_NEMA11, d_NEMA11_collar, d_NEMA11_shaft, cc_NEMA11_mount, d_NEMA11_mount_screw]; 12 | 13 | l_NEMA17 = 42; // length of one side 14 | d_NEMA17_collar = 28; // diameter of collar 15 | d_NEMA17_shaft = 5.4; // diameter of collar 16 | cc_NEMA17_mount = 31; // c-c distance for mount holes 17 | d_NEMA17_mount_screw = d_M3_screw; 18 | NEMA17 = [l_NEMA17, d_NEMA17_collar, d_NEMA17_shaft, cc_NEMA17_mount, d_NEMA17_mount_screw]; 19 | 20 | l_NEMA23 = 56.4; // length of one side 21 | d_NEMA23_collar = 38.1; // diameter of collar 22 | d_NEMA23_shaft = 6.35; // diameter of collar 23 | cc_NEMA23_mount = 47.14; // c-c distance for mount holes 24 | d_NEMA23_mount_screw = d_M5_screw; 25 | NEMA23 = [l_NEMA23, d_NEMA23_collar, d_NEMA23_shaft, cc_NEMA23_mount, d_NEMA23_mount_screw]; 26 | 27 | // motor = [l_NEMAXX(0), d_NEMAXX_collar(1), d_NEMAXX_shaft(2), cc_NEMAXX_mount(3), d_NEMAXX_mount_screw(4)] 28 | module NEMA_X_mount( 29 | height, 30 | l_slot, 31 | motor) { 32 | 33 | c_d_mount = r_mounts(motor[3]); // distance from shaft center to mount hole 34 | 35 | cylinder(r = (motor[1] / 2) + 1.0, h = height, center = true); 36 | 37 | for (i=[0:3]) { 38 | rotate([0, 0, i * 90]) 39 | translate([c_d_mount, 0, 0]) 40 | hull() 41 | for (j = [-1, 1]) 42 | translate([j * l_slot / 2, 0, 0]) 43 | cylinder(r = motor[4] / 2, h = height, center = true); 44 | } 45 | } 46 | 47 | 48 | // motor = [l_NEMAXX(0), d_NEMAXX_collar(1), d_NEMAXX_shaft(2), cc_NEMAXX_mount(3), d_NEMAXX_mount_screw(4)] 49 | module NEMA_parallel_mount( 50 | height, 51 | l_slot, 52 | motor) 53 | { 54 | 55 | hull() 56 | for (i = [-1, 1]) 57 | translate([i * l_slot / 2, 0, 0]) 58 | cylinder(r = motor[1] / 2, h = height, center = true); 59 | 60 | for (i=[-1, 1]) { 61 | translate([i * motor[3] / 2, i * motor[3] / 2, 0]) 62 | hull() 63 | for (j = [-1, 1]) 64 | translate([j * l_slot / 2, 0, 0]) 65 | cylinder(r = motor[4] / 2, h = height, center = true); 66 | 67 | translate([i * motor[3] / 2, -i * motor[3] / 2, 0]) 68 | hull() 69 | for (j = [-1, 1]) 70 | translate([j * l_slot / 2, 0, 0]) 71 | cylinder(r = motor[4] / 2, h = height, center = true); 72 | } 73 | } 74 | 75 | module motor_shim( 76 | motor, 77 | thickness) 78 | { 79 | difference() { 80 | cube([motor[0], motor[0], thickness], center = true); 81 | 82 | NEMA_parallel_mount( 83 | height = thickness + 1, 84 | l_slot = 0, 85 | motor = motor); 86 | } 87 | } 88 | 89 | module stepper_pedestal( 90 | height, 91 | t_wall, 92 | t_mounts, 93 | motor) { 94 | difference() { 95 | pedestal_body(height = height, motor = motor); 96 | 97 | translate([0 ,0, -t_wall]) 98 | difference() { 99 | hull() { 100 | for (i=[0:3]) { 101 | rotate([0, 0, i*90]) 102 | translate([r_mounts(cc_mounts = motor[3]) + d_M3_washer / 2 - t_wall, 0, 0]) 103 | cylinder(r1 = d_M3_washer / 2 + 1, r2 = d_M3_washer / 2, h = height); 104 | } 105 | } 106 | 107 | translate([0, 0, height-t_mounts+t_wall]) 108 | for (i=[0:3]) { 109 | rotate([0, 0, i*90]) 110 | translate([r_mounts(cc_mounts = motor[3]), 0, 0]) 111 | cylinder(r=d_M3_washer/2+1.5, h=t_mounts); 112 | } 113 | } 114 | 115 | translate([0, 0, height / 2]) 116 | rotate([0, 0, 45]) 117 | NEMA_parallel_mount( 118 | height = height + 2, 119 | l_slot = 0, 120 | motor = motor); 121 | } 122 | } 123 | 124 | // pedestal body for the pedestal 125 | module pedestal_body(motor, height) { 126 | hull() { 127 | for (i=[0:3]) 128 | rotate([0, 0, i*90]) 129 | translate([r_mounts(cc_mounts = motor[3]) + d_M3_washer / 2, 0, 0]) 130 | cylinder(r1 = d_M3_washer / 2 + 1, r2 = d_M3_washer / 2, h = height); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /operantLicking/python/blinkenlights.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import RPi.GPIO as gpio 4 | import time 5 | import argparse 6 | 7 | 8 | parser=argparse.ArgumentParser() 9 | parser.add_argument('-times', type=int) 10 | args=parser.parse_args() 11 | times=args.times 12 | 13 | 14 | # BEGIN CONSTANT DEFINITIONS 15 | GREEN_LED_PIN = int(7) 16 | # END CONSTANT DEFINITIONS 17 | 18 | print (str(times)) 19 | 20 | def flashRewardLED(duration): 21 | gpio.output(GREEN_LED_PIN, gpio.HIGH) 22 | time.sleep(duration) 23 | gpio.output(GREEN_LED_PIN, gpio.LOW) 24 | 25 | if __name__ == "__main__": 26 | # Initialize GPIO 27 | gpio.setwarnings(False) 28 | gpio.setmode(gpio.BOARD) 29 | gpio.setup(GREEN_LED_PIN, gpio.OUT) 30 | # flash 31 | flashRewardLED(5) 32 | while times > 1: 33 | time.sleep(10) 34 | flashRewardLED(5) 35 | times-=1 36 | -------------------------------------------------------------------------------- /operantLicking/python/datalogger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # BEGIN IMPORT PRELUDE 4 | import time 5 | import string 6 | # END IMPORT PRELUDE 7 | 8 | # BEGIN CONSTANT DEFINITIONS 9 | DEVID_FILEPATH = '/home/pi/deviceid' 10 | RATID_FILEPATH = '/home/pi/ratid' 11 | TDATA_FILEPRFX = '/home/pi/Pies/ETOH/ETOH_' 12 | SESSIONID='/home/pi/sessionid' 13 | # END CONSTANT DEFINITIONS 14 | 15 | class LickLogger: 16 | def __init__(self): 17 | # read box id 18 | self.datatype="lick" 19 | def createDataFile(self, RatID, schedule): 20 | devidfile = open(DEVID_FILEPATH) 21 | self.devid = str((devidfile.read()).strip()) 22 | devidfile.close() 23 | 24 | # read rat id 25 | self.ratid = RatID 26 | 27 | # read sessin id 28 | sessionid=open(SESSIONID) 29 | self.sessid=str(sessionid.read().strip()) 30 | #print ("sessionid ", self.sessid, "\n") 31 | 32 | # get start time 33 | startTime=time.strftime("%Y-%m-%d_%H:%M:%S", time.localtime()) 34 | 35 | # construct file name 36 | self.datafile = TDATA_FILEPRFX + self.datatype + "_" + str(self.devid)[5:] + '_S' + self.sessid + "_" + str(self.ratid) + '.csv' 37 | 38 | # open data file 39 | with open(self.datafile,"a") as f: 40 | f.write("RatID\tdate\tboxid\tEventType\t"+schedule+"\tseconds\n") 41 | f.close() 42 | def logEvent(self, EventType, timelapsed, ratio=0): 43 | # Create output string 44 | outputstr = self.ratid + "\t" + time.strftime("%Y-%m-%d", time.localtime()) + "\t" + self.devid + "_S" + self.sessid+ "\t" + EventType + "\t" + str(ratio) + "\t"+ str(timelapsed) + "\n" 45 | # Append to file 46 | with open (self.datafile, "a") as datafile: 47 | datafile.write(outputstr) 48 | 49 | 50 | class MotionLogger (LickLogger): 51 | def __init__ (self): 52 | self.datatype="motion" 53 | -------------------------------------------------------------------------------- /operantLicking/python/motion.py: -------------------------------------------------------------------------------- 1 | import RPi.GPIO as gpio 2 | import datalogger 3 | import argparse 4 | import time 5 | #import os 6 | #import sys 7 | #from time import strftime, localtime 8 | 9 | 10 | parser=argparse.ArgumentParser() 11 | parser.add_argument('-SessionLength', type=int) 12 | parser.add_argument('-RatID', type=str) 13 | parser.add_argument('-Schedule', type=str) 14 | args=parser.parse_args() 15 | sessionLength=args.SessionLength 16 | 17 | pirPin=35 18 | motionLed=31 19 | 20 | # setting up GPIO 21 | gpio.setwarnings(False) 22 | gpio.setmode(gpio.BOARD) 23 | gpio.setup(pirPin, gpio.IN) 24 | gpio.setup(motionLed, gpio.OUT) 25 | 26 | dlogger = datalogger.MotionLogger() 27 | dlogger.createDataFile(args.RatID, args.Schedule) 28 | 29 | start=time.time() 30 | 31 | lapse=0 32 | while lapse < sessionLength: 33 | lapse=time.time()-start 34 | if gpio.input(pirPin): 35 | dlogger.logEvent("Motion", lapse) 36 | gpio.output(motionLed, True) 37 | time.sleep(1) 38 | gpio.output(motionLed, False) 39 | time.sleep(1) 40 | if args.Schedule=="pr": 41 | if int(time.time())%5==0: 42 | sessionEnd=open("/home/pi/prend").read().strip() 43 | if sessionEnd=="yes": 44 | sessionLength=lapse-100 45 | else: 46 | sessionLength=lapse+100 47 | 48 | dlogger.logEvent("SessionEnd", lapse) 49 | 50 | -------------------------------------------------------------------------------- /operantLicking/python/motor2.py: -------------------------------------------------------------------------------- 1 | #code from https://www.raspberrypi.org/forums/viewtopic.php?t=220247#p1352169 2 | # pip3 install pigpio 3 | # git clone https://github.com/stripcode/pigpio-stepper-motor 4 | 5 | ''' 6 | # connection to adafruit TB6612 7 | # motor: SY28STH32-0674A 8 | Vcmotor --> 12V 5A power supply 9 | VM --> floating 10 | Vcc --> 3V3 Pin 17 11 | GND --> GND Pin 06 12 | PwmA --> 3V3 Pin 01 13 | AIN2 --> Pin 15 - BCM 22 14 | AIN1 --> Pin 11 - BCM 17 15 | STBY --> Pin 13 - BCM 27 16 | BIN1 --> Pin 16 - BCM 23 17 | BIN2 --> Pin 18 - BCM 24 18 | PwmB --> Pin 32 - BCM 19 | MotorA --> Red (A+) and Green (A-) wires 20 | MotorB --> Blue (B+) and Black (B-) wires 21 | GND of Power supply --> Pin 39 (gnd) Raspberry Pi 22 | ''' 23 | 24 | import pigpio, time 25 | from PigpioStepperMotor import StepperMotor 26 | 27 | pi = pigpio.pi() 28 | motor = StepperMotor(pi, 17, 23, 22, 24) 29 | pwma = pigpio.pi() 30 | pwma.write(18,1) 31 | pwmb = pigpio.pi() 32 | pwmb.write(12,1) 33 | stby = pigpio.pi() 34 | stby.write(27,0) 35 | for i in range(500): 36 | stby.write(27,1) 37 | motor.doClockwiseStep() 38 | -------------------------------------------------------------------------------- /operantLicking/python/pumpcontrol.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Copyright 2013 Michigan Technological University 4 | # Author: Bas Wijnen 5 | # This design was developed as part of a project with 6 | # the Michigan Tech Open Sustainability Technology Research Group 7 | # http://www.appropedia.org/Category:MOST 8 | # 9 | # This program is free software: you can redistribute it and/or modify 10 | # it under the terms of the GNU Affero General Public License as 11 | # published by the Free Software Foundation, either version 3 of the 12 | # License, or(at your option) any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU Affero General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU Affero General Public License 20 | # along with this program. If not, see . 21 | 22 | # BEGIN IMPORT PRELUDE 23 | import sys 24 | import time 25 | import RPi.GPIO as gpio 26 | 27 | # END IMPORT PRELUDE 28 | 29 | gpio.setmode(gpio.BCM) 30 | # BEGIN Pin configuration 31 | DIR = int(17) # pin 11 32 | STEP = int(27) # pin 13 33 | SLEEP = int(22) # pin 15 34 | MS3 = int(10) # pin 19 35 | MS2 = int(9) # pin 21 36 | MS1 = int(11) # pin 23 37 | 38 | #gpio.setup(SW1, gpio.IN, pull_up_down=gpio.PUD_DOWN) 39 | #gpio.setup(SW2, gpio.IN, pull_up_down=gpio.PUD_DOWN) 40 | # END Pin configuration 41 | 42 | # BEGIN constant definitions 43 | DEFAULT_POSITION = float(0.0) 44 | #DEFAULT_PITCH = float(0.8) 45 | DEFAULT_PITCH = float(1.0) 46 | DEFAULT_STEPS = float(3200.0) 47 | DEFAULT_STEPS_PER_MM = DEFAULT_STEPS / DEFAULT_PITCH 48 | DEFAULT_ML_PER_S = float(0.7) 49 | DEFAULT_ML_PER_MM = float(0.1635531002398778) 50 | DEFAULT_MOVEMENT = float(0.05) 51 | # END constant definitions 52 | 53 | # BEGIN CLASS Pump 54 | class Pump: 55 | # BEGIN Constructor method 56 | def __init__(self, gpio): 57 | self.position = DEFAULT_POSITION 58 | self.pitch = DEFAULT_PITCH 59 | self.steps = DEFAULT_STEPS 60 | self.steps_per_mm = DEFAULT_STEPS_PER_MM 61 | self.ml_per_s = DEFAULT_ML_PER_S 62 | self.ml_per_mm = DEFAULT_ML_PER_MM 63 | self.gpio = gpio 64 | # Set up the GPIO for the pump 65 | self.gpio.setup(SLEEP, self.gpio.OUT, initial = self.gpio.HIGH) 66 | self.gpio.setup(STEP, self.gpio.OUT, initial = self.gpio.HIGH) 67 | self.gpio.setup(DIR, self.gpio.OUT, initial = self.gpio.HIGH) 68 | self.gpio.setup(MS1, self.gpio.OUT, initial = self.gpio.HIGH) 69 | self.gpio.setup(MS2, self.gpio.OUT, initial = self.gpio.HIGH) 70 | self.gpio.setup(MS3, self.gpio.OUT, initial = self.gpio.HIGH) 71 | # END Constructor method 72 | # BEGIN Setter and getter methods 73 | def getPosition(self): 74 | return self.position 75 | def setPosition(self, position): 76 | self.position = position 77 | def getPitch(self): 78 | return self.pitch 79 | def setPitch(self, pitch): 80 | self.pitch = pitch 81 | def getSteps(self): 82 | return self.steps 83 | def setSteps(self, steps): 84 | self.steps = steps 85 | def getStepsPerMm(self): 86 | return self.steps_per_mm 87 | def setStepsPerMm(self, steps_per_mm): 88 | self.steps_per_mm = steps_per_mm 89 | def getMlPerS(self): 90 | return self.ml_per_s 91 | def setMlPerS(self, ml_per_s): 92 | self.ml_per_s = ml_per_s 93 | def getMlPerMm(self): 94 | return self.ml_per_mm 95 | def setMlPerMm(self, ml_per_mm): 96 | self.ml_per_mm = ml_per_mm 97 | # END Setter and getter methods 98 | def goto(self, ml): 99 | self.move(ml - self.position) 100 | def move(self, ml): 101 | self.gpio.output(SLEEP, self.gpio.HIGH) 102 | self.gpio.output(DIR, self.gpio.HIGH if ml < 0 else self.gpio.LOW) 103 | s_per_half_step = self.ml_per_mm / self.steps_per_mm / self.ml_per_s / 2 104 | self.steps = int(ml / self.ml_per_mm * self.steps_per_mm + .5) 105 | target = time.time() 106 | for t in range(abs(self.steps)): 107 | self.gpio.output(STEP, self.gpio.HIGH) 108 | target += s_per_half_step 109 | while time.time() < target: 110 | # Yes, this is a busy wait. 111 | pass 112 | self.gpio.output(STEP, self.gpio.LOW) 113 | target += s_per_half_step 114 | while time.time() < target: 115 | # Yes, this is a busy wait. 116 | pass 117 | self.position += ml 118 | def speed(self, ml_per_s): 119 | self.ml_per_s = ml_per_s 120 | def sleep(self): 121 | self.gpio.output(SLEEP, self.gpio.LOW) 122 | # END CLASS Pump 123 | 124 | -------------------------------------------------------------------------------- /operantLicking/python/pumpinterface.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Copyright 2015 University of Tennessee Health Sciences Center 4 | # Author: Matthew Longley 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Affero General Public License as 8 | # published by the Free Software Foundation, either version 3 of the 9 | # License, or(at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Affero General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Affero General Public License 17 | # along with this program. If not, see . 18 | 19 | import pumpcontrol 20 | 21 | # Helper function to clear the screen and reset the cursor 22 | def clearScreen(): 23 | print(chr(27) + "[2J") 24 | print(chr(27) + "[H") 25 | 26 | # BEGIN CLASS PumpInterface 27 | class PumpInterface: 28 | def __init__(self, pumpToInterface): 29 | self.pump = pumpToInterface 30 | self.steps = 0 31 | gpio.setmode(gpio.BOARD) 32 | # BEGIN Main Menu Display Method 33 | def dispMenu(self): 34 | print("----------------------------------------------------") 35 | print("| Pump Control | Ver. 0.01 | Edit parameters below |") 36 | print("----------------------------------------------------") 37 | print("1) Steps: " + str(self.steps)) 38 | print("2) Speed: " + str((self.pump).getMlPerS()) + " ml/s") 39 | print("3) Pitch: " + str((self.pump).getPitch())) 40 | print("4) ml per mm: " + str((self.pump).getMlPerMm())) 41 | print("5) Begin stepping") 42 | print("6) Exit program") 43 | print("D) DEBUG: " + str((self.pump).readSwitch())) 44 | print("----------------------------------------------------") 45 | print("POSITION: " + str((self.pump).getPosition()) + " mm") 46 | print("STEPS PER MM: " + str((self.pump).getStepsPerMm())) 47 | print("----------------------------------------------------") 48 | # END Main Menu Display Method 49 | # BEGIN User Input Section 50 | def readSteps(self): 51 | print("Enter amount to step: ") 52 | self.steps = int(input()) 53 | def readSpeed(self): 54 | print("Enter speed (in ml/s): ") 55 | (self.pump).setMlPerS(float(input())) 56 | def readPitch(self): 57 | print("Enter pitch: ") 58 | (self.pump).setPitch(float(input())) 59 | def readMlPerMm(self): 60 | print("Enter ml per mm: ") 61 | (self.pump).setMlPerMm(float(input())) 62 | # END User Input Section 63 | def startMovement(self): 64 | (self.pump).move(self.steps) 65 | # BEGIN Program Main Loop 66 | def mainLoop(self): 67 | clearScreen() 68 | while(True): 69 | self.useropt = 'derp' 70 | self.dispMenu() 71 | self.useropt = str(input()) 72 | self.switch1 = (self.pump).readSwitch() 73 | if self.useropt == '1': 74 | self.readSteps() 75 | elif self.useropt == '2': 76 | self.readSpeed() 77 | elif self.useropt == '3': 78 | self.readPitch() 79 | elif self.useropt == '4': 80 | self.readMlPerMm() 81 | elif self.useropt == '5': 82 | self.startMovement() 83 | elif self.useropt == '6': 84 | raise SystemExit 85 | else: 86 | print("Invalid choice. Please enter again.") 87 | clearScreen() 88 | # END Program Main Loop 89 | # END CLASS PumpInterface 90 | 91 | if __name__ == "__main__": 92 | p = pumpcontrol.Pump() 93 | pi = PumpInterface(p) 94 | pi.mainLoop() 95 | -------------------------------------------------------------------------------- /operantLicking/python/pumpmove.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Copyright 2016 University of Tennessee Health Sciences Center 4 | # Author: Matthew Longley 5 | # Author: Hao Chen 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU Affero General Public License as 9 | # published by the Free Software Foundation, either version 3 of the 10 | # License, or(at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU Affero General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Affero General Public License 18 | # along with this program. If not, see . 19 | 20 | # BEGIN IMPORT PRELUDE 21 | import RPi.GPIO as gpio 22 | import pumpcontrol 23 | 24 | # BEGIN CONSTANT DEFINITIONS 25 | SW1 = int(26) #pin 37 26 | SW2 = int(20) #pin 38 27 | # END CONSTANT DEFINITIONS 28 | 29 | # Initialize GPIO 30 | gpio.setwarnings(False) 31 | gpio.setmode(gpio.BCM) 32 | 33 | # Setup switch pins 34 | gpio.setup(SW1, gpio.IN, pull_up_down=gpio.PUD_DOWN) 35 | gpio.setup(SW2, gpio.IN, pull_up_down=gpio.PUD_DOWN) 36 | 37 | # Initialize pump 38 | pump = pumpcontrol.Pump(gpio) 39 | 40 | while True: 41 | if gpio.input(SW1): 42 | pump.move(-0.3) 43 | elif gpio.input(SW2): 44 | pump.move(0.3) 45 | -------------------------------------------------------------------------------- /operantLicking/python/touchsensor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Copyright 2016 University of Tennessee Health Sciences Center 4 | # Author: Matthew Longley 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Affero General Public License as 8 | # published by the Free Software Foundation, either version 3 of the 9 | # License, or(at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Affero General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Affero General Public License 17 | # along with this program. If not, see . 18 | 19 | import Adafruit_MPR121.MPR121 as MPR121 20 | import sys 21 | 22 | class TouchSensor: 23 | def __init__(self): 24 | # Initialize hardware 25 | self.cap = MPR121.MPR121() 26 | if not self.cap.begin(): 27 | print('Error initializing MPR121. Check your wiring!') 28 | sys.exit(1) 29 | # Get last touched 30 | self.lasttouched = self.cap.touched() 31 | self.touched = self.lasttouched 32 | def readPinTouched(self): 33 | self.lasttouched = self.touched 34 | self.touched = self.cap.touched() 35 | for i in range(3): 36 | pinbit = 1 << i 37 | if self.touched & pinbit and not self.lasttouched & pinbit: 38 | return i 39 | if not self.touched & pinbit and self.lasttouched & pinbit: 40 | return -i 41 | -------------------------------------------------------------------------------- /operantLicking/scripts/rpi3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Associative array storing revisions 4 | declare -A revisions 5 | revisions["0002"]=1 6 | revisions["0003"]=1 7 | revisions["0004"]=1 8 | revisions["0005"]=1 9 | revisions["0006"]=1 10 | revisions["0007"]=1 11 | revisions["0008"]=1 12 | revisions["0009"]=1 13 | revisions["000d"]=1 14 | revisions["000e"]=1 15 | revisions["000f"]=1 16 | revisions["0010"]=1 17 | revisions["0013"]=1 18 | revisions["0011"]=1 19 | revisions["0012"]=1 20 | revisions["a01041"]=2 21 | revisions["a21041"]=2 22 | revisions["900092"]=0 23 | revisions["a02082"]=3 24 | revisions["a22082"]=3 25 | 26 | function getRaspberryPiVersion { 27 | REVISION="$(cat /proc/cpuinfo | grep Revision | cut -f 2 | tr -d ": " | head -n 1)" 28 | return ${revisions[$REVISION]} 29 | } 30 | 31 | getRaspberryPiVersion 32 | 33 | if [ "$?" == "3" ] ; then 34 | # Update the boot config 35 | echo "bluetooth disabled; please reboot." 36 | echo "dtoverlay=pi3-disable-bt" >>/boot/config.txt 37 | systemctl disable hciuart 38 | else 39 | echo "Not RPi 3, nothing is done." 40 | fi 41 | 42 | -------------------------------------------------------------------------------- /operantLicking/wiring_tables.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantLicking/wiring_tables.ods -------------------------------------------------------------------------------- /operantSensationSeeking/README.md: -------------------------------------------------------------------------------- 1 | # Operant Senstation Seeking 2 | 3 | This is a device for operant sensation seeking. This needs improvements in several areas based on the alcohol self-admin device. It will be updated when I have time. 4 | -------------------------------------------------------------------------------- /operantSensationSeeking/blink.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import RPi.GPIO as gpio 4 | import time 5 | import random 6 | import argparse 7 | 8 | parser=argparse.ArgumentParser() 9 | parser.add_argument('-datafile', type=str) 10 | parser.add_argument('-start', type=float) 11 | parser.add_argument('-RatID', type=str) 12 | parser.add_argument('-interval', type=int) 13 | args=parser.parse_args() 14 | print ("\n") 15 | print ("\n") 16 | print (args.datafile) 17 | print (args.RatID) 18 | print (args.start ) 19 | print ("\n") 20 | 21 | idfile=open("/home/pi/deviceid") 22 | boxid=idfile.read() 23 | boxid=boxid.strip() 24 | 25 | # green and red LEDs are for sensation seeking 26 | greenLed=7 27 | redLed=11 28 | houseLight1=33 29 | houseLight2=37 30 | pins=[greenLed,redLed] 31 | 32 | gpio.setmode(gpio.BOARD) 33 | gpio.setwarnings(False) 34 | gpio.setup(greenLed, gpio.OUT) 35 | gpio.setup(redLed, gpio.OUT) 36 | gpio.setup(houseLight1, gpio.OUT) 37 | gpio.setup(houseLight2, gpio.OUT) 38 | 39 | ## blinks the green LED and/or red LED at a randomly selected frequency for a randomly selected time period, repeat 1-3 times 40 | def blink(pins): 41 | whichpin=random.randint(0,3) 42 | if whichpin==0: 43 | pin=[pins[0]] 44 | Pin="Red" 45 | elif whichpin==1: 46 | pin=[pins[1]] 47 | Pin="Green" 48 | elif whichpin==2: 49 | pin=pins 50 | Pin="Both" 51 | else: 52 | pin=[pins[0],pins[1],9] # 9 = blink alternatively 53 | Pin="Alt." 54 | numTimes=random.randint(1,3) 55 | speed=random.randint(1,9)/float(9) 56 | lapsed=time.time()-args.start 57 | # which house light to turn off? 58 | hL=1 59 | if random.randint(0,9)< 5 : 60 | hL=0 61 | print "blink house lights" 62 | for i in range (0, random.randint(2,4)): 63 | print (str(i)) 64 | gpio.output(houseLight1,False) 65 | gpio.output(houseLight2,False) 66 | time.sleep(random.randint(1,4)/float(8)) 67 | gpio.output(houseLight1,True) 68 | gpio.output(houseLight2,True) 69 | time.sleep(random.randint(1,4)/float(8)) 70 | if len(pin)==3: 71 | print ("blink pins alternately "+str(pin)+" for "+str(numTimes)+" times at "+str(speed) + " speed") 72 | for i in range(0,numTimes): 73 | gpio.output(pin[0],True) 74 | time.sleep(speed) 75 | gpio.output(pin[0],False) 76 | gpio.output(pin[1],True) 77 | time.sleep(speed) 78 | gpio.output(pin[1],False) 79 | time.sleep(speed) 80 | elif len(pin)==2: 81 | print ("blink both pins "+str(pin)+" for "+str(numTimes)+" times at "+str(speed) + " speed") 82 | for i in range(0,numTimes): 83 | gpio.output(pin[1],True) 84 | gpio.output(pin[0],True) 85 | time.sleep(speed) 86 | gpio.output(pin[0],False) 87 | gpio.output(pin[1],False) 88 | time.sleep(speed) 89 | else: 90 | print ("blink pin "+str(pin[0])+" for "+str(numTimes)+" times at "+str(speed) + " speed") 91 | for i in range(0,numTimes): 92 | gpio.output(pin[0],True) 93 | time.sleep(speed) 94 | gpio.output(pin[0],False) 95 | time.sleep(speed) 96 | houseOff=random.randint(0,args.interval) ## house light off is no longer than inteval 97 | time.sleep(houseOff) 98 | gpio.output(houseLight1,True) 99 | gpio.output(houseLight2,True) 100 | # pin=str(pin) 101 | # pin=str.replace(pin, ",",":") # comma in data file causes confusion with the csv format 102 | # pin=str.replace(pin, "7: 11: 9","both") 103 | # pin=str.replace(pin, "11","red") # replace pin with LED color 104 | # pin=str.replace(pin, "7","green") 105 | with open(args.datafile,"a") as f: 106 | f.write(args.RatID+"\treward\t" + time.strftime("%Y-%m-%d\t%H:%M:%S", time.localtime()) + "\t" + str(lapsed) + "\t" + boxid + "\t" + Pin + "\t" + str(numTimes) + "\t" + str(speed) + "\t" + str(args.interval) + "\t" + str(hL) + "\t" + str(houseOff) + "\n") 107 | f.close() 108 | 109 | blink(pins) 110 | -------------------------------------------------------------------------------- /operantSensationSeeking/errorled.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import RPi.GPIO as gpio 4 | import time 5 | 6 | ErrorLed=35 7 | gpio.setmode(gpio.BOARD) 8 | gpio.setup(ErrorLed,gpio.OUT) 9 | 10 | while True: 11 | gpio.output(ErrorLed, True) 12 | time.sleep(0.5) 13 | gpio.output(ErrorLed, False) 14 | time.sleep(0.5) 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /operantSensationSeeking/freecad/Readme.md: -------------------------------------------------------------------------------- 1 | Housing for operant sensation seeking device. The RFID detector is super glued on because it does not print well on my printer. 2 | -------------------------------------------------------------------------------- /operantSensationSeeking/freecad/rfid.annt.lid.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantSensationSeeking/freecad/rfid.annt.lid.stl -------------------------------------------------------------------------------- /operantSensationSeeking/freecad/rfid.annte.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantSensationSeeking/freecad/rfid.annte.stl -------------------------------------------------------------------------------- /operantSensationSeeking/freecad/roof.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantSensationSeeking/freecad/roof.stl -------------------------------------------------------------------------------- /operantSensationSeeking/freecad/touchOSSwithBattery.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantSensationSeeking/freecad/touchOSSwithBattery.stl -------------------------------------------------------------------------------- /operantSensationSeeking/freecad/touchoss.Battery.fcstd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/operantSensationSeeking/freecad/touchoss.Battery.fcstd -------------------------------------------------------------------------------- /operantSensationSeeking/motion.py: -------------------------------------------------------------------------------- 1 | import RPi.GPIO as gpio 2 | import argparse 3 | import time 4 | import os 5 | import sys 6 | from time import strftime, localtime 7 | 8 | 9 | parser=argparse.ArgumentParser() 10 | parser.add_argument('-RatID', type=str) 11 | args=parser.parse_args() 12 | 13 | sessionLength=1800 14 | pirPin=12 15 | motionLed=31 16 | gpio.setwarnings(False) 17 | gpio.setmode(gpio.BOARD) 18 | gpio.setup(pirPin, gpio.IN) 19 | gpio.setup(motionLed, gpio.OUT) 20 | 21 | ## creat data files, Each box has its own ID 22 | idfile=open("/home/pi/deviceid") 23 | boxid=idfile.read() 24 | boxid=boxid.strip() 25 | startTime=time.strftime("%Y-%m-%d_%H:%M:%S", localtime()) 26 | start=time.time() 27 | motionDataFile='/home/pi/Pies/OSS/Motion/'+boxid+'_motion_'+ args.RatID + '_'+ startTime + ".csv" 28 | with open(motionDataFile,"a") as f: 29 | f.write("#Session Started on " +time.strftime("%Y-%m-%d\t%H:%M:%S\t", localtime())+"\n") 30 | f.write("RatID\tdate\tboxid\tseconds\n") 31 | f.close() 32 | 33 | while time.time()-start < sessionLength: 34 | if gpio.input(pirPin): 35 | #print time.strftime("%Y-%m-%d\t%H:%M:%S") 36 | with open(motionDataFile,"a") as f: 37 | lapsed=time.time()-start 38 | f.write(args.RatID+"\t"+time.strftime("%Y-%m-%d\t", localtime()) + boxid +"\t"+ str(lapsed) +"\n") 39 | f.close() 40 | gpio.output(motionLed, True) 41 | time.sleep(0.2) 42 | gpio.output(motionLed, False) 43 | time.sleep(0.2) 44 | 45 | with open(motionDataFile, "a") as f: 46 | f.write("#session Ended at " + time.strftime("%H:%M:%S", localtime())+"\n") 47 | f.close 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /operantSensationSeeking/ossHabituation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pyhon2 2 | 3 | import RPi.GPIO as gpio 4 | import serial 5 | import time 6 | #import os 7 | #import sys 8 | import subprocess 9 | #import random 10 | 11 | def ReadRFID(path_to_sensor) : 12 | baud_rate = 9600 13 | time_out = 0.05 14 | uart = serial.Serial(path_to_sensor, baud_rate, timeout = time_out) 15 | uart.close() 16 | uart.open() 17 | uart.flushInput() 18 | uart.flushOutput() 19 | print(path_to_sensor + " initiated") 20 | Startflag = "\x02" 21 | Endflag = "\x03" 22 | while True: 23 | Zeichen = 0 24 | Tag = 0 25 | ID = "" 26 | Zeichen = uart.read() 27 | if Zeichen == Startflag: 28 | for Counter in range(13): 29 | Zeichen = uart.read() 30 | ID = ID + str(Zeichen) 31 | ID = ID.replace(Endflag, "" ) 32 | print "RFID detected: "+ ID 33 | return (ID) 34 | 35 | def doneSignal(): 36 | while True: 37 | motionLight=31 38 | gpio.output(touchLed,True) 39 | gpio.output(motionLight,False) 40 | time.sleep(1) 41 | gpio.output(touchLed,False) 42 | gpio.output(motionLight,True) 43 | time.sleep(1) 44 | 45 | if __name__ == '__main__': 46 | sessionLength=1800 47 | # disable python automatic garbage collection for greater sensitivity 48 | # session LEDs are on when data are being recorded. These LEDs are located at the end of the head poke holes and serve to attract the attension of the rats. 49 | # touchLed is on when touch sensor is activated 50 | # green and red Leds are for sensation seeking 51 | touchLed=35 52 | # setting up the various LEDs. 53 | time.sleep(20) 54 | gpio.setwarnings(False) 55 | gpio.setmode(gpio.BOARD) 56 | gpio.setup(touchLed,gpio.OUT) 57 | gpio.output(touchLed,True) ## borrow the touch LED to indicate program stared 58 | RatID=ReadRFID("/dev/ttyUSB0") 59 | gpio.output(touchLed,False) 60 | subprocess.call("sudo python /home/pi/openbehavior/oss/motion.py " + " -RatID " + RatID, shell=True) 61 | doneSignal() 62 | subprocess.call('/home/pi/openbehavior/wifi-network/rsync.sh') 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /operantSensationSeeking/touchled.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import RPi.GPIO as gpio 4 | import time 5 | 6 | def touchLED(): 7 | RFIDLed=35 8 | gpio.setmode(gpio.BOARD) 9 | gpio.setwarnings(False) 10 | gpio.setup(RFIDLed,gpio.OUT) 11 | gpio.output(RFIDLed, True) 12 | time.sleep(0.2) 13 | gpio.output(RFIDLed, False) 14 | 15 | touchLED() 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /ratremor/Readme.md: -------------------------------------------------------------------------------- 1 | #Ratremor 2 | 3 | Tremor is a common sign of withdrawal from abused drugs. By fixing an ADXL345 accelerometer to the bottom of a platform that is sitting on a set of four balanced springs, we are testing if the z-axis data can be used to measure tremor in rats. 4 | 5 | ![](./ratremor_prototype.jpg) 6 | 7 | -------------------------------------------------------------------------------- /ratremor/ratremor_prototype.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/ratremor/ratremor_prototype.jpg -------------------------------------------------------------------------------- /ratremor/tremor.py: -------------------------------------------------------------------------------- 1 | ## using the adxl345 to detect tremor associated with alcohol withdrawal. 2 | 3 | from adxl345 import ADXL345 4 | from time import localtime 5 | import time 6 | import RPi.GPIO as gpio 7 | 8 | adxl345 = ADXL345() 9 | 10 | sessionLength=480 11 | #sessionLength=10 12 | datafile='/home/pi/tremor' + time.strftime("%Y-%m-%d_%H:%M:%S", localtime()) + ".csv" 13 | 14 | Led=37 15 | gpio.setmode(gpio.BOARD) 16 | gpio.setup(Led, gpio.OUT) 17 | 18 | gpio.output(Led, True) 19 | start=time.time() 20 | 21 | lapsed= 0.00 22 | data= 'Date\tTime\tSecondsLapsed\tx\ty\tz\n' 23 | 24 | while (lapsed < sessionLength) : 25 | lapsed= time.time()-start 26 | datetime= time.strftime("%Y-%m-%d\t%H:%M:%S", localtime()) 27 | axes = adxl345.getAxes(True) 28 | data = data + datetime+ "\t"+ str(lapsed) + '\t' + str(axes['x']) + '\t' + str(axes['y']) + '\t' + str(axes['x']) + "\n" 29 | time.sleep(.041667) 30 | 31 | with open(datafile, "a") as f: 32 | f.write(data) 33 | 34 | gpio.output(Led, False) 35 | 36 | 37 | -------------------------------------------------------------------------------- /rtc/hwclock.sh: -------------------------------------------------------------------------------- 1 | init_rtc_device() 2 | { 3 | [ -e /dev/rtc0 ] && return 0; 4 | 5 | # load i2c and RTC kernel modules 6 | modprobe i2c-dev 7 | modprobe rtc-ds1307 8 | 9 | # iterate over every i2c bus as we're supporting Raspberry Pi rev. 1 and 2 10 | # (different I2C busses on GPIO header!) 11 | for bus in $(ls -d /sys/bus/i2c/devices/i2c-*); 12 | do 13 | echo ds1307 0x68 >> $bus/new_device; 14 | if [ -e /dev/rtc0 ]; 15 | then 16 | log_action_msg "RTC found on bus `cat $bus/name`"; 17 | break; # RTC found, bail out of the loop 18 | else 19 | echo 0x68 >> $bus/delete_device 20 | fi 21 | done 22 | } 23 | 24 | #echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device 25 | -------------------------------------------------------------------------------- /rtc/remove_fake_hwclock.sh: -------------------------------------------------------------------------------- 1 | 2 | sudo apt-get remove fake-hwclock 3 | sudo rm /etc/cron.hourly/fake-hwclock 4 | sudo update-rc.d -f fake-hwclock remove 5 | sudo rm /etc/init.d/fake-hwclock 6 | -------------------------------------------------------------------------------- /socialDrinking/openscad/rfid_waterspout.scad: -------------------------------------------------------------------------------- 1 | $fn=20; 2 | 3 | module screw(){ 4 | translate([-30,0,0])rotate([0,90,0]) cylinder(r=1.50, h=35,center=true); 5 | } 6 | 7 | module screwset(){ 8 | dist=31; 9 | translate([0,dist,dist])screw(); 10 | translate([0,-dist,dist])screw(); 11 | translate([0,dist,0])screw(); 12 | translate([0,-dist,0])screw(); 13 | translate([0,-dist,-dist])screw(); 14 | translate([0,dist,-dist])screw(); 15 | 16 | } 17 | 18 | 19 | module screwset_frontpanel(){ 20 | dist=31; 21 | translate([0,dist,dist])screw(); 22 | translate([0,-dist,dist])screw(); 23 | translate([0,dist,5])screw(); 24 | translate([0,-dist,5])screw(); 25 | translate([0,-dist,-dist])screw(); 26 | translate([0,dist,-dist])screw(); 27 | 28 | } 29 | 30 | 31 | dia=23; // of the antenna 32 | 33 | module antenna_cover(){ 34 | difference(){ 35 | union(){ 36 | cylinder(r=dia+4,h=6,center=true); 37 | cube([6,dia*2+22,6],center=true); 38 | } 39 | translate([0,0,-1])cylinder(r=dia+2,h=5,center=true); 40 | cylinder(r=dia-2,h=7,center=true); 41 | translate([0,0,30])rotate([0,-90,0])screwset(); 42 | translate([5,0,-2])cube([2,80,2],center=true); 43 | } 44 | } 45 | 46 | module rfid_board_hook(){ 47 | distance=25; 48 | stickout=36; 49 | x=23; 50 | translate([x,stickout,distance]) cube([3,4,4],center=true); 51 | translate([x,stickout,-distance]) cube([3,4,4],center=true); 52 | translate([x,-stickout,distance]) cube([3,4,5],center=true); 53 | translate([x,-stickout,-distance]) cube([3,4,5],center=true); 54 | } 55 | 56 | 57 | module cboard_cover(){ 58 | // translate([5,0,0]) 59 | difference(){ 60 | union(){ 61 | translate([15,43,0])cube([30,12,63],center=true); 62 | translate([15,37,0])cube([30,4,70],center=true); 63 | } 64 | translate([15,40,0])cube([26,10,58],center=true); 65 | translate([18,38,0])cube([26,7,10],center=true); 66 | translate([15,35,0])cboard_screw(dia=2); 67 | } 68 | } 69 | 70 | module spoutholder(){ 71 | rfid_board_hook(); 72 | difference(){ 73 | union(){ 74 | cube([60,70,70],center=true); //outside 75 | translate([13,0,28])rotate([0,35,0])cube([20,30,30],center=true); // plate for spout 76 | } 77 | translate([-14,0,0])screwset(); 78 | translate([-14,0,0])rotate([0,90,0])cylinder(r=dia-3,h=35,center=true);//rfid ring 79 | translate([-20,0,0])cube([55,60,56],center=true); //front chamber 80 | translate([20.1,0,-15])cube([20,50,80],center=true); //back chamber 81 | translate([-25,0,0])cube([10,80,56],center=true);//side slot 82 | translate([-12,11,-29])rotate([4,0,0])cube([40,27,6.2],center=true);//bottom 83 | translate([-12,-11,-29])rotate([-4,0,0])cube([40,27,6.2],center=true);//bottom 84 | translate([-14,0,5])rotate([0,0,90])union(){ // spout assembly 85 | translate([0,-10,0]) rotate([0,90,0]) cylinder(r=2.5, h=75,center=true); //holes for alignment of the spout tip 86 | translate([0,-10,0]) rotate([35,0,0]) cylinder(r=4.6, h=55); // location of the spout 87 | translate([0,-42,31]) rotate([-55, 0,0]) cube([8.4, 18, 4.1], center=true);// hex screw for spout 88 | translate([0,-60,14]) rotate([-55,0,0]) cylinder(r=1.9, h=50); //screw hole for tightening the spout 89 | translate([0,-10,-60]) cylinder(r=5, h=40); //hole for collection tube //yes 90 | } 91 | translate([15,35,0])cboard_screw(); 92 | translate([0,0,30])cylinder(r=2.8,h=20,center=true);//cue light 93 | translate([-8,0,30])cylinder(r=2.8,h=20,center=true);//cue light 94 | } 95 | } 96 | 97 | module cboard_screw(dia=1.5){ 98 | distance=32; 99 | translate([0,0,distance])rotate([90,0,0]) cylinder(r=dia, h=350,center=true); 100 | translate([0,0,-distance])rotate([90,0,0]) cylinder(r=dia, h=350,center=true); 101 | translate([0,19,-distance])rotate([90,0,0]) cylinder(r=dia+3, h=30,center=true); // screw head 102 | translate([0,19,distance])rotate([90,0,0]) cylinder(r=dia+3, h=30,center=true); // screw head 103 | } 104 | 105 | module frontpanel(){ 106 | difference(){ 107 | union(){ 108 | cube([82,77,2],center=true); 109 | translate([0,0,2])cube([82,69,3],center=true); 110 | translate([5,0,5])cylinder(r=dia-1,h=5,center=true); 111 | } 112 | scale([.8,.95,1])translate([1,0,4])cylinder(r=dia-3,h=14,center=true,$fn=100); 113 | translate([0,0,-20])rotate([0,90,0])screwset_frontpanel(); 114 | } 115 | } 116 | 117 | 118 | translate([-40,0,0])rotate([0,90,0])frontpanel(); 119 | //color("red")translate([-35,0,-5])rotate([0,90,0])antenna_cover(); 120 | //spoutholder(); 121 | //color("blue")cboard_cover(); 122 | 123 | -------------------------------------------------------------------------------- /socialDrinking/python/PigpioStepperMotor.py: -------------------------------------------------------------------------------- 1 | # from https://github.com/stripcode/pigpio-stepper-motor 2 | import pigpio 3 | from time import sleep 4 | from collections import deque 5 | 6 | 7 | 8 | fullStepSequence = ( 9 | (1, 0, 0, 0), 10 | (0, 1, 0, 0), 11 | (0, 0, 1, 0), 12 | (0, 0, 0, 1) 13 | ) 14 | 15 | 16 | 17 | halfStepSequence = ( 18 | (1, 0, 0, 0), 19 | (1, 1, 0, 0), 20 | (0, 1, 0, 0), 21 | (0, 1, 1, 0), 22 | (0, 0, 1, 0), 23 | (0, 0, 1, 1), 24 | (0, 0, 0, 1), 25 | (1, 0, 0, 1) 26 | ) 27 | 28 | 29 | 30 | class StepperMotor: 31 | 32 | def __init__(self, pi, pin1, pin2, pin3, pin4, sequence = halfStepSequence, delayAfterStep = 0.0025): 33 | if not isinstance(pi, pigpio.pi): 34 | raise TypeError("Is not pigpio.pi instance.") 35 | pi.set_mode(pin1, pigpio.OUTPUT) 36 | pi.set_mode(pin2, pigpio.OUTPUT) 37 | pi.set_mode(pin3, pigpio.OUTPUT) 38 | pi.set_mode(pin4, pigpio.OUTPUT) 39 | self.pin1 = pin1 40 | self.pin2 = pin2 41 | self.pin3 = pin3 42 | self.pin4 = pin4 43 | self.pi = pi 44 | self.delayAfterStep = delayAfterStep 45 | self.deque = deque(sequence) 46 | 47 | 48 | 49 | def doCounterclockwiseStep(self): 50 | self.deque.rotate(-1) 51 | self.doStepAndDelay(self.deque[0]) 52 | 53 | 54 | 55 | def doClockwiseStep(self): 56 | self.deque.rotate(1) 57 | self.doStepAndDelay(self.deque[0]) 58 | 59 | 60 | 61 | def doStepAndDelay(self, step): 62 | self.pi.write(self.pin1, step[0]) 63 | self.pi.write(self.pin2, step[1]) 64 | self.pi.write(self.pin3, step[2]) 65 | self.pi.write(self.pin4, step[3]) 66 | sleep(self.delayAfterStep) 67 | -------------------------------------------------------------------------------- /socialDrinking/python/PumpTest.py: -------------------------------------------------------------------------------- 1 | 2 | from time import sleep 3 | import RPi.GPIO as GPIO 4 | from gpiozero import Button 5 | from gpiozero import DigitalInputDevice 6 | 7 | GPIO.setwarnings(False) 8 | 9 | request = input(""" 10 | Enter a number to start a test: 11 | 1 - Test left and right buttons 12 | 2 - Test pump forward limit 13 | 3 - Test Pump backward limit 14 | 4 - Test pump move 15 | """) 16 | 17 | while True: 18 | 19 | if request == 1: 20 | left_button = Button("GPIO5") 21 | right_button = Button("GPIO27") 22 | 23 | def left_btn_press(): 24 | while left_button.value == 1: 25 | print("left button pressed") 26 | 27 | def right_btn_press(): 28 | while right_button.value == 1: 29 | print("right button pressed") 30 | 31 | left_button.when_pressed = left_btn_press 32 | right_button.when_pressed = right_btn_press 33 | 34 | elif request == 2: 35 | forward_limit = GPIO.setup("24", GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 36 | 37 | if GPIO.input(24): 38 | print("forward limit pressed.") 39 | 40 | elif request == 3: 41 | backward_limit = DigitalInputDevice("GPIO23") 42 | 43 | if backward_limit.value == 1: 44 | print("backward limit pressed") 45 | 46 | elif request == 4: 47 | steps = 200 48 | rotate_dir = 1 49 | DIR = 26 50 | STEP = 6 51 | CW = 1 52 | CCW = 0 53 | GPIO = GPIO 54 | GPIO.setmode(GPIO.BCM) 55 | GPIO.setup(DIR, GPIO.OUT, initial=GPIO.HIGH) 56 | GPIO.setup(STEP, GPIO.OUT, initial=GPIO.HIGH) 57 | GPIO.output(DIR,CW) 58 | MODE = (17,22) 59 | GPIO.setup(MODE, GPIO.OUT) 60 | RESOLUTION = { 61 | 'Full': (0,0), 62 | 'Half': (1,0), 63 | '1/8': (0,1), 64 | '1/16': (1,1), 65 | } 66 | 67 | step_counts = steps 68 | delay = .0209 / 50 69 | 70 | GPIO.output(STEP, GPIO.HIGH) 71 | GPIO.output(DIR, CW) 72 | for step in range(steps): 73 | GPIO.output(STEP, GPIO.HIGH) 74 | sleep(delay) 75 | GPIO.output(STEP, GPIO.LOW) 76 | sleep(delay) 77 | 78 | 79 | GPIO.output(DIR, CCW) 80 | for step in range(steps): 81 | GPIO.output(STEP, GPIO.HIGH) 82 | sleep(delay) 83 | GPIO.output(STEP, GPIO.LOW) 84 | sleep(delay) 85 | 86 | 87 | GPIO.cleanup(MODE) 88 | 89 | 90 | -------------------------------------------------------------------------------- /socialDrinking/python/__pycache__/PigpioStepperMotor.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/socialDrinking/python/__pycache__/PigpioStepperMotor.cpython-35.pyc -------------------------------------------------------------------------------- /socialDrinking/python/__pycache__/datalogger.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/socialDrinking/python/__pycache__/datalogger.cpython-35.pyc -------------------------------------------------------------------------------- /socialDrinking/python/__pycache__/ids.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/socialDrinking/python/__pycache__/ids.cpython-35.pyc -------------------------------------------------------------------------------- /socialDrinking/python/__pycache__/mover_subproc.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/socialDrinking/python/__pycache__/mover_subproc.cpython-35.pyc -------------------------------------------------------------------------------- /socialDrinking/python/__pycache__/pump_move.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/socialDrinking/python/__pycache__/pump_move.cpython-35.pyc -------------------------------------------------------------------------------- /socialDrinking/python/blinkenlights.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import RPi.GPIO as gpio 4 | import time 5 | import argparse 6 | 7 | import board 8 | import neopixel 9 | 10 | pixels = neopixel.NeoPixel(board.D18,12) 11 | 12 | parser=argparse.ArgumentParser() 13 | parser.add_argument('-reward_happened', type=bool, default=False) 14 | args=parser.parse_args() 15 | reward_happened = args.reward_happened 16 | 17 | 18 | lights_on_hours = [21,22,23,0,1,2,3,4,5,6,7,8] 19 | 20 | 21 | def turn_light(on=True): 22 | for i in range(len(pixels)): 23 | if on: 24 | pixels[i] = (255,255,255) 25 | else: 26 | pixels[i] = (0,0,0) 27 | 28 | def reward_cue_light(): 29 | turn_light() 30 | time.sleep(0.5) 31 | turn_light(on=False) 32 | 33 | if __name__ == "__main__": 34 | if reward_happened: 35 | reward_cue_light() 36 | # if the current hour is in light on period, turn the light on 37 | if time.localtime().tm_hour in lights_on_hours: 38 | turn_light() 39 | else: 40 | turn_light(on=False) 41 | 42 | -------------------------------------------------------------------------------- /socialDrinking/python/datalogger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import time 4 | import string 5 | from ids import * 6 | 7 | class LickLogger: 8 | def __init__(self, devID, sesID): 9 | self.devID = devID 10 | self.sessID= sesID 11 | self.startTime=time.strftime("%Y-%m-%d\t%H:%M:%S", time.localtime()) 12 | 13 | def createDataFile(self, schedule, ratIDs): 14 | date=time.strftime("%Y-%m-%d_%H_%M_%S", time.localtime()) 15 | self.datafile = DATA_DIR + DATA_PREFIX + date + "_" + str(self.devID) + '_S' + str(self.sessID) + "_" + schedule + "_" + str(ratIDs) + '.csv' 16 | print ("\nData file location:\n", self.datafile) 17 | # open data file 18 | with open(self.datafile,"a") as f: 19 | f.write("RatID\tRfidSec\tdate\tstart_time\tboxid\tEventType\t"+schedule+"\tlapsedSec\n") 20 | f.close() 21 | 22 | def logEvent(self, rat, eventSec, eventType, timeLapsed, ratio=0): 23 | # Create output string 24 | outputstr = rat + "\t" + str(eventSec) + "\t"+ time.strftime("%Y-%m-%d\t%H:%M:%S", time.localtime()) + "\t" + self.devID + "_S" + str(self.sessID) + "\t" + eventType + "\t" + str(ratio) + "\t"+ str(timeLapsed) + "\n" 25 | print (outputstr) 26 | with open (self.datafile, "a") as datafile: 27 | datafile.write(outputstr) 28 | 29 | @staticmethod 30 | def finalLog(fname,data_dict): 31 | ratids = [data_dict["ratID1"][0], data_dict["ratID2"][0]] 32 | poke_counts = {ratids[0]:{"act":0, "inact": 0}, ratids[1]:{"act":0, "inact":0}} 33 | poke_count_files = {"ACT_POKE": ["{}_act_count.txt".format(ID) for ID in ratids], 34 | "INACT_POKE": ["{}_inact_count.txt".format(ID) for ID in ratids] 35 | } 36 | 37 | with open(DATA_DIR + "/" + fname, "a+") as f: 38 | for ref, count_files in poke_count_files.items(): 39 | for file in count_files: 40 | try: 41 | with open(DATA_DIR + "/" + file, "r") as f1: 42 | (rfid,poke_count) = f1.read().split(":") 43 | if ref == "ACT_POKE": 44 | poke_counts[rfid]["act"] = poke_count 45 | else: 46 | poke_counts[rfid]["inact"] = poke_count 47 | # remove file after reading 48 | os.remove(DATA_DIR + "/" + file) 49 | except FileNotFoundError: 50 | continue 51 | 52 | with open(DATA_DIR+ "/" + fname, "a+") as f: 53 | ID1_str = (("{}\t"*13).format(*data_dict["ratID1"], poke_counts[ratids[0]]["act"], poke_counts[ratids[0]]["inact"])) + "\n" 54 | ID2_str = (("{}\t"*13).format(*data_dict["ratID2"], poke_counts[ratids[1]]["act"], poke_counts[ratids[1]]["inact"])) + "\n" 55 | ID0_str = (("{}\t"*11).format(*data_dict["ratID0"])) + "\n" 56 | f.write(ID1_str + ID2_str + ID0_str) 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /socialDrinking/python/deviceid: -------------------------------------------------------------------------------- 1 | Box1 2 | -------------------------------------------------------------------------------- /socialDrinking/python/err.txt: -------------------------------------------------------------------------------- 1 | inside operant1 2 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 | Can't connect to pigpio at localhost(8888) 4 | 5 | Did you start the pigpio daemon? E.g. sudo pigpiod 6 | 7 | Did you specify the correct Pi host/port in the environment 8 | variables PIGPIO_ADDR/PIGPIO_PORT? 9 | E.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888 10 | 11 | Did you specify the correct Pi host/port in the 12 | pigpio.pi() function? E.g. pigpio.pi('soft', 8888) 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | 15 | Data file location: 16 | /home/pi/SocialDrinking/Oxy_BOX_X_S80_rat1_rat2.csv 17 | before initialize mover 18 | after initialize mover 19 | mover -> 20 | inside while loop 21 | deleted mover 22 | [59 min Left] 23 | rat1: Active=0 Inactive=0 Reward=0 Timeout: False 24 | rat2: Active=0 Inactive=0 Reward=0 Timeout: False 25 | 26 | ratUnknown: Active=0 Inactive=0 Reward=0 Timeout: False 27 | 28 | inside while loop 29 | mover does not exist yet 30 | inside while loop 31 | mover does not exist yet 32 | inside while loop 33 | mover does not exist yet 34 | inside while loop 35 | mover does not exist yet 36 | inside while loop 37 | mover does not exist yet 38 | inside while loop 39 | mover does not exist yet 40 | inside while loop 41 | mover does not exist yet 42 | inside while loop 43 | mover does not exist yet 44 | inside while loop 45 | mover does not exist yet 46 | inside while loop 47 | mover does not exist yet 48 | inside while loop 49 | mover does not exist yet 50 | inside while loop 51 | mover does not exist yet 52 | inside while loop 53 | mover does not exist yet 54 | inside while loop 55 | mover does not exist yet 56 | inside while loop 57 | mover does not exist yet 58 | inside while loop 59 | mover does not exist yet 60 | inside while loop 61 | mover does not exist yet 62 | inside while loop 63 | mover does not exist yet 64 | inside while loop 65 | mover does not exist yet 66 | inside while loop 67 | mover does not exist yet 68 | inside while loop 69 | mover does not exist yet 70 | inside while loop 71 | mover does not exist yet 72 | inside while loop 73 | mover does not exist yet 74 | inside while loop 75 | mover does not exist yet 76 | inside while loop 77 | mover does not exist yet 78 | inside while loop 79 | mover does not exist yet 80 | inside while loop 81 | mover does not exist yet 82 | inside while loop 83 | mover does not exist yet 84 | inside while loop 85 | mover does not exist yet 86 | inside while loop 87 | mover does not exist yet 88 | inside while loop 89 | mover does not exist yet 90 | inside while loop 91 | mover does not exist yet 92 | inside while loop 93 | mover does not exist yet 94 | inside while loop 95 | mover does not exist yet 96 | inside while loop 97 | mover does not exist yet 98 | inside while loop 99 | mover does not exist yet 100 | inside while loop 101 | mover does not exist yet 102 | inside while loop 103 | mover does not exist yet 104 | inside while loop 105 | mover does not exist yet 106 | inside while loop 107 | mover does not exist yet 108 | inside while loop 109 | mover does not exist yet 110 | inside while loop 111 | mover does not exist yet 112 | inside while loop 113 | mover does not exist yet 114 | inside while loop 115 | mover does not exist yet 116 | inside while loop 117 | mover does not exist yet 118 | inside while loop 119 | mover does not exist yet 120 | inside while loop 121 | mover does not exist yet 122 | inside while loop 123 | mover does not exist yet 124 | inside while loop 125 | mover does not exist yet 126 | inside while loop 127 | mover does not exist yet 128 | inside while loop 129 | mover does not exist yet 130 | inside while loop 131 | mover does not exist yet 132 | Traceback (most recent call last): 133 | File "operant1.py", line 247, in 134 | time.sleep(0.05) # allow 20 licks per sec 135 | KeyboardInterrupt 136 | -------------------------------------------------------------------------------- /socialDrinking/python/ids.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | 4 | import os 5 | import time 6 | 7 | ROOT='/home/pi' 8 | DEVID_FILE = ROOT+'/deviceid' 9 | RATID_FILE = ROOT+'/ratids' 10 | SESSIONID_FILE = ROOT+'/sessionid' 11 | DATA_DIR = ROOT+'/SocialDrinking' 12 | DATA_PREFIX = "/Soc_" 13 | 14 | with open (ROOT+"/_active", "w") as act: 15 | act.write("ratUnknown\t"+str(time.time())) 16 | act.close() 17 | 18 | with open (ROOT+"/_inactive", "w") as inact: 19 | inact.write("00ratUnknown\t"+str(time.time())) 20 | inact.close() 21 | 22 | if not os.path.exists(DEVID_FILE): 23 | print ("please edit " + DEVID_FILE + " to assign device ID") 24 | with open (DEVID_FILE, 'w') as devID: 25 | devID.write("BOX_X") 26 | devID.close() 27 | if not os.path.exists(SESSIONID_FILE): 28 | print ("please edit " + SESSIONID_FILE + " to assign initial session ID") 29 | with open (SESSIONID_FILE, 'w') as sessionID: 30 | sessionID.write("1") 31 | sessionID.close() 32 | 33 | if not os.path.exists(DATA_DIR): 34 | os.system("mkdir " + DATA_DIR) 35 | 36 | class IDS: 37 | def __init__(self): 38 | with open (DEVID_FILE) as devID: 39 | self.devID = str((devID.read()).strip()) 40 | devID.close() 41 | with open (SESSIONID_FILE, "r") as sessID: 42 | self.sesID=int(sessID.read().strip()) 43 | #newSesID=self.sesID+1 44 | #sessID.seek(0) 45 | #sessID.write(str(newSesID)) 46 | #sessID.close() 47 | def sessionIncrement(self): 48 | with open (SESSIONID_FILE, "r+") as sessID: 49 | self.sesID=int(sessID.read().strip()) 50 | newSesID=self.sesID+1 51 | self.sesID = newSesID 52 | sessID.seek(0) 53 | sessID.write(str(newSesID)) 54 | 55 | 56 | -------------------------------------------------------------------------------- /socialDrinking/python/log.err: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | Can't connect to pigpio at localhost(8888) 3 | 4 | Did you start the pigpio daemon? E.g. sudo pigpiod 5 | 6 | Did you specify the correct Pi host/port in the environment 7 | variables PIGPIO_ADDR/PIGPIO_PORT? 8 | E.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888 9 | 10 | Did you specify the correct Pi host/port in the 11 | pigpio.pi() function? E.g. pigpio.pi('soft', 8888) 12 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 | Traceback (most recent call last): 14 | File "/home/pi/.local/lib/python3.5/site-packages/adafruit_bus_device/i2c_device.py", line 68, in __init__ 15 | i2c.writeto(device_address, b'') 16 | File "/home/pi/.local/lib/python3.5/site-packages/busio.py", line 69, in writeto 17 | return self._i2c.writeto(address, buffer, stop=stop) 18 | File "/home/pi/.local/lib/python3.5/site-packages/adafruit_blinka/microcontroller/generic_linux/i2c.py", line 38, in writeto 19 | self._i2c_bus.write_bytes(address, buffer[start:end]) 20 | File "/home/pi/.local/lib/python3.5/site-packages/Adafruit_PureIO/smbus.py", line 244, in write_bytes 21 | self._device.write(buf) 22 | OSError: [Errno 5] Input/output error 23 | 24 | During handling of the above exception, another exception occurred: 25 | 26 | Traceback (most recent call last): 27 | File "/home/pi/.local/lib/python3.5/site-packages/adafruit_bus_device/i2c_device.py", line 74, in __init__ 28 | i2c.readfrom_into(device_address, result) 29 | File "/home/pi/.local/lib/python3.5/site-packages/busio.py", line 59, in readfrom_into 30 | return self._i2c.readfrom_into(address, buffer, stop=stop) 31 | File "/home/pi/.local/lib/python3.5/site-packages/adafruit_blinka/microcontroller/generic_linux/i2c.py", line 44, in readfrom_into 32 | readin = self._i2c_bus.read_bytes(address, end-start) 33 | File "/home/pi/.local/lib/python3.5/site-packages/Adafruit_PureIO/smbus.py", line 155, in read_bytes 34 | return self._device.read(number) 35 | OSError: [Errno 5] Input/output error 36 | 37 | During handling of the above exception, another exception occurred: 38 | 39 | Traceback (most recent call last): 40 | File "operant1.py", line 85, in 41 | mpr121 = adafruit_mpr121.MPR121(i2c) 42 | File "/home/pi/.local/lib/python3.5/site-packages/adafruit_mpr121.py", line 127, in __init__ 43 | self._i2c = i2c_device.I2CDevice(i2c, address) 44 | File "/home/pi/.local/lib/python3.5/site-packages/adafruit_bus_device/i2c_device.py", line 76, in __init__ 45 | raise ValueError("No I2C device at address: %x" % device_address) 46 | ValueError: No I2C device at address: 5a 47 | -------------------------------------------------------------------------------- /socialDrinking/python/mover_subproc.py: -------------------------------------------------------------------------------- 1 | from pump_move import PumpMove 2 | 3 | def forward(): 4 | mover = PumpMove() 5 | mover.move("forward") 6 | del(mover) 7 | 8 | 9 | 10 | # SERVO = 2 11 | # RECEIVER = 26 12 | 13 | # FORWARDBUTTON = 5 14 | # BACKWARDBUTTON = 27 15 | # IR = 17 16 | 17 | 18 | # sensor = InputDevice(IR, pull_up=True) 19 | 20 | 21 | # GPIO.setmode(GPIO.BCM) 22 | # GPIO.setup(FORWARDBUTTON, GPIO.IN, pull_up_down=GPIO.PUD_UP) 23 | # GPIO.setup(BACKWARDBUTTON, GPIO.IN, pull_up_down=GPIO.PUD_UP) 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /socialDrinking/python/pump_move.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | import RPi.GPIO as GPIO 3 | # import argparse 4 | import signal 5 | import sys 6 | from gpiozero import InputDevice 7 | from gpiozero import Servo 8 | import pigpio 9 | # from gpiozero import DigitalInputDevice 10 | # from gpiozero import SmoothedInputDevice 11 | 12 | 13 | steps=150 14 | rotate_dir=1 15 | 16 | 17 | 18 | GPIO.setwarnings(False) 19 | 20 | 21 | class PumpMove: 22 | def __init__(self): 23 | self.DIR = 26 24 | self.STEP = 6 25 | self.CW = 1 26 | self.CCW = 0 27 | # self.BUTTON = 16 28 | # self.STOP_BUTTON = 12 29 | 30 | self.GPIO = GPIO 31 | self.GPIO.setmode(self.GPIO.BCM) 32 | self.GPIO.setup(self.DIR, self.GPIO.OUT, initial=self.GPIO.HIGH) 33 | self.GPIO.setup(self.STEP, self.GPIO.OUT, initial=self.GPIO.HIGH) 34 | # self.GPIO.setup(self.BUTTON, self.GPIO.IN, pull_up_down=self.GPIO.PUD_DOWN) 35 | # self.GPIO.setup(self.STOP_BUTTON, self.GPIO.IN, pull_up_down=self.GPIO.PUD_DOWN) 36 | self.GPIO.output(self.DIR,self.CW) 37 | #self.step_count = stp_cnt 38 | #self.delay = delay 39 | self.MODE = (17,22) 40 | self.GPIO.setup(self.MODE, self.GPIO.OUT) 41 | # self.GPIO.setup(23, GPIO.IN, pull_up_down=) 42 | self.RESOLUTION = { 43 | 'Full': (0,0), 44 | 'Half': (1,0), 45 | '1/8': (0,1), 46 | '1/16': (1,1), 47 | } 48 | 49 | # GPIO.output(self.MODE, self.RESOLUTION['Full']) 50 | # GPIO.output(self.MODE, self.RESOLUTION['Half']) 51 | # self.GPIO.output(self.MODE, self.RESOLUTION['1/8']) 52 | # GPIO.output(self.MODE, self.RESOLUTION['1/16']) 53 | 54 | self.step_counts = steps 55 | self.delay = .0209 / 50 56 | self.rotate_dir = rotate_dir 57 | 58 | def move(self, direction, steps=150): 59 | direction_dict = {"forward": self.CW, "backward": self.CCW} 60 | 61 | try: 62 | self.GPIO.output(self.MODE, self.RESOLUTION['Full']) 63 | self.GPIO.output(self.DIR, direction_dict[direction]) 64 | 65 | for step in range(steps): 66 | self.GPIO.output(self.STEP, self.GPIO.HIGH) 67 | sleep(self.delay) 68 | self.GPIO.output(self.STEP, self.GPIO.LOW) 69 | sleep(self.delay) 70 | 71 | self.GPIO.output(self.STEP, self.GPIO.HIGH) 72 | except KeyError: 73 | print("please enter a correct direction") 74 | # if direction == "forward": 75 | # pass 76 | # elif direction == "backward": 77 | 78 | def __del__(self): 79 | self.GPIO.cleanup(self.MODE) 80 | 81 | 82 | # GPIO.add_event_detect(IR, GPIO.FALLING, callback=ir_callback, bouncetime=100) 83 | 84 | 85 | # GPIO.add_event_detect(FORWARDBUTTON, GPIO.FALLING, callback=forward_btn_callback,bouncetime=100) 86 | # GPIO.add_event_detect(BACKWARDBUTTON, GPIO.FALLING, callback=backward_btn_callback,bouncetime=100) 87 | 88 | 89 | # signal.signal(signal.SIGINT, signal_handler) 90 | # signal.pause() 91 | 92 | 93 | -------------------------------------------------------------------------------- /socialDrinking/python/pumpmove.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # code from https://www.raspberrypi.org/forums/viewtopic.php?t=220247#p1352169 4 | # pip3 install pigpio 5 | # git clone https://github.com/stripcode/pigpio-stepper-motor 6 | 7 | ''' 8 | # connection to adafruit TB6612 9 | # motor: SY28STH32-0674A 10 | Vcmotor --> 12V 5A power supply 11 | VM --> floating 12 | Vcc --> 3V3 Pin 17 13 | GND --> GND Pin 06 14 | PwmA --> 3V3 Pin 01 15 | AIN2 --> Pin 15 - BCM 22 16 | AIN1 --> Pin 11 - BCM 17 17 | STBY --> Pin 13 - BCM 27 18 | BIN1 --> Pin 16 - BCM 23 19 | BIN2 --> Pin 18 - BCM 24 20 | PwmB --> Pin 32 - BCM 21 | MotorA --> Red (A+) and Green (A-) wires 22 | MotorB --> Blue (B+) and Black (B-) wires 23 | GND of Power supply --> Pin 39 (gnd) Raspberry Pi 24 | ''' 25 | 26 | import pigpio, time 27 | from PigpioStepperMotor import StepperMotor 28 | import argparse 29 | 30 | 31 | #move 180 is 60ul using 10ml syringe 32 | 33 | parser=argparse.ArgumentParser() 34 | parser.add_argument('move', type=int) 35 | args=parser.parse_args() 36 | move=args.move 37 | 38 | 39 | 40 | pi = pigpio.pi() 41 | motor = StepperMotor(pi, 17, 23, 22, 24) 42 | pwma = pigpio.pi() 43 | pwma.write(18,1) 44 | pwmb = pigpio.pi() 45 | pwmb.write(12,1) 46 | stby = pigpio.pi() 47 | stby.write(27,0) 48 | if move>0: 49 | for i in range(move): 50 | stby.write(27,1) 51 | motor.doClockwiseStep() 52 | else: 53 | for i in range(-1*move): 54 | stby.write(27,1) 55 | motor.doCounterclockwiseStep() 56 | -------------------------------------------------------------------------------- /socialDrinking/python/ratids: -------------------------------------------------------------------------------- 1 | dkfasl_dfkas;jf -------------------------------------------------------------------------------- /socialDrinking/python/sessionid: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /socialDrinking/python/timers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from threading import Timer 4 | import time 5 | 6 | def resetPumpTimeout(rat): 7 | # global pumptimedout 8 | print (rat + " timeout reset") 9 | pumptimedout[rat] = False 10 | 11 | rat1ID="rat...1" 12 | rat2ID="rat...2" 13 | 14 | pumptimedout={rat1ID:False, rat2ID:False} 15 | #pumptimedout=False 16 | touchcounter={rat1ID:0, rat2ID:0} 17 | nextratio={rat1ID:5, rat1ID:5} 18 | rew={rat1ID:0,rat2ID:0} 19 | timeout=5 20 | print(touchcounter[rat1ID]) 21 | 22 | #resetPumpTimeout(rat1ID) 23 | while True: 24 | rat=rat1ID 25 | time.sleep(1) 26 | print ("timedout"+str(pumptimedout)) 27 | if not pumptimedout[rat] : 28 | touchcounter[rat] += 1 # for issuing rewards 29 | print ("touchcount="+str(touchcounter[rat])) 30 | if touchcounter[rat] >= nextratio[rat]: 31 | rew[rat]+=1 32 | print ("reward"+str(rew[rat])) 33 | touchcounter[rat] = 0 34 | pumptimedout[rat] = True 35 | pumpTimer = Timer(timeout, resetPumpTimeout, [rat]) 36 | pumpTimer.start() 37 | -------------------------------------------------------------------------------- /socialDrinking/python/touchsensor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Copyright 2016 University of Tennessee Health Sciences Center 4 | # Author: Matthew Longley 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Affero General Public License as 8 | # published by the Free Software Foundation, either version 3 of the 9 | # License, or(at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Affero General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Affero General Public License 17 | # along with this program. If not, see . 18 | 19 | import Adafruit_MPR121.MPR121 as MPR121 20 | import sys 21 | 22 | class TouchSensor: 23 | def __init__(self): 24 | # Initialize hardware 25 | self.cap = MPR121.MPR121() 26 | if not self.cap.begin(): 27 | print('Error initializing MPR121. Check your wiring!') 28 | sys.exit(1) 29 | # Get last touched 30 | self.lasttouched = self.cap.touched() 31 | self.touched = self.lasttouched 32 | def readPinTouched(self): 33 | self.lasttouched = self.touched 34 | self.touched = self.cap.touched() 35 | for i in range(3): 36 | pinbit = 1 << i 37 | if self.touched & pinbit and not self.lasttouched & pinbit: 38 | return i 39 | if not self.touched & pinbit and self.lasttouched & pinbit: 40 | return -i 41 | -------------------------------------------------------------------------------- /socialDrinking/python/turnoff_light.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | import board, neopixel 6 | 7 | p = neopixel.NeoPixel(board.D18,12) 8 | 9 | 10 | for i in range(len(p)): 11 | p[i] = (0,0,0) 12 | -------------------------------------------------------------------------------- /socialDrinking/utility_script/check_empty_program.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | program_file_dir="/home/pi/openbehavior/socialDrinking/python" 4 | 5 | num_empty_files=`ls -l $program_file_dir/*.py | awk '{if($7==0) print($9)}' | wc -l` 6 | 7 | cd /home/pi 8 | 9 | redownload_code=`rm -rf ./openbehavior && git clone https://github.com/chen42/openbehavior.git` 10 | 11 | while kill -0 $redownload_code ; do 12 | echo "Program is being downloded. Please Wait....." 13 | sleep 1 14 | done 15 | 16 | echo "Finished...." 17 | 18 | 19 | # if [ $num_empty_files -gt 0 ] 20 | # then 21 | # echo "There are $num_empty_files program files. Please check" 22 | # exit 1 23 | # fi 24 | 25 | 26 | # exit 0 27 | -------------------------------------------------------------------------------- /socialDrinking/utility_script/printEmptySyringeInfo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | read -p "Enter the summary file name: " fname 5 | 6 | 7 | # filter and print which box contains the information of empty syringe 8 | cat $fname | awk '{ if($1 != "ratUnknown" && $11 > 0 ) { print $1 , $4 } }' 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /socialDrinking/utility_script/test.csv: -------------------------------------------------------------------------------- 1 | 00001450 2020-11-21 19:13:43 BOX_1 262 vr10TO10 57600 0 0 0 0 0 0 2 | 3b9ad14d 2020-11-21 19:13:43 BOX_1 262 vr10TO10 57600 14893 22 160 0 352 42 3 | ratUnknown 2020-11-21 19:13:43 BOX_1 262 vr10TO10 57600 6 0 0 0 4 | 00001450 2020-11-21 19:16:17 BOX_2 155 vr10TO10 57600 0 0 0 0 3 0 5 | 3b9ad12b 2020-11-21 19:16:17 BOX_2 155 vr10TO10 57600 20 0 2 0 44 28 6 | ratUnknown 2020-11-21 19:16:17 BOX_2 155 vr10TO10 57600 25 0 0 0 7 | 00001450 2020-11-21 19:16:48 BOX_3 162 vr10TO10 57600 0 0 0 0 0 0 8 | 3b9ad166 2020-11-21 19:16:48 BOX_3 162 vr10TO10 57600 7821 115 96 0 76 54 9 | ratUnknown 2020-11-21 19:16:48 BOX_3 162 vr10TO10 57600 1725 266 0 0 10 | 00001450 2020-11-21 19:20:29 BOX_4 203 vr10TO10 57600 0 0 0 0 0 0 11 | 3b9ad007 2020-11-21 19:20:29 BOX_4 203 vr10TO10 57600 13094 172 210 12731 256 55 12 | ratUnknown 2020-11-21 19:20:29 BOX_4 203 vr10TO10 57600 166 0 0 166 13 | 00001450 2020-11-21 19:20:04 BOX_5 216 vr10TO10 57600 0 0 0 0 0 0 14 | 3b9ad169 2020-11-21 19:20:04 BOX_5 216 vr10TO10 57600 10887 109 159 0 236 16 15 | ratUnknown 2020-11-21 19:20:04 BOX_5 216 vr10TO10 57600 469 0 0 0 16 | 00001450 2020-11-21 19:21:09 BOX_6 156 vr10TO10 57600 0 0 0 0 0 0 17 | 3b9ad119 2020-11-21 19:21:09 BOX_6 156 vr10TO10 57600 122 13 5 0 15 11 18 | ratUnknown 2020-11-21 19:21:09 BOX_6 156 vr10TO10 57600 10 3 0 0 19 | 3b9acfed 2020-11-21 19:24:37 BOX_7 72 vr10TO10 57600 3587 116 53 0 97 12 20 | 3b9ad15d 2020-11-21 19:24:37 BOX_7 72 vr10TO10 57600 5249 203 82 0 130 15 21 | ratUnknown 2020-11-21 19:24:37 BOX_7 72 vr10TO10 57600 2689 22 0 0 22 | 3b9ad036 2020-11-21 19:27:44 BOX_8 64 vr10TO10 57600 4382 24 82 4014 154 37 23 | 3b9ad156 2020-11-21 19:27:44 BOX_8 64 vr10TO10 57600 4674 162 74 3803 145 18 24 | ratUnknown 2020-11-21 19:27:44 BOX_8 64 vr10TO10 57600 200 0 0 136 25 | 3b9ad027 2020-11-21 19:26:59 BOX_9 81 vr10TO10 57600 6348 178 116 0 204 107 26 | 3b9ad162 2020-11-21 19:26:59 BOX_9 81 vr10TO10 57600 10792 370 164 0 286 127 27 | ratUnknown 2020-11-21 19:26:59 BOX_9 81 vr10TO10 57600 969 26 0 0 28 | -------------------------------------------------------------------------------- /socialDrinking/utility_script/update_and_reboot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | branch=$1 5 | 6 | git checkout $branch && git pull 7 | 8 | sudo reboot -------------------------------------------------------------------------------- /tailTimer/config.py: -------------------------------------------------------------------------------- 1 | USER_RFIDs = { 2 | "4fb3": "Hao Chen", 3 | "b0b2": "Mallory Udell", 4 | "f277": "Paige Lemen", 5 | "dfea": "Shuang Ying", 6 | } 7 | 8 | SPEED_RFIDs = { 9 | "cc44": "1", 10 | "5743": "2", 11 | } 12 | 13 | COMMAND_RFIDs = { 14 | "f27e": "n", 15 | "2588": "d", 16 | "8874": "e", 17 | "3131": "a", 18 | } -------------------------------------------------------------------------------- /tailTimer/readme.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # TailTimer: Automating the tail immersion assay 5 | 6 | # Please do not pull from this repo. Tailtimer submodule has been moved to [this](https://github.com/chen42/tailTimer) repo. All updates will be done there. 7 | 8 | The tail immersion assay is a widely used method for measuring acute thermal pain in rodents. TailTimer uses the Raspberry Pi computer to automatically record both tail withdrawal latency and water temperature. The device has a radio frequency identification (RFID) system that can record the ID of animals. The software recognizes several specific RFID keys as user interface commands, which allows TailTimer to be operated via RFID fobs. We also programmed the device to only allow tests to be conducted when the water is within ± 0.25 °C of the target temperature. 9 | 10 | ![](tailTimer.jpg) 11 | -------------------------------------------------------------------------------- /tailTimer/runtailtimer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "------------------------" 4 | echo "Please write down the data and time shown above if it is not correct!" 5 | echo "-----------------------------------------------------------" 6 | sudo python /home/pi/openbehavior/tailTimer/tailwithdrawal.py 7 | 8 | echo "" 9 | echo "--------------------------------" 10 | echo "Please plug in a usb drive, enter anything to continue" 11 | echo "--------------------------------" 12 | echo "" 13 | read dummy 14 | sudo mount /dev/sda1 /mnt 15 | echo "" 16 | echo "" 17 | echo "START COPYING FILES" 18 | 19 | sudo cp /home/pi/Pies/tailwithdrawl/* /mnt/ -v 20 | echo "FILES COPIED" 21 | sudo umount /dev/sda1 22 | echo "PLEASE REMOVE THE USB DRIVE" 23 | 24 | 25 | -------------------------------------------------------------------------------- /tailTimer/tailTimer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/tailTimer/tailTimer.jpg -------------------------------------------------------------------------------- /touchscreen/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/touchscreen/circle.png -------------------------------------------------------------------------------- /touchscreen/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen42/openbehavior/f2d94cf2dc8312ae9e5fc149849a6ac7abaee278/touchscreen/star.png -------------------------------------------------------------------------------- /touchscreen/touchscreen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | from Tkinter import * 3 | 4 | root = Tk() 5 | 6 | def Correct(): 7 | print ("reward") 8 | 9 | def Incorrect(): 10 | print ("timeout") 11 | 12 | circle=PhotoImage(file='circle.png') 13 | 14 | frame1=Frame(root) 15 | frame1.pack(side=TOP, fill=X) 16 | star=PhotoImage(file='star.png') 17 | button1=Button(frame1, compound=TOP, width=683, height=768, image=star, command=Correct) 18 | button1.pack(side=LEFT, padx=2, pady=2) 19 | 20 | button2=Button(frame1, compound=TOP, width=683, height=768, image=circle, command=Incorrect) 21 | button2.pack(side=RIGHT, padx=2, pady=2) 22 | 23 | root.geometry('{}x{}'.format(1366,768)) 24 | 25 | root.mainloop() 26 | root.destroy() 27 | -------------------------------------------------------------------------------- /wifi-network/cronsync.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rsync -auvp -e ssh /home/pi/SocialDrinking/ root@149.56.128.122:~/Dropbox/Pies/SocialDrinking/ 3 | 4 | -------------------------------------------------------------------------------- /wifi-network/deviceinfo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # wait for wifi connection before run htpdate (because ntp is blocked on my network 5 | # then set hwclock 6 | 7 | ## make sure wlan0 is up 8 | sudo ifconfig wlan0 up 9 | 10 | while [ `sudo ifconfig wlan0 |grep Bcast |wc -l` -ne 1 ] 11 | do 12 | sleep 2 13 | cnt=$[$cnt+1] 14 | echo "waiting $cnt" 15 | if [ $cnt -eq 10 ] # max 20 sec 16 | then 17 | sudo ifconfig wlan0 down # disconnect wifi if not connected 18 | echo "Give up on wifi" 19 | break 20 | fi 21 | done 22 | 23 | echo "Sync time with the internet" 24 | sudo htpdate -t -s www.ntp.org www.uthsc.edu www.freebsd.org > /home/pi/htpdateout 25 | if grep -v -q ExtBox /home/pi/deviceid ; then 26 | if grep -q "Setting.*seconds" /home/pi/htpdateout ; then 27 | cat /home/pi/htpdateout 28 | echo "update hw clock" 29 | sudo hwclock -w 30 | else 31 | sudo hwclock -s 32 | fi 33 | fi 34 | 35 | date >>/home/pi/Pies/DeviceInfo/`cat /home/pi/deviceid`.info 36 | cat /home/pi/deviceid >>/home/pi/Pies/DeviceInfo/`cat /home/pi/deviceid`.info 37 | ifconfig wlan0 >>/home/pi/Pies/DeviceInfo/`cat /home/pi/deviceid`.info 38 | ifconfig eth0 >>/home/pi/Pies/DeviceInfo/`cat /home/pi/deviceid`.info 39 | echo "_______________________________" >>/home/pi/Pies/DeviceInfo/`cat /home/pi/deviceid`.info 40 | 41 | rsync -az -e ssh /home/pi/Pies/ root@149.56.128.122:~/Dropbox/Pies/ 42 | 43 | 44 | -------------------------------------------------------------------------------- /wifi-network/interfaces: -------------------------------------------------------------------------------- 1 | # interfaces(5) file used by ifup(8) and ifdown(8) 2 | 3 | # Please note that this file is written to be used with dhcpcd 4 | # For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf' 5 | 6 | # Include files from /etc/network/interfaces.d: 7 | source-directory /etc/network/interfaces.d 8 | 9 | auto lo 10 | iface lo inet loopback 11 | 12 | iface eth0 inet manual 13 | 14 | allow-hotplug wlan0 15 | iface wlan0 inet manual 16 | wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf 17 | iface default inet dhcp 18 | 19 | #allow-hotplug wlan1 20 | #iface wlan1 inet manual 21 | # wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf 22 | -------------------------------------------------------------------------------- /wifi-network/killhtpd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sleep 30 3 | sudo killall htpdate 4 | -------------------------------------------------------------------------------- /wifi-network/rsync.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # introduce a small random delay so that the server does not get too many requrests at the same time. 4 | delay=`shuf -i1-3 -n1` 5 | 6 | # make sure wlan0 is up 7 | ifconfig wlan0 up 8 | while [ `sudo ifconfig wlan0 |grep broadcast |wc -l` -ne 1 ] 9 | do 10 | sleep 2 11 | cnt=$[$cnt+1] 12 | if [ $cnt -eq 30 ] # max 60 sec 13 | then 14 | break 15 | fi 16 | done 17 | 18 | # remove files older than 15 days 19 | rm `find /home/pi/SocialDrinking/* -mtime +15` 20 | 21 | gzip -f /home/pi/SocialDrinking/*csv 22 | 23 | rsync -auvp -e ssh /home/pi/SocialDrinking/ root@149.56.128.122:~/Dropbox/Pies/SocialDrinking/ 24 | sleep 1m 25 | #sync one more time 26 | rsync -auvp -e ssh /home/pi/SocialDrinking/ root@149.56.128.122:~/Dropbox/Pies/SocialDrinking/ 27 | 28 | sudo reboot 29 | 30 | -------------------------------------------------------------------------------- /wifi-network/wlan0down.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | while [ `sudo ifconfig wlan0 |grep Bcast |wc -l` -eq 1 ] 5 | do 6 | sleep 1 7 | echo "turnning off wlan0" 8 | ifconfig wlan0 down 9 | done 10 | 11 | -------------------------------------------------------------------------------- /wifi-network/wpa_supplicant.conf: -------------------------------------------------------------------------------- 1 | country=US 2 | ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev 3 | update_config=1 4 | 5 | network={ 6 | identity="x@x.edu" 7 | password="" 8 | eap=PEAP 9 | scan_ssid=1 10 | phase2="auth=MSCHAPv2" 11 | ssid="eduroam" 12 | key_mgmt=WPA-EAP 13 | } 14 | --------------------------------------------------------------------------------