{"id":15066523,"url":"https://github.com/sdesalas/botbrains","last_synced_at":"2025-07-26T10:36:45.905Z","repository":{"id":57355541,"uuid":"92646350","full_name":"sdesalas/botbrains","owner":"sdesalas","description":"Robot brain tools to automate your nodebot","archived":false,"fork":false,"pushed_at":"2024-09-13T15:53:40.000Z","size":4855,"stargazers_count":11,"open_issues_count":6,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-20T10:14:54.070Z","etag":null,"topics":["3d","arduino","artificial-learning","neural-network","nodebots","nodejs","robot","webgl"],"latest_commit_sha":null,"homepage":"http://botbrains.net/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sdesalas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-05-28T07:24:15.000Z","updated_at":"2024-09-13T16:20:16.000Z","dependencies_parsed_at":"2022-09-26T16:31:40.701Z","dependency_job_id":null,"html_url":"https://github.com/sdesalas/botbrains","commit_stats":null,"previous_names":["sdesalas/robokit","sdesalas/botbrain"],"tags_count":36,"template":false,"template_full_name":null,"purl":"pkg:github/sdesalas/botbrains","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sdesalas%2Fbotbrains","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sdesalas%2Fbotbrains/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sdesalas%2Fbotbrains/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sdesalas%2Fbotbrains/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sdesalas","download_url":"https://codeload.github.com/sdesalas/botbrains/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sdesalas%2Fbotbrains/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267150480,"owners_count":24043473,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-26T02:00:08.937Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d","arduino","artificial-learning","neural-network","nodebots","nodejs","robot","webgl"],"created_at":"2024-09-25T01:08:57.475Z","updated_at":"2025-07-26T10:36:45.883Z","avatar_url":"https://github.com/sdesalas.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/sdesalas/botbrains.svg?branch=master)](https://travis-ci.org/sdesalas/botbrains)\n\n# BotBrains\n\nBotBrains is a set of artificial learning tools to automate an [Arduino](http://arduino.org)-based robot.\n\nIts been built as part of an educational workshop on artificial learning specifically for [International Nodebots Day](https://www.eventbrite.com.au/e/international-nodebots-day-melbourne-2017-tickets-34845310261).\n\nThis material here is very basic and aimed more at communicating the core concept of a neural network through practice than dealing with all the theoretical stuff that is available out there.\n\nTo read more about how this library came to be see the article on [Asynchronous Neural Networks](http://desalasworks.com/article/asynchronous-neural-networks-in-javascript/) on my blog.\n\n## Interact with your robot brains in 3D.\n\nThe key aspect of BotBrains is the ability to watch signals travel across your robot's neural network in 3D, and train it with positive and negative reinforcement.\n\n![brain-3d.png](brain-3d.gif)\n\n## Quick start\n\nYou need [NodeJS](https://nodejs.org/en/download/) installed, version 6 or above.\n\n```sh\n$ mkdir my-bot \u0026\u0026 cd my-bot\n$ npm install botbrains\n$ cd node_modules/botbrains\n$ npm start\n```\n\nThe above will perform a quick test with a random visualization. For a full test you need to rig up a robot.\n\n## Proper setup\n\nYou should be adding this to an existing robot project such as [johnny-five](http://johnny-five.io/).\n\nHere is a longer example:\n\n```sh\n$ mkdir my-bot \u0026\u0026 cd my-bot\n$ npm install johnny-five\n$ npm install botbrains\n```\n\n### robot.js\n```js\nconst five = require('johnny-five');\nconst botbrains = require('botbrains');\n\nconst board = new five.Board({port: process.argv[2] || '' });\n\nboard.on('ready', () =\u003e {\n\n    const network = new botbrains.NeuralNetwork(32);\n\n    // PROXIMITY SENSOR INPUT (pin A6)\n    const sensor = new five.Sensor({ pin: 'A6', freq: 200 });\n    sensor.on('change', () =\u003e network.input('Proximity')(sensor.value / 1024));\n\n    // MOTOR OUTPUT (pins D6-D8)\n    const left_motor = new five.Motor({ pins: { pwm: 6, dir: 7, }, invertPWM: true, });\n    const right_motor = new five.Motor({ pins: { pwm: 9, dir: 8, }, invertPWM: true, });\n\n    // Output binding can be reasonably random.\n    // It doesn't matter what gets mapped to what\n    // since the robot will learn to coordinate itself\n    // using positive and negative feedback.\n\n    network.output('Wheel (L)')\n        .on('data', (power) =\u003e { // between 0 and 1\n            const speed = Math.floor(power * 255);\n            if (power \u003e 0.25) left_motor.forward(speed);\n            else left_motor.stop();\n        });\n\n    network.output('Wheel (R)')\n        .on('data', (power) =\u003e { // between 0 and 1\n            const speed = Math.floor(power * 255);\n            if (power \u003e 0.25) right_motor.forward(speed);\n            else right_motor.stop();\n        });\n\n    // DISPLAY VIA LOCAHOST (http.Server)\n    const server = botbrains.Toolkit.visualise(network);\n    const address = server.address();\n\n    console.log('Bot brain ready for interaction. Please open http://localhost:' + address.port);\n\n});\n```\n\nThen run it!\n\n```sh\n$ node robot.js\n```\n## API :: NeuralNetwork\n\nNeuralNetwork is a class in the botbrains module and can be loaded in the following ways:\n\n```js\nimport { NeuralNetwork } from 'botbrains'; // ES6  \n\nconst NeuralNetwork = require('botbrains').NeuralNetwork; // Node, CommonJS\n\nconst NeuralNetwork = (window || this).botbrains.NeuralNetwork; // Browser, in global context\n```\n\n### new NeuralNetwork(size, opts)\n\nGenerates a neural network.\n\n- **`size`**: The number of neurons in the neural network\n- **`opts`**: A map of settings for the network\n    - `.shape`: Choice of 'drum', 'tube', 'ring', 'ball', 'sausage', 'snake', or any other in [NetworkShaper.js](src/NetworkShaper.js). Defaults to 'drum'.\n    - `.shaper`: The [shaper function](#shaper-function) used for giving shape to the network. If available will ignore `.shape`.\n    - `.connectionsPerNeuron`: Average synapses per neuron. Defaults to `4`.\n    - `.signalFireThreshold`: Threshold (between 0 and 1) needed to trigger onward neurons. Defaults to `0.3`.\n    - `.signalSpeed`: Speed in neurons per second. Defaults to `20`.\n    - `.startingWeight`: Starting weight per synapse. Defaults to `signalFireThreshold(/3 x connectionsPerNeuron)`.\n    - `.neuronRecovery`: Neuron recovery as fraction of `signalSpeed`. Defaults to `1/5`.\n    - `.learningRate`: Max increase/decrease to connection strength when learning. Defaults to `0.05`.\n    - `.learningPeriod`: Milliseconds in the past on which learning applies. Defaults to `20 * 1000` ms.\n\nFor example, to create a network of 100 neurons using all default options:\n\n```js\nlet network = new NeuralNetwork(100);\n```\n\nTo create a ring-shaped network of 100 neurons with double the speed and learning rate.\n\n```js\nlet network = new NeuralNetwork(1000, { shape: 'ring', signalSpeed: 40, learningRate: 0.3 });\n```\n\nIf a `String` is passed in as the `opts` parameter, its interpreted as the network shape.\n\n```js\nlet network = new NeuralNetwork(100, 'ring');\n```\n\nIf a `Function` is passed as the `opts` parameter, its interpreted as the [shaper function](#shaper-function), see examples in [NetworkShaper.js](src/NetworkShaper.js).\n\n```js\nlet network = new NeuralNetwork(100, (count) =\u003e Math.floor(Math.random() * count));\n```\n\n### network.input(label [, neurons=1])\n\nCreates an input into the network.\n\n- **`label`**: A label used to visually identify the neurons involved.\n- **`neurons`**: Optional `Number` of neurons involved, or array of numbers (`Number[]`) defining the network nodes that are involved in the input.\n\nReturns:\n\n- **`Function(signal 0-1)`**: A function that accepts incoming signals (a float between 0 and 1).\n\nUsage:\n\n```js\nvar input1 = network.input('Microphone') // 1 x Neuron assigned automatically\nsensor.on('data', data =\u003e input1(data / 1024));\n\nvar input2 = network.input('LightSensor (L)', 3) // How many neurons? =\u003e 3 \nsensor.on('data', data =\u003e input2(data / 1024));\n\nvar input3 = network.input('LightSensor (R)', [10,11,12]) // Which neurons? =\u003e 10, 11 \u0026 12\nsensor.on('data', data =\u003e input3(data / 1024));\n```\n\n### network.output(label [, neurons=1])\n\nReturns an [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter) with 2 events: `data` and `change`. \n\n- **`label`**: A label used to visually identify the neurons involved.\n- **`neurons`**: Optional `Number` of neurons involved, or array of numbers (`Number[]`) defining the network nodes that are involved in the input.\n\n**Event: `data`**:\n\nFires whenever there is data to output.\n\nThe event handler function will receive the following arguments.\n\n- **`data`**: A numeric floating point value between 0 and 1, containing the strength of the outgoing signal.\n\n```js\nnetwork.output('Motor (L)') // 1 x Neuron assigned automatically\n    .on('data', (pwr) =\u003e console.log(`Power: ${pwr}.`));\n\nnetwork.output('Motor (R)', 4) // How many neurons? =\u003e 3 \n    .on('data', (pwr) =\u003e console.log(`Power: ${pwr}.`));\n\nnetwork.output('Buzzer', [6,7,8]) // Which neurons? =\u003e 6, 7 \u0026 8\n    .on('data', (pwr) =\u003e console.log(`Power: ${pwr}.`));\n```\n\n**Event: `change`**:\n\nAn event that fires whenever there is a change in the outgoing data. \n\nThe event handler function will receive the following arguments.\n\n- **`data`**: A numeric floating point value between 0 and 1, containing the strength of the outgoing signal.\n- **`last`**: The previous value output. \n- **`diff`**: The difference between `last` and `data`.\n\n```js\nnetwork.output('Buzzer')\n    .on('change', function(data, last, diff) {\n        console.log(`Buzzer output is: ${data}. Previous output was ${last}. Difference is ${diff}`);\n    });\n```\n\n\n### network.join(network, at, surfaceArea)\n\nMerges a network into another network, or into itself.\n\n```js\nconst network = new NeuralNetwork(100, 'ball');\nnetwork.join(new NeuralNetwork(100, 'ring'), 0.5, 0.1); // join on the middle, using 10% of nodes.\nnetwork.join(network); // join on itself\n```\n\n### Shaper Function\n\nA shaper is a function that determines the shape of the network by returning the onward connections made by each neuron. \n\nFor example, if a neuron is connected to other neurons at random, the final shape of the network will be a ball. If its connected to nearby neurons the shape will be more of a snake or cylinder. If neurons close to the end are linked to neurons at the beginning, the end product will be more of a ring or a doughnut.\n\nThe shaper function is executed *once for every synapse in the network*. If there are 10 nodes, and 4 synapses per node, it will fire 40 times to determine the onward neuron in each of those synapses.\n\n![shaper.png](shaper.png)\n\nA shaper function has the following inputs: \n\n- **`count`**: The total number of nodes in the network. In other words, in a network of 10 neurons, this will be `10`. Useful for linking up the end of the network back to its beginning or for discarding links outside the network.\n- **`index`**: The position of the originating neuron inside the `nodes` array. In a network of 10 nodes, the first node is `0`, the last node is `9`, so a value of `9` means the last neuron in the network.\n- **`connectionCount`**: A neuron has several connections (synapses) originating from it. For example if the neuron has 4 connections, this will be 4.\n- **`connectionIndex`**: The position in the array of the connection currently being made. In other words, if there are 4 connections (synapses) in the originating neuron, the shaper function will execute 4 times for it, with a `connectionIndex` value of `0` to `3` accordingly.\n\n\nAnd returns:\n\n - **`target`**: The destination position of an onward neuron (for connecting to it). In a network of 10 nodes, when we are mapping a neuron `index` of `0` (the first node) and `connectionIndex` of `0` (the first synapse), a `target` of `9` means that connection is made towards the last neuron.\n\nBear in mind that since the shaper function will be executed *multiple times per neuron* to determine the onward neuron for each connection. You will want these to connect to different onward neurons. This can be done either choosing an onward `target` at random, or by using the `synapseIndex` argument to calculate the `target` neuron in a deterministic manner.\n\nHere is an example of simple shaper function:\n\n```js\n// Random ball shape\nnew NeuralNetwork(100, (count, index) =\u003e Math.floor(Math.random() * count));\n```\n\nAnother more involved example:\n\n```js\n// Ring shape\nconst network = new NeuralNetwork(100, ring);\n\nfunction ring(count, index) {\n  const width = count / 12;\n  const forwardBias = Math.ceil(width * Math.random());\n  const target = index + forwardBias;\n  if (target \u003c count) {\n    return target;\n  }\n  return target - count; // link to beginning\n}\n```\n\nThere are more examples in [NetworkShaper.js](src/NetworkShaper.js).\n\n**Why does shape matter?**\n\nThe Neural Network model used for [botbrains](https://www.npmjs.com/package/botbrains) is [asynchronous](https://en.wikipedia.org/wiki/Asynchrony_(computer_programming)). Signal propagate across the network in the same manner as they would in an animal brain, one neuron at a time. Different shapes matter because they create resonance and oscillation patterns that are important for producing particular outputs to inputs in a time-dependent manner.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsdesalas%2Fbotbrains","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsdesalas%2Fbotbrains","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsdesalas%2Fbotbrains/lists"}