NOC – Forces Homework – Sam Arellano

For this week I used forces to make a pong game. This game will be my starting point for my midterm project which will be training a neural network to play this game in 2 ways, first against a computer, and second with 2 neural networks learning from eachother at the same time. The second is totally experimental and might just not work, but I will do it for the case of science.

For this week’s project however, implementing it was pretty simple. I took code from the bouncing ball example and then adding two new classes, the player class and the computer class. The player took simple user input that moves the bumper up and down. The computer class has some rudimentary AI included that needs to be improved (the big issue is that it doesn’t calculate for bounces, only for future y position of the ball, so if the y position goes off screen it doesn’t calculate correctly). I then added to the ball class to make it properly respond the bouncing off the paddles and to reset its position when going off the screen.

There are a lot of things that could be improved, such as adding extra features, a two player mode would also be quick to implement, but I just wanted to start working on a backbone for my midterm to build upon.

"use strict"

var ball;
var player;
var computer;
var down = false;
var up = false;
var force;
var outSide;
var p1score = 0;
var p2score = 0;


function setup() {
  createCanvas(1000, 600);
  background(0);
  ball = new Particle(width / 2, height / 2);
  player = new Player(19*(width/20),height/2);
  computer = new Computer(1*(width/20),height/2);
  // let's give a random velocity
  ball.vel = createVector(5,-5);
}

function draw() {
  background(0);
  fill(255);
  textSize(32);
  text(p2score, 100,10,30,30);
  text(p1score, 800,10,30,30);

  if(down){
    force = createVector(0,1);
    player.applyForce(force);
  }
  else if(up){
    force = createVector(0,-1);
    player.applyForce(force);
  }

  player.checkBoundaries();
  player.update();
  player.display();

  if(computer.prediction(ball.pos.x,ball.pos.y,ball.vel.x,ball.vel.y)){
    force = createVector(0,-1);
    computer.applyForce(force);
  }
  else{
    force = createVector(0,1);
    computer.applyForce(force);
  }

  computer.checkBoundaries();
  computer.update();
  computer.display();



  ball.checkCollision(player.pos.x,player.pos.y);
  ball.checkCollision(computer.pos.x,computer.pos.y);

  outSide = ball.checkBoundaries();

  if(outSide === 1){
    p1score++;
  }
  else if(outSide === -1){
    p2score++;
  }

  ball.update();
  ball.display();


}

function keyPressed(){
  if(keyCode === UP_ARROW){
    up = true;
  }
  else if(keyCode === DOWN_ARROW){
    down = true;
  }
}

function keyReleased(){
  if(up === true){
    up = false;
  }
  else if(down === true){
    down = false;
  }
}

//ball

class Particle {
  constructor(x,y) {
    this.pos = createVector(x,y);
    this.vel = createVector(0,0);
    this.acc = createVector(0,0);
    this.dia = 30;
  }
  update() {
    this.vel.add(this.acc);  
    this.pos.add(this.vel);  
    this.acc.mult(0);        
  }
  display() {
    push();
    translate(this.pos.x, this.pos.y);
    noStroke();
    fill(255);
    ellipse(0,0, this.dia, this.dia);
    pop();
  }
  checkBoundaries() {
    // x
    if (this.pos.x < 0) {
      this.pos.x = width/2;
      this.pos.y = height/2;
      this.vel.x = random(4,10);
      this.vel.y = random(-4,-10);
      return(1);
    } else if (this.pos.x > width) {
      this.pos.x = width/2;
      this.pos.y = height/2;
      this.vel.x = random(-4,-10);
      this.vel.y = random(4,10);
      return(-1);

    }
    // y
    if (this.pos.y < 0) {
      this.pos.y = 0;
      this.vel.y = -this.vel.y;
    } else if (this.pos.y > height) {
      this.pos.y = height;
      this.vel.y = -this.vel.y;
    }

    return(0);
  }
  checkCollision(locX,locY){

    if((this.pos.x > locX) &&(this.pos.x<locX+30) &&(this.pos.y > locY) &&(this.pos.y < locY+250)){
      console.log("collision");
      this.vel.x = -this.vel.x;
      this.vel.mult(1.1);
    }
  }
  applyForce(f){
    this.acc.add(f);
  }
}

//player

class Player {

  constructor(x,y){
    this.pos = createVector(x,y);
    this.vel = createVector(0,0);
    this.acc = createVector(0,0);
  }

  update(){
    this.vel.add(this.acc);
    this.pos.add(this.vel);
    this.acc.mult(0);

  }

  display(){
    push();
    translate(this.pos.x,this.pos.y);
    noStroke();
    fill(255);
    rect(0,0,30,250);
    pop();
  }

  applyForce(f){
    this.acc.add(f);
  }

  checkBoundaries(){
    if (this.pos.y > height-250) {
      this.pos.y = height-250;
      this.vel.y = 0;
    } else if (this.pos.y < 0) {
      this.pos.y = 0;
      this.vel.y = 0;
    }
  }




}

//computer 

class Computer {

  constructor(x,y){
    this.pos = createVector(x,y);
    this.vel = createVector(0,0);
    this.acc = createVector(0,0);
  }

  update(){
    this.vel.add(this.acc);
    this.pos.add(this.vel);
    this.acc.mult(0);

  }

  display(){
    push();
    translate(this.pos.x,this.pos.y);
    noStroke();
    fill(255);
    rect(0,0,30,250);
    pop();
  }

  applyForce(f){
    this.acc.add(f);
  }

  checkBoundaries(){
    if (this.pos.y > height-250) {
      this.pos.y = height-250;
      this.vel.y = 0;
    } else if (this.pos.y < 0) {
      this.pos.y = 0;
      this.vel.y = 0;
    }
  }

  prediction(ballX,ballY,balldx,balldy){
    var time = abs(ballX - this.pos.x) / balldx 
    var newY = ballY + time * balldy;
    if(newY < this.pos.y){
      return(0);
    }
    else{
      return(1);
    }
  }


}


Cerecares Trip Response – Sam Arellano

Cerecares Trip

This trip was really enjoyable. My aunt is disabled and has been through different day programs and care facilities so I’ve had experience going to them and seeing them before. Thankfully, the majority of the ones I’ve seen have been happy places where she was given good opportunities to work on tasks, learn skills, and interact with others, but I’ve also come in contact with some of the facilities that create the stigmas against care homes. The kind of places where the tenants aren’t adequately taken care of, where the facility is understaffed, tenants are ignored, the location is filthy and so are the tenants. By no means is this is the fault of the tenants staying there, and it isn’t the fault of the caretakers either most of the time, they are often overworked and underpaid. But regardless of where the blame lies, it was a great surprise that Cerecares was nothing like one of those institutions.

Walking through the halls, it was easy to see that the staff and organizers loved the students. Their work was on the walls to show off, the way that staff and volunteers looked at the kids with genuine pride when the student was able to complete a task. The kids weren’t being looked at as a burden or a task to take care of, but as legitimate students that were learning new things and had bright futures ahead of them along with great personalities.

The story of the whole facility was also very heartwarming. The first video they showed about the founder’s own life journey and her eventual opening of Cerecares was pretty inspiring. That being said, the other promotional materials felt a little, patronizing? They felt like “suffer porn” where people can look at someone else’s situation and be like “well I might have it bad but at least I’m not them”, or to put in a overly inspirational light that just comes off as ingenuine. I’m not sure the exact way to phrase it, but they felt uncomfortable. The story of the boy being adopted was framed as a story of him overcoming hardship with a closed happy ending, but even the “happy ending” felt at best bittersweet, at worst very depressing and not even in his best interests. And the music montage video was Sarah McLachlan singing over dying puppies levels of manipulative. We did discuss on the bus how this is rooted in cultural differences between China and the United States, but even so, it still feels over the top and against the essence of the facility’s mission statement.

Awkward promotional materials aside, It was a great trip and its easy to see the facility is making great impacts in the students lives. I hope that it can get the funding it deserves to continue making a difference and helping these individuals learn the skills they need for more independence.

Assistive Tech Week 3 Response – Sam Arellano

How to switch adapt a toy

This video surprised me at just how simple the entire process was. I primarily work with software, and honestly, messing around with hardware often intimidates me. I know it shouldn’t, but theres just something so malleable and low stakes about coding. Arduino and breadboards are fine, but once it gets to soldering or messing with existing wiring, I don’t think of that as my domain. This video showed just how simple, and moreover, cheap it is to do. When I see the toys that are usually sold for disabled people and the equipment its usually in the hundreds of dollars, when this toy could be put together with 10 dollars and 15 minutes of time. Even if its not a business idea, it seems like a great skill to have to be able to help people out.

Feelings meets Testing

This article was extremely interesting. I often take the current state of design for granted, assuming industry standards have just always been that way. Growing up in California everyone had their “lean startup mentality” and you were always running into people putting together prototypes and MVP’s, so its easy to think that this is the way its always been as opposed to a new development. This article went more into how prototyping has developed, specifically when it comes to creating an experience of usage for your testers. The other point of interest is just how recently a lot of these developments have occurred. The focus on usage and user interface design really only seems to have took off in the past two to three decades. I feel this is a great development not just for disabled individuals, but for everyone. Calling back to the curb cut effect, this new way of designing and prototyping just naturally leads to a better user experience. What good is form and features if the actual user experience just sucks? This then leads me to thinking how much more will change in just the time of my own career. Who knows what the next big development to come is.

 

NOC Inspiration: MarI/O – Sam Arellano

One thing that has really interested me is how neural networks are kind of the inverse of what we’ve learned about nature of code so far, yet they do go hand in hand. Nature of code is very focused on using code to emulate natural behaviors we observe around us, while neural networks use natural concepts to improve the performance and end result of different algorithms. Neural networks were massive paradigm shift in terms of the work being done in machine learning. The general idea is to try to emulate the way that our brains learn new concepts with different individual neurons that interact with one another and influence eachother. This allowed for the advancement of what many know as deep learning, very deep complex layers of these neurons that convert information into a usable format to teach the computer how to make decisions. We hear about many applications of machine learning, finance, biology, customer interaction, natural language processing, but there are some really fun ones too. My piece of inspiration I chose is one such really fun example of neural networks that shows its applications in video games of all things.

In this video, video game youtuber and computer scientist SethBling shows off a program that he made to train a computer to beat a level of Super Mario World. It uses many natural cconcepts you would expect to hear in a biology class, evolution, natural selection, mutation, species, yet all of these things refer to iterations of code that develop over time and teach the computer how to make progress. Its an extremely interesting video that I feel takes another look just what we can be aiming for with this class.

NOC Week 3 Assignment – Force – Sam Arellano

For this week I worked on building on top of more examples from the book. I’m extremely interested in making systems of autonomous agents and eventually want to use them for my midterm and final so I read up to those chapters in the book and worked on implementing the flocking example in my own code.

Once I had the example from the book done, I had to figure out a way to have more external forces act on the individual agents. The first one to pop to mind is some sort of wind force so I made it so that when the user pressed a key, there would be wind that pushed all the individual agents to the right. Having only one direction of wind seemed pretty boring however, so I allowed the user to press any directional key and have corresponding wind force.

The last thing I did to expand upon it was to make it so that when you click the mouse, the wind partitions the screen and doesn’t affect all the agents. For example, if you click the mouse and press the right arrow key, only agents on the right of the mouse will be affected. I felt this feature could be used for some further applications in the future when I continue working on giving more depth to this system.

There are a lot more things I could implement, but I think it works fine as a demo for now. The only thing I do want to address is I feel my method of checking for user input is extremely clunky and inefficient. There are definitely better ways to do it, but this doesn’t cut into performance issues so long as I keep the number of agents under around 150.

var flock;
var rightWind = false;
var leftWind = false;
var upWind = false;
var downWind = false;
var pressed = false;

function setup() {
  createCanvas(640,360);

  flock = new Flock();
  for (var i = 0; i < 50; i++) {
    var b = new Boid(width/2,height/2);
    flock.addBoid(b);
  }
}

function draw() {
  background(51);
  flock.run();
}


function Flock() {
  this.boids = [];
}

Flock.prototype.run = function() {
  for (var i = 0; i < this.boids.length; i++) {
    this.boids[i].run(this.boids);
  }
}

Flock.prototype.addBoid = function(b) {
  this.boids.push(b);
}



function Boid(x,y) {
  this.acceleration = createVector(0,0);
  this.velocity = createVector(random(-1,1),random(-1,1));
  this.position = createVector(x,y);
  this.r = 3.0;
  this.maxspeed = 3;
  this.maxforce = 0.05;
}

Boid.prototype.run = function(boids) {
  this.flock(boids);
  this.update();
  this.borders();
  this.render();
}

Boid.prototype.applyForce = function(force) {
  // We could add mass here if we want A = F / M
  this.acceleration.add(force);
}

Boid.prototype.flock = function(boids) {
  var sep = this.separate(boids);
  var ali = this.align(boids);
  var coh = this.cohesion(boids);
  sep.mult(1.5);
  ali.mult(1.0);
  coh.mult(.5);
  this.applyForce(sep);
  this.applyForce(ali);
  this.applyForce(coh);
  if(pressed){
    if(rightWind){
      var right = createVector(random(.02,.2),0);
        if(this.position.x > mouseX){
          this.applyForce(right);
        }
    }
    if(leftWind){
      var left = createVector(random(-.2,-.02),0);
        if(this.position.x < mouseX){
          this.applyForce(left);
        }
    }
    if(upWind){
      var up = createVector(0,random(-.2,-.02));
      if(this.position.y < mouseY){
        this.applyForce(up);
      }
    }
    if(downWind){
      var down = createVector(0,random(.2,.02));
      if(this.position.y > mouseY){
        this.applyForce(down);
      }
    }
  }
  else{
    if(rightWind){
      var right = createVector(random(.02,.2),0);
      this.applyForce(right);
    }
    if(leftWind){
      var left = createVector(random(-.2,-.02),0);
      this.applyForce(left);
    }
    if(upWind){
      var up = createVector(0,random(-.2,-.02));
      this.applyForce(up);
    }
    if(downWind){
      var down = createVector(0,random(.2,.02));
      this.applyForce(down);
    }
  }
}

Boid.prototype.update = function() {
  this.velocity.add(this.acceleration);
  this.velocity.limit(this.maxspeed);
  this.position.add(this.velocity);
  this.acceleration.mult(0);
}


Boid.prototype.seek = function(target) {
  var desired = p5.Vector.sub(target,this.position);
  desired.normalize();
  desired.mult(this.maxspeed);
  var steer = p5.Vector.sub(desired,this.velocity);
  steer.limit(this.maxforce);
  return steer;
}

Boid.prototype.render = function() {
  var theta = this.velocity.heading() + radians(90);
  fill(127);
  stroke(200);
  push();
  translate(this.position.x,this.position.y);
  rotate(theta);
  beginShape();
  vertex(0, -this.r*2);
  vertex(-this.r, this.r);
  vertex(this.r, this.r);
  endShape(CLOSE);
  pop();
}

Boid.prototype.borders = function() {
  if (this.position.x < -this.r)  this.position.x = width +this.r;
  if (this.position.y < -this.r)  this.position.y = height+this.r;
  if (this.position.x > width +this.r) this.position.x = -this.r;
  if (this.position.y > height+this.r) this.position.y = -this.r;
}


Boid.prototype.separate = function(boids) {
  var desiredseparation = 25.0;
  var steer = createVector(0,0);
  var count = 0;
  for (var i = 0; i < boids.length; i++) {
    var d = p5.Vector.dist(this.position,boids[i].position);
    if ((d > 0) && (d < desiredseparation)) {
      var diff = p5.Vector.sub(this.position,boids[i].position);
      diff.normalize();
      diff.div(d);
      steer.add(diff);
      count++;
    }
  }
  if (count > 0) {
    steer.div(count);
  }

  if (steer.mag() > 0) {
    steer.normalize();
    steer.mult(this.maxspeed);
    steer.sub(this.velocity);
    steer.limit(this.maxforce);
  }
  return steer;
}


Boid.prototype.align = function(boids) {
  var neighbordist = 50;
  var sum = createVector(0,0);
  var count = 0;
  for (var i = 0; i < boids.length; i++) {
    var d = p5.Vector.dist(this.position,boids[i].position);
    if ((d > 0) && (d < neighbordist)) {
      sum.add(boids[i].velocity);
      count++;
    }
  }
  if (count > 0) {
    sum.div(count);
    sum.normalize();
    sum.mult(this.maxspeed);
    var steer = p5.Vector.sub(sum,this.velocity);
    steer.limit(this.maxforce);
    return steer;
  } else {
    return createVector(0,0);
  }
}


Boid.prototype.cohesion = function(boids) {
  var neighbordist = 50;
  var sum = createVector(0,0);
  var count = 0;
  for (var i = 0; i < boids.length; i++) {
    var d = p5.Vector.dist(this.position,boids[i].position);
    if ((d > 0) && (d < neighbordist)) {
      sum.add(boids[i].position);
      count++;
    }
  }
  if (count > 0) {
    sum.div(count);
    return this.seek(sum);
  } else {
    return createVector(0,0);
  }
}



function keyPressed(){
  if(keyCode === RIGHT_ARROW){
    rightWind = true;
    console.log("wind on");
  }

  if(keyCode === LEFT_ARROW){
    leftWind = true;
    console.log("wind on");
  }

  if(keyCode === UP_ARROW){
    upWind = true;
    console.log("wind on");
  }

  if(keyCode === DOWN_ARROW){
    downWind = true;
    console.log("wind on");
  }

  return false;
}

function keyReleased(){
  if(keyCode === RIGHT_ARROW){
    rightWind = false;
    console.log("wind off");
  }
  if(keyCode === LEFT_ARROW){
    leftWind = false;
    console.log("wind off");
  }
  if(keyCode === UP_ARROW){
    upWind = false;
    console.log("wind off");
  }
  if(keyCode === DOWN_ARROW){
    downWind = false;
    console.log("wind off");
  }

  return false;
}

function mousePressed(){
  pressed = true;
  return false;
}

function mouseReleased(){
    pressed = false;
    return false;
}

Assistive Technology Week 2 Readings

New York Has a Great Subway if you’re not in a wheelchair

In this piece a Google software engineer discusses the challenges he now faces as a wheelchair user in getting around New York by subway. The really interesting thing to me about this piece is it very well captures the overarching theme of this week’s readings, people aren’t often malicious towards the disabled population, they just don’t care. The author himself states how he only realized these challenges after requiring a wheelchair himself, issues like only a fifth of the stations having elevators, those elevators being constantly under service, and no real way for someone to know this is the case until they get there. This is just another case of the disabled population being sadly forgotten, but hopefully work can be done to fix this issue and improve accessibility in New York.

Are Colleges Doing Enough to Make Videos Accessible to the Blind?

Continuing the trend of the forgotten, I honestly wouldn’t have even thought these videos were an issue had I not read this article. Yet those individuals that are affected definitely realize the problem. I feel a lot of these problems, rather than being about blatant stigmas or issues of hate simply stem from uneducation on these topics. When it comes to the monetary cost of making these internet videos accessible to the blind, I’m certain that it would be less if these considerations were included in the creation process than in trying to go back and remedy those issues after the fact. Foresight is a better plan in these situations.

Becky, Barbie’s Wheelchair Bound Friend

This whole story just makes me sad. This can’t be attributed to just forgetfulness. They obviously released this toy with a specific demographic in mind. It would be one thing if there was just no demand for the product and so they discontinued the line, but there was obvious demand and happiness over the release of Becky. What happened seemed more like the company just decided it wasn’t worth the trouble. While I can blame individuals for just being forgetful, once it gets to an organizational and company level, it becomes a discussion of whether the investment will pay off. Are these people worth it? In the case of Becky, the company decided they are not.

From Charity to Independent Living

This is an amazing story that I’m honestly surprised isn’t told more in schools. I heard nothing of this throughout any of my history books, not even in California history with as much as California loves to show off how progressive it is. I knew that there was a disabled rights movement in the same time frame of the black civil rights movement and the gay rights movement, but that’s about as far as my knowledge went. I knew of big activists like Martin Luther King Jr., Malcolm X, Harvey Milk, but I had never heard of Ed Roberts or Judith Heumann, let alone the massive amount of change they made. I have to wonder why this isn’t more widely included in our educational materials, but its probably because content space is limited, and once again, the disabled community just isn’t worth it.

A Brief Historical Review of Rehabilitation Practices

It is a little disheartening that it seems we can only move the public to action when we put on the tag of “help our veterans” and even then it doesn’t always work. It is good that there have been massive amounts of development for the disabled community, but it seems to just be aimed at soldiers and then trickle down to every day people. Are these problems only valid enough to be solved if they’re happening to a soldier that was hurt on the front lines and not your neighbor who was born into this world with that same condition? This is probably just me soapboxing too much, but regardless, it is good to be informed of another history I didn’t know much about.

NOC Week 2 Homework – Object

For this week I decided to build a few features on top of the example in the nature of code book in chapter 4. In this chapter, it discusses particle systems and gives a simple “fountain” of particles that it generates. There were a few parts I wanted to add to it. The first was simple, adding color to the particles as they are rather dull just in grey.

Next was making the system “run out” of particles. This gave me a little trouble at first as I gave the particle system a lifespan just like the particles themselves, but once the lifespan ran out I was having the particle system stop calling run. This made the entire particle system just disappear once the lifespan ran out. I switched it to stop calling addParticle and that fixed the issue.

Next, it was a little boring having the system only in the middle of the screen. I thought this effect would be cool as a click effect for some other application so I wanted the particleSystem to appear wherever the mouse clicked. I tried doing this in the draw function by tracing mouse location and resetting it there, but I ended up with a single circle being constantly overwritten. This wasn’t exactly what I was looking for, and I realized I needed to include a mouse click function that reset the location of the system. This worked better and if I set the lifespan of the system low enough it looked like a little explosion on each click rather than the fountain before.

Finally, the last issue was that each time I clicked it would remove previous particle systems. To remedy this I just needed to make an array to have multiple systems all at once instead of just reassigning the same system to new locations. Initially I just made an array and pushed all the systems to that array. The issue with this was the as I made more and more systems, even if they weren’t making any more particles, they still existed and took up memory and slots in the list which was just bad form. So I gave the list a max length variable made it check if the list was full and if it was just reassign the earlier slots in the list to new locations instead of constantly making new systems.

There’s a lot more that could be added, but I think it would be a cool module for just adding effects to mouse presses in a different more complete application.

 

var systems = [];
var total = 10;
var counter = 0;
function setup(){
  createCanvas(500,300);

}

function draw(){
  background(0);
  for(var i=0;i<systems.length;i++){
    if(systems[i].isAlive()){
      systems[i].addParticle();
    }
    systems[i].run();
  }
}

var Particle = function(position) {
  this.acceleration = createVector(0,.05);
  this.velocity = createVector(random(-1,1),random(-1,0));
  this.position = position.copy();
  this.lifespan = 255.0;
  this.colorA = random(0,255);
  this.colorB = random(0,255);
  this.colorC = random(0,255);
};

Particle.prototype.update = function(){
  this.velocity.add(this.acceleration);
  this.position.add(this.velocity);
  this.lifespan -=2;
};

Particle.prototype.run = function(){
  this.update();
  this.display();
};

Particle.prototype.display = function(){
  stroke(200, this.lifespan);
  strokeWeight(2);
  fill(this.colorA,this.colorB,this.colorC, this.lifespan);
  ellipse(this.position.x, this.position.y, 12, 12);
};

Particle.prototype.isDead = function(){
  if(this.lifespan < 0){
    return true;
  }
  else {
    return false;
  }
};

var ParticleSystem = function(position) {
  this.lifespan = random(10,100);
  this.origin = position.copy();
  this.particles = [];
};

ParticleSystem.prototype.addParticle = function(){
  this.particles.push(new Particle(this.origin));
};

ParticleSystem.prototype.isAlive = function(){
  if(this.lifespan > 0){
    return true;
  }
  else{
    return false;
  }
};

ParticleSystem.prototype.run = function(){
  if(this.lifespan > -100){
    for(var i = this.particles.length-1;i>=0;i--){
      var p = this.particles[i];
      p.run();
      if(p.isDead()){
        this.particles.splice(i,1);
      }
    }
    this.lifespan -= 1;
  }
};

function mousePressed(){
  if(systems.length < total){
    newSystem = new ParticleSystem(createVector(mouseX,mouseY));
    systems.push(newSystem);
  }
  else{
    newSystem = new ParticleSystem(createVector(mouseX,mouseY));
    systems[counter%total] = newSystem;
  }
  counter += 1;
  console.log(counter);
}

Assistive Technology Week 1

EverydayUseofTech_part1

EverydayUseofTech_part2

Stella Young’s I am not your Inspiration

In this talk Stella Young discusses her feelings towards the often uttered phrase “you inspire me” and how much it legitimately confuses and offends her. In her own words, she isn’t doing anything remarkable, she’s just getting up and living her life day by day like the rest of us are.

Aimee Mullen’s My 12 Pairs of Legs

This was quite an interesting piece when it comes to taking the normal discussions of disability and assistive technology and really flipping them on their head. Usually the discussion is framed as giving disabled individuals back the abilities they had before they were disabled or the abilities of other “normal” individuals. Aimee Mullen brings the conversation to the idea of augmentation and the extra abilities or aesthetics her legs give her that non-disabled people don’t have access to. I do find this piece a bit too ideal, it is a great case study and one off story, but taken fully at face-value it may lead an inidividual to think that the conversation about disability has completely flipped and disabled individuals don’t need extra assistance or attention at a societal or individual level. One piece of information I found the most interesting however is her account of her interaction with children at a school. I do fully agree that the stigma that many have against the disabled as one of fear and misunderstanding is a learned response. Young children have nothing but curiosity towards the unknown. While this may often clash with our classical perceptions of good manners, their actions have no malice behind them. Its not until they’re told to hush up and be respectful that they are taught there is a true divide or something to be feared or disgusted with.

Paralympics Least Favorite Word: Inspiration

This piece falls right in line with the points discussed in Stella Youngs Ted Talk. I have a high school classmate who is a paralympic swimmer and I am sure these remarks would apply just as aptly to his own story. He posted a lot on facebook about the journey to Rio, all the qualifiers, diets, training, travel, everything that went into his eventual big races, and if you hadn’t seen the pictures of him swimming without a right leg, there’d be no way for you to know that this was the story of a paralympic swimmer as opposed to someone there just a month before for the olympics. The journey was the same, as was the time and effort he put in, he should inspire people in my community for that, not for the detail that he did all this with a slightly different body.

All Technology is Assistive

Another piece that takes a commonly held discussion and frames it in a very different way. I really enjoyed this piece and its look at redifining what we think of as assistive technology in an attempt to remove any stigma that goes along with it. What it says is definitely true that all technology we work with is created for the purpose of assisting us in some task or another, why else would it exist? With this in mind, the discussion shifts from those types of technology, assistive and “normal” to yet another specific demographic or audience that such technology is designed for.

Writing code on a laptop with only aceessibility settings

I do a lot of coding both for school and work and began to wonder if I would still be able to do my job with out some of the senses or abilities I take for granted. First I thought about what I need the most to be able to code. Losing my hearing wouldn’t really impact my ability to interact with the computer and write into my text editor. Losing sight however, that would be a massive hindrance. I decided to use a virtual machine running Ubuntu as that is my normal working environment and I wanted to see how it held up to more popular operating systems like OSX and Windows. The goal: write a simple for-loop with my eyes closed.

Off the bat, the access menu was pretty lackluster. There was a screen reader, mouse keys, and not much else. Definitely a step down from other operating systems in terms of number of options. I played around with the screen reader and it was hard to get used to. Once I figured out how to open and close files with it, it wasn’t too hard to write the code itself mainly due to muscle memory on the keyboard. All in all, the task took me about half an hour with most of the time being figuring out the screen reader, but I could see it taking much longer if the person had to rely on clicking different locations on the screen instead of doing everything through the terminal or with keybindings and macros.

I then decided to try another experiment. What if I had very little fine motor skills? I could see waht was happening and read the screen, but I couldn’t get my hands to properly interact with the keyboard as I can now. I decided to set up mouse keys and try to write a for loop with just mouse keys controlling the mouse on screen and using it to select buttons on an onscreen keyboard, as this could be an approximation of how someone might use a keyboard with this rig connected to their head or other limb they can move. This process took forever. It was extremely slow and mistakes were costly. The slowness of it often prompted me to rush and then make more mistakes which took a long time to correct.

While these accessibility options are available, they are oftne far from intuitive, easy to use, and definitely not enjoyable. That being said, they are an interface like any other so as I used it more my abilities would increase and speed of the processes. But while they may be janky and slower than my normal expectations of computer interaction, it is great that they exist and offer some sort of interface for many people that wouldn’t have one otherwise.

 

Bouncing Ball Documentation

For this week’s assignment, I fixed some of the issues with the bouncing ball code we worked on in class. The first issues was to make sure the gravity applied correctly, which was solved by simply placing the statement that changed the y value to under the the checks for if the ball was out of bounds or not.

Once that was done the ball acted normally on the yaxis, but after it was stuck at the bottom, it would go back and forth forever. This is at odds with what would normally happen in a system as the ball would eventually slow down and stop. To fix this I set the xspeed value to xspeed = xspeed * .999 for each frame to simulate energy leaving the system. This caused the ball to slow down in its movement from left to right as time went on. The only issue is it never really stopped because it was constantly decreasing, but multiplication of the number would never results in 0 (unless I left it on for a REALLY long time and it either ran out of bit space in the numbers it was storing the speed in, but honestly I’m not sure if that would result in it just reaching the limit of small number and staying there, rounding down to 0, or having digit overflow occur and giving a really big number instead) so I added a final conditional that just set the value of xspeed to zero when its absolute value was less than .3.

All in all it works like a normal ball would in that system now, I’d like to expand on it more in the future though and have more than a single ball bouncing around.

var x, y;
var xspeed, yspeed;
var gravity;
var direction;

function setup() {
  createCanvas(600, 400);
  x = width / 2;
  y = height / 2;
  xspeed = random(-1, 1) * 10;
  yspeed = random(-1, 1) * 10;
  gravity = 1.0;
}

function draw() {
  background(0);



  x = x + xspeed;
  y = y + yspeed;


  if (x < 0) {
    x = 0
    xspeed *= -1;
  }
  if (x > width) {
    x = width;
    xspeed *= -1;
  }
  if (y < 0) {
    y = 0;
    yspeed *= -1;

  }
  if (y > height) {
    yspeed *= -1;
    y = height;

  }
    if(Math.abs(xspeed)>.3){
      xspeed = xspeed*.999;
    }
    else{
      xpseed=0;
    }
    print(xspeed);
    yspeed += gravity;


  ellipse(x, y, 30, 30);
}

Digital Farm Final – PlantMail

For my final project I originally planned to extend my midterm, which was focused on a completely closed system for growing plants. One small feature I had planned was for the plant to be able to message you and tell you to add more water or food or anything to the system when that was necessary. Once I started working on this feature however, I found it to be more interesting than the rest of the system. While my original idea was to explore how little user interaction I could rely on, this instead focused on pushing the interaction to 11, to the point that your plant was now sending you email messages and complaining about you on its twitter account.

The first step was to figure out which API’s and services I would be using. I focused mainly on email and twitter in this project (more social media could easily be added as well, but for the sake of time and proof of concept I started with these) and decided on working with Mailgun for the email service and tweepy, a set of python wrappers for the twitter API which I had used in past projects. These were pretty easy to set up and I quickly had some mock code to trigger the sending of the email and tweets.

The next step was to figure out how to make Python and Processing talk to each other. To do so, I set up a mock server on python and then had processing act as a client to that server. Even though they were both run locally, this seemed to be the quickest and simplest option. With a bit of basic socket programming, the two talked to each other just fine.

The final major step was to figure out how to gauge the plant’s levels. I used arduino sensors and decided to monitor 3 levels: UV, temperature, and moisture. The big issue here was how unreliable temperature and UV were when taken a snapshot of. To remedy this, I set those values to take the average over the observation period. For presentation purposes the observation intervals were lowered to a minute to give a quicker example, however in actual use, it should have at least an hour to get an accurate reading of the conditions.

With each individual part in place, I was ready to put it together. The following is a basic architecture diagram of the process. PlantMail Architecture Map (1)

Overall I am pleased with the project. If I continue it in the future there are a few issues to remedy. First, I want a more extensive vocabulary for the plant. The results are currently a set of three, so options for speech are limited. I would like to either make this a more sliding scale or add more options to each outcome and have it choose randomly. As it stands, it doesn’t have to feel of giving the plant a personality when it simply goes through if else statements and has only 9 speech possibilities. The other issue is that of outliers. When taking the average of reading with arduino, since I average it over the observation time period, the room could technically be freezing cold for half and hour then burning hot for half an hour and it would report as just fine. I should include a log that reports any individually extreme results.

 

// python code

import socket
import requests
import tweepy

consumer_key = "jXUSVWtNT2qkcjL80Gvlmy7FQ"
consumer_secret = "gRdUvWRUJs1kFSNSul0i8i3ZLhigN3t5lKMhs7qyOJ5h0XF2eS"

access_token = "831141872202502144-00boHhZVKmk1xO4ipunsm3VTfggPGpE"
access_secret = "c1nnaNb5bEx4LtjBKAmctlHShZGaqbovbpHLgtLLiXxRL"

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token,access_secret)

api = tweepy.API(auth)             

curTemp = -1
curUV = -1
curMoist = -1

def send_email(text):
    print("email sent")
    return requests.post(
        "https://api.mailgun.net/v3/sandbox1f65f03f51814fc18ab6231dd72fbde0.mailgun.org/messages",
        auth=("api", "key-36dd7247883ea5bb74c12c83ec18829c"),
        data={"from": "Mailgun Sandbox <postmaster@sandbox1f65f03f51814fc18ab6231dd72fbde0.mailgun.org>",
              "to": "Sam Arellano <msa455@nyu.edu>",
              "subject": "Hello Sam Arellano",
              "text": text})
    
    
def form_message(moist,temp):
    tempMessage = ""
    if moist == 2:
        tempMessage += "I'm drowning over here. "
    elif moist == 0:
        tempMessage += "I could use a bit of water, I'm parched. "
    
    if temp == 2:
        tempMessage += "It's burning up in here. Turn on the ac or something! "
    elif temp == 0:
        tempMessage += "Could you grab me a blanket or something? I'm freezing. "
    
    if temp == 1 and moist == 1:
        tempMessage = "Honestly, I can't complain. I'm feeling great"
    
    return tempMessage

def form_email(moist,temp):
    tempMessage = ""
    if moist == 0:
        tempMessage = "Hey man, I could really use some water. I'm feeling parched."
    elif moist == 2:
        tempMessage = "I'm kinda drowning over here, mind draining me out a bit?"
    elif temp == 0:
        tempMessage = "Mind turning on the heater? I'm about to become an ice cube."
    elif temp == 2:
        tempMessage = "I'm about to fry, turn on the ac or something!!"
    return tempMessage
#store your api key below
key = "key-36dd7247883ea5bb74c12c83ec18829c"
#designate your host and port info
#the blank host info designates it will accept any host
host = ''
port = 5555



#determine if this is first connection for the client
firstConnect = True

#create socket object s
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#attempt to bind the socket object to the designated host and port
#if there is a failure, print the error
try:
    s.bind((host,port))
except socket.error as e:
    print(str(e))
#listen for the processing client to connect to the server
s.listen(1)
print("waiting for a connection...")


while True:    
    conn, addr = s.accept()
    #on initiation notify the client they connected
    if(firstConnect):
        conn.send(str.encode("Server and client connected"))
        print("Server and client connected")
        firstConnect = False
    while True:           
        #notify server side of connection info
        print('connected to: ' + addr[0]+":"+str(addr[1]))
        #create a new thread for server client communication

        data = conn.recv(2048)
        message = (data.decode("utf-8"))
        print(message)
        statuses = message.split(",")
        curUV = int(statuses[0])
        curMoist = int(statuses[1])
        curTemp = int(statuses[2])
            
        newUpdate = form_message(curMoist, curTemp)   
        print(newUpdate)
        try:
            api.update_status(status = newUpdate)
            print("tweeted")
        except:
            pass
        
        if(curMoist == 0 or curTemp == 0 or curTemp == 2):
            email = form_email(curMoist, curTemp)
            print(email)
            send_email(email)
        reply = ("Server: " + message)
   
        print(curUV)
        print(curMoist)
        print(curTemp)

        if not data:
            s.close()
            break

        
// processing code
import processing.net.*; 
import processing.serial.*;
import processing.video.*;
//initiate the client, capture  and serial objects
Client myClient;
Serial myPort;

int curMessage;
int curTemp;
int curUV;
int curMoist;


String messageToSend;
int newMessage;
//this string will be used as a sort of buffer for processing to designate
//where it stored the file to
int newIssue = 0;
void setup() { 
  size(640, 480); 
  myPort = new Serial(this, Serial.list()[0],9600);
  
  //initialize the client on home ip with same port as python server 
  //(the port is arbitrary, just has to be the same as the server)
  myClient = new Client(this, "127.0.0.1", 5555); 
  
  //setup communication to arduino
  //myPort = new Serial(this, "COM6", 9600);
  //setup webcam to take frames from stream
}

void draw() { 
  //read the camera stream and display that in the window
//  image(cam,0,0);

  //check the client is active. Then check if the string value has been changed
  //if the string value has been changed, send that value to the python server
  //then reset the string value to empty
  while(myPort.available() > 0){
    curMessage = myPort.read();
    checkMessage(curMessage);
    print("n");
    newIssue = 1;
    messageToSend = str(curUV) + "," + str(curMoist) + "," + str(curTemp);
  }
  //return server output after it has processed the file
  //*TO DO*: handle dropped client connections 
  if (myClient.active()) {
    if (newIssue == 1) {
      myClient.write(messageToSend);
      newIssue = 0;
    }  
    String cur = myClient.readString();
    if (cur != null) {
      println(cur);
    }
  }
//  println(frameCount);
} 

void mouseClicked() {
  if(mouseX > width/2 && mouseY > height/2){
    myClient.stop();
  }
}

void checkMessage(int message){
  if(message == 'a'){
    curUV = 2;
    print("High UV");
  }
  else if(message == 'b'){
    curUV = 1;
    print("Medium UV");
  }
  else if(message == 'c'){
    curUV = 0;
    print("Low UV");
  }
  else if(message == 'd'){
    curMoist = 2;
    print("High Moisture");
  }
  else if(message == 'e'){
    curMoist = 1;
    print("Medium Moisture");
  }
  else if(message == 'f'){
    curMoist = 0;
    print("Low Moisture");
  }
  else if(message == 'g'){
    curTemp = 2;
    print("High Temperature");
  }
  else if(message == 'h'){
    curTemp = 1;
    print("Medium Temperature");
  }
  else if(message == 'i'){
    curTemp = 0;
    print("Low Temperature");
  }
}

//arduino code

int uvSensorPin = A0;
int uvSensorValue;
int moistSensorPin = A1;
int moistSensorValue;
int tempPin = A2;
int tempValue;
int curMessage = 0;
int moistHigh = 400;
int moistMed = 25;
long uvHigh = 75000;
long uvMed = 40000;
int tempHigh = 30;
int tempMed = 20;

void setup(){
  Serial.begin(9600);
  pinMode(uvSensorPin, INPUT);
  pinMode(moistSensorPin,INPUT);
  pinMode(tempPin, INPUT);
}

void loop(){
  long uvSum = 0;
  long moistSum = 0;
  long tempSum = 0;
  
  for(int i = 0; i<1024;i++){
    uvSensorValue = analogRead(uvSensorPin);
    uvSum = uvSensorValue + uvSum;
    moistSensorValue = analogRead(moistSensorPin);
    moistSum = moistSensorValue + moistSum;
    tempValue = analogRead(tempPin);
    tempSum = tempValue + tempSum;
    delay(2);
  }

  long uvMean = uvSum / 1024;
  long moistMean = moistSum / 1024;
  long tempMean = tempSum / 1024;
  float cel = ((tempMean/1024.0)*5000)/10;
  float uv = (uvMean*1000/4.3-83)-21;

  //Serial.print("Current UV index is: ");
  //Serial.print((uvMean*1000/4.3-83)-21);
  //Serial.print(",");
  //Serial.print("n");
  //Serial.print("Current moisture level is: ");
  //Serial.print(moistMean);
  //Serial.print(",");
  //Serial.print("n");
  //Serial.print("Current temperature is: ");
  //Serial.print(cel);
  //Serial.print("n");
  
  if(uv > uvHigh){
    Serial.write('a');
  }
  else if(uv < uvHigh && uv > uvMed){
    Serial.write('b');
  }
  else{
    Serial.write('c');
  }

  if(moistMean > moistHigh){
    Serial.write('d');
  }
  else if(moistMean < moistHigh && moistMean > moistMed){
    Serial.write('e');
  }
  else{
    Serial.write('f');
  }

  if(cel > tempHigh){
    Serial.write('g');
  }
  else if(cel < tempHigh && cel > tempMed){
    Serial.write('h');
  }
  else{
    Serial.write('i');
  }
  
  //Serial.write((uvMean*1000/4.3-83)-21);
  //Serial.write(",");
  //Serial.write(moistMean);
  //Serial.write(",");
  //Serial.write(cel);
  
  delay(120000);
}