├── LICENSE ├── README.md ├── RoFish_cpg └── RoFish_cpg.ino └── figures └── animation.gif /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Martin Stokroos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RoFish 2 | 3 | *RoFish_cpg* is an example sketch for the Arduino to demonstrate the Central Pattern Generator (CPG) locomotion control of a robotic fish. The CPG from the example *RoFish_cpg* has three coupled oscillators for driving an equal number of joints of the robotic fish. The frequency of the oscillators, the amplitude of the motion and the angle-offset, used for steering, can be set via a terminal console, connecting with the UART of the Arduino. The swimming gait can be switched between forward and backward direction. 4 | This example has not been completely worked out with remote control. It is only meant to demonstrate the CPG. 5 | 6 | 7 | ![CPG swimming gait](figures/animation.gif "Animation") 8 | 9 | 10 | The used type of RC-servo motor for joints 1 and 2, is the Futaba S3003. The tail motor is a Futaba S3102. 11 | -------------------------------------------------------------------------------- /RoFish_cpg/RoFish_cpg.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * File: RoFish_cpg.ino 4 | * Purpose: Example of a Central Pattern Generator controlled Robotic Fish 5 | * Version: 1.0.0 6 | * Date: 23-11-2018 7 | * Created by: Martin Stokroos 8 | * URL: https://github.com/MartinStokroos/RoFish 9 | * License: MIT License 10 | * 11 | * The CPG algorithm in the main loop of this program was taken over from Garcia-Saura[1]. The CPG 12 | * parameters were originally chosen for generating walking patterns of a micro-hexapod. In this 13 | * example, the pattern is modified for a three joint robotic fish. 14 | * 15 | * Many suggestions for the construction of a mechanical framework for a robotic fish with 16 | * linked RC-servo motors, are described in literature[2][3]. 17 | * 18 | * References: 19 | * [1] Garcia-Saura, Carlos (2015). Central Pattern Generators for the control 20 | * of robotic systems. MSc in Computing (Spec. in Artificial Intelligence) Imperial College London. 21 | * 22 | * [2] J. Shao, L. Wang and J. Yu, Development of an artificial fish-like robot and its application 23 | * in cooperative transportation, Control Engineering Practice, vol.16, no.5, pp.569-584, 2008. 24 | * 25 | * [3] Yu, J., Chen, S., Z. Wu, and Wang, W. (2016). On a miniature free-swimming robotic fish with 26 | * multiple sensors. International Journal of Advanced Robotic Systems, 13(62). 27 | * 28 | */ 29 | 30 | 31 | #include "Arduino.h" 32 | #include 33 | 34 | #define LED_PIN 13 35 | #define LPERIOD 10000L // loop period time in us. 36 | #define N 3 // number of oscillators 37 | #define T LPERIOD/1000000.0 // T=10ms. 38 | 39 | #define SERVO1_PIN 3 // towards head 40 | #define SERVO2_PIN 10 // middle 41 | #define SERVO3_PIN 11 // tail 42 | 43 | unsigned long nextLoop; 44 | char c; 45 | int i,j; 46 | float w[N][N], f[N][N], b[N][N]; 47 | bool forward=true; 48 | 49 | // constant vars 50 | float ar=20; // rad/sec 51 | float ax=20; // rad/sec 52 | 53 | // control inputs 54 | float W=3.5, R=0.3, X=0; // common control inputs frequency/amplitude/offset of the joints 55 | float cW[N]={PI, PI, PI}; // OHMEGAi - desired frequency rad/s. 56 | float cR[N]={0.42, 0.31, 0.40}; // Ri - desired amplitude in radians. 57 | float cX[N]={0, 0, 0}; // Xi - desired offset in radians. 58 | 59 | // states 60 | float sA[N]={0,0,0}; // phase 61 | float sr[N]={0,0,0}; // amplitude 62 | float sx[N]={0,0,0}; // offset 63 | float sA_new[N]={0,0,0}; // phase 64 | float sr_new[N]={0,0,0}; // amplitude 65 | float sx_new[N]={0,0,0}; // offset 66 | 67 | // derivatives 68 | float sA_d=0; // phase dot 69 | float sr_d[N]={0,0,0}; // amplitude dot 70 | float sx_d[N]={0,0,0}; // offset dot 71 | float sr_d_new[N]={0,0,0}; // amplitude dot 72 | float sx_d_new[N]={0,0,0}; // amplitude dot 73 | 74 | // second derivatives 75 | float sr_dd=0; 76 | float sx_dd=0; 77 | float out_deg[N]={0,0,0}; // output phase time vector 78 | 79 | Servo servo1; 80 | Servo servo2; 81 | Servo servo3; 82 | 83 | 84 | //The setup function is called once at startup of the sketch 85 | void setup() 86 | { 87 | pinMode(LED_PIN, OUTPUT); // for checking loop period time and loop execution time (signal high time) 88 | Serial.begin(115200); 89 | servo1.attach(SERVO1_PIN); 90 | servo2.attach(SERVO2_PIN); 91 | servo3.attach(SERVO3_PIN); 92 | servo1.write(90); // turn servos to the center position 93 | servo2.write(90); 94 | servo3.write(90); 95 | delay(1500); 96 | 97 | // init, 1/s coupling weights 98 | w[1][1] = 0; 99 | w[1][2] = 5; 100 | w[1][3] = 5; 101 | w[2][1] = 5; 102 | w[2][2] = 0; 103 | w[2][3] = 5; 104 | w[3][1] = 5; 105 | w[3][2] = 5; 106 | w[3][3] = 0; 107 | 108 | // forward swimming, 1/s phase biases 109 | f[1][1] = 0.0; 110 | f[1][2] = -0.7; 111 | f[1][3] = -1.41; 112 | f[2][1] = -f[1][2]; 113 | f[2][2] = 0.0; 114 | f[2][3] = f[1][3] - f[1][2]; 115 | f[3][1] = -f[1][3]; 116 | f[3][2] = -f[2][3]; 117 | f[3][3] = 0.0; 118 | 119 | // backward swimming, 1/s phase biases 120 | b[1][1] = 0.0; 121 | b[1][2] = 0.7; 122 | b[1][3] = 1.41; 123 | b[2][1] = -b[1][2]; 124 | b[2][2] = 0.0; 125 | b[2][3] = b[1][3] - b[1][2]; 126 | b[3][1] = -b[1][3]; 127 | b[3][2] = -b[2][3]; 128 | b[3][3] = 0.0; 129 | 130 | nextLoop = micros() + LPERIOD; // Set the loop timer variable. 131 | } 132 | 133 | 134 | // The loop function is called in an endless loop 135 | void loop() 136 | { 137 | digitalWrite(LED_PIN, true); 138 | 139 | for(i=0; i micros()); //wait until the end of the time interval 230 | nextLoop += LPERIOD; //set next loop time at current time + LOOP_PERIOD 231 | } 232 | 233 | -------------------------------------------------------------------------------- /figures/animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinStokroos/RoFish/eccaf454810fc2be8f53f0221360e33525cd80a6/figures/animation.gif --------------------------------------------------------------------------------