Skip to content

Commit

Permalink
Fast Forward.... 4 years later... (#13)
Browse files Browse the repository at this point in the history
* hopefully more accurate

* some spellchecking and cleaning, also fixing CLI

* fixed whitespace

* testing new functionality for motor drivers and automatic current setting

* squashing bugs

* bug fixin

* no functionality added, just cleaning code

* added sensor reset for magnetometer

* works pretty well, needs some control theory and finishing touches

* hopefully didn't break anything, hopefully made system faster/more responsive

* Updated

Updated with previous edits to remove unnecessary branches.

* Added Arduino Code and README

Added new folder that includes code and README description for Arduino. The purpose is for the Arduino to interact with the magnetometer.

---------

Co-authored-by: PandnotPthereforeQ <[email protected]>
Co-authored-by: jejor <[email protected]>
Co-authored-by: Cordet <[email protected]>
  • Loading branch information
4 people authored Feb 12, 2023
1 parent 5fcdc16 commit 652c9e6
Show file tree
Hide file tree
Showing 13 changed files with 386 additions and 109 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ __pycache__/
*.so

# Distribution / packaging
.vscode
.Python
build/
develop-eggs/
Expand Down
49 changes: 49 additions & 0 deletions Arduino_Comms/COMMS_README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
COMMS_README.TXT

This document is the decode key to "ArduinoComms.py" and "PSAS_HHCage.ino"

General:
The arduino will initialize the magnetic sensor (if present) and listen on USB-Serial (115200) for one byte messages from the Raspberry PI / Python. The Arduino will control 3 H-bridges (X,Y,Z) and interact with a magnetometer (MMC5603). Some commands from the PI will recieve a serial data return.

Note that decode values are case sensitive.The following are the commands the arduino is listening for without any serial data returned:
x - Activate X H-bridge in Positive Polarity
y - Activate Y H-bridge in Positive Polarity
z - Activate Z H-bridge in Positive Polarity
X - Activate X H-bridge in Negative Polarity
Y - Activate Y H-bridge in Negative Polarity
Z - Activate Z H-bridge in Negative Polarity
a - De-activate all H-Bridges (X,Y,Z)
b - De-activate X H-Bridge
c - De-activate Y H-Bridge
d - De-activate Z H-Bridge
The following are the commands the arduino is listening for with a serial data return:
m - Request current magnetic field reading
Data return is "X,Y,Z" magnetic field in uT.
The values of each value X,Y,Z can be positive or negative
Here is an example return: "1000.05,-200.33,500.79"
Note: Refer to the nomen on the magnetometer to interpret positive and negative field directions
q - Request magnetometer status
Data return is "0" -- magnetometer not initialized
"1" -- magnetometer is initialized
note: magnetometer is initialized on setup/startup of arduino script. Restarting the serial interface will reset the arduino and will attempt re-initialization. If failures persist inspect wiring to sensor and the physical sensor.
s - Request H-Bridge Status:
Data return is "XYZ" where
X is X axis H-Bridge status
Y is Y axis H-Bridge status
Z is Z axis H-Bridge status
Each position can be 0, 1, or 2:
0: Bridge is de-activated
1: Bridge is activated in positive polarity
2: Bridge is activated in negative polarity
Example:
021
X axis H-Bridge is de-activated
Y axis H-Bridge is activated in negative polarity
Z axis H-Bridge is activated in positive polarity
t - Request Ambient Temperature from Magnetometer:
The magnetometer has a temperature sensor built in, might as well provide the ability to read it.
The Serial data return is in degrees Celsius:
##.##
Example: 17.80

# Credit to Christian Bennett (2022) for assisting with Arduino code and testing
154 changes: 154 additions & 0 deletions Arduino_Comms/PSAS_HHCage.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#include <Adafruit_MMC56x3.h>
/* Assign a unique ID to this sensor at the same time */
Adafruit_MMC5603 mmc = Adafruit_MMC5603(12345);

int xina = 6;
int xinb = 7;
int yina = 4;
int yinb = 5;
int zina = 2;
int zinb = 3;
int xstat = 0;
int ystat = 0;
int zstat = 0;
int magstat = 0;


int incomingByte = 0; // for incoming serial data

void setup() {
// put your setup code here, to run once:
pinMode(xina, OUTPUT);
pinMode(xinb, OUTPUT);
pinMode(yina, OUTPUT);
pinMode(yinb, OUTPUT);
pinMode(zina, OUTPUT);
pinMode(zinb, OUTPUT);
digitalWrite(xina,LOW);
digitalWrite(xinb,LOW);
digitalWrite(yina,LOW);
digitalWrite(yinb,LOW);
digitalWrite(zina,LOW);
digitalWrite(zinb,LOW);
Serial.begin(115200);


// Initialise the mag sensor */
if (mmc.begin(MMC56X3_DEFAULT_ADDRESS, &Wire)) { // I2C mode
magstat = 1;
//mmc.printSensorDetails();
}

}

void loop() {
// put your main code here, to run repeatedly:

// reply only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();

// say what you got:
// Serial.print("I received: ");
// Serial.println(incomingByte, DEC);
}
if (incomingByte != 0){
//Shutdown
if (incomingByte == 97){
digitalWrite(xina,LOW);
digitalWrite(xinb,LOW);
digitalWrite(yina,LOW);
digitalWrite(yinb,LOW);
digitalWrite(zina,LOW);
digitalWrite(zinb,LOW);
xstat = 0;
ystat = 0;
zstat = 0;
}
//X Bridge Off
if (incomingByte == 98){
digitalWrite(xina,LOW);
digitalWrite(xinb,LOW);
xstat = 0;
}
//Y Bridge Off
if (incomingByte == 99){
digitalWrite(yina,LOW);
digitalWrite(yinb,LOW);
ystat = 0;
}
//Z Bridge Off
if (incomingByte == 100){
digitalWrite(zina,LOW);
digitalWrite(zinb,LOW);
zstat = 0;
}
//H-Bridge Status message
if (incomingByte == 115){
Serial.print(xstat);
Serial.print(ystat);
Serial.println(zstat);
}
//mag Status message
if (incomingByte == 113){
Serial.println(magstat);
}
//positive "x"
if (incomingByte == 120){
digitalWrite(xinb,LOW);
digitalWrite(xina,HIGH);
xstat = 1;
}
//negative "X"
if (incomingByte == 88){
digitalWrite(xina,LOW);
digitalWrite(xinb,HIGH);
xstat = 2;
}
//positive "y"
if (incomingByte == 121){
digitalWrite(yinb,LOW);
digitalWrite(yina,HIGH);
ystat = 1;
}
//negative "Y"
if (incomingByte == 89){
digitalWrite(yina,LOW);
digitalWrite(yinb,HIGH);
ystat = 2;
}
//positive "z"
if (incomingByte == 122){
digitalWrite(zinb,LOW);
digitalWrite(zina,HIGH);
zstat = 1;
}
//negative "Z"
if (incomingByte == 90){
digitalWrite(zina,LOW);
digitalWrite(zinb,HIGH);
zstat = 2;
}
//mag reading
if (incomingByte == 109){
sensors_event_t event;
mmc.getEvent(&event);
Serial.print(event.magnetic.x);
Serial.print(",");
Serial.print(event.magnetic.y);
Serial.print(",");
Serial.println(event.magnetic.z);
}
//temp reading
if (incomingByte == 116){
sensors_event_t event;
mmc.getEvent(&event);
float temp_c = mmc.readTemperature();
Serial.println(temp_c);
}
//end of loop
incomingByte = 0;
Serial.flush();
}
}
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
PY=python3 -m py_compile
DRIVER=driver.py
SRC=driver.py cage_controler.py window.py utilities.py
SRC=driver.py cage_controller.py window.py utilities.py
GUIS=window.ui
GSRC=new_window.py

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
## oresat-helmholtz
# oresat-helmholtz

![alt text](https://user-images.githubusercontent.com/33878769/50576984-cde2d900-0dd2-11e9-8117-1c2e21f85c7d.png)

## Magnetic Environment Simulator for CubeSats
## Magnetic Environment Simulator for CubeSats

SOP can be found [here](http://psu-epl.github.io/doc/equip/testing/ETL/) at the Electronics Prototyping Lab website

![alt text](https://user-images.githubusercontent.com/33878769/48651456-dfe9f300-e9af-11e8-9a90-02227cccc314.jpg)


MCECS BETA Project 2018
62 changes: 44 additions & 18 deletions cage_controller.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,25 @@
import time # Stuff for regulated sensor delays
import smbus # Stuff for controlling temperature and magnetic sensors
import utilities as utils # Stuff for debugging and/or general info
from gpiozero import LED

WIRE_WARN_TEMP = 100 # Min cage wire temperatures in F for warning
WIRE_HCF_TEMP = 120 # Max cage wire temperatures in F for forced halting
pin = 'BOARD'

class Coil(): # controls for motor drivers
def __init__(self, psu_index):
self.in_a = LED(pin + utils.COIL_ADDRS[psu_index][0])
self.in_b = LED(pin + utils.COIL_ADDRS[psu_index][1])
self.positive()

def positive(self):
self.in_b.off()
self.in_a.on()

def negative(self):
self.in_a.off()
self.in_b.on()

class PowerSupply(serial.Serial):
def __init__(self, port_device, input_delay=utils.INPUT_DELAY, baudrate=9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=1):
Expand All @@ -18,6 +34,7 @@ def __init__(self, port_device, input_delay=utils.INPUT_DELAY, baudrate=9600, pa
self.timeout = timeout
self.warn_temp = 35 # Min cage wire temperatures in F for warning
self.halt_temp = 40 # Max cage wire temperatures in F for forced halting
self.coil = Coil(self.index())

utils.log(0, 'Initialized Power supply with the following:\n\tPort: ' + str(port_device)
+ '\n\tInput Delay: ' + str(input_delay)
Expand All @@ -26,18 +43,25 @@ def __init__(self, port_device, input_delay=utils.INPUT_DELAY, baudrate=9600, pa
+ '\n\tStop Bits: ' + str(stopbits)
+ '\n\tByte Size: ' + str(bytesize)
+ '\n\tTimeout: ' + str(timeout))
def index(self):
return int(self.port_device[-1]) # uses last character of device name for index

def toggle_supply(self, mode):
utils.log(0, 'Setting ' + self.name + ' to: ' + str(mode))
self.write(str("Aso" + str(mode) + "\n").encode())

def set_voltage(self, voltage):
utils.log(0, 'Setting ' + self.name + ' voltage to: ' + str(voltage) + ' volts.')
self.write(str("Asu" + str(voltage * 100) + "\n").encode())
self.write(str("Asu" + str(abs(voltage) * 100) + "\n").encode())

def set_current(self, amperage):
utils.log(0, 'Setting ' + self.name + ' current to: ' + str(amperage) + ' amps.')
self.write(str("Asi" + str(amperage * 1000) + "\n").encode())
self.write(str("Asi" + str(abs(amperage) * 1000) + "\n").encode())
self.amperage = amperage
if(amperage < 0):
self.coil.negative()
else:
self.coil.positive()

def check_temperatures():
utils.log(0, 'Checking ' + self.name + ' temperatures...')
Expand Down Expand Up @@ -84,17 +108,30 @@ def temperature_check_bounds(temp, warning, shutoff):
utils.log(1, "Reached maximum warning temperature! Auto-powering down the cage!")
toggle_all_power_supply(0)

# function to get magnetic field components from sensors
def magnetometer():
# see page 21 of https://www.nxp.com/docs/en/data-sheet/MAG3110.pdf
# "When asserted, initiates a magnetic sensor reset cycle that will restore
# correct operation after exposure to an excessive magnetic field"
# Value goes back to 0 after completion
def init_magnetometer():
# Get I2C bus
bus = smbus.SMBus(1)
time.sleep(utils.INPUT_DELAY)

# MAG3110 address, 0x0E(14)
# Select Control register, 0x10(16)
# 0x01(01) Normal mode operation, Active mode
bus.write_byte_data(0x0E, 0x10, 0x01)
time.sleep(utils.INPUT_DELAY)

# MAG3110 address, 0x0E(14)
# Select Control register2, 0x11(17)
bus.write_byte_data(0x0E, 0x11, 0b00010000)
time.sleep(utils.INPUT_DELAY)
return bus

# function to get magnetic field components from sensors
def magnetometer(bus):
time.sleep(utils.INPUT_DELAY)
# MAG3110 address, 0x0E(14)
# Read data back from 0x01(1), 6 bytes
# X-Axis MSB, X-Axis LSB, Y-Axis MSB, Y-Axis LSB, Z-Axis MSB, Z-Axis LSB
Expand Down Expand Up @@ -137,7 +174,7 @@ def temperature():
# 0x03(03) Resolution = +0.0625 / C
bus.write_byte_data(0x18, 0x08, 0x03)

time.sleep(0.2)
time.sleep(utils.INPUT_DELAY)

# MCP9808 address, 0x18(24)
# Read data back from 0x05(5), 2 bytes
Expand All @@ -154,7 +191,7 @@ def temperature():
bus.write_i2c_block_data(0x1c, 0x01, config)
bus.write_byte_data(0x1c, 0x08, 0x03)

time.sleep(0.2)
time.sleep(utils.INPUT_DELAY)

data = bus.read_i2c_block_data(0x1c, 0x05, 2)

Expand All @@ -166,14 +203,3 @@ def temperature():
temperature_check_bounds(ctemp1, WIRE_WARN_TEMP, WIRE_HCF_TEMP)
temperature_check_bounds(ctemp2, PSU_WARN_TEMP, PSU_HCF_TEMP)
return ctemp1, ctemp2

def poll_data(duration = 10.0, dt = 1.0):
time_step = [0.0]
# temp_array = [temperature()]
mag_array = [magnotometer()]
while time_step[-1] < duration:
time.sleep(dt)
time_step.append(time_step[-1] + dt)
# temp_array.append(temperature())
mag_array.append(magnotometer())
return time_step, mag_array #temp_array, mag_array
Loading

0 comments on commit 652c9e6

Please sign in to comment.