You are on page 1of 37

Final Report

‫‪.1‬פרק ‪ - 1‬מבוא‬
‫‪.1.1‬ניסויים התנהגותיים‬

‫ניסויים נוירופיזיולוגיים התנהגותיים דורשים רישום אותות חשמליים מבעל‬


‫חיים חי ובמקרים מסוימים גם מתנהג‪ ,‬כשהתנהגות מוגדרת כתגובה של בעל‬
‫החיים לגירויים חיצוניים‪.‬‬
‫קיים מספר רב של פרוטוקולים לניסויים התנהגותיים‪ .‬ניתן לחלק אותם‬
‫לקבוצות לפי סוגי גירוי ודרגות התנהגות ובהתאם לכך גם דרישות ממערכת‬
‫הניסויית ומתוכנה התנהגותית‪.‬‬
‫‪.1‬קבוצה של ניסויים בהם הנבדק רדום‪ .‬הגירוי החשמלי מוכל על‬
‫נוירון מסוים או קבוצת נוירונים והתגובה ה"התנהגותית" נמדדת‬
‫באזור אחר מתא בודד או קבוצה של תאים‪.‬‬
‫בניסויים מסוג זה אין צורך במערכת התנהגותית‪ ,‬כל הדרוש הן‬
‫אלקטרודות לגירוי ואלקטרודות לרישום (בד"כ ‪.)Patch-clamp‬‬

‫‪1. Henrik Jo¨rntell, Carl-Fredrik Ekerot (2006) Properties of Somatosensory‬‬


‫‪Synaptic Integration in Cerebellar Granule Cells In Vivo. J Physiol‬‬

‫‪.2‬קבוצה של ניסויים בהם הנבדק ער ונדרש לבצע פעולה‬


‫התנהגותית פשוטה יחסית‪ ,‬כגון להסתכל על נקודה מסוימת‬
‫במרחב או לחיצה על כפתור‪ .‬בניסויים מסוג זה בנוסף למערכת‬
‫הרישום ישנה גם מערכת התנהגותית‪ ,‬כגון תוכנה התנהגותית‬
‫אשר מציגה את התמונות לנבדק או בודקת האם הכפתור נלחץ‬
‫וכדומה‪.‬‬
‫‪1. AK Kreiter, W Singer (1996) Stimulus-dependent synchronization of‬‬
‫‪neuronal responses in the visual cortex of the awake macaque monkey.‬‬
‫‪Journal of Neuroscience‬‬
‫)‪2. Thomas Wachtler, Terrence J. Sejnowski, Thomas D. Albright (2003‬‬
‫‪Representation of Color Stimuli in Awake Macaque Primary Visual‬‬
‫‪Cortex, Neuron‬‬

‫‪.3‬קבוצה של ניסויים בהם הנבדק ער ונדרש לבצע פעולות מוטוריות‬


‫מסובכת יחסית‪ .‬בעל החיים מתנהג במלא מובן המילה‪ .‬בנוסף‬
‫למערת הרישום נדרשת חומרה אשר מייצרת גירויים (ויזואליים‪,‬‬
‫קוליים‪ ,‬הָפטיים וכדומה) ומודדת את התנועה (כוון‪ ,‬מהירות‪,‬‬
‫כוח)‪.‬‬
‫‪1. Kris M. Horn, Milton Pong and Alan R. Gibson (2003) Discharge of‬‬
‫‪inferior olive cells during reaching errors and perturbations, Brain‬‬
‫‪Research‬‬

‫‪.4‬קבוצה של ניסויים בהם הנבדק מקבל גירויים משולבים ממערכת‬


‫‪ .)VR (Virtual Reality‬מערכות כאלה בד"כ כוללות רובוטים‬
‫הָפטיים ומחשב בעל יכולת הצגה של תמונה תלת‪-‬ממדית‪.‬‬
‫מטרת המחקר של ד"ר עופר דונחין היא לחקור את תפקידם של קורטקס המוטורי‬
‫והצרבלום בלמידה מוטורית‪ ,‬ולכן הנבדקים יהיו ערים ויבצעו משימות התנהגותיות‬
‫שונות‪ .‬למידה מוטורית תושג ע"י הפעלת כוחות הפרעה (‪ )Perturbation forces‬על‬
‫הגפה שתבצע את המשימה וחזרה על המשימה עד שהתבנית של התנועה עם‬
‫ההפרעה תהיה דומה לתבנית של התנועה בלי ההפרעה‪ .‬הניסויים לא יכללו (לפחות‬
‫לא בשלב הראשון) הדמיה וירטואלית (‪.)VR‬‬

‫‪.1.2‬מבנה כללי של המערכת‬

‫מערכת הניסוי מורכבת ממרכיבי חומרה שונים ותוכנה התנהגותית‪.‬‬

‫‪1.‬‬ ‫‪Perturbation Phantom‬‬


‫‪2.‬‬ ‫‪Reward Phantom‬‬
‫‪3.‬‬ ‫‪Food Pump‬‬
‫‪4.‬‬ ‫‪Sound cue‬‬
‫‪5.‬‬ ‫‪Force Plates‬‬
‫‪6.‬‬ ‫‪Behavioral Software‬‬

‫מערכת הניסוי כוללת את כל המרכיבים הדרושים לביצוע ניסוי התנהגותי‬


‫ולבצע את כל המשימות הדרושות‪.‬‬
‫המערכת כוללת שני רובוטים הָפטיים – פאנטומים‪ ,‬כאשר לכל אחד מהם‬
‫תפקיד שונה‪ .‬תפקידו של פאנטום (‪ )1‬פרמיום (‪ )Premium‬הוא להפעיל כוחות‬
‫מפריעים (‪ )Perturbation forces‬על הגפה של החתול‪ .‬הכוחות יכולים להיות‬
‫מסוגים שונים ודרגות שונות של מורכבות‪ :‬כוח קבוע בכוון קבוע‪ ,‬כוח קבוע‬
‫המאונך לכוון התנועה‪ ,‬כוח משתנה בהתאם למהירות וכוון התנועה וכו'‪.‬‬
‫תפקידו של פאנטום (‪ )2‬אומני (‪ )Omni‬הוא לשמש מטרה (גירוי ויזואלי) שאותה‬
‫החתול ירצה לתפוס כדי לקבל תגמול‪ .‬פאנטום זה מספק את המסגרת של מהלך‬
‫הניסוי ומבחינת החתול זהו הממשק הוויזואלי של המערכת‪ .‬הוא לא מפעיל‬
‫כוחות על החתול‪ ,‬אלא מבצע פעולות כגון‪ :‬הגעה לנקודה שבה הוא נגיש לחתול‪,‬‬
‫המתנה בגובה מסוים‪ ,‬הדמיה של משטח חסר חיכוך וכולי‪ ,‬בהתאם לדרישות‬
‫מהלך הניסוי‪.‬‬
‫תפקידה של המשאבה הוא לספק את האוכל (התגמול) לחתול‪ .‬האוכל יכול‬
‫להינתן בצורה אוטומטית לפי ההגדרות של הניסוי או בצורה ידנית ע"י לחוצה‬
‫על כפתור בתוכנה‪.‬‬
‫החתול יקבל סימנים קוליים בשלבים שונים של הניסוי‪ ,‬למשל‪ ,‬צליל שיסמן את‬
‫תחילת הניסוי‪.‬‬
‫תפקידם של ‪ force plates‬הוא לספק מידע נוסף למערכת על מיקומו והתנהגותו‬
‫של החתול בזמן הניסוי‪ .‬לפי המשקל ניתן לדעת האם החתול עומד עם שני‬
‫הגפיים‪ ,‬מושיט גפה וכו'‪.‬‬
‫כל המערכת מנוהלת ע"י תוכנה התנהגותית‪ .‬היא זו שיודעת לאסוף את כל‬
‫המידע מכל החומרה ולנהל את הניסוי לפי תוצאות העיבוד של מידע זה‪.‬‬

‫‪.1.3‬תאור התוכנה ההתנהגותית‬

‫תוכנת ‪ Cats‬היא תוכנה התנהגותית אשר מנהלת את כל ההיבטים של הניסוי ע"י‬


‫כך שמספקת לחוקר כלים פשוטים‪ ,‬אך גמישים‪ ,‬להרכבת מהלך הניסוי‪ ,‬שליטה‬
‫על ביצועו‪ ,‬ע"י שליטה על כל מרכיבי החומרה והסנכרון ביניהם‪ ,‬ושליטה על‬
‫התנהגות בעל החיים (באמצאות החומרה) כאשר מבצע תנועות ההושטה במהלך‬
‫הניסוי‪.‬‬
‫‪.1‬פרק ‪ – 2‬רקע תכני‬
‫‪ – Object Oriented Programming .1.4‬תכנות מונחה עצמים‬

‫תכנות מונחה עצמים הוא פרדיגמה תכנותית שמשתמשת ב"אובייקטים" (‬


‫‪ )Objects‬ליצירת תוכנות מחשב ואפליקציות‪ .‬שפת ‪ ,++C‬בניגוד לשפת ‪ , C‬היא‬
‫שפה מונחת עצמים‪.‬‬
‫מושגים שמתקשרים עם תכנות מונחה עצמים הם הורשה (‪,)Inheritance‬‬
‫מודולאריות (‪ ,)Modularity‬פולימורפיזם – ריבוי צורות (‪ )Polymorphism‬ו‬
‫אנקפסולציה (‪.)Encapsulation‬‬
‫אובייקט בתכנות הוא כמו אובייקט בחיים – יש לו תכונות ויש פעולות שאפשר‬
‫לעשות איתו (עליו)‪ .‬רכב הוא אובייקט‪ .‬צבע הרכב‪ ,‬מספר גלגלים‪ ,‬יצרן וכו' הן‬
‫התכונות של הרכב‪ .‬הרכב יכול לנסוע‪ ,‬לעצור‪ ,‬לחנות וכו' – אלא הן הפעולות‬
‫שהוא יכול לבצע‪.‬‬
‫הדוגמא הכי פשוטה לאובייקט בתכנות היא משתנה‪ ,‬שהוא סוג של אובייקט‪.‬‬
‫משתנה מסוג ‪ Integer‬הוא משתנה פשוט‪ .‬המאפיין היחיד שלו (או בשפה יותר‬
‫מקצועית ‪ )Data member‬הוא הערך שהוא יכול להחזיק‪ .‬הפעולות שאפשר לבצע‬
‫עליו הן – חיבור‪ ,‬חיסור וכו'‪ .‬כאשר המשתנה מוגדר‬
‫;‪int iVariable‬‬
‫אנחנו בעצם יוצרים אובייקט מסוג ‪ ,int‬ההגדרה של סוג האובייקט נקראת‬
‫מחלקה (‪ .)class‬המחלקה היא זו שמגדירה מה הם ה‪ data members-‬של‬
‫האובייקט ומה הם ה‪ Member functions-‬שלו (הפעולות שאפשר לבצע בהקשר‬
‫לאובייקט)‪.‬‬
‫הורשה (‪ )Inheritance‬היא יכולת להשתמש במחלקה קיימת כדי ליצור סוג‬
‫אובייקט חדש (כמו ההורשה בהקשר הגנטי)‪ .‬למחלקת הבת יהיו אותן תכונות‬
‫ויכולות כמו למחלקת האם עם אפשרות להוסיף אפשרויות חדשות או לשנות‬
‫את הישנות‪.‬‬
‫לדוגמא אם יש לנו מחלקה "בעל חיים" (שתכלול הגדרות הכי כלליות עבור יצור‬
‫חי) ונרצה להוריש ממנה מחלקה "בן‪-‬אדם" אז נרצה להוסיף למחלקה החדשה‬
‫תכונה של "דיבור"‪ ,‬וכך "בן‪-‬אדם" מקבל את כל התכונות של "בעל חיים"‬
‫ובנוסף יודע "לדבר"‪( .‬לא השתמשתי בדוגמא ב"חושב" מכוון שיכולת זו שנויה‬
‫במחלוקת)‪.‬‬
‫מודולאריות (‪ )Modularity‬מתארת את היכולת של השפה לקבץ פעולות ליחידות‬
‫עצמאיות ולהשתמש ביחידות אלה‪ .‬חשיבה מודולארית מאפשרת "למחזר" את‬
‫הקוד – להשתמש במודול מסוים מספר פעמיים במקום לשכתב את הקוד‪.‬‬
‫קבוצה של מתכנתים יכולה לחלק את העבודה וכך כל אחד יעובד על המודולים‬
‫שלו ובסוף רק יחברו אותם ביחד (הגישה הזו מקלה מאוד בעבודה על פרויקטים‬
‫משוטפים)‪.‬‬
‫פולימורפיזם (‪ - )Polymorphism‬במילים פשוטות זוהי היכולת להתייחס‬
‫למחלקת בת כאילו היא מחלקת אם‪ .‬אשתמש שוב בדוגמא של מחלקת "בעל‬
‫חיים" ומחלקה מורשת ממנה "בן‪-‬אדם"‪ .‬השפה מאפשרת להגדיר מצביע מסוג‬
‫"בעל חיים" ולהצביע איתו על "בן‪-‬אדם"‪( .‬תכונה זו מאוד הגיונית‪ ,‬כי הרי בן‪-‬‬
‫אדם הוא רק מקרה פרטי של בעל החיים)‪.‬‬
‫אנקפסולציה (‪ – )Encapsulation‬המשמעות של המושג היא "הסתרת מידע"‪.‬‬
‫השאיפה היא שהמשתמש של המחלקה שהוגדרה על‪-‬ידי (משתמש הוא מתכנת‬
‫אחר שרוצה ליצור אובייקט מסוג המחלקה או רוצה להוריש מחלקה‬
‫מהמחלקה שלי) לא יצטרך לדעת שום דבר על מבנה הפנימי של המחלקה שלי‪,‬‬
‫הוא ידע רק איך להשתמש בה‪ .‬דוגמא מהחיים – טלוויזיה – רובינו יודעים‬
‫להשתמש בה‪ ,‬אבל לא יודעים איך היא בנויה‪.‬‬
‫תכנות מונחה עצמים מאפשר צורת תיכונות שונה מהגישה הקלאסית של שפת‬
‫‪ ,C‬ונותן למתכנת כלים רבים ומגוונים ליצירת אפליקציות טובות יותר‪ ,‬אך‬
‫לגישה זו ישנם גם חסרונות מכוון שלא כל רעיון בתכנות ניתן להפוך לאובייקט‬
‫וגם שימוש מוגזם בחלוקה של משימות לחלקים קטנים יותר ויותר הופך את‬
‫הקוד ללא ברור ולא קריא‪.‬‬

‫‪MFC - Microsoft Foundation Class Library.1.5‬‬

‫זוהי ספריית קוד (‪ )code library‬שעוטפת חלק מ‪ Windows API-‬בתוך מחלקות של‬
‫‪ ,++C‬במטרה ליצור מסגרת לפיתוח אפליקציות‪ .‬היא כוללת מחלקות רבות‬
‫המוגדרות כדי לטפל בפקודות מערכת‪ ,‬חלונות ואובייקטים גרפים (‪common‬‬
‫‪ )controls‬שונים‪ .‬בנוסף‪ ,‬מיקרוסופט הרחיבה את הסינטקס של ‪ ++C‬עם סדרה‬
‫של מאקרו (‪ )macros‬לניהול של ‪ Windows messages, Exceptions‬וכו'‪.‬‬
‫‪ MFC‬מספקת מסגרת של ‪ Document/View‬במטרה להפריד את המידע (‪)Data‬‬
‫מממשק משתמש (‪ ,)User interface‬וכך כאשר עובדים עם המידע שבתוכנה‬
‫ניגשים ל‪ Document-‬וכאשר עובדים עם ממשק משתמש נגשים ל‪( View-‬אשף‬
‫הפרויקטים של ‪ Ms Visual Studio‬יוצר שתי מחלקות לפי התבנית ‪AppNameView‬‬
‫ו‪AppNameDoc -‬ולכן אם התוכנה נקראת ‪ Cats‬מתקבלות שתי מחלקות‪:‬‬
‫‪ CatsView‬ו‪.)CatsDoc-‬‬

‫‪.1.6‬ריבוי משימות‪Multithreading ,‬‬

‫ישנם שני סוגים של ריבוי משימות‪ :‬מבוססות ‪ process‬ומבוססות ‪.thread‬‬


‫‪ process‬הוא בעצם תוכנה שרצה במחשב וריבוי משימות מבוסס ‪ process‬מאפשר‬
‫למספר תוכנות לרוץ במקביל‪ .‬בסוג זה של ריבוי משימות ה"תוכנה" היא‬
‫היחידה הכי קטנה ובסיסית שהמערכת יכולה להריץ‪.‬‬
‫‪ thread‬הוא יחידה של קוד שניתן להרצה‪ .‬בריבוי משימות מבוסס ‪ thread‬לכל‬
‫‪ process‬ישנו לפחות ‪ thread‬אחד‪ .‬המשמעות היא שכל תוכנה יכולה לבצע מספר‬
‫משימות בו‪-‬זמנית‪.‬‬
‫ניתן לסכם את ההבדלים בין שני הסוגים של ריבוי משימות בכך שריבוי‬
‫משימות מבוסס ‪ process‬אחראי על הרצה בו זמנית של תוכנות וריבוי משימות‬
‫מבוסס ‪ thread‬אחראי על הרצה בו זמנית של חלקים שונים של אותה התוכנה‪.‬‬
‫כאן חשוב לציין שריבוי משימות בו‪-‬זמני אמיתי ניתן ליישם רק במערכות‬
‫מבוססות מספר מעבדים (‪ ,)multiple-CPU‬כאשר לכל ‪ process‬או ‪ thread‬ישנה‬
‫גישה בלתי מוגבלת למעבד‪.‬‬
‫כאשר המערכת כוללת רק מעבד אחד‪ ,‬ריבוי המשימות הוא מדומה‪ ,‬זמן המעבד‬
‫מחולק בין ה‪ threads-‬השונים‪,‬וגודלו נקבע לפי מספר פקטורים‪ ,‬כולל ה‪priority-‬‬
‫שלהם‪.‬‬
‫ריבוי משימות (‪ )thread‬משונה בצורה פונדמנטלית את הארכיטקטורה של‬
‫התוכנה‪ .‬בניגוד לתוכנה בעלת ‪ thread‬אחד שמתבצעת בצורה ליניארית‪ ,‬תוכנה‬
‫בעלת מספר ‪ threads‬כוללת אלמנטים של פרלליות‪ ,‬ולכן האתגר הוא לנהל את‬
‫התקשורת בין ה –‪.threads‬‬
‫‪.1.7‬זמן‪-‬אמת‬

‫מערכת נקראת מערכת זמן‪-‬אמת אם הצלחת הפעולה תלויה לא רק בנכונות‬


‫לוגית של התוצאה‪ ,‬אלא גם בזמן ביצוע הפעולה‪.‬‬
‫ישנם שני סוגים של מערכות זמן‪-‬אמת‪ :‬קשיחות (‪ )hard‬ומתונות (‪.)soft‬‬
‫במערכת קשיחה אי ביצוע הפעולה הדרושה בזמן שהוקצב נחשבת לכישלון‬
‫המערכת‪ .‬מערכות מסוג זה מתבססות על אינטראקציה מאוד קרובה עם‬
‫חומרה‪ .‬קוצב לב הוא דוגמא טובה למערכת כזאת‪ ,‬תגובה מאוחרת תגרום‬
‫למוות של המטופל‪.‬‬
‫במערכות מתונות אי ביצוע הפעולה הנדרשת בזמן שהוקצב לא נחשבת לכישלון‬
‫אלא רק מורידה את הביצועים של המערכת‪ .‬נגן מדיה שמפספס את ההצגה של‬
‫חלק מהפריימים הוא דוגמא טובה‪.‬‬
‫מערכת הפעלה "חלונות" אינה מערכת זמן‪-‬אמת ולכן גם כל אפליקציה שרצה‬
‫במערכת זו אינה יכולה להיות אפליקציית זמן‪-‬אמת‪.‬‬
‫תוכנת "‪ "Cats‬שואפת‪ ,‬במסגרת המגבלות של מערכת ההפעלה‪ ,‬להיות מערכת‬
‫זמן‪-‬אמת‪ ,‬כאשר שימוש בריבוי המשימות הוא אחד הכלים המשמשים למטרה‬
‫זו‪.‬‬

‫‪.1.8‬רובוטים הָפֵטיים – ‪Haptic Devices‬‬

‫‪ – Haptic Device‬התקן שמטרתו היא לדמות תחושה עורית‪ ,‬לדמות אפקטים של‬
‫חיכוך‪ ,‬צמיגות‪ ,‬קשיחות וכו'‪ .‬ההתקן מפעיל כוחות מתאימים על האדם (או בעל‬
‫חיים) שמשתמש בו וע"י כך נותן תחושה של האפקט הרצוי‪.‬‬
‫המערכת כוללת שני רובוטים הָפֵטיים (‪ )haptic‬של חברת ‪.Sensable‬‬
‫מטרתם של הרובוטים האלה במערכת הניסוי שונה ברוב המקרים מייעודם‬
‫המקורי‪ ,‬במקום לדמות תחושה הרובוט מופעל ע"י התוכנה ומבצע משימות‬
‫שונות ללא הספקת גירוי לחתול‪.‬‬
‫לכל רובוט תפקיד משלו במערכת‪:‬‬
‫‪ – Phantom Omni‬מתפקד כמטרה שאותה החתול צריך לתפוס‪ .‬מבצע פעולות‬
‫כגון תזוזה למקום מסוים‪ ,‬המתנה בנקודה מסוימת‪ ,‬הדמיה של משטח ללא‬
‫חיכוך וכו'‪.‬‬
‫‪ – Phantom Premium‬מתפקד כמפריעה לתנועה (‪ .)Perturbatoion‬מפעיל כוחות על‬
‫הגפה של החתול בהתאם להגדרות הניסוי‪ ,‬כגון כוח קבוע בכוון מסוים‪ ,‬כוח‬
‫אנכי לתנועה וכו'‪.‬‬
‫‪.1.9‬משאבה‬

‫המשאבה משמשת להזרמת אוכל (‪ )reward‬לחתול בזמן ביצוע הניסוי‪.‬‬


‫מפרט של המשאבה מצורף לדו"ח‪.‬‬

‫המשאבה כוללת אפשרות של שליטה מרחוק‪.‬‬


‫ניתן לראות שני טרמינלים (‪ )Remote Start/Stop Input‬בצידה האחורי של‬
‫המשאבה שמאפשרים לשלוט על הפעלה או הפסקה של המשאבה (אין אפשרות‬
‫לשלוט על כוון או הכוח מרחוק)‪.‬‬
‫שני הטרמינלים חוברו לכרטיס ‪ A/D‬וכך התקבלה האפשרות לשלוט על עבודת‬
‫המשאבה מתוך התוכנה ההתנהגותית‪.‬‬
‫החיבור נעשה לא ישירות‪ ,‬אלא דרך מעגל אלקטרו‪-‬אופטי‪.‬‬
‫למעגל שתי מטרות‪:‬‬
‫‪.1‬התמרת האות של כרטיס ה‪ A/D-‬להפעלת‬
‫המשאבה (‪.)5V-on, 0V-off‬‬
‫‪.2‬בידוד המערכת (ע"י שתי דיודות אופטיות)‪.‬‬

‫‪Pump Control Opto‬‬

‫‪Pulse TTL‬‬
‫‪#4‬‬
‫‪1‬‬ ‫‪R1‬‬ ‫‪1k‬‬ ‫‪Pump‬‬
‫‪6‬‬ ‫‪2‬‬ ‫‪8‬‬
‫‪Rear‬‬
‫‪2‬‬ ‫‪Manual‬‬
‫‪7‬‬ ‫‪7‬‬ ‫‪Panel‬‬
‫‪3‬‬ ‫‪#3‬‬
‫‪8‬‬ ‫‪3‬‬ ‫‪6‬‬
‫‪4‬‬
‫‪9‬‬ ‫‪5‬‬ ‫‪Computer‬‬
‫‪5‬‬
‫‪Control‬‬
‫‪U1‬‬ ‫‪6N139‬‬ ‫‪SW1‬‬
‫‪P1‬‬ ‫‪DB9 Female‬‬ ‫‪SWKEY-SPDT‬‬

‫‪Switch C.K. 7101‬‬

‫‪.1.10‬כרטיס ‪D/A‬‬

‫‪NI PCI-6229‬‬
‫מפרט של הכרטיס מצורף לדו"ח‪ .‬כמה מילים על ‪ A/D‬ולהזכיר שגם לכרטיס יש‬
‫‪.API‬‬
‫כבל שמתחבר לכרטיס ‪ A/D‬מתחבר בצידו השני לקופסת חיבורים (‪SCB-68‬‬
‫‪ )Shielded I/O connector block‬מוגנת ומותאמת להקטנת רעש‪ ,‬בעלת ‪ 68‬ערוצים‪.‬‬

‫‪Force Plates.1.11‬‬
‫תפקידם של ‪ Force Plates‬הוא לספק מידע על מידת הלחץ שאותו מפעיל החתול‬
‫על המשטח שעליו הוא עומד‪ ,‬וע"י כך לקבוע את מצבו של החתול ברגע נתון‬
‫(האם נשען עם שתי הגפיים הקדמיות‪ ,‬גפה אחת‪ ,‬זז למקום לא רצוי וכו')‪.‬‬
‫בשלב זה אין במעבדה את החומרה המתאימה ולכן גם לא קיים קוד בתוכנה‬
‫שמטפל באירועים של החומרה הזו‪ .‬כאשר יבנו‪/‬יקנו את החומרה המתאימה‬
‫היא תעבוד מול כרטיס ה‪.A/D-‬‬

‫‪.1.12‬רמקולים‬
‫חתולים הם בעלי טווח שמיעה רחב יותר מאשר בני אדם‬
‫(חתולים‪ , Hz 45-64,000 :‬בני אדם ‪ )Hz 64-23,000‬ולכן אין צורך במכשור מיוחד‬
‫להשמעת צלילים‪.‬‬
‫אנחנו משתמשים ברמקול מחשב סטנדרטי של חברת ‪.Creative‬‬
‫‪.2‬פרק ‪ – 3‬מבנה התוכנה ממבט של משתמש‬
‫‪ .1.13‬מבוא‬

‫תוכנת ‪ CATS‬מיודעת לניהול וביצוע ניסויים נוירו פיזיולוגיים התנהגותיים‬


‫בחתולים‪.‬‬
‫התוכנה נותנת אפשרות להרכיב מהלך ניסוי‪ ,‬מבצעת את הניסוי ע"י שליטה‬
‫בחומרה חיצונית ורושמת את תוצאות הניסוי‪.‬‬
‫בפרק הזה אני אתאר את התיאוריה הכללית של בנית הניסוי ואז אתן סקירה‬
‫של ממשק המשתמש בהקשר של בניית ניסוי‪.‬‬

‫כפי שנאמר קודם‪ ,‬התוכנה נבנתה על בסיס תוכנת ‪ Monkey‬וחלק מהשמות של‬
‫מחלקות "הורשו" גם הם מהתוכנה הקודמת‪.‬‬
‫במשך בניית התוכנה הגענו למסכנה שיש צורך בשמות שמתארים טוב יותר את‬
‫התפקיד של המחלקות אשר מייצגות בלוקים אשר מרכיבים את הניסוי‪.‬‬
‫מכיוון שההחלטה הסופית בקשר לשמות התקבלה ברגע האחרון‪ ,‬החלטנו‬
‫לשמור על שמות המחלקות כמו שהם‪ ,‬אך מצד השני להוסיף לכל החלונות של‬
‫ממשק המשתמש את השמות החדשים‪ .‬בשלבים הבאים של פיתוח התוכנה‬
‫ישתנו גם השמות של המחלקות עצמן‪.‬‬

‫‪.1.14‬תאור כללי של מבנה הניסוי (‪)Session‬‬

‫היחידה הביצועית הכי קטנה של התוכנה היא ניסיון (‪ .)Trial‬ישנם שני שלבים‬
‫בהגדרת ניסיון – סוג ניסיון (‪ )Trial Type‬ו‪ -‬הגדרת ניסיון (‪.)Trial Definition‬‬
‫סוגי ניסיונות מוגדרים ע"י המתכנת בהתאם לניסיונות שנכתבו עבור התוכנה –‬
‫המשתמש אינו משנה הגדרות ברמה זו‪.‬‬
‫המשתמש יוצר הגדרות של ניסיונות (‪ )Trial Definitions‬מתוך הסוגי הניסיונות‬
‫שהוגדרו ע"י המתכנת‪ .‬ניתן ליצור מספר רב של ניסיונות שונים מכל סוג‬
‫ניסיונות‪ ,‬כאשר מהלך הניסיון יהיה קבוע אבל פרמטרים שונים (זמנים‪ ,‬מיקום‬
‫הפנטומים‪ ,‬צלילים וכו')‪.‬‬
‫ניסיונות מאוגדים לבלוקים (‪ .)Blocks‬בלוק יכול להכיל בתוכו סוג אחד או יותר‬
‫של ניסיונות מסוג אחד או יותר‪ .‬בלוקים הם יחידות נוחות מאוד לבניית הניסוי‬
‫– ניתן לשכפל אותם ולשנות את הסדר שלהם וכך להקל על שינויים במהלך‬
‫הניסוי‪.‬‬
‫הניסוי (‪ )Session‬מורכב מאחד או יותר בלוקים‪ ,‬המסודרים בסדר מסוים שנקבע‬
‫מראש ע"י המשתמש‪.‬‬
‫‪Session‬‬

‫‪Block 1‬‬
‫‪Trial Definition A‬‬ ‫‪Repeat L Times‬‬

‫‪Trial Definition B‬‬ ‫‪Repeat M Times‬‬


‫‪Block 2‬‬

‫‪Trial Definition A‬‬ ‫‪Repeat N Times‬‬

‫‪Block 3‬‬ ‫‪Trial Definition C‬‬ ‫‪Repeat O Times‬‬

‫‪Trial Definition B‬‬ ‫‪Repeat P Times‬‬

‫‪Block 4‬‬

‫‪Block 5‬‬

‫פרמטרים הם הערכים שהמשתמש יכול לשנות וע"י כך להשפיע על התנהגות‬


‫התוכנה‪ .‬דוגמא לפרמטרים היא נקודה שעליה הפאנטום צריך להגיע בתחילת‬
‫הניסיון ‪ -‬המשתמש יכול לספק את הקואורדינאטות וכך לשנות את המיקום‬
‫(הדרך הנכונה לשינוי פרמטרים מפורטת בהמשך)‪.‬‬

‫כל ניסיון מכיל בתוכו הגדרה של מהלך הביצוע ותנאים להצלחה או לכישלון‬
‫שלו‪ .‬מהלך הניסיון זהו אוסף של פקודות הניתנות לחומרה‪ ,‬כאשר הפקודות‬
‫ניתנות בהתאם לשלב בניסיון ובהתאם לתגובת הנבדק באותו שלב‪ .‬ב‪ fig-‬ניתן‬
‫לראות מספר דוגמאות למהלכי הביצוע של ניסיונות פשוטים יחסית‪.‬‬
Start

Reward Phantom
- Start position

“Go ”cue to the cat

Wait for limb movement


No Yes

RewardPhantom
- Move Away Give Reward

Reward Phantom
-Move Away
Falure

Success

Start

Reward Phantom
- Start position

“Go ”cue to the cat

Wait for limb movement


No Yes

RewardPhantom Perturbation Phantom


- Move Away - Force On

Falure
Wait for Target reach

No Yes

Perturbation Phantom - Force Off Perturbation Phantom - Force Off


Reward Phantom - Move Away Give Reward

RewardPhantom
-Move Away
Falure

Success
‫‪.1.15‬ממשק משתמש‬

‫האינפורמציה מהסעיף הקודם תעזור לנו להבין טוב יותר את החלקים השונים‬
‫בממשק המשתמש‪ .‬סעיף זה יתאר איך מתבצעות למעשה הפעולות שתוארו‬
‫בסעיף הקודם‪.‬‬
‫ממשק המשתמש של התוכנה תוכנן כך שכל המידע יהיה זמין וכל פעולה‬
‫שהמשתמש ירצה לבצע תהיה במרחק של לחיצת עכבר‪.‬‬

‫חלקי הממשק הדומיננטיים הם שלושת החלונות (‪ )Documents‬שמטרתם היא‬


‫להציג מידע למשתמש (לחלון העליון ישנם גם תפקידים אחרים) והסרגל כלים‬
‫מצידו השמאלי של המסך‪.‬‬
‫החלון העליון‬
‫חלון הפאנטומים‪ .‬החלון מציג את מיקום הפאנטומים וגם מאפשר לכייל‬
‫אותם‪ .‬המשתמש יכול להפעיל או להפסיק את עדכון המיקום של‬
‫הפאנטומים (כל פאנטום בנפרד) ובנוסף יכול לספק את תדירות העדכון‬
‫(במילישניות)‪.‬‬
‫חלון אמצעי‬
‫חלון סטטיסטיקת הצלחות בניסוי‪ .‬החלון מציג ‪ 4‬ערכים‪ :‬סה"כ ניסיונות‬
‫שנעשו‪ ,‬הצלחות‪ ,‬כישלונות וכמה פעמים הניסיון הופסק באמצע ע"י‬
‫המשתמש‪.‬‬
‫החלון התחתון‬
‫חלון המשתנים‪ .‬חלון זה מציג את כל המשתנים שהוגדרו עבור הניסוי ע"י‬
‫המשתמש‪.‬‬
‫סרגל כלים‬
‫סרגל הכלים הוא מרכז השליטה העיקרי של התוכנה‪ .‬בעזרת הכפתורים‬
‫שעליו ניתן לבנות את מהלך הניסוי‪ ,‬להריץ את הניסוי‪ ,‬להפסיק אותו ולבצע‬
‫פעולות נוספות אחרות כגון הפעלה ידנית של צליל או הפעלת משאבת‬
‫התגמול בצורה ידנית בכל שלב של הניסוי‪.‬‬

‫‪Start Session‬‬

‫‪Run Section‬‬
‫‪Stop Session‬‬

‫‪Parameters‬‬

‫‪Blocks‬‬
‫‪Build Section‬‬

‫‪Trial Definitions‬‬

‫‪Trial Types‬‬

‫‪Manual Control‬‬ ‫‪Manual Pump‬‬


‫‪Section‬‬
‫‪Manual Sound‬‬

‫ממשק בניית מהלך הניסוי‬ ‫‪.i‬‬


‫תהליך בניית מהלך הניסוי (‪ )Session‬מורכב ממספר שלבים‪:‬‬
‫‪.1‬הגדרת סוג הניסיון (‪ )Trial Type‬בקוד ע"י המתכנת‬
‫(בהמשך) והוספתו לרשימת הניסיונות‪.‬‬
‫‪.2‬הרכבת הגדרות הניסיונות (‪.)Trial Definitions‬‬
‫‪.3‬הרכבת בלוקים (‪ )Blocks‬מהגדרות של ניסיונות‪.‬‬
‫‪.4‬הוספת הפרמטרים (‪ )Parameters‬לניסוי‪.‬‬
‫עבור כל שלב ברשימה לעיל ישנו כפתור על סרגל הכלילים הראשי‪ ,‬אשר פותח‬
‫תיבת דו‪-‬שיח אשר מאפשרת לבצע את הפעולות הרצויות‪.‬‬
‫לבדוק האם לשינוי של פרמטרים וכו' בזמן הרצה יש משמעות ולציין את זה‬
‫איפשהו‬
‫) פותח את תיבת הדו‪-‬שיח הבאה‪:‬‬ ‫‪.1‬כפתור ה‪( Trials Types-‬‬

‫כאן ניתן לראות את רשימת ה‪ Trial Types-‬הקיימים כרגע בתוכנה (בדוגמא זו‬
‫רואים את ה‪ .)Taming Trial-‬שלושת הכפתורים בחלון זה נותנים את האפשרות‬
‫להוסיף‪ ,‬לערוך או למחוק את הניסיון (כפתורים ‪ Edit‬ו‪ Delete -‬הופכים להיות‬
‫פעילים רק כאשר נבחר את הניסיון שאותו נרצה לערוך או למחוק)‪.‬‬
‫לחיצה על כפתור ה‪ Add-‬תפתח חלון דו‪-‬שיח של הוספת ניסיון חדש‪:‬‬

‫בחלון זה ניתן להוסיף את שם הניסיון בלבד‪ ,‬את שאר הפרטים מוסיפים ע"י‬
‫תיבת דו‪-‬שיח ‪:Edit‬‬

‫בחלון זה מוסיפים את שם הפונקציה שמפעילה את הניסיון ואת כל הפרמטרים‬


‫שלה‪.‬‬
‫הוספת הניסיון תעשה ע"י המתכנת שכותב את הפונקציה ורוצה להפוך אותה‬
‫לזמינה לשימוש‪.‬‬
‫) פותח את תיבת הדו‪-‬שיח שבה מגדירים‬ ‫‪.2‬כפתור ה‪( Trial Definitions -‬‬
‫את הניסיונות‪:‬‬

‫בחלון זה יש לנו אפשרות להוסיף‪ ,‬לערוך‪ ,‬למחוק או לשכפל את אחד‬


‫מהניסיונות (במקום ליצור חדש)‪.‬‬
‫לחיצה על כפתור ה‪ Add-‬תפתח את תיבת דו‪-‬שיח הבאה‪:‬‬

‫בחלון זה יש לנו אפשרות להגדיר סוג חדש‪ .‬הניסיון מבוסס על סוג ניסיון‬
‫כלשהו בתוספת פרמטרים מיוחדים‪ .‬בתיבה זו ניתן לבחור את סוג הניסיון‬
‫שעליו נתבסס‪ ,‬להוסיף פרמטרים ולתת שם ו‪ ID -‬לניסיון חדש‪.‬‬

‫) פותח את תיבת הדו‪-‬שיח שבה מוגדרים הבלוקים‪.‬‬ ‫‪.3‬כפתור ה‪( Blocks-‬‬


‫בתיבה זו ניתן לראות אילו בלוקים מוגדרים עבור ה‪ Session-‬הנוכחי‪ ,‬מהו‬
‫סדר הביצוע שלהם בזמן ההרצה והאם הם פעילים (אם בלוק מסוים מוגדר‬
‫כ‪ Not Active-‬הוא לא יבוצע בזמן הרצת ה‪.)Session-‬‬
‫לחיצה על כפתור ה‪ Add-‬תפתח את תיבת דו‪-‬שיח שבה ניתן להוסיף בלוק‬
‫חדש ע"י הוספת השם שלו ולחיצה על כפתור ‪.Ok‬‬

‫לחיצה על כפתור ה‪ Edit-‬תפתח את תיבת דו‪-‬שיח שבה ניתן לערוך את‬


‫הבלוק‪.‬‬

‫ברשימה מופיעים כל ה‪ Trials-‬שהוספנו לבלוק הזה‪ ,‬מספר הפעמים שנבצע‬


‫את הניסיון בזמן ההרצה והאם לבצע אותו או לא (האם הוא ‪.)Active‬‬
‫בחירה של אחד הניסיונות מהרשימה ולחיצה על ‪ Edit‬תפתח תיבת דו‪-‬שיח‬
‫שבה ניתן לשנות את מספר הפעמים שהניסיון יבוצע‪:‬‬

‫לחיצה על כפתור ‪ Add‬תיפתח תיבת דו‪-‬שיח שבה ניתן לבחור את הניסיון‬


‫שנרצה להוסיף לבלוק‪ ,‬מתוך רשימה של ניסיונות מוגדרים‪:‬‬
‫‪.4‬כפתור ה‪ ) ( Parameters-‬פותח את תיבת הדו‪-‬שיח שבה ניתן להוסיף‬
‫פרמטרים ולשנות את ערכם‪:‬‬

‫כמו בכל שאר החלונות‪ ,‬לחיצה על כפתור ה‪ Add-‬תפתח תיבת דו‪-‬שיח שבה‬
‫ניתן להוסיף פרמטר חדש‪ .‬לחיצה על כפתור ‪ Edit‬תיתן אפשרות לשנות‬
‫פרמטר קיים‪.‬‬
‫‪.3‬פרק ‪ – 4‬הקוד‬
‫‪.1.16‬מבוא‬
‫תוכנת ‪ Cats‬התבססה בראשית על קוד של תוכנה שמשמשת לניהול ניסויים‬
‫בקופים – ‪ .Monkey‬התכנון הראשוני היה לבצע שינויים קלים בתוכנה זו‬
‫ולהכניס אותה לשימוש‪ ,‬אך אחרי בחינה של יכולות התוכנה התברר שהיא‬
‫עובדת עם כלים שונים ולמרות הדמיון הרעיוני הרב האימפלמנטציה של רוב‬
‫חלקי התוכנה לא התאימה לצרכים שלנו‪.‬‬
‫להמשיך‪.....‬‬

‫‪.1.17‬מבט כללי על הקוד‬


‫כאמור התוכנה מחלקת את המשימות שלה למספר ‪ ,threads‬שרצים במקביל‬
‫וע"י כך מושגת היעילות המרבית בניצול משאבי המערכת‪.‬‬
‫להוסיף הסבר בהתחלה של ‪ OO‬ושל ‪( MFC‬עבור כל מושג שאני משתמש בו)‬
‫להוסיף גם תאור של ‪UINT‬‬
‫‪ CatsDoc‬היא המחלקה (‪ )class‬הראשית של התוכנה‪ ,‬היא זו שמגיבה לפעולות‬
‫של המשתמש (כגון לחיצה על כפתור) והיא זו שמפעילה את ההליכים (‪.)threads‬‬
‫ישנם ‪ 3‬הליכים בתוכנה‪:‬‬

‫;)‪1. UINT TrialThread(LPVOID param‬‬


‫;)‪2. UINT PhantomsThread(LPVOID param‬‬
‫;)‪3. UINT UtilityThread(LPVOID param‬‬

‫* ‪.UINT- Unsigned Integer‬‬


‫* ‪ – LPVOID‬מצביע ‪ 32‬ביט לסוג (‪ )type‬לא מוגדר (ולכן יכול להצביע לכל סוג של‬
‫אובייקט)‪.‬‬
‫שלושת ההליכים מוגדרים בקובץ נפרד הנקרא ‪.Threads.cpp‬‬
‫‪TrialThread.1‬‬
‫הליך זה אחראי על קומפילציה של כל הפרמטרים ומהלך הניסוי‬
‫והרצתם בסדר הרצוי‪.‬‬
‫‪PhantomsThread.2‬‬
‫הליך זה משמש להפעלת הפאנטום (כאשר יהיו שני פאנטומים יהיה‬
‫צורך בהליך נוסף זהה)‪.‬‬
‫‪UtilityThread.3‬‬
‫תפקידו היחיד של הליך זה הוא "לחכות" לאות סיום של הניסוי‬
‫ולעצור את ה‪.TrialThread-‬‬
‫‪CatsDoc‬‬

‫‪TrialThread‬‬ ‫‪PhantomsThread‬‬ ‫‪UtilityThread‬‬

‫שלושת ההליכים מקבלים כפרמטר מצביע (‪ )pointer‬ל‪ CatsDoc-‬ולכן יש להם‬


‫גישה לכל המשאבים של המחלקה הזו‪.‬‬
‫תקשורת בין שני ההליכים ‪ PhatomsThread‬ו‪ TrialThread-‬מתבצעת ע"י מחלקה‬
‫שנקראת ‪ .PhantomMessenger‬אובייקט של מחלקה זו מוגדר ב‪.CatsDoc-‬‬

‫‪CatsDoc‬‬

‫‪Communication‬‬ ‫‪Communication‬‬

‫‪TrialThread‬‬ ‫‪PhantomMessenger‬‬ ‫‪PhantomsThread‬‬

‫‪ PhantomsThread‬ו‪ UtilityThread -‬מופעלים ב‪ InitializeDocument -‬של המחלקה‬


‫‪ ,CatsDoc‬ז"א הם קיימים במשך כל זמן פעילות התוכנה‪ ,‬מרגע ההרצה ועד‬
‫הסיום (הם לא מופסקים בשום מקום)‪.‬‬
‫‪ TrialThread‬מופעל רק כאשר המשתמש לוחץ על כפתור ההרצה של הניסוי‬
‫ומופסק כאשר הניסוי נגמר או כאשר המשתמש לוחץ על כפתור העצירה‪.‬‬
‫המשך הפרק נכנס לפרטי הקוד‪ ,‬ומכוון שישנם חלקי קוד שמופעלים במקביל‬
‫עומדת בפני משימה לא קלה בלתאר אותו‪ .‬לסדר שבו יתוארו המחלקות בהמשך‬
‫יש משמעות והוא מנסה להעביר צורת מחשבה מסוימת‪ ,‬שלדעתי תסייע בהבנת‬
‫המבנה של הקוד בפרט והתוכנה בכלל‪.‬‬
‫כאמור ‪ threads‬מחלקים את המשימות של התוכנה למספר חלקים שרצים‬
‫במקביל‪ .‬בשלב הראשון אתאר את המחלקות הקשורות לבניית מהלך הניסוי‪.‬‬
‫תהליך בניית מהלך הניסוי יוצר תבנית מסוימת (לפי הגדרות המשתמש) ולפיה‬
‫מריצה את הניסיונות השונים‪ ,‬ולכן בשלב השני אתאר את המחלקה ‪Trial‬‬
‫שממנה מורשים כל המחלקות שמגדירות ניסיונות וגם ‪ TamingTrial‬שהיא‬
‫מחלקה שמורשת מ‪.Trial-‬‬
‫מכוון שמהלך הניסיון מורכב בעיקרו מהפעלה של חומרה שונה‪ ,‬בשלב השלישי‬
‫אתחיל לתאר את המחלקות שקשורות לחלקי חומרה שונים ואיך מתבצעת‬
‫התקשורת בין ה‪ Trial-‬והחומרה‪.‬‬
‫‪.1.18‬תהליך בניית מהלך הניסוי‬

‫תהליך זה מורכב מאסיפת המידע מהמשתמש‪ ,‬קומפילציה והרצת הניסיונות (‬


‫‪ )trials‬לפי הסדר הנתון‪ .‬במהלך ההרצה נאסף הקלט מהפאנטומים ומקורות‬
‫אחרים ומתקבלת ההחלטה על הצלחתו של הניסיון ועל המשך ה‪.session-‬‬

‫המחלקה ‪Trials‬‬
‫קובץ ‪ Trials.cpp‬מגדיר חמש מחלקות שתפקידן להיות מיכלים (‪)containers‬‬
‫למידע על מהלך הניסוי‪ .‬המחלקות הן‪:‬‬
‫)‪1‬‬ ‫‪class CTrialParam:public CObject‬‬
‫)‪2‬‬ ‫‪class CTrialList:public CObject‬‬
‫)‪3‬‬ ‫‪class CTrialDef:public CObject‬‬
‫)‪4‬‬ ‫‪class CTrialOrder:public CObject‬‬
‫)‪5‬‬ ‫‪class CTrialGroup:public CObject‬‬

‫חמשת המחלקות מורשות מ‪ CObject-‬שהיא מחלקה בסיסית לרוב המחלקות‬


‫של ‪ MFC‬ומורישה מספר תכונות בסיסיות שימושיות למחלקות כגון‬
‫סריאליזציה (‪ .)Serialization‬לפי שמות המחלקות ניתן לראות שכל אחת מהן‬
‫אחראית על מידע מסוג שונה‪ ,‬כגון פרמטרים של הניסיון‪ ,‬הגדרת הניסיון וכו'‪.‬‬
‫המחלקה הראשית שמוגדרת בקובץ זה היא‪:‬‬
‫להזכיר שוב את השמות החדשים‬
‫‪class CTrials:public CObject‬‬

‫היא מחזיקה את כל המידע של הניסוי (‪ )session‬הנוכחי‪ ,‬כאשר היא מחזיקה‬


‫אובייקטים מחמשת המחלקות כ‪( .data members-‬למעשה כל ה‪data members-‬‬
‫מוגדרים מסוג ‪ CObject‬וה‪ casting-‬מתבצע בכל פעם שנגשים למידע)‪ .‬מחלקה זו‬
‫שומרת בנוסף ‪ data members‬שמחזיקים פלט ביניים של המהדר (‪.)compiler‬‬
class CTrials:public CObject {
DECLARE_SERIAL(CTrials);
public:
virtual void Serialize(CArchive& ar);

CObArray m_TrialParam; //info from Param dialog box


CObArray m_TrialOrder; //info from Order dialog box
CObArray m_TrialList; //info from List dialog box
CObArray m_TrialDef; //info from TrialDef dialog box

CObArray m_code_seg; //array of objects returned from compiler - code


CObArray m_data_seg; //array of objects returned from compiler - data
CObArray m_fun_tab; //holds constant function list from functions.cpp
CObArray m_event_tab; // holds constant events declared at CCatsDoc.cpp

CUIntArray m_seq_tab; //holds sequence of all trials - returned from gen_seq()


CUIntArray m_startGroups; //also returned from gen_seq()

CTrials();
~CTrials(); //calls clear_all()

CObArray & GetDef();


CObArray & GetList();
CObArray & GetOrder();
CObArray & GetParam();
CObArray & GetEvents();

CTextFile *txtTrialsData;

void WriteToText(CTextFile &txtFile); // writes all class data to text file


void ReadFromText(CTextFile &txtFile); //reads all data from text file

void clear_all();
void clear();
void compile();
void gen_seq();
void run(int n);

};

‫ שמטרתן היא להכין את המידע‬,‫למחלקה מוגדרות גם מספר פונקציות‬


.‫ תפקידן יובהר בהמשך‬.‫שבמחלקה ולהעביר אותו לעיבוד ע"י המהדר‬
.CatsDoc-‫אובייקט מסוג זה נמצא ב‬
Compile ‫המחלקה‬

‫ שתפקידה להדר‬compile ‫ מכיל בתוכו הגדרה של מחלקה‬compile.cpp ‫קובץ‬


.‫ולהריץ את הניסוי‬
‫ ולכן לא אכנס לפרטי הקומפילציה ואפרט‬Monkey ‫מחלקה זו מיובאת מהתוכנה‬
.‫רק מספר פונקציות שאיתן אני מתממשק‬
compile();
gen_seq();
run();
‫() מבצעת את הקומפילציה הבסיסית הכוללת בדיקת תאימות‬compile ‫פונקציה‬
‫ פונקציה זו קוראת לשלוש פונקציות אחרות‬.‫המידע שהוזן ע"י המשתמש‬
:‫המוגדרות באותה המחלקה‬
‫;)(‪lexical‬‬
‫;)(‪syntax‬‬
‫;)(‪semantic‬‬
‫שמות הפונקציות מתארות את הבדיקות שהן מבצעות‪.‬‬
‫‪ )(compile‬מחזירה שתי מחרוזות (‪ )lists‬מסוג ‪ CObject‬לאובייקט מסוג ‪.CTrials‬‬
‫פונקציה ‪ )(gen_seq‬מקבלת כקלט את הפלט של ‪ )(compile‬ומחזירה שתי‬
‫מחרוזות של מספרים (‪ )integers‬המקודדים את סדר הביצוע של הניסוי‪.‬‬
‫פונקציה ‪ )(run‬קוראת למצביעים (‪ )pointers‬לפונקציות המתאימות וכך מריצה‬
‫את הניסוי‪.‬‬
‫מהלך האירועים בהפעלת הניסוי‬
‫שתי המחלקות שתוארו לעיל הן השחקניות העיקריות של הפעלת הניסוי (אך‬
‫לא היחידות)‪.‬‬
‫‪ TrialThread‬מופעל בפונקציה ‪ )(CCatsDoc::OnStart‬שנקראת כאשר המשתמש‬
‫לוחץ על לחצן ה‪.Start-‬‬
‫ההליך ‪ TrialThread‬מבצע מספר פעולות לפי הסדר‪:‬‬
‫‪.1‬מאפס ומנקה את כל המשתנים הזמניים שיכולים להכיל מידע‬
‫מהרצה קודמת של הניסוי‪.‬‬
‫‪.2‬קורא לפונקציה ‪ )(compile‬של אובייקט מסוג ‪( CTrials‬והיא‬
‫קוראת ל‪ )(compile -‬של המהדר)‪.‬‬
‫‪.3‬קורא לפונקציה ‪ )(gen_seq‬של אובייקט מסוג ‪( CTrials‬והיא‬
‫קוראת ל‪ )(gen_seq -‬של המהדר)‪.‬‬
‫‪.4‬נכנס ללולאה ועבור כל איבר במחרוזת ‪m_seq_tab (member‬‬
‫‪ variable‬של אובייקט מסוג ‪ CTrials‬שמאוכלס ע"י הרצת‬
‫פונקצית ‪ )(gen_seq‬של המהדר) קורא לפונקצית ‪ )(run‬של‬
‫אובייקט מסוג ‪( CTrials‬שיקרא לפונקצית ‪ )(run‬של המהדר)‪.‬‬
‫‪.5‬בכל סבב של הלולאה אחרי הקריאה ל‪ )(run-‬נאסף כל המידע‬
‫שהתקבל בזמן ההרצה ובהתאם להצלחה או כשלון של הניסיון‬
‫מתקבלת ההחלטה האם להמשיך או להפסיק את ביצוע‬
‫הניסוי‪.‬‬
‫‪.6‬מתבצע חישוב של זמן ‪ )ITI (Inter Trial Interval‬ונקראת פונקצית‬
‫‪ )Sleep(t‬ש"מרדימה" את ההליך לזמן ה‪.ITI-‬‬
‫‪ .1.19‬הגדרת הניסיון (‪)Trial‬‬
‫תפקידה של מחלקה זו‪ ,‬והמחלקות שמורשות ממנה‪ ,‬לתאר את מהלך הניסיון‬
‫ע"י שליחת אירועים לחומרה וקבלת פידבק ממנה‪.‬‬
‫כל ‪ Trial‬שיכול להיות מוגדר בתוכנה יהיה מורש ממחלקת האם ‪ Trial‬שמוגדרת‬
‫בקובץ ‪.Trial.cpp‬‬
‫מחלקת האם ‪ Trial‬מגדירה את הפרמטרים האוניברסאליים עבור כל ניסיון‬
‫שיכול להיות מורש ממנה‪ .‬פרמטרים מיוחדים יכולים להיות מוגדרים במחלקת‬
‫הבת‪.‬‬
‫הפונקציה שאחראית על קריאת הערכים של הפרמטרים שהוזנו ע"י המשתמש‬
‫נקראת‪ .)(getParams :‬מחלקת הבת שתגדיר פרמטרים מיוחדים תצטרך להגדיר‬
‫פונקציה זו מחדש ולקרא לפונקציה של מחלקת האם כדי לקרא לכל‬
‫הפרמטרים‪.‬‬
‫)(‪void Trial::getParams‬‬
‫{‬
‫;)‪CParam* param=(CParam*)in_param.GetAt(0‬‬
‫;)‪if (param->type==CO_NUMBER) m_TargetStartX=atof(param->name‬‬

‫;)‪param=(CParam*)in_param.GetAt(1‬‬
‫;)‪if (param->type==CO_NUMBER) m_TargetStartY=atof(param->name‬‬

‫;)‪param=(CParam*)in_param.GetAt(2‬‬
‫;)‪if (param->type==CO_NUMBER) m_TargetStartZ=atof(param->name‬‬

‫;)‪param=(CParam*)in_param.GetAt(3‬‬
‫;)‪if (param->type==CO_NUMBER) m_ForceStart=atof(param->name‬‬

‫)‪………..(more parameters‬‬
‫}‬

‫* המחלקה ‪ CParam‬מוגדרת ב‪.compile.cpp-‬‬


‫מחלקת האם ‪ Trial‬כוללת את הפונקציה ‪ )(runTrial‬שתכלול את מהלך הביצוע‬
‫של הניסיון‪ .‬פונקציה זו היא וירטואלית טהורה (‪ )pure virtual‬מכוון שאין הגדרה‬
‫ברירת מחדל לביצוע הניסיון וכל מחלקה שתהיה מורשת ממחלקת האם תהיה‬
‫חייבת להגדיר את מהלך הביצוע של הניסיון‪.‬‬
‫;‪virtual void runTrial(){}; // = 0‬‬

‫בנוסף‪ Trial ,‬מגדיר מספר פונקציות שמעדכנות משתנים שמקפיצות אירועם‬


‫הקשורים להצלחה או כשלון של הניסיון‪.‬‬
‫‪protected:‬‬
‫‪virtual void successfulTrial(); //set Trial Successful‬‬
‫‪virtual void trialFail(int catsEventID); //set Trial Failed‬‬
‫)…‪void sendCatsEvent(int catsEventID); //Send Current Event (like: cat started eating‬‬

‫‪TamingTrial‬‬
‫מחלקת הבת ‪ TamingTrial‬היא מחלקה שמורשת מ‪ Trial-‬ומגדירה מהלך ניסיון‬
‫של אילוף החתול‪ .‬בניסיון זה משתתף רק פאנטום אחד‪ ,‬מכוון שרוצים לאלף‬
‫את החתול להושיט את הגפה ולא להפריע לו בתנועה‪.‬‬
‫לניסיון זה אין משתנים שמיוחדים רק לו‪ ,‬ולכן אין צורך עקרוני בהגדרה‬
‫מחודשת של פונקצית ‪ ,)(getParams‬אבל היא מוגדרת כדי לשמור על המבנה‬
‫הבסיסי של המחלקות מסוג ‪ .Trial‬פונקציה זו רק קוראת לפונקצית ‪)(getParams‬‬
‫של ‪.Trial‬‬
‫)(‪void TamingTrial::getParams‬‬
‫}‬
‫;)(‪Trial::getParams‬‬
‫{‬

‫המחלקה צריכה להגדיר מחדש את הפונקציה הוירטואלית הטהורה ‪)(runTrial‬‬


‫של מחלקת האם ‪.Trial‬‬
‫הקוד בנוי על ראיון של שליחת הוראה לפעולה (הפעלת פאנטום‪ ,‬צליל‪ ,‬כרטיס‬
‫‪ A/D‬או חומרה אחרת) והמתנה עד לקבלת אות של סיום הפעולה‪.‬‬

‫‪//Phantom moves to starting position‬‬


‫_ ‪p_msgr->MoveToPoint(m_TargetStartX,‬‬
‫;)‪m_TargetStartY,m_TargetStartY,m_ForceStart,m_TimeInitialPosition‬‬
‫)‪while(true‬‬
‫{‬
‫)‪if(WaitForSingleObject(p_msgr->ph_finished_event, 0) == WAIT_OBJECT_0‬‬
‫{‬
‫;‪break‬‬
‫}‬
‫;)‪Sleep(1‬‬
‫}‬
‫הפעלת הפאנטום‬.1.20
Phantoms)( ‫ שמשווק עם הפאנטומים‬API-‫ משמשת כממשק ל‬Phantom ‫המחלקה‬
., OpenHaptics 2.0 toolkit
‫המחלקה נבנתה כך שתהיה אפשרות להתייחס לפאנטום כאל אובייקט שיכול‬
‫לבצע פעולות שונות (בניגוד לגישה של פונקציה אחת שיודעת לבצע את כל‬
‫ במקרה של צורך‬.‫ ובכך ניתן לבנות בקלות מהלכי ביצוע שונים‬,)‫הפעולות‬
.‫בהוספת "יכולת" כלשהי כל מה שנדרש הוא להוסיף פונקציה נוספת למחלקה‬
class Phantom
}
public:
Phantom(int p_num);
virtual ~Phantom();

void StartFriction(HDdouble gain, HDdouble magnitude); //friction effect


void StartSpring(HDdouble gain, HDdouble magnitude, _
hduVector3Dd anchor ); //spring effect
void StartViscosity(HDdouble gain, HDdouble magnitude); //viscosity effect
void StartConstForce(HDdouble gain, HDdouble magnitude, _
hduVector3Dd direction); //constant force effect
void StartPointMass(); //point mass effect
void StartFrictionlessPlane(hduVector3Dd point, double stiff); //Frictionless plane effect
void StartAntiGrav(); //Antigravity effect

void EndFriction();
void EndSpring();
void EndViscosity();
void EndConstForce();
void EndPointMass();
void EndFrictionlessPlane();
void EndAntiGrav();

hduVector3Dd GetPosition(); //return position of the current phantom


hduVector3Dd GetForce(); //return force of the current phantom
HDboolean Calibrate();
private:
void initHL(HHD hHD, HHLRC &hHLRC); // Initialize an HL rendering context for a
//particular device instance
void initHD(HDstring pConfigName, HHD &m_hHD); //Initialize an HD device instance

bool b_calibrated;
void SetCalibration(bool val);
bool GetCalibration();
void MakeCurrent();

HDstring p_name;
HLuint friction_force;
HLuint spring_force;
HLuint viscous_force;
HLuint constant_force;
HLuint pointmass_force;
HLuint frictionless_plane_force;

PointMass *pointMass;
FrictionlessPlane * frictionlessPlane;
};
‫) מקבל‬constructor( ‫ הבונה של המחלקה‬,‫המחלקה אינה אוניברסאלית לגמרי‬
‫) והם אלה שקובעים את הזהות של הפאנטום (ז"א שכרגע‬2 ‫ או‬1 ‫פרמטר (ערכים‬
.)‫התוכנה יכולה להשתמש רק בשני פאנטומים‬
Phantom::Phantom(int p_num)
{
switch(p_num){
case 1:
initHD("PHANToM 1", hHD1);
initHL(hHD1, hHLRC1);
break;
case 2:
initHD("PHANToM 2", hHD2);
initHL(hHD2, hHLRC2);
break;
default:
this.~Phantom();
}
//hlGenEffects - Generates unique identifiers for effects that
//may be used with the hlStartEffect function
friction_force = hlGenEffects(1);
spring_force = hlGenEffects(1);
viscous_force = hlGenEffects(1);
constant_force = hlGenEffects(1);
pointmass_force = hlGenEffects(1);
frictionless_plane_force = hlGenEffects(1);
//create an object of custom effect
frictionlessPlane = new FrictionlessPlane();
}

API-‫כוחות מובנים ב‬
‫ ולכן אין צורך‬,‫ של הפאנטומים מספק מספר כוחות מובנים סטנדרטיים‬API-‫ה‬
:‫ צורת השימוש היא‬.‫ אלא ניתן להשתמש בהם‬,‫להגדירם מחדש‬
void Phantom::StartFriction(HDdouble gain, HDdouble magnitude)
{
MakeCurrent(); //make the phantom current
hlBeginFrame(); //enter the rendering block
hlEffectd(HL_EFFECT_PROPERTY_GAIN, gain); //set force gain
hlEffectd(HL_EFFECT_PROPERTY_MAGNITUDE, magnitude); //set force magnitude
hlStartEffect(HL_EFFECT_FRICTION, friction_force); //set force type
hlEndFrame(); //exit rendering block (send to phantom)
}

void Phantom:: EndFriction ()


{
MakeCurrent();
hlBeginFrame();
hlStopEffect(friction_force); //stop effect
hlEndFrame();
}

)Custom Forces( ‫כוחות מוגדרים בצורה מיוחד‬


‫ של הפאנטומים נותן אפשרות להגדיר כוחות מיוחדים ומתאר צעדים‬API-‫ה‬
‫ פונקציות שמגדירות את‬3 ‫ לצורך הגדרת כוח מיוחד מגדירים‬.‫לכתיבתם‬
.‫ המהלך והסיום של אפקט הכוח המיוחד‬,‫ההתחלה‬
‫אפקט הכוח המיוחד שמוגדר בתוכנה הוא משטח ללא חיכוך (הכוח יתואר‬
.)‫בהמשך‬
:Phantom ‫הפונקציה להפעלת אפקט הכוח המיוחד במחלקה‬
void Phantom::StartFrictionlessPlane(hduVector3Dd point, double stiff)
{
frictionlessPlane->SetParameters(point,stiff);
MakeCurrent();
hlBeginFrame();

hlCallback(HL_EFFECT_COMPUTE_FORCE, (HLcallbackProc) _
FrictionlessPlane::computeForceCB, frictionlessPlane);
hlCallback(HL_EFFECT_START, (HLcallbackProc) _
FrictionlessPlane::startEffectCB, frictionlessPlane);
hlCallback(HL_EFFECT_STOP, (HLcallbackProc) _
FrictionlessPlane::stopEffectCB, frictionlessPlane);
hlStartEffect(HL_EFFECT_CALLBACK, frictionless_plane_force);

hlEndFrame();
}

‫שלושת הפונקציות הדרושות מוגדרות במחלקה נפרדת הנקראת‬


‫ אבל‬,‫ אינו מחייב את הכוח להיות מוגדר כמחלקה‬API-‫ ה‬.FrictionlessPlane
.)‫הגדרה כזו מאפשרת טיפול יותר נוח באפקט (כגון אתחול‬

FrictionlessPlane ‫המחלקה‬
‫המחלקה מגדירה את שלושת הפונקציות הדרושות להפעלת האפקט הרצוי‬
.‫ובנוסף את כל המשתנים הפנימיים הדרושים ליצירת האפקט‬
class FrictionlessPlane
{
public:
FrictionlessPlane(); //default constructor
FrictionlessPlane(hduVector3Dd point, double stiff);//with parameters
SetParameters(hduVector3Dd point, double stiff); //set parameters
virtual ~FrictionlessPlane(); //destructor

//functions required for effect rendering


static void HLCALLBACK computeForceCB(HDdouble force[3], _
HLcache *cache, void *userdata);
static void HLCALLBACK startEffectCB(HLcache *cache, void *userdata);
static void HLCALLBACK stopEffectCB(HLcache *cache, void *userdata);
private:
hduVector3Dd m_position;
hduVector3Dd m_velocity;
HDdouble m_kStiffness; // Stiffnes, i.e. k value, of the plane.
//Higher stiffness results in a harder surface.
hduVector3Dd m_point_in_space; //point defines 3 perpendicular surfaces (by axis)
hduVector3Dd m_direction_flag; //defines which of 3 surfaces to use and the direction
//only one value is not zero, possible values -1,0,1
};

:computeForce ‫יצירת אפקט הכוח מתרחשת בפונקצית‬


void FrictionlessPlane::computeForceCB(HDdouble force[3], HLcache *cache, void *userdata)
}

FrictionlessPlane *pFrictionlessPlane = static_cast<FrictionlessPlane *>(userdata);

// Get the current proxy position from the state cache.


// Note that the effect state cache is maintained in workspace coordinates,
// so we don't need to do any transformations in using the proxy
// position for computing forces
hduVector3Dd PhantomPosition;
hlCacheGetDoublev(cache, HL_PROXY_POSITION, PhantomPosition);

hduVector3Dd x; //F=kx
hduVector3Dd f(0,0,0); //returned force
double PenetrationDistance;

for(int i=0; i<3; i++) //try each possible plane (3 possibilities)


{
if(pFrictionlessPlane->m_direction_flag[i] == 0) continue; //no plane

if ((PhantomPosition[i] <= pFrictionlessPlane->m_point_in_space[i]


&& pFrictionlessPlane->m_direction_flag[i] > 0)
||(PhantomPosition[i] > pFrictionlessPlane->m_point_in_space[i])
&&(pFrictionlessPlane->m_direction_flag[i] < 0))
{
// Create a force vector repelling the user from the plane proportional
// to the penetration distance, using F=kx where k is the plane
// stiffness and x is the penetration vector. Since the plane is
// oriented at the Y=0, the force direction is always either directly
// upward or downward, i.e. either (0,1,0) or (0,-1,0);
PenetrationDistance =fabs(fabs(PhantomPosition[i]) – _
fabs(pFrictionlessPlane->m_point_in_space[i])); //relative to plane

// Hooke's law explicitly:


x[i] = PenetrationDistance*(pFrictionlessPlane->m_direction_flag[i]);
f[i] = (pFrictionlessPlane->m_kStiffness)*x[i];

}//end if
}//end for

// Send the force to the device


force[0] = f[0];
force[1] = f[1];
force[2] = f[2];
{

‫ניתן לראות שהפונקציה מאוד גמישה ומאפשרת (ע"י שינוי הפרמטרים) להגדיר‬
‫) ולכל סוג ניתן לספק אחד משני‬z-x ‫ ציר‬,y-z ‫ ציר‬,x-y ‫ סוגי משטחים (ציר‬3
.)‫ סוגים של משטחים‬6 ‫כוונים (סה"כ‬
‫ ולכן הבונה של‬,‫הגמישות הזו לא מנוצלת כרגע בתוכנה כתוצאה מחוסר צורך‬
‫המחלקה מגדיר את הכוון ולא מקבל את הפרמטר מהמשתמש (כמובן שכאשר‬
.)‫ השינוי יהיה כל יחסית‬,‫יהיה הצורך‬
‫‪PhantomThread‬‬
‫זהו ההליך שמפעיל את הפאנטום (כאשר יתווסף פאנטום נוסף לתוכנה‪ ,‬יהיה‬
‫צורך בהליך זהה נוסף)‪.‬‬
‫הליך זה מופעל‪ ,‬בניגוד לשני ההליכים האחרים‪ ,‬מרגע שהתוכנה מתחילה לרוץ‬
‫ומופסק ביחד עם סיום התוכנה‪.‬‬
‫ההליך נכנס ללולאה ומחקה לאירועים שמגיעים מהליך אחר (‪)TrialThread‬‬
‫ומבצע משימות בהתאם לאירועים אלה‪.‬‬
‫‪case(WAIT_OBJECT_0+1): //Frictionless Plane‬‬
‫_ ‪ph_ptr1->StartFrictionlessPlane(p_msgr->m_vSurfacePoint,‬‬
‫;)‪p_msgr->m_dSurfaceStiffness‬‬

‫)‪while (EventCurT-EventStartT<p_msgr->m_dTimeToReachTarget‬‬
‫{‬
‫‪//get phantoms position‬‬
‫;)(‪CSec.Lock‬‬
‫‪//update the current location‬‬
‫;)(‪p_msgr->m_vPhCurLocation=ph_ptr1->GetPosition‬‬
‫;)(‪CSec.Unlock‬‬
‫)‪if(WaitForSingleObject(p_msgr->ph_stop_event, 0)==WAIT_OBJECT_0‬‬
‫{‬
‫‪break;//leave if get stop event‬‬
‫}‬
‫‪Sleep(1); //less processor usage‬‬
‫;)(‪EventCurT = timeGetTime‬‬
‫}‬

‫;)(‪ph_ptr1->EndFrictionlessPlane‬‬
‫;)(‪p_msgr->SignalPhFinishedTask‬‬
‫;‪ph_todo_ev_occured= WAIT_TIMEOUT‬‬
‫;‪break‬‬

‫‪.1.21‬תקשורת בין ‪ Phantom‬ו‪Trial -‬‬


‫המחלקה ‪ PhantomMessanger‬מאפשרת העברת מידע בין שני ההליכים וכך‬
‫הפקודות שנשלחות מההליך של ‪ Trial‬מגיעות להליך של ‪.Phantom‬‬
‫ממבט ראשון יצירת מחלקה זו נראה מיותר מכוון שאפשר להפעיל אירועים (‬
‫‪ )events‬וכך ‪ Trial‬יוכל להפעיל את ה‪ ,Phantom-‬אבל אירוע לא יכול להעביר‬
‫משתנים ולכן יצירתה של המחלקה היה נחוץ‪ .‬בנוסף תפקידה של מחלקה זו‬
‫לבודד בין שני ההליכים‪ ,‬כך שכשאחד מהם ישתנה לא יהיה צורך בשינוי בשני‪.‬‬
‫מחלקה זו מוגדרת ב‪ CatsDoc-‬ומכוון שמצביע ל‪ CatsDoc-‬מועבר לשני ההליכים‬
‫שניהם מקבלים גישה לאובייקט מסוג ‪.PhantomMessanger‬‬
‫כאשר ‪ Trial‬צירך להפעיל את הפאנטום הוא קורא לפונקציה מתאימה ב‪-‬‬
‫‪ PhantomMessanger‬ומעביר אליה את כל הפרמטרים הנחוצים כארגומנטים‪.‬‬
‫‪ PhantomMessanger‬שומר את הפרמטרים במשתנים הפנימיים שלו (‪data‬‬
‫‪ )members‬ומקפיץ אירוע (‪ .)event‬ההליך של פאנטום מקשיב כל הזמן לאירועים‬
‫ולכן קולט את האירוע וניגש למשתנים של ‪ PhantomMessanger‬כדי לקבל את‬
‫הפרמטרים המתאימים‪.‬‬
class PhantomMessenger
{
public:
PhantomMessenger();
virtual ~PhantomMessenger();

void MoveToPoint(double x, double y, double z, double force, double time);


void RunAwayToPoint(double x, double y, double z, double force, double time);
void SetSurface(double x, double y, double z, double stiff, double time);
void StopMoving();
void SignalPhFinishedTask();
void SignalEventOccured();
bool CheckArea(double x,double y, double z, double r);
bool CheckArea(hduVector3Dd v, double r);
void SetReward(double t_before_reward, double t_reward);
void SetPhToDoEventStatus(DWORD ev);
DWORD GetPhToDoEventStatus();

//Events which signal the phantom to do something


HANDLE ph_todo_events[NUM_OF_PHANTOM_TODO_EVENTS];

CEvent ev_todo_surface;
CEvent ev_todo_move;
CEvent ev_todo_runaway;
CEvent ev_todo_reward;

HANDLE ph_stop_event;
CEvent ev_todo_stop_move;
HANDLE ph_finished_event;
CEvent ev_finished_move;
HANDLE ph_event_status;
CEvent ev_event_status;

//Phantom Parameters

hduVector3Dd m_vPointToMoveTo;
double m_dMoveForce;
hduVector3Dd m_vSurfacePoint;
double m_dSurfaceStiffness;
hduVector3Dd m_vFeedCenter;
double m_dFeedRadius;
hduVector3Dd m_vPhCurLocation;

//Timing Parameters
double m_dTimeToReachTarget; //time given to Cat to grab the target
double m_dTimeMoveToPosition; //time given the target to get to point
double m_dTimeForReward;
double m_dTimeEscape;

private:

DWORD dw_ph_event_status; //holds the current phantom todo event

};
‫‪.1.22‬כרטיס ‪ A/D‬והמשאבה‬
‫כאמור האות להפעלת ועצירת המשאבה מועבר למשאבה דרך כרטיס ‪.A/D‬‬
‫המעגל שמתפקד כמתאם בין הכרטיס והמשאבה עובד כמו מפסק‪ ,‬הוא מפעיל‬
‫את המשאבה כאשר הכרטיס מספק לו מתח של ‪ 5V‬ומפסיק אותה כאשר אין‬
‫מתח‪ .‬למטרה הזו השתמשתי ב‪ line-‬אחד של הכרטיס ו‪.ground-‬‬
‫בכרטיס ‪ A/D‬כל ‪ line‬יכול לקבל ערך ‪ )on( 1‬או ‪ .)off( 0‬כאשר הוא במצב ‪on‬‬
‫מסופק דרכו מתח של ‪.5V‬‬
‫האימפלמנטציה של התקשורת עם הכרטיס מוגדרת במחלקה ‪.DIO‬‬
‫‪class DIO‬‬
‫{‬
‫‪public:‬‬
‫;)(‪DIO‬‬
‫;)(‪virtual ~DIO‬‬
‫‪void setLine(int line, int value); //set the value of a line‬‬
‫‪int getLine(int line); //get the value of a line‬‬
‫‪private:‬‬
‫‪int32‬‬ ‫;‪error‬‬
‫;‪TaskHandle taskHandle‬‬
‫‪uInt8‬‬ ‫;]‪data[8‬‬
‫‪char‬‬ ‫;]‪errBuff[2048‬‬
‫;}‬

‫אובייקט ממחלקה זו מסוגל לרשום או לקרא ערך מערוץ אחד של הכרטיס‪.‬‬


‫בגרסאות הבאות כרטיס ‪ A/D‬יאסוף בנוסף מידע מה‪ Force Plates-‬ויתקשר עם‬
‫המערכת של ‪ Alpha-Omega‬ולכן יהיה צורך להוסיף יכולות נוספות למחלקה זו‪,‬‬
‫כגון באפר‪.‬‬

‫‪.1.23‬צלילים‬
‫התוכנה נותנת אפשרות להשמיעה קבצי ‪ *wav.‬כדי לאפשר לתת אותות קוליים (‬
‫‪ )audio cues‬לביצוע משימה לחתול‪.‬‬
‫הגדרות ההשמעה נמצאות במחלקה ‪.Sound‬‬
‫מחלקה זו כוללת פונקציה אחת בלבד‪ ,)play(int iSound ,‬אשר נקראת כאשר יש‬
‫צורך בהשמעה של צליל‪ .‬הפרמטר יכול לקבל ערך מ‪ 1-‬עד ‪( 8‬עם אופציה‬
‫להרחבה) וכך ניתן לבחור בין ‪ 8‬צלילים שונים‪.‬‬
‫אובייקט מסוג ‪ Sound‬מוגדר במחלקה ‪ CatsDoc‬ולכן הוא נגיש לכל ההליכים‪.‬‬
‫‪class Sound‬‬
‫}‬
‫‪public:‬‬
‫;)(‪Sound‬‬
‫;)(‪virtual ~Sound‬‬
‫;)‪void Play(int iSound‬‬
‫;}‬
‫‪.4‬פרק ‪ – 5‬תוצאות‬
‫‪.5‬פרק ‪ – 6‬סיכום ומסקנות‬